Skip to content

Instantly share code, notes, and snippets.

@larsaugustin
Created May 23, 2020 14:04
Show Gist options
  • Save larsaugustin/1ba0b01ace8772cf5ecbda8f4e3cf63d to your computer and use it in GitHub Desktop.
Save larsaugustin/1ba0b01ace8772cf5ecbda8f4e3cf63d to your computer and use it in GitHub Desktop.
A simple synthesizer class in Swift
class Synthesizer {
// MARK: - Variables
var audioEngine: AVAudioEngine!
var sourceNode: AVAudioSourceNode!
var time = Float.zero
var frequencyRamp = Float.zero
var currentFrequency: Float = 20 {
didSet {
frequencyRamp = currentFrequency - oldValue
}
}
// MARK: - Setup
public func setup() {
audioEngine = AVAudioEngine()
sourceNode = AVAudioSourceNode(renderBlock: { (_, _, frameCount, bufferList) -> OSStatus in
let listPointer = UnsafeMutableAudioBufferListPointer(bufferList)
let rampValue = self.frequencyRamp
let frequency = self.currentFrequency
let period = 1 / frequency
for frame in 0..<Int(frameCount) {
let completion = self.time
let sample = sin(2.0 * .pi * (frequency + rampValue * completion) * self.time)
self.time += 1 / Float(self.audioEngine.outputNode.inputFormat(forBus: 0).sampleRate)
self.time = fmod(self.time, period)
for buffer in listPointer {
let bufferPointer = UnsafeMutableBufferPointer<Float>(buffer)
bufferPointer[frame] = sample
}
}
return noErr
})
let format = audioEngine.outputNode.inputFormat(forBus: 0)
let inputFormat = AVAudioFormat(commonFormat: format.commonFormat,
sampleRate: format.sampleRate,
channels: 1,
interleaved: format.isInterleaved)
audioEngine.attach(sourceNode)
audioEngine.connect(sourceNode, to: audioEngine.outputNode, format: inputFormat)
do {
try audioEngine.start()
} catch {
print("Error: " + error.localizedDescription)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment