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.
SuperStrict
EnableOpenALAudio()
SetAudioDriver("OpenAL")
Graphics 500,30,0
Const cIDLE% = 0
Const cLISTEN% = 1
Const cRECORDING% = 2
Const cPLAYBACK_IDLE% = 3
Const cPLAYBACK% = 4
' create the openal sampler
Local Sampler:TOpenALSampler = TOpenALSampler.Create(44100,SF_MONO8) 'SF_STEREO16LE)
Local AudioSample:TAudioSample
Local Sound:TSound
Local Channel:TChannel
Global mode:Int = cIDLE
Repeat
Cls
Select mode
Case cIDLE ' idle, wait to start recording
DrawText("Idle... Press SPACE to start listing",10,10)
If KeyHit(KEY_SPACE)
AudioSample = Null
Sampler.Start
Mode = cLISTEN
EndIf
Case cLISTEN 'listen
DrawText("Listing...",10,10)
Case cRECORDING ' record
DrawText("Recording..."+Sampler.Size+" bytes",10,10)
Case cPLAYBACK_IDLE ' idle, wait to playback recorded sound
If Audiosample=Null Then AudioSample = Sampler.Stop()
DrawText("Recorded "+AudioSample.length+" samples - Press SPACE to start playback",10,10)
If KeyHit(KEY_SPACE)
Sound = LoadSound(AudioSample)
Channel = PlaySound(sound)
Mode = cPLAYBACK
EndIf
Case cPLAYBACK ' playing
DrawText("Playing... Press SPACE to stop playback",10,10)
If ChannelPlaying(Channel)=False Or KeyHit(KEY_SPACE)
StopChannel(Channel)
Mode=cIDLE
EndIf
EndSelect
Flip
Until AppTerminate() Or KeyHit(KEY_ESCAPE)
' ---------------------------------------------------------------------------------
' the sampler!
Type TOpenALSampler
Field ChunkList:TList = New TList
Field recordedsamplelength:Int
Field DefaultSpecifier:String
Field CaptureDevice:Int
Field oalFormat:Int
Field Format:Int
Field Hertz:Int
Field Timer:TTimer
Field Size:Int
Field silence:Int
' create a recorder
Function Create:TOpenALSampler(Hertz:Int=44100,Format:Int=SF_STEREO16LE)
Local This:TOpenALSampler = New TOpenALSampler
This.DefaultSpecifier = String.FromCString(alcGetString(Null, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) ; This.OpenALError
This.Hertz = Hertz
This.Format = Format
Print BytesPerSample[format]
' DebugStop()
Select Format
Case SF_MONO8 ; This.oalFormat = AL_FORMAT_MONO8
Case SF_MONO16LE ; This.oalFormat = AL_FORMAT_MONO16
Case SF_MONO16BE ; This.oalFormat = AL_FORMAT_MONO16
Case SF_STEREO8 ; This.oalFormat = AL_FORMAT_STEREO8
Case SF_STEREO16LE ; This.oalFormat = AL_FORMAT_STEREO16
Case SF_STEREO16BE ; This.oalFormat = AL_FORMAT_STEREO16
EndSelect
This.CaptureDevice = alcCaptureOpenDevice(This.DefaultSpecifier,Hertz,This.oalFormat,44100*16) ; This.OpenALError
Return This
EndFunction
' start recording
Method Start()
If Timer Return
Timer = CreateTimer(60)
AddHook EmitEventHook,eventhook,Self
alcCaptureStart(CaptureDevice) ; OpenALError
EndMethod
' stop recording and return a TAudioSample
Method Stop:TAudioSample()
StopTimer Timer ; Timer = Null
RemoveHook EmitEventHook,eventhook,Self
alcCaptureStop(CaptureDevice) ; OpenALError
CaptureAudioChunk ' flush remaining audio
Local samplesbank:TBank
Local AudioSample:TAudioSample = CreateAudioSample(size/BytesPerSample[format],hertz,format)
Local bptr:Byte Ptr = AudioSample.samples
For samplesbank=EachIn ChunkList
MemCopy(bptr,BankBuf(samplesbank),BankSize(samplesbank))
bptr:+BankSize(samplesbank)
Next
ClearList(ChunkList)
Size=0
Return AudioSample
EndMethod
Function eventhook:Object(id:Int,data:Object,context:Object)
Local Sampler:TOpenALSampler = TOpenALSampler(context)
If Sampler
Local event:TEvent = TEvent(data)
If Event.ID=EVENT_TIMERTICK And Event.Source=Sampler.Timer
Sampler.CaptureAudioChunk
EndIf
EndIf
Return data
EndFunction
Method CaptureAudioChunk()
Local recordedsamplelength:Int
alcGetIntegerv(CaptureDevice,ALC_CAPTURE_SAMPLES,4,Varptr recordedsamplelength) ; OpenALError
If recordedsamplelength
Local samplesbank:TBank = CreateBank(recordedsamplelength*BytesPerSample[format])
alcCaptureSamples(CaptureDevice,BankBuf(samplesbank),recordedsamplelength) ; OpenALError
If mode = cLISTEN Then
If isSound(samplesbank) Then 'a ha! There is someone.
mode = cRECORDING
ListAddLast(ChunkList,samplesbank)
Size:+BankSize(samplesbank)
End If
Else
If isSound(samplesbank) Then 'there is still noise
ListAddLast(ChunkList,samplesbank)
Size:+BankSize(samplesbank)
silence = 0 'reset silence counter
Else
silence:+1
If silence < 30 Then 'less than half a second
ListAddLast(ChunkList,samplesbank)
Size:+BankSize(samplesbank)
Else 'stop recording
mode = cPLAYBACK_IDLE
'I can remove the last 30 silent samplebanks from the list here to reduce sampleSize. I choose to remove 20.
'size:-BankSize(samplesbank) * 20
'don't know how to remove the last objects from ChunckList...
End If
End If
End If
EndIf
EndMethod
Method OpenALError()
Local result:Int = alcGetError(CaptureDevice)
If result<>0 RuntimeError "Sampler OpenAL Error Code = "+result
EndMethod
Method isSound%(samplesbank:TBank)
For Local i% = 0 To BankSize(samplesbank)-BytesPerSample[format] Step 8
If Abs(PeekByte(samplesbank, i)-128) > 15 Then Return True
Next
Return False
End Method
EndType