« Xojo's picture cache | Home | SQLite turned 20 »

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:

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

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.

The biggest plugin in space...
28 05 20 - 10:19