Hello,
My goal is to provide simple audio play thru (take audio from an input device and send it to an output device).
I was a little confused by the examples about PortAudio, because none seems to do exactly what I want. So I chose the 2 projects to send and receive audio over a network and am attempting to merge them.
My current code has two issues:
1: playback just gives a small noise at the beginning and then nothing.
2: after around 7 seconds, I’m getting an error with Buffer.AddFloatAudio; but the error number is 0 and the explanation is empty
Overall, I don’t have much clue about what’s wrong.
So, this is a console application and here’s my code with the values used for this test (I made sure to select the correct default devices in the OS, which happens to be Windows 10 for this project):
Class CInput, for recording the microphone
2 properties:
Public Property mb As MemoryBlock
Public Property Recorder As PortAudioStreamRecorderMBS
2 methods:
Public Function InitAudio() As Boolean
mb=newMemoryBlock(4*102400) // read maximum 102400 samples per timer loop
Recorder=new PortAudioStreamRecorderMBS(1024*1024*16)
dim e as integer=Recorder.OpenDefaultStream(1,8000.0)
if e=0 then
if Recorder.Start=0 then
Print "Recording started."
Return True //State is valid
else
Print "Failed to start audio recording."
end if
else
Print "Audio Error: "+str(e)+" with host error: "+str(Recorder.HostError.ErrorCode)+" "+Recorder.HostError.ErrorText
end if
End Function
Public Sub Destructor()
if Recorder<>nil then
call Recorder.Close
Recorder=nil //Probably not necessary, but taken from example
end if
End Sub
Class COutput, to send to the earphone
3 properties:
Public Property Buffer As PortAudioStreamBufferedMBS
Public Property LastTime As Double
Public Property pa As PortAudioMBS
3 methods:
Public Function InitAudio() As Boolean
dim e as integer
pa=new PortAudioMBS
Buffer=new PortAudioStreamBufferedMBS
Buffer.NoUnderflow=True
e=Buffer.OpenDefaultStream(1,8000.0)
if e=0 then
Return True //State is valid
else
Print "Audio Error: "+str(e)+" with host error: "+str(Buffer.HostError)
end if
End Function
Public Sub ProcessNext(Data As MemoryBlock)
//Called manually to process the next frame
if Buffer=nil then Return
if Data=nil or Data.Size=0 then Return //Empty
if not Buffer.AddFloatAudio(Data) then
Print "Failed to play audio! "+Buffer.HostError.ErrorCode.ToString
else
if Buffer.IsStreamActive<>1 then
var e as integer=Buffer.Start
if e<>0 then. Print "Audio Error: "+str(e)
end if
end if
dim n as double=Data.Size/4
Print "Received "+str(n)+" frames. "+str(floor(n/((Microseconds-LastTime)/1000000.0)))+" frames/s"
LastTime=Microseconds
End Sub
Public Sub Destructor()
if Buffer<>nil then call Buffer.Close
End Sub
And finally, this is the app.Run event:
var PInput As CInput
var POutput As COutput
PInput=new CInput
if not PInput.InitAudio then
Print "Input not inited."
Return 1
end if
POutput=new COutput
if not POutput.InitAudio then
Print "Output not inited."
Return 2
end if
var StartTime As Integer=System.Ticks //Loop for some seconds only
do
if System.Ticks-StartTime>1000 then exit //10 seconds for testing
var l as integer
// we ask for samples in the buffer
l=PInput.Recorder.ReadFrames(PInput.mb,PInput.mb.Size)
if l>0 then
POutput.ProcessNext PInput.mb
Print "Sending "+str(l)+" frames."
end if
app.DoEvents //I tried with or without it
loop
Print Input //Prevent the console window from automatically closing so I can see the printed strings
This is a new area for me so I’m puzzled. Is a console app not suitable for this or I’ve implemented it inappropriately?
Advices greatly appreciated.