Reputation: 7203
I'm using AudioKit 4.10. I use this simple code to sample frequency and amplitude from a microphone:
import AudioKit
protocol MicAnalyzerDelegate {
/**
* The MicAnalyzer calls this delegate function.
*/
func micAnalyzerInfos(infos: (frequency : Double, amplitude : Double)?)
}
class MicAnalyzer: NSObject {
// MARK: - Properties
private static var micAnalyzer: MicAnalyzer = MicAnalyzer()
var delegate: MicAnalyzerDelegate?
fileprivate var mic: AKMicrophone!
fileprivate var tracker: AKFrequencyTracker!
fileprivate var silence: AKBooster!
fileprivate var timer: Timer?
// MARK: - Initializations
private override init() {
super.init()
AKSettings.audioInputEnabled = true
self.initMicTracker()
}
private func initMicTracker(){
/* Add the built-in microphone. */
mic = AKMicrophone()
/* Add a traker */
tracker = AKFrequencyTracker(mic)
silence = AKBooster(tracker, gain: 0)
}
// MARK: - Accessors
class func shared() -> MicAnalyzer {
return micAnalyzer
}
func startMonitoring() {
/* Start the microphone and analyzer. */
AudioKit.output = silence
do {
try AudioKit.start()
} catch {
AKLog("AudioKit did not start!")
}
/* Initialize and schedule a new run loop timer. */
timer = Timer.scheduledTimer(timeInterval: 0.1,
target: self,
selector: #selector(MicAnalyzer.tick),
userInfo: nil,
repeats: true)
}
// Stopped as described here: https://github.com/AudioKit/AudioKit/issues/1716
func stopMonitoring() {
do {
AudioKit.disconnectAllInputs()
try AudioKit.stop()
try AudioKit.shutdown()
} catch {
print("AudioKit did not stop")
}
AudioKit.output = nil
// Interrupts polling on tick infos
timer?.invalidate()
timer = nil
}
var infos: (frequency : Double, amplitude : Double)? {
if(!tracker.isStopped){
let frequency = tracker.frequency
let amplitude = tracker.amplitude
return (frequency: frequency, amplitude: amplitude)
} else {
return nil
}
}
/* Call the delegate. */
@objc func tick() {
self.delegate?.micAnalyzerInfos(infos: infos)
}
}
Calling in order the following code I have that situation:
MicAnalyzer.shared().startMonitoring() // --> Everything works good
MicAnalyzer.shared().stopMonitoring() // --> I think it is stopped correctly
MicAnalyzer.shared().startMonitoring() // --> From now on the delegate is called but I get always 0 as frequency and amplitude
Why after recalling the AudioKit.start()
(inside the MicAnalyzer.shared().startMonitoring()
) I can't sample frequency and amplitude anymore? How should I restart the whole thing?
If I reinitiate each time the variables mic
, tracker
and silence
the memory grows as they are not really deallocated.
This is a second version of the same code idea:
import AudioKit
protocol MicAnalyzerDelegate : class {
/**
* The tuner calls this delegate function
*/
func micAnalyzerInfos(infos: (frequency : Double, amplitude : Double)?)
}
// https://audiokit.io/examples/MicrophoneAnalysis/
class MicAnalyzer: NSObject {
// MARK: - Properties
private weak var delegate: MicAnalyzerDelegate?
fileprivate var mic: AKMicrophone!
fileprivate var tracker: AKFrequencyTracker!
fileprivate var silence: AKBooster!
fileprivate var timer: Timer?
// MARK: - Initializations
init(delegate: MicAnalyzerDelegate) {
print("Init called!!!")
self.delegate = delegate
super.init()
}
deinit {
print("Deinit called!!!")
}
// MARK: - Accessors
func startMonitoring() {
AKSettings.audioInputEnabled = true
/* Add the built-in microphone. */
mic = AKMicrophone()
/* Add a traker */
tracker = AKFrequencyTracker(mic)
silence = AKBooster(tracker, gain: 0)
/* Start the microphone and analyzer. */
AudioKit.output = silence
do {
try AudioKit.start()
} catch {
AKLog("AudioKit did not start!")
}
/* Initialize and schedule a new run loop timer. */
timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(MicAnalyzer.tick),
userInfo: nil,
repeats: true)
}
func stopMonitoring() {
do {
AudioKit.disconnectAllInputs()
try AudioKit.stop()
try AudioKit.shutdown()
} catch {
print("AudioKit did not stop")
}
AudioKit.output = nil
// Interrupts polling on tick infos
timer?.invalidate()
timer = nil
silence.stop()
silence = nil
tracker.stop()
tracker = nil
mic.stop()
mic = nil
}
var infos: (frequency : Double, amplitude : Double)? {
if(!tracker.isStopped){
let frequency = tracker.frequency
let amplitude = tracker.amplitude
return (frequency: frequency, amplitude: amplitude)
} else {
return nil
}
}
/* Call the delegate. */
@objc func tick() {
print(infos?.frequency ?? "0.0")
//self.delegate.micAnalyzerInfos(infos: infos)
}
}
And then I could call that 'second code test' like this in order:
override func viewDidAppear() {
super.viewDidAppear()
print("viewDidAppear!!!")
tuner = Tuner(delegate: self)
tuner?.startMonitoring()
}
override func viewDidDisappear() {
super.viewDidDisappear()
print("viewDidDisappear!!!")
tuner?.stopMonitoring()
tuner = nil
}
Upvotes: 0
Views: 159
Reputation: 7707
You need to make sure the AKFrequencyTracker is part of the signal chain, as that's an AVAudioEngine engine requirement.
Which means that if you do:
do {
AudioKit.disconnectAllInputs()
try AudioKit.stop()
try AudioKit.shutdown()
} catch {
// error handler
}
AudioKit.output = nil
You have to call initMicTracker
to have the AKFrequencyTracker
back in the signal chain. So, to restart you'd do:
Because your stopMonitoring did:
(stop)MicTracker
You know that you already created instances for AKMicrophone
, AKFrequencyTracker
and AKBooster
free it from memory
func stopMonitoring() {
...
self.mic = nil
self.tracker = nil
self.silence = nil
}
Upvotes: 1