MiniAudio-Wrapper for BlitzMax enables WASAPI Playback and Recording + MP3

Started by Midimaster, April 23, 2021, 14:12:00

Previous topic - Next topic

Midimaster

There is a new update 1.25 of the miniaudio wrapper avaiable. You will find it here:

https://github.com/MidimasterSoft/BlitzMax-Miniaudio-Wrapper

Here are some of the new functions/features:
  • Capturing Audio from Hardware USB-Devices upto 32 channels simultanously

  • New extended ExTaudioSample object for handling 32bit and multichannel Samples

  • Converting TAudioSamples into ExTAudioSamples

  • List and Select all avaiable Devices

  • Redesign of the wrapper for simplified use of the Library

  • Detailed Help-File in BlitzMax with a lot of examples

Here are three code examples related to capture:

Simply Capture into old BlitzMax TAudioSample
Code (BlitzMax) Select
SuperStrict
Import mima.miniaudio

Graphics 400,300

' Setup of the device:
Const  HERTZ:Int = 48000

Global MiniAudio:TMiniAudio=New TMiniAudio

MiniAudio.OpenDevice( MiniAudio.DUPLEX, Miniaudio.FORMAT_S16, 1, HERTZ, MyCallBack)

' we need a TaudioSample for storing the incoming samples and a SHORT PTR to handle them
Global Recording:TAudioSample=CreateAudioSample( HERTZ*61,  HERTZ, SF_MONO16LE)  '60 seconds
Global RecordingRam:Short Ptr = Recording.Samples

Global WritePointer:Int, RecordMode%, Audio:TChannel
Local Music:TSound =LoadSound(Recording)
Audio=PlaySound(Music)

SetClsColor 255,255,255
Repeat
    Cls
DrawScreen
If MouseHit(1)
RecordMode=1-RecordMode
If RecordMode=0
Print "PLAY"
MiniAudio.StopDevice()
Local Music:TSound =LoadSound(Recording)
Audio=PlaySound(music)
Else
Print "RECORD"
ClearSample()
StopChannel Audio
WritePointer=0
MiniAudio.StartDevice()
EndIf
EndIf 
    Flip 0
Until AppTerminate()
Miniaudio.CloseDevice()


Function MyCallBack(a%, PlayBackBuffer:Short Ptr, RecordingBuffer:Short Ptr, Frames:Int)
' cares about not to overrun the TAudioSample-size:
If WritePointer>HERTZ*60 Then WritePointer=0

For Local i:Int=0 To frames-1
' fetch the sample:
Local value:Short   = RecordingBuffer[i]

' duplx it immediately:
PlayBackBuffer[i] = value

'and transfer it to the TAudioSample:
RecordingRAM[WritePointer+i] = value
Next
    WritePointer = WritePointer + Frames
End Function


Function ClearSample()
For Local i:Int=0 To HERTZ*60
RecordingRAM[i]=0
Next
End Function

Function DrawScreen()
...
End Function



Stereo Capture with high quality 32bit-Float and save to WAV-file
Code (BlitzMax) Select
SuperStrict
Import mima.miniaudio

Graphics 400,300

' Setup of the device:
Const    HERTZ:Int = 48000
Const CHANNELS:Int = 2

Global MiniAudio:TMiniAudio=New TMiniAudio

Global Recording:ExTAudioSample = ExTAudioSample.Create(HERTZ*61,  HERTZ, MiniAudio.FORMAT_F32, CHANNELS)
Print Recording.format
Print Recording.Hertz
Print Recording.channels
MiniAudio.OpenDevice( MiniAudio.DUPLEX, Miniaudio.FORMAT_F32, CHANNELS, HERTZ, MyCallBack)


Global WritePointer:Int, RecordMode%
SetClsColor 255,255,255
Repeat
    Cls
DrawScreen
If MouseHit(1)
RecordMode=1-RecordMode
If RecordMode=0
Print "PLAY"
MiniAudio.StopDevice()
MiniAudio.SaveExTAudioSample "MySong.WAV", Recording
Else
Print "RECORD"
Recording.Clear
WritePointer=0
MiniAudio.StartDevice()
EndIf
EndIf 
    Flip 0
Until AppTerminate()
Miniaudio.CloseDevice()
End


Function MyCallBack(a%, PlayBackBuffer:Float Ptr, RecordingBuffer:Float Ptr, Frames%)
' cares about not to overrun the ExTAudioSample-size:
If WritePointer>HERTZ*60 Then WritePointer=0

For Local i:Int=0 To frames-1
' fetch the sample:
Local value:Float   = RecordingBuffer[i]

' duplx it immediately:
PlayBackBuffer[i] = value

'and transfer it to the TAudioSample:
Recording.SampleFloat[WritePointer+i] = value
Next
    WritePointer = WritePointer + Frames

End Function




Function DrawDrawScreen()
...
End Function



8-Channel Capture from USB-hardware device and save as 8track-file
Code (BlitzMax) Select
' example to demonstrate MULTI-CHANNEL capturing audio with miniaudio
' and transfering datas to the NEW extended ExTAudioSample type
' Quality is FORMAT_S32 only for demonstration
' the DUPLEX will reduce the 8 channels to 2 "manually"
' when recording is stopped the ExTAudioSample is saved as a 8track-16bit WAV-file
' this make it necessary to convert from S32 to S16
SuperStrict
Import mima.miniaudio

Graphics 400,300

' Setup of the device:
Const    HERTZ:Int = 44100
Const CHANNELS:Int = 8

Global MiniAudio:TMiniAudio=New TMiniAudio

'only hardware devices can capture 8 channels. So connect your USB-device and select it with its ID:
Print   "Capture-Devices:"
Local i:Int
For Local DeviceName:String= EachIn MiniAudio.CaptureDevices()
Print  "ID=" + i + ": " + DeviceName
i=i+1
Next
Local MyUsbDevice:Int=1
Miniaudio.SelectDevices(-1,MyUsbDevice)


Global Recording:ExTAudioSample = ExTAudioSample.Create(HERTZ*61,  HERTZ, MiniAudio.FORMAT_S32, CHANNELS)
Print Recording.format
Print Recording.Hertz
Print Recording.channels
' use OpenDevice_II when Playback and Capture needs different parameters:
MiniAudio.OpenDevice_II( MiniAudio.DUPLEX, Miniaudio.FORMAT_S32, 2, Miniaudio.FORMAT_S32, CHANNELS, HERTZ, MyCallBack)


Global WritePointer:Int
Global RecordMode%

SetClsColor 255,255,255
Repeat
    Cls
DrawScreen
If MouseHit(1)
RecordMode=1-RecordMode
If RecordMode=0
Print "PLAY"
MiniAudio.StopDevice()
'this would easily save the wav with 32bit-INT:
MiniAudio.SaveExTAudioSample "MySong.WAV", Recording

' but we can also change the format during saving:
Local StreamID:MMStreamID = MiniAudio.OpenWavFile("My16bitsong.Wav" , Miniaudio.FORMAT_S16, CHANNELS, HERTZ)
MiniAudio.WriteWavFile StreamID, Recording.SampleInt, Recording.Frames, Recording.Format, CHANNELS, HERTZ
MiniAudio.CloseWavfile StreamID
Else
Print "RECORD"
Recording.Clear
WritePointer=0
MiniAudio.StartDevice()
EndIf
EndIf 
    Flip 0
Until AppTerminate()
Miniaudio.CloseDevice()
End


Function MyCallBack(a%, PlayBackBuffer:Int Ptr, RecordingBuffer:Int Ptr, Frames:Int)
If WritePointer > (HERTZ*60*CHANNELS) Then WritePointer=0

For Local i:Int=0 To Frames-1
For Local j:Int=0 To CHANNELS-1
' fetch the samples:
Local value:Int = RecordingBuffer[i*CHANNELS + j]

'and transfer it to the TAudioSample:
Recording.SampleInt[WritePointer+i*CHANNELS + j] = value
Next
' now route the 8 capture channels to only 2 playbak channels as you like:
' to prevent Distortion we divide each sample volume by 2
Local valueL:Int = RecordingBuffer[8*i+0]/2 + RecordingBuffer[8*i+1]/2 + RecordingBuffer[8*i+2]/2 + RecordingBuffer[8*i+3]/2
Local valueR:Int = RecordingBuffer[8*i+4]/2 + RecordingBuffer[8*i+5]/2 + RecordingBuffer[8*i+6]/2 + RecordingBuffer[8*i+7]/2
PlayBackBuffer[2*i+0] = valueL
PlayBackBuffer[2*i+1] = valueR
Next
    WritePointer = WritePointer + Frames*CHANNELS
End Function


Function DrawScreen()
...
End Function


Full example code can be downloaded form the GitHub repository!
...back from Egypt

Baggey

Absolutly awsome!

Got some more time to play with the sound side of my spectrum emulator

Ive down loaded mima.mod and extracted to  C:/Blitzmax/mod

when i try C:\BlitzMax\mod\mima.mod\miniaudio.mod\examples\PlayNoise.bmx

I am using Windows 10 and Blitzmax 1.5 I think it's called Vanilla

Code (blitzmax) Select
SuperStrict
Import mima.miniaudio

Graphics 800,600

' Setup of the device:
Global MiniAudio:TMiniAudio=New TMiniAudio
MiniAudio.OpenDevice( MiniAudio.PLAYBACK, Miniaudio.FORMAT_S16, 1, 48000, MyCallBack)



' now start it:
MiniAudio.StartDevice()
Global NOISE%=0, Zeit%=MilliSecs()
Repeat
Cls
DrawText "Kick LEFT MOUSE for NOISE",100,100
If MouseDown(1)
NOISE=1
Else
NOISE=0
EndIf
Flip 0
Until AppTerminate()
Miniaudio.CloseDevice()
End


Function MyCallBack(a%, PlayBuffer:Short Ptr, RecordingBuffer:Short Ptr, Frames%)
' here you manipulate the sound:
If NOISE=1
For Local i%=0 To frames-1
PlayBuffer[i]=Rand(-32000,+32000)
Next
EndIf
End Function


Im getting Compile Error Can't find interface for module 'mima.miniaudio'



:-[

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

So Ive tried in,

Blitzmax 1.5 ' It Dosent Work!  :'(

Works in Blitzmax NG  Thou? :-X

Any idea Why this dosent work in Blitzmax 1.5 or do the files need to be put into different places.

Kind regards Baggey
Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

Did you already build the modules?
What were the complate error mesages you received?


Also Hardcoal had problems using it with BlitzMax 1.50. Did you find his post already?
https://www.syntaxbomb.com/index.php/topic,8467.msg347050348.html#msg347050348

We could change some code lines to make it more compatible to BlitzMAX 1.50 too. But afterwards Hardcoal reported more issues and canceled futher testings.

We think the problems now are related to the reduced multi-thread-capabilities of old BlitzMax.
See this answer from Col:
https://www.syntaxbomb.com/index.php/topic,8467.msg347050389.html#msg347050389

Maybe he can write something here?
...back from Egypt

Baggey

My error messages are from the Output window! I don't know how to get a more detailed Log?



Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 Quad core 16GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Hardcoal

i tried to compile the  mima.miniaudio and it didnt work..

im using blitzmax vanilla

it gives me this error

►mima.miniaudio was scheduled to next iteration
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s: Assembler messages:
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:2: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:3683: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:93856: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:93857: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:93858: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:96818: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:97458: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:97672: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:98312: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:98408: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:99048: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:99144: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:99784: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:99880: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:100520: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:108021: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:108661: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:108757: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:109397: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:109493: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:110133: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:110229: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:110869: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:112495: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:113135: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:115440: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:116049: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:122339: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:148911: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:166658: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccpKnT8e.s:166805: Error: junk at end of line, first unrecognized character is `,'
Build Error: failed to compile D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c
►►►►mima.miniaudio was not built. See error information on latest attempt.
Code

Midimaster

Quote from: Hardcoal on August 06, 2021, 09:36:27
i tried to compile the  mima.miniaudio and it didnt work..

im using blitzmax vanilla



Sorry MiniAudio is for BlitzMax NG only. We tried to convert, but there a re too many problems. Maybe in the far future...

Problems are:

  • BlitzMax Vanilla has not full Threaded support

  • BlitzMax Vanilla does not compile with GCC-, but with FASM-Compiler

  • BlitzMax casting problems
...back from Egypt

Derron

Blitzmax vanilla compiles C stuff with GCC - hence the required MinGW installation (or a copy - if you use NGs BMK, which finds MinGW inside MinGW32 or MinGWx86 ...)

BlitzMax vanilla has threaded support - but requires you do do a threaded build while NG defaults to threaded builds.
Nonetheless the "buffer refill threads" could be kicked off from threads written in C.

For an example check these codes:
https://github.com/TVTower/TVTower/blob/master/source/Dig/base.sfx.soundmanager.freeaudio.bmx
https://github.com/TVTower/TVTower/blob/master/source/Dig/base.sfx.soundmanager.freeaudio.c

In essence you have the C code run your thread and on "tick" it calls back into the (non threaded built) blitzmax vanilla part.


bye
Ron

Midimaster

@derron

I can send you a list of problem I had when comping it with BlitzMax 1.50.

some of the problems I could already solve with compiler branches. But the list is still long, and always new message appear if old problems are solved.



Maybe we succedd in getting it run on BlitzMax 1.50 too...
...back from Egypt

Hardcoal

Its ok..

I dont expect people to convert things just for me lol..

ill manage somehow..

in the case of turning MP3 into wave ill just make something on NG and call it from BM 1.50
Code