Listen with openAL
BlitzMax Forums/BlitzMax Programming/Listen with openAL
| ||
In topic record with openAL we've addressed the option of recording sound with Bmax/OpenAL. I want to have my BlitzMax program to listen if there is coming a signal from the microphone and if there is start recording as fast as possible. The recording should last untill there is no more sound for (let's say) 700ms or after 10 seconds. How can I do that? I hope you have some bright ideas! |
| ||
I would really love this too. As I posted in that thread I have a project where I'm recording sounds in Blitz. Currently it starts recording when the person presses a button, but having it record automatically would be much better. Incidentally, there was another thread I posted in shortly after that one where REDi provided code to record without the need for an addon framework: http://www.blitzmax.com/Community/posts.php?topic=74048#831031 |
| ||
My thoughts on this... You'd need to have openal recording all the time, then check each captured chunk of audio for activity, if you find some then store that chunk to a list, if you dont find activity and there is chunks in the list already then build the sample and clear the list. Hope that makes sense mate, bit baked ATM lol. If you have any trouble give me a shout, always happy to help. |
| ||
@ REDi: At the moment I have no idea how to execute most of the steps you suggest. Specially the steps: - check for activity (?) - build sample from list (?) I'll need to dig in the OpenAL commands to find out. Your sample code in the treat jhocking mentioned is a nice starting point, though. Btw. I wonder how much processor time is consumed by this approach. @jhocking: thanks for the tip and if you come up with something... let me know. edit: I think I can solve this! Right now I have other obligations :( I hope to find some time over the weekend to look at this. |
| ||
- check for activity (?) cycle through the samples in the audio data and check if sample[i]<>0 (or maybe abs(sample[i])>5 or something to eliminate low level static), you could also get away with a step of 16 or so to reduce cpu usage. build sample from list (?) code for that is already in that TOpenALSampler type I posted (in the Stop method). Good luck mate :) |
| ||
About the "check for activity"step... I would like to follow your advice to cycle through the samples but I don't know how to do that. I presume in the folowing method the variable samplesbank contains the audio data. Is that correct? samplesbank is a TBank type. But how do I read the data in this data bank? Something like: For Local i:Int = EachIn samplesbank 'do something like If Abs(i) > 5 then ... Next But the local i must be an Object so this will not work. |
| ||
I came up with this modification:For Local i% = 0 To BankSize(samplesbank)-BytesPerSample[format] 'Step 16 Local sample% = PeekInt(samplesbank, i) Print sample NextI don't get a compiling error but I have no idea what the values mean. I think I have to do something with the audio format, right? |
| ||
Ok. I have made a demo with 8 bits mono recordings. Eventually I will use high quality mono sound recording. @REDi: many thanks for you sample code! Now I have all the puzzle pieces to complete my project. |
| ||
Nice one Kistjes, its coming on a treat :) This might be of some help... Function SignedByte:Int(unsignedbyte:Byte) Local signed:Int = unsignedbyte If signed>127 Then signed:-256 Return signed EndFunction |
| ||
oo I'll have to check this out later, could be just what I need! |
| ||
BTW Kistjes, there is another error in your isSound method... but I wont subtract your fun by giving you the answer :P |
| ||
Ok, I'll try your SignedByte function. But after that I'll focus on the SF_MONO16LE format. Apart from that I don't see the error in the isSound method. It runs through the sampledata (the Step 8 speeds this process a little bit up) and as soon as it finds an audiolevel above a certain threshold (in this method 15) it returns true otherwise false. |
| ||
Cool mate, you'll realize when you do SF_MONO16LE anyway ;) |
| ||
Here is my MONO16LE format isSound method:'mono16le format Method isSound%(samplesbank:TBank) Local sound% For Local i% = 0 To BankSize(samplesbank)-BytesPerSample[format] Step 8 sound = PeekByte(samplesbank, i) | (PeekByte(samplesbank, i+1) Shl 8) If Abs(sound - 32768) < 32000 Then Return True Next Return False End Method Tell me REDi, what's wrong with it? It works fine here! ;-p |
| ||
hmm nearly! That (byte[i]|byte[i+1] shl 8)-32768 is giving you an incorrect value, you'll need to PeekShort for 16bit audio and then convert it to a signed short (like I did for bytes) Anyway, did you miss my hint on my original post about the error ;) Why Minus BytesPerSample from BankSize??? :P |
| ||
Function SignedShort:Int(unsignedshort:Short) Local signed:Int = unsignedshort If signed=>32768 Then signed:-65536 Return signed EndFunction |
| ||
That (byte[i]|byte[i+1] shl 8)-32768 is giving you an incorrect value, you'll need to PeekShort for 16bit audio and then convert it to a signed short (like I did for bytes) Ok thats a good tip. But it seems to work, though. Ah, you call that an error :p If I leave out the minus part I get an index out of range error because I do a peekbyte(samplesbank, i+1) With your suggestion of using PeekShort there is no need of doing that anymore, I suppose. One more question. Now I have my correct recorded sample, how can I save that to an ogg-file? I can only find a LoadAudioSample() function. |
| ||
Just knocked this up for ya (not tested). I used a short pointer instead of peekshort...Method isSound16Bit%(samplesbank:TBank) Local sptr:Short Ptr = Short Ptr(BankBuf(samplesbank)) For Local i% = 0 Until BankSize(samplesbank)/BytesPerSample[format] Step 8 If Abs(SignedShort(sptr[i]))>15 Then Return True Next Return False End Method Notice the divide ;) As for saving to ogg vorbis There is a SaveOgg command ready to use. |
| ||
Ok. My new isSound method for MONO16LE format:'mono16le format Method isSound%(samplesbank:TBank) Local sound% For Local i% = 0 To BankSize(samplesbank) Step 8 sound = SignedShort(PeekShort(samplesbank, i)) If Abs(sound) > 500 Then Return True Next Return False End Method Now I only have to figure out how to do the SaveAudioSample() |
| ||
Cool mate, That'll do the job, Nice one! :D |
| ||
Oops my mistake, I thought the oggsaver module was standard but its actualy one of skidracers modules, so if you dont have it already you'll need to synchronize modules and tick the AXE checkbox to get it. *EDIT* Just noticed in the last code you posted, you may need to replace that "To" with an "Until" to stop you from reading out of bounds memory. |
| ||
I found out I already have the oggsaver module installed. So a simple Import axe.oggsaver line at the top of my demo did the trick. Many thanks for helping me out. |
| ||
My pleasure Kistjes, good luck with your project mate. |
| ||
Just tested your code (and made the modifications posted to do 16 bit sound) and it works great. Awesome work man, thanks for sharing! |