Last active
December 9, 2016 09:31
-
-
Save dolphinsue319/040454d135a4a6093f8ee41643712781 to your computer and use it in GitHub Desktop.
Learn AudioUnit from live demo in WWDC 2016 session 507.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
update for Swift 3