3

Apple's documentation :

AudioToolbox Framework Reference > Audio File Services Reference > Reading and Writing Audio Files > AudioFileWriteBytes

Declaration Swift func AudioFileWriteBytes(_ inAudioFile: AudioFileID,
                   _ inUseCache: Boolean,
                   _ inStartingByte: Int64,
                   _ ioNumBytes: UnsafeMutablePointer<UInt32>,
                   _ inBuffer: UnsafePointer<Void>) -> OSStatus

Code in XCode Version 7.0 beta 4 (7A165t)

audioErr = AudioFileWriteBytes(audioFile, false, Int64(sampleCount * 2), bytesToWriteMem, sampleMem as! UnsafePointer<Void>)

XCode's reponse :

Cannot invoke 'AudioFileWriteBytes' with an argument list of type '(AudioFileID, Bool, Int64, UnsafeMutablePointer<UInt32>, UnsafePointer<Void>)'

Any idea ?

EDIT : Thanks Martin R for your response, here is my full code and i don't understand why the AudioFileWriteBytes call returns an error ... :

import Foundation
import AudioToolbox
import Darwin
import AudioUnit
import CoreFoundation

extension Int {
    func format (f:String) -> String {
        return NSString(format:"%\(f)d", self) as String
    }
}


let SAMPLE_RATE:Float64 = 44100                             // 1
let DURATION = 0.1                                          // 2
// #define FILENAME_FORMAT @"%0.3f-square.aif"                 3 skipped

if (Process.arguments.count < 2) {
    print("Usage: CAToneFileGenerator n\n(where n is tone in Hz)")
    exit(0)
}

var hz:Double = atof(Process.arguments[1])                  // 4 (atof convert ASCII string to double)
assert(hz > 0)
print("generating \(hz) tone")
var fileName:String = String(format:"%d-square.aif", hz)    // 5
var filePath:String = NSFileManager.defaultManager().currentDirectoryPath.stringByAppendingPathComponent(fileName)
var fileURL:NSURL = NSURL.fileURLWithPath(filePath)     // the Audio File Services functions take URLs, not file paths

// Prepare the format

var asbd = AudioStreamBasicDescription()                    // 6
memset(&asbd, 0, sizeof(AudioStreamBasicDescription))       // 7
asbd.mSampleRate = SAMPLE_RATE                              // 8
asbd.mFormatID = AudioFormatID(kAudioFormatLinearPCM)
asbd.mFormatFlags = AudioFormatFlags(kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked)
asbd.mBitsPerChannel = 16
asbd.mChannelsPerFrame = 1
asbd.mFramesPerPacket = 1
asbd.mBytesPerFrame = 2
asbd.mBytesPerPacket = 2

// Set up the file

var audioFile:AudioFileID = AudioFileID()
var audioErr:OSStatus = noErr
audioErr = AudioFileCreateWithURL(fileURL,                  // 9
                                  AudioFileTypeID(kAudioFileAIFFType),
                                  &asbd,
                                  .EraseFile,
                                  &audioFile)

// 1 -> AudioFileFlags(kAudioFileFlags_EraseFile)
assert(audioErr == noErr)

// Start writing samples

var maxSampleCount:CLong = CLong(SAMPLE_RATE * DURATION)    // 10
var sampleCount:CLong = 0

var bytesToWrite:UInt32 = 2
/*
var bytesToWriteMem = UnsafeMutablePointer<UInt32>.alloc(1)
bytesToWriteMem.initialize(bytesToWrite)
*/
var wavelengthInSamples:Double = SAMPLE_RATE / hz           // 11

var sample:UInt16
//var sampleMem = UnsafeMutablePointer<UInt16>.alloc(1)
//sampleMem.initialize(sample)


while sampleCount < maxSampleCount {
    for i in 0..<Int(wavelengthInSamples) {
        // Square wave
        if ( i < Int(wavelengthInSamples/2)) {              // 12
            sample = UInt16.max                             // 13
        } else {
            sample = UInt16.min
        }

        //let bytesToWrite2 = bytesToWrite
        audioErr = AudioFileWriteBytes(audioFile,           // 14
                                       false,
                                       Int64(sampleCount * 2),
                                       &bytesToWrite,               //UnsafeMutablePointer<UInt32>
                                       &sample)                     //UnsafePointer<Void>
        assert(audioErr == noErr)
        sampleCount++                                       // 15

    }
}
/*
bytesToWriteMem.destroy()
bytesToWriteMem.dealloc(1)
sampleMem.destroy()
sampleMem.dealloc(1)
*/
audioErr = AudioFileClose(audioFile)                        // 16
assert(audioErr == noErr)
print("wrote \(sampleCount) samples")
Fafa
  • 93
  • 8
  • Why do you think it is *unavailable*? The error message states that you are calling it with *wrong arguments*. – Martin R Aug 02 '15 at 12:14
  • Is it because : [link]http://stackoverflow.com/questions/25057161/how-to-use-the-coreaudio-api-in-swift "You can't (currently) use an API requiring a C callback pointer from pure Swift code. " – Fafa Aug 02 '15 at 13:40
  • Ok i'm looking at http://stackoverflow.com/questions/25341632/pass-c-function-callback-in-swift ... – Fafa Aug 02 '15 at 14:08
  • Do you have a problem with the format saying kAudioFormatFlagIsSignedInteger yet your sample is UInt16 instead of Int16? – Gene De Lisa Dec 06 '16 at 16:40

1 Answers1

3

That was tricky to find, because the error message does not help at all. The problem is that the type of the second parameter of AudioFileWriteBytes() is Boolean, not Bool:

audioErr = AudioFileWriteBytes(audioFile,
            Boolean(0), // <--- HERE
            Int64(sampleCount * 2),
            &bytesToWrite,
            &sample)

For more information about the difference between Boolean and Bool see for example Type 'Boolean' does not conform to protocol 'BooleanType'.

Update: As of Swift 2/Xcode 7, the Mac type Boolean is mapped to the Swift Bool, so you have to pass false or true now:

audioErr = AudioFileWriteBytes(audioFile,
            false, // <--- HERE
            Int64(sampleCount * 2),
            &bytesToWrite,
            &sample)
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • I'm looking at this in Xcode 7.2, and it looks like the declaration for the function changed. It's now requiring a Bool. `func AudioFileWriteBytes(_ inAudioFile: AudioFileID, _ inUseCache: Bool, _ inStartingByte: Int64, _ ioNumBytes: UnsafeMutablePointer, _ inBuffer: UnsafePointer) -> OSStatus` – Jeff V Dec 25 '15 at 00:28
  • @Jeff: Yes, the way how Boolean is imported to Swift has changed. I will check it after the holidays and then update the answer. Thanks for the feedback and Merry Christmas to everybody ! – Martin R Dec 25 '15 at 09:43