Produce sounds of different frequencies in Swift
Swift 4.2:
create this class in your project.
import Foundation
import AudioUnit
import AVFoundation
final class ToneOutputUnit: NSObject {
var auAudioUnit: AUAudioUnit! = nil // placeholder for RemoteIO Audio Unit
var avActive = false // AVAudioSession active flag
var audioRunning = false // RemoteIO Audio Unit running flag
var sampleRate : Double = 44100.0 // typical audio sample rate
var f0 = 880.0 // default frequency of tone: 'A' above Concert A
var v0 = 16383.0 // default volume of tone: half full scale
var toneCount : Int32 = 0 // number of samples of tone to play. 0 for silence
private var phY = 0.0 // save phase of sine wave to prevent clicking
private var interrupted = false // for restart from audio interruption notification
func setFrequency(freq : Double) { // audio frequencies below 500 Hz may be
f0 = freq // hard to hear from a tiny iPhone speaker.
}
func setToneVolume(vol : Double) { // 0.0 to 1.0
v0 = vol * 32766.0
}
func setToneTime(t : Double) {
toneCount = Int32(t * sampleRate);
}
func enableSpeaker() {
if audioRunning {
print("returned")
return
} // return if RemoteIO is already running
do { // not running, so start hardware
let audioComponentDescription = AudioComponentDescription(
componentType: kAudioUnitType_Output,
componentSubType: kAudioUnitSubType_SystemOutput, // For output to the local sound system
componentManufacturer: kAudioUnitManufacturer_Apple,
componentFlags: 0,
componentFlagsMask: 0 )
if (auAudioUnit == nil) {
auAudioUnit = try AUAudioUnit(componentDescription: audioComponentDescription)
let bus0 = auAudioUnit.inputBusses[0]
let audioFormat = AVAudioFormat(
commonFormat: AVAudioCommonFormat.pcmFormatInt16, // short int samples
sampleRate: Double(sampleRate),
channels:AVAudioChannelCount(2),
interleaved: true ) // interleaved stereo
try bus0.setFormat(audioFormat ?? AVAudioFormat()) // for speaker bus
auAudioUnit.outputProvider = { ( // AURenderPullInputBlock?
actionFlags,
timestamp,
frameCount,
inputBusNumber,
inputDataList ) -> AUAudioUnitStatus in
self.fillSpeakerBuffer(inputDataList: inputDataList, frameCount: frameCount)
return(0)
}
}
auAudioUnit.isOutputEnabled = true
toneCount = 0
try auAudioUnit.allocateRenderResources() // v2 AudioUnitInitialize()
try auAudioUnit.startHardware() // v2 AudioOutputUnitStart()
audioRunning = true
} catch /* let error as NSError */ {
print("error 2 \(error)")
}
}
// helper functions
private func fillSpeakerBuffer( // process RemoteIO Buffer for output
inputDataList : UnsafeMutablePointer<AudioBufferList>, frameCount : UInt32 ) {
let inputDataPtr = UnsafeMutableAudioBufferListPointer(inputDataList)
let nBuffers = inputDataPtr.count
if (nBuffers > 0) {
let mBuffers : AudioBuffer = inputDataPtr[0]
let count = Int(frameCount)
// Speaker Output == play tone at frequency f0
if ( self.v0 > 0)
&& (self.toneCount > 0 )
{
// audioStalled = false
var v = self.v0 ; if v > 32767 { v = 32767 }
let sz = Int(mBuffers.mDataByteSize)
var a = self.phY // capture from object for use inside block
let d = 2.0 * Double.pi * self.f0 / self.sampleRate // phase delta
let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData)
if var bptr = bufferPointer {
for i in 0..<(count) {
let u = sin(a) // create a sinewave
a += d ; if (a > 2.0 * Double.pi) { a -= 2.0 * Double.pi }
let x = Int16(v * u + 0.5) // scale & round
if (i < (sz / 2)) {
bptr.assumingMemoryBound(to: Int16.self).pointee = x
bptr += 2 // increment by 2 bytes for next Int16 item
bptr.assumingMemoryBound(to: Int16.self).pointee = x
bptr += 2 // stereo, so fill both Left & Right channels
}
}
}
self.phY = a // save sinewave phase
self.toneCount -= Int32(frameCount) // decrement time remaining
} else {
// audioStalled = true
memset(mBuffers.mData, 0, Int(mBuffers.mDataByteSize)) // silence
}
}
}
func stop() {
if (audioRunning) {
auAudioUnit.stopHardware()
audioRunning = false
}
}
}
and in your view controller create object of this class out of viewDidLoad() method.
let myUnit = ToneOutputUnit()
and To create sound of specific frequency (here 10,000) use below code
myUnit.setFrequency(freq: 10000)
myUnit.setToneVolume(vol: currentVolume)
myUnit.enableSpeaker()
myUnit.setToneTime(t: 20000)
and to stop sound
myUnit.stop()
swift 3 FFT get frequency of sound m4a
Your code is working. Your settings are not fitting your needs.
Set
filterParams.gain = -96.0
(the mininimal possible value)A low pass filter has no
bandwidth
, delete it.
For more radical results set the cutoff frequency to 100 HZ first:
filterParams.frequency = 100.0
Your expectation to the result of a low pass filter (cutting of 100% above cutoff frequency) does not fit the reality of filters. Depending on the implementation (used algorithm and order) a filter cuts off more or less fast.
See this typical filter response from Wikipedia:
Related Topics
Notification in Swift Returning Userinfo in Dictionary
How to Get .Adjustsfontsizetofitwidth to Function Properly
Can't Load Images on MAC Screensaver Release Build (It Works on Xcode Debug Build)
Bad_Access During Recursive Calls in Swift
Nscalendar in Swift - Init Can Return Nil, But Isn't Optional
Get Output Frames Failed, State 8196
Swift: Rsa Encrypt a String with a Specific Private Key
How to Specify Japanese Encoding for a UIlabel
How to Print Http Request to Console
How to Invoke Method with Cvalistpointer Parameters in Swift
How to Byte Reverse Nsdata Output in Swift The Littleendian Way
Easiest Way to Truncate Float to 2 Decimal Places
Scrolltoitem at Indexpath at .Top Hides Cell Under Header When Sectionheaderspintovisiblebounds
Module Compiled with Swift X.1 Cannot Be Imported in Swift X.0.2