Audio Synthesis

Mac OSX specific forum
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Audio Synthesis

Post by wilbert »

Wolfram wrote:Do you get the same effect on your system?
I haven't tried yet; don't know if I have a mono wave file to test with.

How does your sample callback procedure look ?
Did you modify it in the right way to only output mono samples ?
Windows (x64)
Raspberry Pi OS (Arm64)
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

hello,

I'm not sure why, but on my new system (OSX 10.13.6) this example does not work anymore.
After the MessageRequester() the program frees and I get no error.

I changed the structure and some typedefenitions to LONG, but it doesn't help.

Code: Select all

Structure AudioQueueBuffer Align #PB_Structure_AlignC
  mAudioDataBytesCapacity.l
  mAudioData.i
  mAudioDataByteSize.l
  mUserData.i
  mPacketDescriptionCapacity.l
  mPacketDescriptions.i
  mPacketDescriptionCount.l
EndStructure

ImportC "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
  AudioQueueAllocateBuffer(inAQ, inBufferByteSize.l, *outBuffer)
  AudioQueueDispose(inAQ, inImmediate = #True)
  AudioQueueEnqueueBuffer(inAQ, inBuffer, inNumPacketDescs.l = 0, *inPacketDescs = #Null)
  AudioQueueNewOutput(*inFormat, inCallbackProc, *inUserData, inCallbackRunLoop.i, inCallbackRunLoopMode.i, inFlags.l, *outAQ)
  AudioQueueSetParameter(inAQ, inParamID.l, inValue.f)
  AudioQueueStart(inAQ, *inStartTime = #Null)
  AudioQueueStop(inAQ, inImmediate = #True)
EndImport
I hope some one can help me.
macOS Catalina 10.15.7
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

I found the reason, I have to disable the debugger for the callback.
macOS Catalina 10.15.7
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

How can I stopp these stream if I reach the end of the sampleData.
I tried to call AudioStream_Start(), but then next time I press play the sound crackers.

Code: Select all

Procedure SampleCallback(*out.AudioStreamSamples)
  Protected i = 0
  While i < #AUDIOBUFFER_SAMPLES
    If SamplePos < NumSamples
      *out\ss[i]\l = WaveBuffer(SamplePos)\l
      *out\ss[i]\r = WaveBuffer(SamplePos)\r
      SamplePos + 1      
    Else
      AudioStream_Start() ;-This does not work as expected
      *out\ss[i]\l = 0
      *out\ss[i]\r = 0
    EndIf
    i + 1
  Wend
EndProcedure
[quote="wilbert"]@Wolfram,
There were multiple things wrong with your code.
Here's my attempt.

Code: Select all

EnableExplicit
;-AudioStream.pbi

#AUDIOBUFFER_SIZE = 8192
#AUDIOBUFFER_SAMPLES = #AUDIOBUFFER_SIZE >> 2



    #kAudioFormatFlagIsFloat                     = (1 << 0)     ;// 0x1
    #kAudioFormatFlagIsBigEndian                 = (1 << 1)     ;// 0x2
    #kAudioFormatFlagIsSignedInteger             = (1 << 2)     ;// 0x4
    #kAudioFormatFlagIsPacked                    = (1 << 3)     ;// 0x8
    #kAudioFormatFlagIsAlignedHigh               = (1 << 4)     ;// 0x10
    #kAudioFormatFlagIsNonInterleaved            = (1 << 5)     ;// 0x20
    #kAudioFormatFlagIsNonMixable                = (1 << 6)     ;// 0x40
    #kAudioFormatFlagsAreAllClear                = (1 << 31)
    
    #kLinearPCMFormatFlagIsFloat                 = #kAudioFormatFlagIsFloat
    #kLinearPCMFormatFlagIsBigEndian             = #kAudioFormatFlagIsBigEndian
    #kLinearPCMFormatFlagIsSignedInteger         = #kAudioFormatFlagIsSignedInteger
    #kLinearPCMFormatFlagIsPacked                = #kAudioFormatFlagIsPacked
    #kLinearPCMFormatFlagIsAlignedHigh           = #kAudioFormatFlagIsAlignedHigh
    #kLinearPCMFormatFlagIsNonInterleaved        = #kAudioFormatFlagIsNonInterleaved
    #kLinearPCMFormatFlagIsNonMixable            = #kAudioFormatFlagIsNonMixable
    #kLinearPCMFormatFlagsSampleFractionShift    = 7
    #kLinearPCMFormatFlagsSampleFractionMask     = ($3F << #kLinearPCMFormatFlagsSampleFractionShift)
    #kLinearPCMFormatFlagsAreAllClear            = #kAudioFormatFlagsAreAllClear
    
    #kAppleLosslessFormatFlag_16BitSourceData    = 1
    #kAppleLosslessFormatFlag_20BitSourceData    = 2
    #kAppleLosslessFormatFlag_24BitSourceData    = 3
    #kAppleLosslessFormatFlag_32BitSourceData    = 4

    
Structure AudioStreamBasicDescription
  mSampleRate.d
  mFormatID.l
  mFormatFlags.l
  mBytesPerPacket.l
  mFramesPerPacket.l
  mBytesPerFrame.l
  mChannelsPerFrame.l
  mBitsPerChannel.l
  mReserved.l
EndStructure

Structure AudioQueueBuffer
  mAudioDataBytesCapacity.i
  mAudioData.i
  mAudioDataByteSize.i
  mUserData.i
  mPacketDescriptionCapacity.i
  mPacketDescriptions.i
  mPacketDescriptionCount.i
EndStructure

Structure AudioStreamStereoSample
  l.w
  r.w
EndStructure

Structure AudioStreamSamples
  ss.AudioStreamStereoSample[0]
EndStructure

ImportC "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
  AudioQueueAllocateBuffer(inAQ, inBufferByteSize, *outBuffer)
  AudioQueueDispose(inAQ, inImmediate = #True)
  AudioQueueEnqueueBuffer(inAQ, inBuffer, inNumPacketDescs = 0, *inPacketDescs = #Null)
  AudioQueueNewOutput(*inFormat, inCallbackProc, *inUserData, inCallbackRunLoop, inCallbackRunLoopMode, inFlags, *outAQ)
  AudioQueueSetParameter(inAQ, inParamID, inValue.f)
  AudioQueueStart(inAQ, *inStartTime = #Null)
  AudioQueueStop(inAQ, inImmediate = #True)
EndImport

Prototype AudioStream_Callback_Proto(*SampleData.Float)
Global AudioStream_Callback.AudioStream_Callback_Proto

Global *AudioStream_Buf1.AudioQueueBuffer, *AudioStream_Buf2.AudioQueueBuffer
Global AudioStream_Queue = 0

ProcedureC AudioStream_Callback_(*ptr, queue, *buf.AudioQueueBuffer)
  AudioStream_Callback(*buf\mAudioData)
  AudioQueueEnqueueBuffer(queue, *buf)
EndProcedure

Procedure AudioStream_Init(*Callback)
  AudioStream_Callback = *Callback
  Protected fmt.AudioStreamBasicDescription
  fmt\mSampleRate = 44100
  fmt\mFormatID = $6C70636D; kAudioFormatLinearPCM
  fmt\mFormatFlags = #kAudioFormatFlagIsPacked | #kLinearPCMFormatFlagIsSignedInteger
  fmt\mFramesPerPacket = 1
  fmt\mBytesPerFrame = 4
  fmt\mBytesPerPacket = 4
  fmt\mChannelsPerFrame = 2
  fmt\mBitsPerChannel = 16
  If AudioQueueNewOutput(@fmt, @AudioStream_Callback_(), #Null, #Null, #Null, 0, @AudioStream_Queue) = 0
    AudioQueueAllocateBuffer(AudioStream_Queue, #AUDIOBUFFER_SIZE, @*AudioStream_Buf1)
    AudioQueueAllocateBuffer(AudioStream_Queue, #AUDIOBUFFER_SIZE, @*AudioStream_Buf2)
    *AudioStream_Buf1\mAudioDataByteSize = #AUDIOBUFFER_SIZE
    *AudioStream_Buf2\mAudioDataByteSize = #AUDIOBUFFER_SIZE
  EndIf
EndProcedure

Procedure AudioStream_SetVolume(volume.f)
  If AudioStream_Queue
    AudioQueueSetParameter(AudioStream_Queue, 1, volume); 1 = kAudioQueueParam_Volume
  EndIf
EndProcedure

Procedure AudioStream_Start()
  If AudioStream_Queue
    AudioStream_Callback_(#Null, AudioStream_Queue, *AudioStream_Buf1)
    AudioStream_Callback_(#Null, AudioStream_Queue, *AudioStream_Buf2)
    AudioQueueStart(AudioStream_Queue)
  EndIf
EndProcedure

Procedure AudioStream_Stop()
  If AudioStream_Queue
    AudioQueueStop(AudioStream_Queue)
  EndIf
EndProcedure

Procedure AudioStream_Dispose()
  If AudioStream_Queue
    AudioQueueDispose(AudioStream_Queue)
    AudioStream_Queue = 0  
  EndIf
EndProcedure

;-Main


; XIncludeFile "AudioStream.pbi"
Define FileName.s = "/Users/YourNmae/Desktop/16bit_44100WAVE_Stereo.wav"
If OpenFile(1, FileName)
  Define FileSize.i = Lof(1)
  Global SamplePos = 44
  Global NumSamples = FileSize / SizeOf(AudioStreamStereoSample)
  Global Dim WaveBuffer.AudioStreamStereoSample(NumSamples)
  ReadData(1, @WaveBuffer(), FileSize)
  
  CloseFile(1)
EndIf


Procedure SampleCallback(*out.AudioStreamSamples)
  Protected i = 0
  While i < #AUDIOBUFFER_SAMPLES
    If SamplePos < NumSamples
      *out\ss[i]\l = WaveBuffer(SamplePos)\l
      *out\ss[i]\r = WaveBuffer(SamplePos)\r
      SamplePos + 1      
    Else
      *out\ss[i]\l = 0
      *out\ss[i]\r = 0
    EndIf
    i + 1
  Wend

EndProcedure

AudioStream_Init(@SampleCallback())
AudioStream_SetVolume(0.5)
AudioStream_Start()

MessageRequester("Audio Synthesis Demo", "Playing audio")

AudioStream_Dispose()
macOS Catalina 10.15.7
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Audio Synthesis

Post by wilbert »

Wolfram wrote:How can I stopp these stream if I reach the end of the sampleData.
I tried to call AudioStream_Start(), but then next time I press play the sound crackers.
Did you try AudioStream_Stop() as well ?
Windows (x64)
Raspberry Pi OS (Arm64)
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

wilbert wrote: Did you try AudioStream_Stop() as well ?
:)
Of cause I use AudioStream_Stop() not AudioStream_Stat()
I also tried AudioQueuePause(AudioStream_Queue), which works better and stopped the streaming immediately.
But alway it I call it from the callback I get crackle on the next playback.
This is not if I call the stop or pause function over a Button, it's only if I called from the SampleCallback().

EDIT:
if I use PostEvent() to call the AudioStream_Stop() function it works. But to me it looks like a workaround.
Or not?

Code: Select all

Procedure SampleCallbackOneShot(*out.AudioStreamSamplesMono)
  Protected i 
  
  i= 0
  While i < #AUDIOBUFFER_SAMPLES
    If viewData\pp <= viewData\sampleCount
      
      *out\s[i] = waveBuffer(viewData\pp)
      
      viewData\pp +1
    Else
      AudioStream_Pause() ;- Is needed otherwise the last Samples are not played.
      PostEvent(#eventStopAudio)
      
      While i < #AUDIOBUFFER_SAMPLES
        *out\s[i] =0
        
        i +1
      Wend
      
    EndIf
    
    i + 1
  Wend
  
 EndProcedure
macOS Catalina 10.15.7
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Audio Synthesis

Post by wilbert »

Wolfram wrote:if I use PostEvent() to call the AudioStream_Stop() function it works. But to me it looks like a workaround.
Or not?
It doesn't seem like a bad solution to me.

You could also try AudioQueueStop(AudioStream_Queue, #False) instead of AudioQueueStop(AudioStream_Queue) so it doesn't stop immediately. :?
Windows (x64)
Raspberry Pi OS (Arm64)
collectordave
Addict
Addict
Posts: 1309
Joined: Fri Aug 28, 2015 6:10 pm
Location: Portugal

Re: Audio Synthesis

Post by collectordave »

Hi All

Looked at tone matrix and it reminded me of something I wrote a while ago to play midi.

You can add notes and change instrument etc.

Right click on the matrix to add more notes where you want them.

https://www.dropbox.com/s/a1ztdaft4apyo ... i.zip?dl=0

Any use?

Regards

CD
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

After getting more problems with the first code I switched to Wilbert's "AUHAL" version wich seams to work fine and faster.
But I don't understand how to use the AudioUnitSetProperty()???
I want to switch the playback sampleRate to a 32000 and could find any information how to do it.

May be this helps someone else: https://github.com/alfredh/baresip/comm ... a86c03579e
macOS Catalina 10.15.7
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

Got it!

Code: Select all

#kAudioFormatFlagIsBigEndian                 = (1 << 1)
#kAudioFormatLinearPCM = $6C70636D
#kAudioFormatFlagIsPacked                    = (1 << 3)
#kAudioFormatFlagIsSignedInteger             = (1 << 2) 
#kLinearPCMFormatFlagIsSignedInteger         = #kAudioFormatFlagIsSignedInteger
#kAudioUnitProperty_StreamFormat = 8

#kAudioUnitScope_Output =2
#kAudioUnitScope_Input =1


fmt.AudioStreamBasicDescription

fmt\mSampleRate = 32000.0
fmt\mFormatID = #kAudioFormatLinearPCM 
fmt\mFormatFlags = #kAudioFormatFlagIsPacked | #kLinearPCMFormatFlagIsSignedInteger
fmt\mBytesPerPacket = 2
fmt\mFramesPerPacket = 1
fmt\mBytesPerFrame = 2
fmt\mChannelsPerFrame = 1
fmt\mBitsPerChannel = 16

AudioUnitSetProperty_(Audio_Unit, #kAudioUnitProperty_StreamFormat, #kAudioUnitScope_Input, 0, @fmt, SizeOf(AudioStreamBasicDescription))
macOS Catalina 10.15.7
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Audio Synthesis

Post by wilbert »

Wolfram wrote:Got it!
That's great :)

I also updated the other constants that are used in this post
viewtopic.php?p=494443#p494443
Maybe it makes more sense this way. :wink:
Windows (x64)
Raspberry Pi OS (Arm64)
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

Great, so it's getting more clear.

Do you know how to put a AU PlugIn into the stream?
macOS Catalina 10.15.7
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Audio Synthesis

Post by wilbert »

Wolfram wrote:Do you know how to put a AU PlugIn into the stream?
Sorry, I don't know.
Do you have plugins you want to use ?
Windows (x64)
Raspberry Pi OS (Arm64)
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Audio Synthesis

Post by Wolfram »

wilbert wrote: Do you have plugins you want to use ?
Yes, I have some plugins. But I could find an example how to pass the audio data thru it.
Maybe AudioUnitRender(_:_:_:_:_:_:) is a starting point.

You should have also some have some AU plugins. I guess there are some default plugins from Apple.
Run terminal auval -a to get a list.

Edit:
or run these code

Code: Select all

ImportC ""
  AudioComponentGetDescription(comp.i, *outName)
  AudioComponentCopyName(comp.i, *outName)
  AudioComponentCount(*outName)
EndImport

ImportC "-framework CoreServices"
  CFStringCreateWithCString(alloc, cStr.p-utf8, encoding = $8000100)  
  MDItemCopyAttribute(item, name)
  MDItemCreate(allocator, path)
EndImport

Procedure.s getCFString(CFString.i)
  Protected CFStringLength.i = CFStringGetLength_(CFString)
  Protected Dim CharacterData.u(CFStringLength) 
  CFStringGetCString_(CFString, @CharacterData(), CFStringLength + 1, #kCFStringEncodingUTF8)
  ProcedureReturn PeekS(@CharacterData(), -1, #PB_UTF8)
EndProcedure

Structure AudioComponentDescription
   componentFlags.l
   componentFlagsMask.l
   componentManufacturer.l
   componentSubType.l
   componentType.l
 EndStructure
 
 #aufx = $61756678
 
ACD.AudioComponentDescription
ACD\componentType = #aufx

Define outName
Define count = AudioComponentCount(@ACD)

Repeat
  comp = AudioComponentFindNext_(comp, @ACD)
  If comp

    If Not AudioComponentCopyName(comp, @outName)
      
      Debug getCFString(outName)
    EndIf

  EndIf
  
  i +1
Until i =count
macOS Catalina 10.15.7
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Audio Synthesis

Post by wilbert »

Wolfram wrote:Yes, I have some plugins. But I could find an example how to pass the audio data thru it.
Maybe AudioUnitRender(_:_:_:_:_:_:) is a starting point.
Have you looked at AUGraph ?
It looks to me like you need to set up a graph to connect things.
Unfortunately I have no experience with AUGraph.
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply