B4A Library AudioRecord Library

This is an Audio Recording Library based on the Android AudioRecord object which allows capturing of sound input to a data file for further processing (maybe realtime if we're lucky).

Included in the demo program is a WAV file header routine that allows saving captured sound as an uncompressed wav file.

Please read the documentation of the AudioRecord object. It's a little more complicated that the media recorder version, but gives additional flexibility.

Please test it and hopefully we can get it to work well for us.

Added libs 1.01 - Additional constants and Capitalized

12/6/2012 Artest updated to better manage thread on closedown.

For use with V2 of B4a (more specifically the latest threading library) you'll need to add a parameter to the start thread call in artest. Line 89, Record.Start("Recording",Null) becomes Record.Start(Null,"Recording",Null)

artest 1155
 

Attachments

  • AudioRecord1.01.zip
    4.9 KB · Views: 2,853
  • artest1.02.zip
    8.2 KB · Views: 1,071
Last edited:

stevel05

Expert
Licensed User
Longtime User
Updated library to 1.01 with additional and capitalized constants
 

JohnC

Expert
Licensed User
Longtime User
This looks very promising - I will be writing my first android app in about a month and it needs to record audio - so I will let you know how your lib works out!
 

AHilton

Active Member
Licensed User
Longtime User
In my tests today, it seems to be working fine except for playback within your sample. It just sounds like background noise.

However, when I try playing the wav file directly (through a file manager app that opens up my phones' native media player), it plays just fine.

Atrix4G, Android 2.3.6
B4A 1.80
AudioRecord library 1.01
 

stevel05

Expert
Licensed User
Longtime User
I don't see that behaviour, the recorded sound plays back via the standard MediaPlayer. And it works OK on my HTC hero.

Have you tried playing any other files with the Mediaplayer?
 

AHilton

Active Member
Licensed User
Longtime User
Never mind. I forgot to include the "Audio" library. After doing that, it worked fine. On with testing ...
 

AHilton

Active Member
Licensed User
Longtime User
In my attempts to combine your AudioRecord library (for saving a wav file) and your AudioTrack library (for streaming it out with some audio effects immediately afterward), I've run into a problem.

Simply copying code from each of your examples and doing very minor placement so that one would run before the other, not having media player doing the playback and so on, produced really good results.

My attempts to streamline everything by moving code around and grouping things where (I thought) they should go has caused a problem. I'm now getting a very short "pop" and "squelch" (like the CB radios) sounds at the beginning of each AudioTrack playback.

Any ideas before I start all over and try to get it back to where I started?
 

stevel05

Expert
Licensed User
Longtime User
The only thing that springs to mind without seeing your code would be if you are not skipping the WAV header when you play back the file.

Any sort of random or pseudo random data will generate a sound similar to white noise.

If you'd like to post your code, zip it from the file menu first, I'd be happy to take a look.
 

AHilton

Active Member
Licensed User
Longtime User
Yeah, that's what I was thinking, too. Somehow, that the wav header wasn't getting skipped properly. But, I left that code in there and even played around with the positioning (ie pos=44) a little; to no avail.

I also thought that the multiple threading (one for recording, the other for playing) might have been interfering with each other because that's mainly what I was messing with when I started getting this 'squelch' sound.

What's weird, though, is that on the initial record/play pass, it gives just a little 'pop' sound on playback. No big deal. On subsequent passes, it gives that 'squelch' sound.

I'll play around with it a bit more today and if I can't get it going, I'll post the code. Thanks for the help.
 

AHilton

Active Member
Licensed User
Longtime User
It has something to do with the multiple threading because instead of having the end of the recording thread (rec_ended method) calling the start of the playing thread to immediately playback what was said, I've put those commands to start the threads in a button and there's no problem.

So, I'll go in and mess with the threading to see if I can block things better now.
 

stevel05

Expert
Licensed User
Longtime User
A delay of a second or two may do the trick. Easy to test with a timer.
 

AHilton

Active Member
Licensed User
Longtime User
Yep. I threw out all of the other threading and just ran them both (record and play) on one thread. It still had the problem. So, I threw in a 500ms delay between the playback of one recording to the recording of a new sample and that fixed it.

I'm assuming that the recording was picking up the last few ms of playback of the previous recording because the AudioTrack android streaming processes are delaying a little bit.
 

AHilton

Active Member
Licensed User
Longtime User
Since I have it worked out how to combine AudioRecord (sending recorded audio to a wav file) and AudioTrack (reading that wav file and streaming it back out immediately after recording), I'm going to play around with getting things near-realtime between these two.

Could you tell me more about the SetPositionNotificationPeriod method ? I think (big guess here) I'm after something like the Android AudioRecord.setRecordPositionUpdateListener but I don't see it in your library.

I've never really messed with audio before (databases and communications are my specialties) and so it's fun to try new things ... and on a completely new programming environment, to boot!
 

stevel05

Expert
Licensed User
Longtime User
Yes I tried messing about with the libraries, realtime is not quite a reality yet until Android has a realtime kernal. But it can come close, the thing to watch out for is matching the buffer sizes and feedback, with the mic and speakers in the same box it doesn't take a lot of volume. The lower the sample rate you can live with the quicker it will be.

I only really know what is on the android developers website and haven't used these libraries a lot yet. The documentation is here.

The AudioRecord.setRecordPositionUpdateListener is driven by the method setPositionNotificationPeriod and calls AudioRecord_PeriodPassed when the period (in frames) has elapsed.

Similarly SetNotificationMarkerPosition will call AudioRecord_MarkerPassed.

Let us know how you get on.
 

AHilton

Active Member
Licensed User
Longtime User
After a day of messing with this, I couldn't get it to work reliably. Note: I'm just talking about getting a realtime or near-realtime link between the AudioRecord and AudioTrack.

Basically, the AudioRecord.ReadBytes is just too slow to keep data flowing into a buffer for AudioTrack.WriteByte to play back out smoothly. If AudioTrack.WriteByte doesn't have a steady flow of bytes to stream out, you get pops and cracks in the sound making it unusable.

I was giving AudioRecord a whole bunch of frames (about 5 seconds worth of a 10 second total) of a headstart in one thread to fill a buffer before starting the AudioTrack thread to read from that buffer and AudioTrack very quickly would overwhelm what AudioRecord was feeding it. I could see in the log I kept of data recorded/played from each thread, that AudioRecord would keep up for a little bit but quickly fall behind and then AudioTrack would be starved and waiting for bytes to stream out.

If nothing else from this weekends' playtime, I learned a bit more about b4a's threading, collections, linked lists and, of course, the fine AudioRecord and AudioTrack libraries. Thanks for the help, stevel05. I'm going to backtrack to where it's doing the recording and then the playing completely separately (although not writing to a wav file anymore as when I first started out).
 

stevel05

Expert
Licensed User
Longtime User
This was as close as I got to passing a signal through. Attempting any kind of manipulation broke the process, although I didn't persevere with that for too long. I will probably come back to it at some stage.
 

Attachments

  • audtest.zip
    6.5 KB · Views: 687

AHilton

Active Member
Licensed User
Longtime User
As is usually the case, a few seconds after I posted my last message, I thought of something. I started playing around with the record (AudioRecord) buffers and the play (AudioTrack) buffers and I think I have something close to what I was after. It's very very tough for my ears to pick up what's going on because, to eliminate feedback, I'm using earbuds and trying to speak clearly while hearing myself delayed half a second!

I'll report back once I can verify this.
 

AHilton

Active Member
Licensed User
Longtime User
Yep. It's working as I thought. Finally. What I had to do was manipulate the record and play buffers differently so that the record buffer was much higher than the play. Record is twice or 3 times as much as the play. This allows the record thread to not have to as quickly get back to read that data. The play thread is doing more things more often, but in smaller chunks but it's not overwhelming the record thread this way.

So, now that THAT is worked out, I'm going to see if there's any room to do some processing of that signal between the time it's recorded, buffered and then sent out. There should be, since I'm buffering that data between threads anyway. It'll introduce a little delay (but I'm artificially introducing a delay right now so I'll take that out), but as long as I can keep the processing timing consistent once started, it might work out alright.

Our code is very similar, steve, except that I'm working with multiple threads instead of just the one in yours. Otherwise, it's scary just how close our little commented-out sections of different methods we tried are.
 

stevel05

Expert
Licensed User
Longtime User
Yes it's an interesting process, there is not a lot of information available on the internet about audio processing especially at a basic level, so there's a lot of trial and error to be done I think.
 

AHilton

Active Member
Licensed User
Longtime User
I was messing with the AudioTrack.SetPlaybackRate method at the same time I was doing all the rest and it seems that that was what was really kicking me. It changes how I had to do buffering and other things. Once I left that alone, I could figure out all the rest. Coming back to that and it messes with me again. But, at least I understand now how it all fits in.

I agree, not much information out there on working the raw data. Especially for someone who doesn't have a clue what I'm doing in that area = me. Fast Furior Transform (spelling?) has me cross-eyed. I'd love to be able to detect silence and also to filter out the background sounds, too. I'll keep plugging away at it today but tomorrow I have to get back to the real work.
 
Top