From 4248b667321b9b10a9b0bb93c632c049406153da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CRyan?= <“hi@spongefork.com”> Date: Fri, 24 Aug 2018 10:20:45 -0700 Subject: [PATCH 1/5] * Ignore gain, pitch and rate setter values if they are already that value. * whitespace linting --- .../Playback/Players/Player/AKDynamicPlayer.swift | 15 ++++++++++++--- .../Players/Player/AKPlayer+Buffering.swift | 2 -- .../Playback/Players/Player/AKPlayer+Fader.swift | 4 +--- .../Players/Player/AKPlayer+Playback.swift | 2 +- .../Nodes/Playback/Players/Player/AKPlayer.swift | 7 +++++-- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKDynamicPlayer.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKDynamicPlayer.swift index a3317cd4da..ba9b0e2faa 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKDynamicPlayer.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKDynamicPlayer.swift @@ -7,7 +7,6 @@ // public class AKDynamicPlayer: AKPlayer { - /// The time pitch node - disabled by default public private(set) var timePitchNode: AKTimePitch? @@ -18,6 +17,10 @@ public class AKDynamicPlayer: AKPlayer { } set { + if newValue == rate { + return + } + // timePitch is only installed if it is requested. This saves resources. if timePitchNode != nil && newValue == 1 { removeTimePitch() @@ -42,6 +45,9 @@ public class AKDynamicPlayer: AKPlayer { } set { + if newValue == pitch { + return + } // timePitch is only installed if it is requested. This saves resources. if timePitchNode != nil && newValue == 0 { removeTimePitch() @@ -76,25 +82,28 @@ public class AKDynamicPlayer: AKPlayer { internal override func connectNodes() { guard let processingFormat = processingFormat else { return } - AKLog(processingFormat) - if let timePitchNode = timePitchNode, let faderNode = faderNode { AudioKit.connect(playerNode, to: timePitchNode.avAudioNode, format: processingFormat) AudioKit.connect(timePitchNode.avAudioNode, to: faderNode.avAudioNode, format: processingFormat) AudioKit.connect(faderNode.avAudioNode, to: mixer, format: processingFormat) timePitchNode.bypass() // bypass timePitch by default to save CPU + AKLog(audioFile?.url.lastPathComponent ?? "URL is nil", processingFormat, "Connecting timePitch and fader") } else if let timePitchNode = timePitchNode, faderNode == nil { AudioKit.connect(playerNode, to: timePitchNode.avAudioNode, format: processingFormat) AudioKit.connect(timePitchNode.avAudioNode, to: mixer, format: processingFormat) timePitchNode.bypass() + AKLog(audioFile?.url.lastPathComponent ?? "URL is nil", processingFormat, "Connecting timePitch") } else if let faderNode = faderNode { // if the timePitchNode isn't created connect the player directly to the faderNode AudioKit.connect(playerNode, to: faderNode.avAudioNode, format: processingFormat) AudioKit.connect(faderNode.avAudioNode, to: mixer, format: processingFormat) + AKLog(audioFile?.url.lastPathComponent ?? "URL is nil", processingFormat, "Connecting fader") + } else { AudioKit.connect(playerNode, to: mixer, format: processingFormat) + AKLog(audioFile?.url.lastPathComponent ?? "URL is nil", processingFormat, "Connecting player to mixer") } } diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Buffering.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Buffering.swift index 6da6ba6342..e5435ded93 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Buffering.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Buffering.swift @@ -7,7 +7,6 @@ // extension AKPlayer { - // Fills the buffer with data read from audioFile internal func updateBuffer(force: Bool = false) { if !isBuffered { return } @@ -129,5 +128,4 @@ extension AKPlayer { AKLog("Faded Buffer") } } - } diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift index 8a68d99799..a598253451 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift @@ -6,8 +6,8 @@ // Copyright © 2018 AudioKit. All rights reserved. // +/// The Fader is also used for the gain stage of the player extension AKPlayer { - internal func createFader() { // AKLog("Creating fader AKBooster") faderNode = AKBooster() @@ -40,7 +40,6 @@ extension AKPlayer { userInfo: nil, repeats: false) } - } internal func resetFader(_ state: Bool) { @@ -112,5 +111,4 @@ extension AKPlayer { // AKLog("Fading out to", Fade.minimumGain, ", shape:", fade.outRampType.rawValue) } } - } diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift index 1c9d583102..5aabfb3999 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift @@ -7,7 +7,6 @@ // extension AKPlayer { - /// Play entire file right now @objc public func play() { play(from: startTime, to: endTime, at: nil, hostTime: nil) @@ -62,6 +61,7 @@ extension AKPlayer { play(from: pauseTime) AKLog("Resuming at \(pauseTime)") } + /// Stop playback and cancel any pending scheduled playback or completion events @objc public func stop() { playerNode.stop() diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift index 15aba3c529..70cd469c96 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift @@ -44,7 +44,6 @@ import AVFoundation Please note that pre macOS 10.13 / iOS 11 the completionHandler isn't sample accurate. It's pretty close though. */ public class AKPlayer: AKNode { - /// How the player should handle audio. If buffering, it will load the audio data into /// an internal buffer and play from RAM. If not, it will play the file from disk. /// Dynamic buffering will only load the audio if it needs to for processing reasons @@ -59,11 +58,13 @@ public class AKPlayer: AKNode { if newValue != start { needsUpdate = true } } } + public var end: Double = 0 { willSet { if newValue != end { needsUpdate = true } } } + var needsUpdate: Bool = false } @@ -71,7 +72,7 @@ public class AKPlayer: AKNode { public init() {} /// a constant - public static var minimumGain: Double = 0.000_2 + public static var minimumGain: Double = 0.0002 /// the value that the booster should fade to, settable public var maximumGain: Double = 1 @@ -310,6 +311,7 @@ public class AKPlayer: AKNode { } // MARK: - Public Options + /// true if the player is buffering audio rather than playing from disk public var isBuffered: Bool { return isNormalized || isReversed || buffering == .always @@ -348,6 +350,7 @@ public class AKPlayer: AKNode { } // MARK: - Initialization + public override init() { super.init(avAudioNode: mixer, attach: false) } From 75237db5e5f3493203f2809bd583789ae2f64428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CRyan?= <“hi@spongefork.com”> Date: Mon, 10 Sep 2018 08:58:27 -0700 Subject: [PATCH 2/5] added optional stop() fade envelope to prevent clicks on stop. envelope time is set with new property 'stopEnvelopeTime'. The faderNode AKBooster is used for this fade, same as for fade in/outs. --- .../Playback/Players/Player/AKPlayer+Fader.swift | 2 +- .../Players/Player/AKPlayer+Playback.swift | 15 +++++++++++++++ .../Nodes/Playback/Players/Player/AKPlayer.swift | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift index a598253451..84a24c8c30 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Fader.swift @@ -100,7 +100,7 @@ extension AKPlayer { } } - private func fadeOutWithTime(_ time: Double) { + @objc internal func fadeOutWithTime(_ time: Double) { guard let faderNode = faderNode else { return } if time > 0 { diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift index 5aabfb3999..57a77d65aa 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift @@ -64,6 +64,21 @@ extension AKPlayer { /// Stop playback and cancel any pending scheduled playback or completion events @objc public func stop() { + guard stopEnvelopeTime > 0 else { + stopCompletion() + return + } + + fadeOutWithTime(stopEnvelopeTime) + self.faderTimer = Timer.scheduledTimer(timeInterval: stopEnvelopeTime, + target: self, + selector: #selector(self.stopCompletion), + userInfo: nil, + repeats: false) + + } + + @objc private func stopCompletion() { playerNode.stop() faderNode?.stop() completionTimer?.invalidate() diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift index 5e4f5eee70..81c025124d 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift @@ -121,6 +121,14 @@ public class AKPlayer: AKNode { /// Holds characteristics about the fade options. public var fade = Fade() + public var stopEnvelopeTime: Double = 0 { + didSet { + if faderNode == nil { + createFader() + } + } + } + // MARK: - Nodes /// The underlying player node From 1a128d7b4e3bc542f0fac8dab791191e8c83aa95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CRyan?= <“hi@spongefork.com”> Date: Tue, 11 Sep 2018 18:56:44 -0700 Subject: [PATCH 3/5] invalidate pending fades on play start --- .../Nodes/Playback/Players/Player/AKPlayer+Playback.swift | 2 ++ AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift | 3 +++ 2 files changed, 5 insertions(+) diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift index 57a77d65aa..32b50431c5 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift @@ -43,6 +43,8 @@ extension AKPlayer { hostTime: UInt64? = nil) { let refTime = hostTime ?? mach_absolute_time() let avTime = AVAudioTime.secondsToAudioTime(hostTime: refTime, time: scheduledTime) + + // Note, final play command is in AKPlayer.swift for subclass override play(from: startingTime, to: endingTime, at: avTime, hostTime: refTime) } diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift index 81c025124d..35373aa555 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift @@ -474,6 +474,9 @@ public class AKPlayer: AKNode { /// Placed in main class to be overriden in subclasses if needed. public func play(from startingTime: Double, to endingTime: Double, at audioTime: AVAudioTime?, hostTime: UInt64?) { // AKLog(startingTime, "to", endingTime, "at", audioTime, "hostTime", hostTime) + + faderTimer?.invalidate() + preroll(from: startingTime, to: endingTime) schedule(at: audioTime, hostTime: hostTime) playerNode.play() From 228d4ecfbcd67364545c55dfac6ffa4da88294fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CRyan?= <“hi@spongefork.com”> Date: Tue, 11 Sep 2018 18:58:44 -0700 Subject: [PATCH 4/5] > --- AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift index 35373aa555..299e3da0ae 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer.swift @@ -121,6 +121,8 @@ public class AKPlayer: AKNode { /// Holds characteristics about the fade options. public var fade = Fade() + /// Optional Auto-Fade to audio on stop(). Useful for eliminating clicks with a short 0.1 second fade. + /// Default is 0, or off. public var stopEnvelopeTime: Double = 0 { didSet { if faderNode == nil { From 969426beea5614ff01e7e992dc9973eca122538b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CRyan?= <“hi@spongefork.com”> Date: Tue, 11 Sep 2018 19:01:22 -0700 Subject: [PATCH 5/5] whitespace --- .../Playback/Players/Player/AKPlayer+Playback.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift index 32b50431c5..acec2b911d 100644 --- a/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift +++ b/AudioKit/Common/Nodes/Playback/Players/Player/AKPlayer+Playback.swift @@ -72,12 +72,11 @@ extension AKPlayer { } fadeOutWithTime(stopEnvelopeTime) - self.faderTimer = Timer.scheduledTimer(timeInterval: stopEnvelopeTime, - target: self, - selector: #selector(self.stopCompletion), - userInfo: nil, - repeats: false) - + faderTimer = Timer.scheduledTimer(timeInterval: stopEnvelopeTime, + target: self, + selector: #selector(stopCompletion), + userInfo: nil, + repeats: false) } @objc private func stopCompletion() {