Advertisement
Guest User

Untitled

a guest
Jan 21st, 2017
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.32 KB | None | 0 0
  1. import AVFoundation
  2. import Foundation
  3.  
  4. // The maximum number of audio buffers in flight. Setting to two allows one
  5. // buffer to be played while the next is being written.
  6. private let kInFlightAudioBuffers: Int = 2
  7.  
  8. // The number of audio samples per buffer. A lower value reduces latency for
  9. // changes but requires more processing but increases the risk of being unable
  10. // to fill the buffers in time. A setting of 1024 represents about 23ms of
  11. // samples.
  12. private let kSamplesPerBuffer: AVAudioFrameCount = 1024
  13.  
  14.  
  15. public class FMSynthesizer {
  16.  
  17. // The audio engine manages the sound system.
  18. private let engine: AVAudioEngine = AVAudioEngine()
  19.  
  20. // The player node schedules the playback of the audio buffers.
  21. private let playerNode: AVAudioPlayerNode = AVAudioPlayerNode()
  22.  
  23. // Use standard non-interleaved PCM audio.
  24. let audioFormat = AVAudioFormat(standardFormatWithSampleRate: 44100.0, channels: 2)
  25.  
  26. // A circular queue of audio buffers.
  27. private var audioBuffers: [AVAudioPCMBuffer] = [AVAudioPCMBuffer]()
  28.  
  29. // The index of the next buffer to fill.
  30. private var bufferIndex: Int = 0
  31.  
  32. // The dispatch queue to render audio samples.
  33. private let audioQueue = DispatchQueue(label: "FMSynthesizerQueue")
  34.  
  35. // A semaphore to gate the number of buffers processed.
  36. private let audioSemaphore = DispatchSemaphore(value: kInFlightAudioBuffers)
  37.  
  38. public class func sharedSynth() -> FMSynthesizer {
  39. return FMSynthesizer()
  40. }
  41.  
  42. init() {
  43. // Create a pool of audio buffers.
  44. for _ in 0 ..< kInFlightAudioBuffers {
  45. let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: kSamplesPerBuffer)
  46. audioBuffers.append(audioBuffer)
  47. }
  48.  
  49. // Attach and connect the player node.
  50. engine.attach(playerNode)
  51. engine.connect(playerNode, to: engine.mainMixerNode, format: audioFormat)
  52.  
  53. do {
  54. try engine.start()
  55. } catch {
  56. print(error.localizedDescription)
  57. }
  58.  
  59. NotificationCenter.default.addObserver(self, selector: Selector(("audioEngineConfigurationChange:")), name: NSNotification.Name.AVAudioEngineConfigurationChange, object: engine)
  60. }
  61.  
  62. public func play(carrierFrequency: Float32, modulatorFrequency: Float32, modulatorAmplitude: Float32) {
  63. let unitVelocity = Float32(2.0 * M_PI / audioFormat.sampleRate)
  64. let carrierVelocity = carrierFrequency * unitVelocity
  65. let modulatorVelocity = modulatorFrequency * unitVelocity
  66. audioQueue.async {
  67. var sampleTime: Float32 = 0
  68. while true {
  69. // Wait for a buffer to become available.
  70. self.audioSemaphore.wait(timeout: DispatchTime.distantFuture)
  71.  
  72. // Fill the buffer with new samples.
  73. let audioBuffer = self.audioBuffers[self.bufferIndex]
  74. let leftChannel = audioBuffer.floatChannelData?[0]
  75. let rightChannel = audioBuffer.floatChannelData?[1]
  76. for sampleIndex in 0 ..< Int(kSamplesPerBuffer) {
  77. let sample = sin(carrierVelocity * sampleTime + modulatorAmplitude * sin(modulatorVelocity * sampleTime))
  78. leftChannel?[sampleIndex] = sample
  79. rightChannel?[sampleIndex] = sample
  80. sampleTime += 1
  81. }
  82. audioBuffer.frameLength = kSamplesPerBuffer
  83.  
  84. // Schedule the buffer for playback and release it for reuse after
  85. // playback has finished.
  86. self.playerNode.scheduleBuffer(audioBuffer) {
  87. self.audioSemaphore.signal()
  88. return
  89. }
  90.  
  91. self.bufferIndex = (self.bufferIndex + 1) % self.audioBuffers.count
  92. }
  93. }
  94.  
  95. playerNode.pan = 0.8
  96. playerNode.play()
  97. }
  98.  
  99. @objc private func audioEngineConfigurationChange(notification: NSNotification) -> Void {
  100. NSLog("Audio engine configuration change: \(notification)")
  101. }
  102.  
  103. }
  104.  
  105.  
  106. // The single FM synthesizer instance.
  107. private let gFMSynthesizer: FMSynthesizer = FMSynthesizer()
  108.  
  109.  
  110.  
  111. // Play a bell sound:
  112. FMSynthesizer.sharedSynth().play(carrierFrequency: 440.0, modulatorFrequency: 679.0, modulatorAmplitude: 0.8)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement