Write audio file with samples using AVFoundation

Today we have a tip for everyone using AVFoundation classes in MBS Xojo Plugins. If you work with AVAudioPCMBufferMBS objects from either an audio file or with samples from microphone, it may be useful to write them to a file. So here is a little function, which takes a memory block of samples and writes them to a file on the desktop.

To make it work, we have to add a few new methods to AVAudioPCMBufferMBS class to pass in sample data. While you could do it yourself with Ptr already, it’s convenient to let the plugin handle the stride and double pointer dereferencing for you to copy values and return true on success:

  • setFloatChannelData(ChannelIndex as Integer, Data as Memoryblock) as boolean
  • setInt32ChannelData(ChannelIndex as Integer, Data as Memoryblock) as boolean
  • setInt16ChannelData(ChannelIndex as Integer, Data as Memoryblock) as boolean

As you see in the code we build two settings dictionary as we pass data in in 32-bit floating point numbers, but want to write it as 16bit integer to the file to save a bit of space:

[code]Private Sub WriteAudioFile(ChnData as MemoryBlock, SampleRate as Double, Duration as Double)
// write a few samples to disk with AVFoundation classes

Dim wavError As NSErrorMBS

// Create new file for new WAV
Dim newFile As FolderItem = SpecialFolder.Desktop.Child("Export.wav")

// Create settings for file as 16-bit WAV
Dim FileSettings As New Dictionary
FileSettings.Value(AVFoundationMBS.AVNumberOfChannelsKey) = 1
FileSettings.Value(AVFoundationMBS.AVSampleRateKey) = SampleRate
FileSettings.Value(AVFoundationMBS.AVLinearPCMBitDepthKey) = 16
FileSettings.Value(AVFoundationMBS.AVLinearPCMIsBigEndianKey) = False
FileSettings.Value(AVFoundationMBS.AVLinearPCMIsNonInterleaved) = False
FileSettings.Value(AVFoundationMBS.AVLinearPCMIsFloatKey) = False
FileSettings.Value(AVFoundationMBS.AVFormatIDKey) = OSTypeFromStringMBS(AVFoundationMBS.kAudioFormatLinearPCM)

// Create settings for processing as 32-bit float
Dim ProcessingSettings As New Dictionary
ProcessingSettings.Value(AVFoundationMBS.AVNumberOfChannelsKey) = 1
ProcessingSettings.Value(AVFoundationMBS.AVSampleRateKey) = SampleRate
ProcessingSettings.Value(AVFoundationMBS.AVLinearPCMBitDepthKey) = 32
ProcessingSettings.Value(AVFoundationMBS.AVLinearPCMIsBigEndianKey) = False
ProcessingSettings.Value(AVFoundationMBS.AVLinearPCMIsNonInterleaved) = False
ProcessingSettings.Value(AVFoundationMBS.AVLinearPCMIsFloatKey) = True
ProcessingSettings.Value(AVFoundationMBS.AVFormatIDKey) = OSTypeFromStringMBS(AVFoundationMBS.kAudioFormatLinearPCM)

// Create new Processing Format with new settings
Dim ProcessingFormat As New AVAudioFormatMBS(ProcessingSettings)

// check length
Dim SampleLength As Integer = SampleRate * Duration
If SampleLength * 4 <> ChnData.size Then
	Break
	MsgBox "Size mismatch between length and samples!"
	Return
End If

// Create WAV with new settings
Dim newAudioFile As New AVAudioFileMBS(newFile, FileSettings, wavError)

If wavError <> Nil Then
	MsgBox wavError.LocalizedDescription
	Return
End If

// Create new mono AVAudioPCMBufferMBS
Dim newBuff As New AVAudioPCMBufferMBS(ProcessingFormat, SampleLength)

// set buffer size
newBuff.frameLength = SampleLength

// fill in frames
If Not newBuff.setFloatChannelData(0, ChnData) Then
	Break
End If

// Write new mono buffer to new file
If newAudioFile.writeFromBuffer(newBuff, wavError) Then
	MsgBox "OK"
Elseif wavError <> Nil Then
	MsgBox wavError.LocalizedDescription
Else
	MsgBox "Failed?"
End If

End Sub[/code]

Please do not hesitate to contact us with your questions.

If you need this cross platform, please check the SoundFileMBS class or one of our examples, which directly writes WAV file in Xojo.