Skip to content

Instantly share code, notes, and snippets.

@dolphinsue319
Last active December 9, 2016 09:31
Show Gist options
  • Save dolphinsue319/040454d135a4a6093f8ee41643712781 to your computer and use it in GitHub Desktop.
Save dolphinsue319/040454d135a4a6093f8ee41643712781 to your computer and use it in GitHub Desktop.
Learn AudioUnit from live demo in WWDC 2016 session 507.
//
// main.swift
// SquareWaveGenerator
//
// Created by dolphin on 2016/8/7.
// Copyright © 2016年 dolphin. All rights reserved.
//
import Foundation
import AudioToolbox
import AVFoundation
class SquareWaveGenerator {
// 一秒有幾個 frame
let sampleRate: Double
// 波形密度, 音高
let frequency: Double
// 波形高度, 音量
let amplitude: Float
var counter: Double = 0.0
init(sampleRate: Double, frequency: Double, amplitude: Float) {
self.sampleRate = sampleRate
self.frequency = frequency
self.amplitude = amplitude
}
func render(buffer: AudioBuffer) {
let nFrames = Int(buffer.mDataByteSize) / Int(MemoryLayout<Float>.size)
var ptr = UnsafeMutablePointer<Float>.allocate(capacity: nFrames)
var j = self.counter
// 用一個 frame 裡會包含幾個波形來推算出一個波形的長度
let cycleLength = self.sampleRate / self.frequency
let halfCycleLength = cycleLength / 2
let amp = self.amplitude
let minusAmp = -amp
for _ in 0..<nFrames {
if j < halfCycleLength {
ptr?.pointee = amp
} else {
ptr?.pointee = minusAmp
}
ptr = ptr?.successor()
j += 1.0
if j > cycleLength {
j -= cycleLength
}
self.counter = j
}
}
}
func main() {
#if os(iOS)
let kOutputUnitSubType = kAudioUnitSubtype_RemoteIO
#else
let kOutputUnitSubType = kAudioUnitSubType_HALOutput
#endif
let ioUnitDesc = AudioComponentDescription(componentType: kAudioUnitType_Output, componentSubType: kOutputUnitSubType, componentManufacturer: kAudioUnitManufacturer_Apple, componentFlags: 0, componentFlagsMask: 0)
// AUAudioUnit: 我們用來操作 AudioUnit 的介面
let ioUnit = try! AUAudioUnit(componentDescription: ioUnitDesc, options: AudioComponentInstantiationOptions())
let hardwareFormat = ioUnit.outputBusses[0].format
let renderFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareFormat.sampleRate, channels: min(2, hardwareFormat.channelCount))
try! ioUnit.inputBusses[0].setFormat(renderFormat)
let generatorLeft = SquareWaveGenerator(sampleRate: renderFormat.sampleRate, frequency: 440.0, amplitude: 0.1)
let generatorRight = SquareWaveGenerator(sampleRate: renderFormat.sampleRate, frequency: 440.0, amplitude: 0.1)
// The block that the output unit will call to get audio to send to the output.
// 當 output unit 要丟音檔資料給 output 裝置時,會 call 這個 block
ioUnit.outputProvider = {(actionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, timeStamp: UnsafePointer<AudioTimeStamp>, frameCount: AUAudioFrameCount, busIndex: Int, rawBufferList: UnsafeMutablePointer<AudioBufferList>) -> AUAudioUnitStatus in
let bufferList = UnsafeMutableAudioBufferListPointer(rawBufferList)
if bufferList.count > 0 {
generatorLeft.render(buffer: bufferList[0])
if bufferList.count > 1 {
generatorRight.render(buffer: bufferList[1])
}
}
return noErr
}
try! ioUnit.allocateRenderResources()
try! ioUnit.startHardware()
// 播放 3 秒
sleep(3)
ioUnit.stopHardware()
}
main()
@dolphinsue319
Copy link
Author

update for Swift 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment