B4A Library AudioTrack

This is a wrapper library for the AudioTrack Object, simlar to the AudioRecord object, it's more complex to use than the MediaPlayer but has some functionality that is useful for audio processing.

I haven't had time to test this one thoroughly, I thought you may like to play with it as well. Let me know if you find anything that doesn't work.

The attachment is quite big as it has an example wav file that is loaded via a random access file and played via Audiotrack, just to give an idea.

Edit: V1.01 fixed a typo and Separate file for libs only
17/1/12 Added swt.zip, quick and dirty sine wave generator as an example.
Added swt1-1.zip a few more refinements.
Added swt1-2.zip better tuning
Updated lib files to 1.2 - needed for swt1-2
13/2/12 Added and reformatted Constants - audiotrack1.3
19/3/12 Updated SWT to reach 19khz and added input fields (touch the display labels)

15/1/21
  • Added attest2
  • Updated example with a Stream Static and looping example.
  • Replaced threading with Wait For and Sleep in the streaming example. For heavy usage, it may still be necessary to use threading, so I'll leave the original example here as well.
 

Attachments

  • attest.zip
    305.8 KB · Views: 1,701
  • AudioTrack1.3.zip
    7.8 KB · Views: 1,858
  • swt1-3.zip
    8.5 KB · Views: 1,496
  • attest2.zip
    298.4 KB · Views: 517
Last edited:

yo3ggx

Active Member
Licensed User
Longtime User
To be more specific, I'm talking about an Android stick (MK-802) to be used as remote audio device, connected through WiFi to an Android smartphone/tablet, both running a b4a application for low latency duplex audio streaming.
The OS version is 4.0.4 (uberoid flavour)

Some details about how to make it work for the mic part here:
How to use Skype on an MK802 Android Mini PC

Installing USBAudioTester application from Play store, selecting the USB sound device and a loop between mic and headphone I can hear myself in the headphones, so for sure there are drivers installed.

Now I have to find how can the audio source be selected in AudioTrack library.

I am so close...:)
Dan
 

stevel05

Expert
Licensed User
Longtime User
Unfortunately I don't think it's going to be as simple as that. I think the apps that give access to the usb devices use the USB accessory mode which is part of the USB library the example given deals with a host connection. That's the place to start. There's some more info on the Android Developers site.

Let us know how you get on.
 

Rusty

Well-Known Member
Licensed User
Longtime User
Hi Steve,
Rusty here again...different thread.
I was able to chain a playlist of audio files using both mediaplayer and the SoundPool library.
I recently found this discussion of audiotrack.
In order to smoothly blend multiple small audio tracks (currently .mp3), would it be possible with the Audiotrack library? Also, could the files be "blended"/merged within a playable stream within memory (no write to a file)?
Regards,
Rusty
 

stevel05

Expert
Licensed User
Longtime User
Hi Rusty,

The audio track library only works with raw audio, and has no encoder/decoder.

From API 16 (JellyBean) it is apparently possible to access MediaCodecs on order to do this, it will require a wrapper library for B4A.

But if you are only using short audio files, then using wav files may not cause any problems due to the size of the files. Bearing in mind that the compresed file format only saves storage, to play the files they still need to be decompressed in memory.

And yes, the process you require can be done in memory and streamed without needing to be written to a file first.
 
Last edited:

kentco

Member
Licensed User
Longtime User
Hi

Been playing with this library but i have a question, in the SWT demo files there is a subroutine
B4X:
Sub Play_Ended(endedOK As Boolean,Error As String)

how is this routine triggered? The problem i am having is that this is not triggered every time the playsound is complete. the code should just loop and the tone will repeat. sometimes it will and sometimes may only get 2 or 3 loops. is there any better way of detecting when the sound has been completed?

B4X:
Sub PlayBtn_Click
    CreateSineWave2
    'Play the sound on a separate thread
    Play.Start(Null, "PlaySound",Array As Object(DurSB))
End Sub

Sub PlaySound(Duration As Int)

    'Start playing (will wait for data to arrive)
    at.Play
    'Set the volume
    at.SetStereoVolume(at.GetMaxVolume,at.GetMaxVolume)

    'Label1.Text = CycleSh100.Length
    'how many cycles make up the required duration?
    Loops=Frequency*Duration/1000
   
        'Write the complete loops
        For i = 0 To Loops
            at.WriteShort(CycleSh100,0,CycleSh100.Length)
        next
End Sub


Sub Play_Ended(endedOK As Boolean,Error As String)
Play.Start(Null, "PlaySound",Array As Object(DurSB))
End Sub


Thanks Colin
 

stevel05

Expert
Licensed User
Longtime User
Play_Ended is en event of the Threading Library and is called when the thread Play terminates. It should be called every time it finishes, but I didn't test it under this situation. You may need to incorporate a slight delay before restarting the thread. You could try this with a timer if you need to.

Other alternatives would be to set a notification marker (see the initialization method in the documentation here or you could check the Playstate within a timer to see if the audiotrack is still playing.

The SineWave code was really designed as a quick experiment for playing sine waves as part of a discussion and is not the best place to start if you want to build an app.

For your experimentation, the best way to extend the playing time, would be to increase the Duration passed to Playsound.
 

kentco

Member
Licensed User
Longtime User
Play_Ended is en event of the Threading Library and is called when the thread Play terminates. It should be called every time it finishes, but I didn't test it under this situation. You may need to incorporate a slight delay before restarting the thread. You could try this with a timer if you need to.

Other alternatives would be to set a notification marker (see the initialization method in the documentation here or you could check the Playstate within a timer to see if the audiotrack is still playing.

The SineWave code was really designed as a quick experiment for playing sine waves as part of a discussion and is not the best place to start if you want to build an app.

For your experimentation, the best way to extend the playing time, would be to increase the Duration passed to Playsound.

Just putting a slight delay solved the problem thanks for the help
 

cmartins

Member
Licensed User
Longtime User
Hi steve

I have a square wave input using the mic, I would like to measure the frequency of this waves, but the frequency is variable, is it possible?
 

stevel05

Expert
Licensed User
Longtime User
The easy answer is yes, the raw data is available. Analyze the data in the buffer and count the leading edge of the wave as it crosses zero, and use an averaging algorithm.

In practice I suspect that this may take too much processing time to be achieved effectively on an Android device in Java. There are discussions in the internet and there may also be more appropriate / effective methods. You may be able to find a C library to do the heavy lifting which will then need to be wrapped for use with B4a.
 

shaxboz

Member
Licensed User
Longtime User
Parsing code. 0.00
Compiling code. Error
Error compiling program.
Error description: Missing parameter.
Occurred on line: 66
Play.Start("Playing",True)
Word: )
 

stevel05

Expert
Licensed User
Longtime User
The Threading library has changed since this was written, you need to change it to Play.Start(Null,"Playing",True)
 

stari

Active Member
Licensed User
Longtime User
The Threading library has changed since this was written, you need to change it to Play.Start(Null,"Playing",True)
stevel05, i have question: how can i make player with variable speed. I wish to play wav normal and faster, eg 50 times faster. Is this possible ?
 

stevel05

Expert
Licensed User
Longtime User
It is not possible to do it directly, you would need a library, something like soundtouch by surina.net.
 

giacomo-italy

Member
Licensed User
Longtime User
I need to generate a sound (simple sine wave form) but i want to change its frequency and its amplitude in a continuous manner,
while the sound is continuosly generated.
I tried with AudioStreamer library without success.
Some noise and 'click' are present in the sound generated.
If I play in changing the parameters with the seek-bar, i can listen the problem of noise described above,
and i can listen the problem of:
- if i reduce 'duration' parameter i can variate more continuosly the freq and vol parameters, but noises ('click') are incremented
- if i increment the 'duration' parameter the noises are reduced, but i can not variate in continuosly way the parameters freq and gain...

I am far far away to a generation of sound like this:
https://play.google.com/store/apps/details?id=com.sokin.android.leon

Is there an alternative way to generate a sound and change frequency and amplitude, in a continuos way, while the sound is generated (to obtain an effect type like 'theremin' described in the link above)?
I want to change its frequency and its amplitude in a continuous manner, while the sound is continuosly generated.

It is possible with AudioTrack (modifying the audiotracktest code)?
Any ideas to do this?

Thanks a lot
 

moster67

Expert
Licensed User
Longtime User
@giacomo-italy

I really don't understand the subject of your question that much (I haven't looked into it to be fair) but just out of curiosity I googled and found quite a few sources available for apps that emulate "theremin". Here is one source:

https://shkspr.mobi/blog/2012/06/optical-theremin-demo/

Looking at the sources it seems like it indeed uses the AudioTrack object which stevel05 kindly wrapped in this thread. I noted that many methods and properties used in the source-code linked above are also available in this wrapper.

If you study the source-code linked (perhaps the genTone method), maybe you can implement in B4A what you are looking for...
I for sure don't have the knowledge to help you further though :)

Also this link may be helpful:
http://stackoverflow.com/questions/2413426/playing-an-arbitrary-tone-with-android
 

giacomo-italy

Member
Licensed User
Longtime User
Thank you for reply.

I have modified the sinewavetest for continuous suond generation, based on AudioTrack lib.

I posted here the project.

Please look it.

The problem is not solved.
Some discontinuity as noise and 'click' are present in the sound generated.

If you play in changing the parameters with the seek-bar, you can listen the problem of noise described above,
and you can listen the problem of:
- if you reduce ‘dur’ parameter you can variate more continuosly the ‘gain’ and ‘freq’ parameters, but noises and discontinuity ('click') in the sound are incremented
- if you increment the ‘dur’ parameter the noises are reduced, but you can not variate in continuosly way the parameters...
 

Attachments

  • SineWaveTest-continuous generation.zip
    398 KB · Views: 293

stevel05

Expert
Licensed User
Longtime User
As I said, I don't have much time at the moment, I'll try to take a look in the next couple of days.
 

moster67

Expert
Licensed User
Longtime User
I don't understand this stuff but did you add amplitude ramp up and ramp down to avoid the clicks as suggested in the SO-thread? Maybe that code will work to solve at least the clicks?
 

stevel05

Expert
Licensed User
Longtime User
I have had a quick look, but not had time to write a complete example yet. You should be using the Audiotrack loop facility with a Static mode to play smooth looped sounds, you then only need to fill the buffer once with the data you want to play for each frequency / amplitude.

Clicks can be introduced by a variety of problems, as Moster67's response intimates, when a new sound i played when the wave value is not zero (known as zero crossing) and when the buffer is not filled quickly enough between playing.

Using the loop avoids this possibility, you can then create a new buffer full of data while the current sound is playing, then stop and start the Audiotrack with the new data. You only need to create and loop one cycle in the buffer, although the buffer should be at least the size of the minimum required buffer (the rest of the buffer will contain 0's) so that the Audiotrack will play.
 
Last edited:
Top