Page 1 of 3

Audio Synthesis

Posted: Mon Feb 25, 2013 6:40 pm
by wilbert
The code below creates a simple audio stream for audio synthesis.
What it does is already possible using PortAudio but this is a native approach not requiring anything else.

Include file

Code: Select all

; AudioStream.pbi

#AUDIOBUFFER_SIZE = 16384
#AUDIOBUFFER_SAMPLES = #AUDIOBUFFER_SIZE >> 3

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.f
  r.f
EndStructure

Structure AudioStreamSamples
  StructureUnion
    s.d[0]
    ss.AudioStreamStereoSample[0]
  EndStructureUnion
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, Stereo = #False)
  AudioStream_Callback = *Callback
  Protected fmt.AudioStreamBasicDescription
  fmt\mSampleRate = 44100
  fmt\mFormatID = $6C70636D; kAudioFormatLinearPCM
  fmt\mFormatFlags = 1; kAudioFormatFlagIsFloat
  fmt\mFramesPerPacket = 1
  fmt\mBytesPerFrame = 8
  fmt\mBytesPerPacket = 8
  If Stereo
    fmt\mChannelsPerFrame = 2
    fmt\mBitsPerChannel = 32
  Else
    fmt\mChannelsPerFrame = 1
    fmt\mBitsPerChannel = 64
  EndIf
  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

Re: Audio Synthesis

Posted: Mon Feb 25, 2013 6:42 pm
by wilbert
Example code (mono)

Code: Select all

EnableExplicit

XIncludeFile "AudioStream.pbi"

Global Phase.d

Procedure SampleCallback(*out.AudioStreamSamples)
  Protected i = 0
  While i < #AUDIOBUFFER_SAMPLES
    *out\s[i] = Sin(Phase) / 6
    Phase + 0.06
    i + 1
  Wend
EndProcedure

AudioStream_Init(@SampleCallback())
AudioStream_SetVolume(0.7)
AudioStream_Start()

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

AudioStream_Dispose()
Example code (stereo)

Code: Select all

EnableExplicit

XIncludeFile "AudioStream.pbi"

Global Phase.d

Procedure SampleCallback(*out.AudioStreamSamples)
  Protected i = 0
  While i < #AUDIOBUFFER_SAMPLES
    *out\ss[i]\l = Sin(Phase) / 6
    *out\ss[i]\r = Sin(Phase * 2) / 6
    Phase + 0.06
    i + 1
  Wend
EndProcedure

AudioStream_Init(@SampleCallback(), #True)
AudioStream_SetVolume(0.7)
AudioStream_Start()

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

AudioStream_Dispose()

Re: Audio Synthesis

Posted: Mon Feb 25, 2013 8:39 pm
by WilliamL
Thanks wilbert!

It works fine. Now just to figure out what to do with it... :)

Re: Audio Synthesis

Posted: Tue Feb 26, 2013 9:21 am
by J. Baker
Jiminy Cricket!!!

What ever you do, don't do "*output + 2" with headphones on.

Nice work wilbert! But I'll wait till day, when I don't need headphones on to fiddle around with it. ;)

Re: Audio Synthesis

Posted: Tue Feb 26, 2013 11:09 am
by wilbert
J. Baker wrote:What ever you do, don't do "*output + 2" with headphones on.
I made a similar mistake with speakers on; wasn't nice :shock:

Anyway, I changed the include file and example above.
I changed it so mono is 1 x 64-bit float and stereo is 2 x 32-bit float.
This way the number of samples is the same for both and with a structure union it is easier to access the samples (no need to increase a memory pointer).

@William,
Something like this would be nice http://tonematrix.audiotool.com
It's created by someone else using Flash but I suppose it should be possible to create something similar using the canvas gadget.

Re: Audio Synthesis

Posted: Tue Feb 26, 2013 7:02 pm
by WilliamL
wilbert,

tonematrix is a lot of fun and the site is a real time-waster :) I agree it looks like a canvas gadget waiting to happen.

I was listening to http://www.audiotool.com/track/yesterday-pa8gus/ ...enviro-synthesis (just made that up)

Re: Audio Synthesis

Posted: Tue Feb 26, 2013 8:35 pm
by J. Baker
wilbert wrote:
J. Baker wrote:What ever you do, don't do "*output + 2" with headphones on.
I made a similar mistake with speakers on; wasn't nice :shock:

Anyway, I changed the include file and example above.
I changed it so mono is 1 x 64-bit float and stereo is 2 x 32-bit float.
This way the number of samples is the same for both and with a structure union it is easier to access the samples (no need to increase a memory pointer).
Cool. ;)

Re: Audio Synthesis

Posted: Tue Feb 26, 2013 9:29 pm
by J. Baker
Hello? Who is it? :D

Code: Select all

EnableExplicit

XIncludeFile "AudioStream.pbi"

Global Phase.d

Procedure SampleCallback(*out.AudioStreamSamples)
  Protected i = 0
  While i < #AUDIOBUFFER_SAMPLES
    *out\s[i] = Sin(Phase) / 3
     If i / 500
       Phase + 0.35
     Else
       Phase + 0.25
     EndIf
    i + 1
  Wend
EndProcedure

Define Ring = 0

AudioStream_Init(@SampleCallback())
AudioStream_SetVolume(0.7)

Repeat
  
 AudioStream_Start()

  Delay(1000)

   AudioStream_Stop()

  Delay(100)

 Ring + 1

Until Ring = 2

AudioStream_Dispose()

Re: Audio Synthesis

Posted: Tue Feb 26, 2013 10:00 pm
by wilbert
@Joe, was that your phone ringing ? :wink:

@William, you are right, it is fun that tone matrix. Don't know if it would be hard to recreate using PB.

Re: Audio Synthesis

Posted: Thu Sep 15, 2016 12:03 pm
by wilbert
For MacroTune we used the hardware abstraction layer which is more low-level.

Code: Select all

ImportC ""
  AudioUnitSetVolume__(Unit, ID, Scope, Element, Value.f, BufferOffsetInFrames) As "_AudioUnitSetParameter"
EndImport

#kAudioDevicePropertyBufferFrameSize  = $6673697a; 'fsiz'
#kAudioFormatFlagIsPacked             = 8
#kAudioFormatFlagIsSignedInteger      = 4
#kAudioFormatLinearPCM                = $6C70636D; 'lpcm'
#kAudioUnitManufacturer_Apple         = $6170706C; 'appl'
#kAudioUnitProperty_SetRenderCallback = 23
#kAudioUnitProperty_StreamFormat      = 8
#kAudioUnitScope_Input                = 1
#kAudioUnitSubType_DefaultOutput      = $64656620; 'def '
#kAudioUnitType_Output                = $61756F75; 'auou'
#kHALOutputParam_Volume               = 14

Structure AudioComponentDescription
  componentType.l
  componentSubType.l
  componentManufacturer.l
  componentFlags.l
  componentFlagsMask.l
EndStructure

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

Structure AURenderCallbackStruct
  *inputProc
  inputProcRefCon.i
EndStructure


Global Audio_Unit.i

Procedure Audio_SetVolume(Volume); 0 - 100
  Protected factor.f
  If Volume
    factor = Pow(10, 40 * (Volume - 100) * 0.0005)
  EndIf
  AudioUnitSetVolume__(Audio_Unit, #kHALOutputParam_Volume, #kAudioUnitScope_Input, 0, factor, 0)
EndProcedure

Procedure Audio_Init(*CallbackFunction, BufferSize.l = 2048)
  
  Protected ACD.AudioComponentDescription
  Protected ASBD.AudioStreamBasicDescription
  Protected CallbackStruct.AURenderCallbackStruct
  
  ACD\componentType         = #kAudioUnitType_Output
  ACD\componentSubType      = #kAudioUnitSubType_DefaultOutput
  ACD\componentManufacturer = #kAudioUnitManufacturer_Apple
  
  ASBD\mSampleRate        = 44100
  ASBD\mFormatID          = #kAudioFormatLinearPCM
  ASBD\mFormatFlags       = #kAudioFormatFlagIsPacked | #kAudioFormatFlagIsSignedInteger
  ASBD\mBytesPerPacket    = 4
  ASBD\mFramesPerPacket   = 1
  ASBD\mBytesPerFrame     = 4
  ASBD\mChannelsPerFrame  = 2
  ASBD\mBitsPerChannel    = 16
  
  CallbackStruct\inputProc = *CallbackFunction

  AudioComponentInstanceNew_(AudioComponentFindNext_(#Null, @ACD), @Audio_Unit)
  AudioUnitSetProperty_(Audio_Unit, #kAudioUnitProperty_SetRenderCallback, #kAudioUnitScope_Input, 0, @CallbackStruct, SizeOf(AURenderCallbackStruct))
  AudioUnitSetProperty_(Audio_Unit, #kAudioUnitProperty_StreamFormat, #kAudioUnitScope_Input, 0, @ASBD, SizeOf(AudioStreamBasicDescription))
  AudioUnitSetProperty_(Audio_Unit, #kAudioDevicePropertyBufferFrameSize, #kAudioUnitScope_Input, 0, @BufferSize, SizeOf(Long))
  AudioUnitInitialize_(Audio_Unit)
  
EndProcedure

Procedure Audio_Start()
  ProcedureReturn Bool(AudioOutputUnitStart_(Audio_Unit) = 0)
EndProcedure

Procedure Audio_Stop()
  AudioOutputUnitStop_(Audio_Unit)
EndProcedure

Procedure Audio_Terminate()
  If Audio_Unit
    AudioOutputUnitStop_(Audio_Unit)
    AudioUnitUninitialize_(Audio_Unit)
    AudioComponentInstanceDispose_(Audio_Unit)
    Audio_Unit = 0
  EndIf
EndProcedure


; *** Audio test ***

Global Phase.f = 0
Global Phase_add.f = 0.1
Global Sample.w

ProcedureC Callback(*inRefcon, *ioActionFlags, *inTimeStamp, inBusNumber.l, inNumberFrames.l, *ioData)
  Protected i.i, *out.Word = PeekI(*ioData + SizeOf(Integer) + 8)
  While i < inNumberFrames
    Phase + Phase_add
    If Phase >= 2*#PI : Phase - 2*#PI : EndIf
    Sample = Sin(Phase) * 32767
    *out\w = Sample : *out + 2
    *out\w = Sample : *out + 2
    i + 1
  Wend
  ProcedureReturn 0
EndProcedure

Audio_Init(@Callback())
Audio_SetVolume(50)

If Audio_Start()
  MessageRequester("", "Click to close application")
  Audio_Terminate()
EndIf

Re: Audio Synthesis

Posted: Thu Sep 15, 2016 1:37 pm
by Wolfram
Hi Wilbert,

thanks for these example.
I try to use it to play back a WAVE file but it crashes.
Do you have any idea why?

Code: Select all

EnableExplicit
;-AudioStream.pbi

#AUDIOBUFFER_SIZE = 16384
#AUDIOBUFFER_SAMPLES = #AUDIOBUFFER_SIZE >> 3



    #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.f
  r.f
EndStructure

Structure AudioStreamSamples
  StructureUnion
    s.d[0]
    ss.AudioStreamStereoSample[0]
  EndStructureUnion
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, Stereo = #False)
  AudioStream_Callback = *Callback
  Protected fmt.AudioStreamBasicDescription
  fmt\mSampleRate = 44100
  fmt\mFormatID = $6C70636D; kAudioFormatLinearPCM
  fmt\mFormatFlags = #kAudioFormatFlagIsBigEndian ; #kAudioFormatFlagIsFloat
  fmt\mFramesPerPacket = 1
  fmt\mBytesPerFrame = 8
  fmt\mBytesPerPacket = 8
  fmt\
  If Stereo
    fmt\mChannelsPerFrame = 2
    fmt\mBitsPerChannel = 16
  Else
    fmt\mChannelsPerFrame = 1
    fmt\mBitsPerChannel = 64
  EndIf
  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 Dim WaveBuffer.w(FileSize)
  Global WaveLength =30000
  ReadData(1, @WaveBuffer(), FileSize)
  
  CloseFile(1)
EndIf


Procedure SampleCallback(*out.AudioStreamSamples)
  Protected i = 0
  Protected L = 128 ;Start of the Wave Samples

  While L = < WaveLength
    While i < #AUDIOBUFFER_SAMPLES
      *out\ss[i]\l = WaveBuffer(L )
      *out\ss[i]\r = WaveBuffer(L  +1)
      
      L +1
      i + 1
    Wend
    i = 0
    L +1
  Wend

EndProcedure

AudioStream_Init(@SampleCallback(), #True)
AudioStream_SetVolume(0.5)
AudioStream_Start()

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

AudioStream_Dispose()

Re: Audio Synthesis

Posted: Thu Sep 15, 2016 3:19 pm
by 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 "-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()
AUHAL version

Code: Select all

ImportC ""
  AudioUnitSetVolume__(Unit, ID, Scope, Element, Value.f, BufferOffsetInFrames) As "_AudioUnitSetParameter"
EndImport

DataSection
  dOut:
  Data.l $61756f75,$64656620,$6170706c,0,0
  PCM16Bit:
  Data.l 0,$40E58880,$6C70636D,12,4,1,4,2,16,0
  PCM32BitFloat:
  Data.l 0,$40E58880,$6C70636D,1,8,1,8,2,32,0
EndDataSection

Global Audio_Unit.i

Procedure Audio_SetVolume(Volume); 0 - 100
  Protected factor.f
  If Volume
    factor = Pow(10, 40 * (Volume - 100) * 0.0005)
  EndIf
  AudioUnitSetVolume__(Audio_Unit, 14, 1, 0, factor, 0)
EndProcedure

Procedure Audio_Init(*CallbackFunction, BufferSize.l = 2048)
  Protected Dim CallbackStruct.i(1) : CallbackStruct(0) = *CallbackFunction
  AudioComponentInstanceNew_(AudioComponentFindNext_(#Null, ?dOut), @Audio_Unit)
  AudioUnitSetProperty_(Audio_Unit, 23, 1, 0, @CallbackStruct(), SizeOf(Integer) << 1)
  AudioUnitSetProperty_(Audio_Unit, 8, 1, 0, ?PCM16Bit, 40)
  AudioUnitSetProperty_(Audio_Unit, $6673697a, 1, 0, @BufferSize, 4)
  AudioUnitInitialize_(Audio_Unit)
EndProcedure

Procedure Audio_Start()
  ProcedureReturn Bool(AudioOutputUnitStart_(Audio_Unit) = 0)
EndProcedure

Procedure Audio_Stop()
  AudioOutputUnitStop_(Audio_Unit)
EndProcedure

Procedure Audio_Terminate()
  If Audio_Unit
    AudioOutputUnitStop_(Audio_Unit)
    AudioUnitUninitialize_(Audio_Unit)
    AudioComponentInstanceDispose_(Audio_Unit)
    Audio_Unit = 0
  EndIf
EndProcedure


;-Main

Structure AudioStreamStereoSample
  l.w
  r.w
EndStructure

Structure AudioStreamSamples
  ss.AudioStreamStereoSample[0]
EndStructure

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


ProcedureC SampleCallback(*inRefcon, *ioActionFlags, *inTimeStamp, inBusNumber.l, inNumberFrames.l, *ioData)
  Protected i.i, *out.AudioStreamSamples = PeekI(*ioData + SizeOf(Integer) + 8)
  While i < inNumberFrames
    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

Audio_Init(@SampleCallback())
Audio_SetVolume(50)
Audio_Start()

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

Audio_Terminate()

Re: Audio Synthesis

Posted: Sat Sep 16, 2017 11:39 pm
by Wolfram
Hello,

I'm trying to play a 16 bit mono WAVE file by using this code, but there is something wrong.
The WAVE file plays to slow. This is not happened if I use 4 for BytesPerFrame and mBytesPerPacket and 2 per ChannelsPerFrame

Code: Select all

Protected fmt.AudioStreamBasicDescription
  fmt\mSampleRate = SampleRate
  fmt\mFormatID = $6C70636D; kAudioFormatLinearPCM
  fmt\mFormatFlags = #kAudioFormatFlagIsPacked | #kLinearPCMFormatFlagIsSignedInteger
  fmt\mFramesPerPacket = 1
  fmt\mBytesPerFrame = 2
  fmt\mBytesPerPacket = 2
  fmt\mChannelsPerFrame = 1
  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

Re: Audio Synthesis

Posted: Tue Sep 19, 2017 6:24 am
by wilbert
Wolfram wrote:I'm trying to play a 16 bit mono WAVE file by using this code, but there is something wrong.
The WAVE file plays to slow. This is not happened if I use 4 for BytesPerFrame and mBytesPerPacket and 2 per ChannelsPerFrame
I'm not sure why this is happening. You can try adding #kAudioFormatFlagIsNonInterleaved to the format flags (value of the constant is 32).
If it doesn't work, maybe the AUHAL version (see above) works.

Re: Audio Synthesis

Posted: Tue Sep 19, 2017 4:42 pm
by Wolfram
Hi Wilbert,

I already tried that.
Do you get the same effect on your system?