fade out sound

main
Laurent 3 years ago
parent 51b0430b47
commit 2ce1b66eff
  1. 37
      LeCountdown/Conductor.swift
  2. 2
      LeCountdown/CountdownScheduler.swift
  3. 7
      LeCountdown/LeCountdownApp.swift
  4. 33
      LeCountdown/Sound/DelaySoundPlayer.swift
  5. 6
      LeCountdown/Sound/SoundPlayer.swift
  6. 3
      LeCountdown/Views/ContentView.swift
  7. 23
      LeCountdown/Views/Reusable/VolumeView.swift

@ -61,9 +61,8 @@ class Conductor: ObservableObject {
}
}
func removeLiveTimer(id: String) {
Logger.log("removeLiveTimer")
func removeLiveTimer(id: TimerID) {
// Logger.log("removeLiveTimer")
self.liveTimers.removeAll(where: { $0.id == id })
self.cancelledCountdowns.removeAll(where: { $0 == id })
if let soundPlayer = self._delayedSoundPlayers[id] {
@ -77,7 +76,7 @@ class Conductor: ObservableObject {
fileprivate func _buildLiveTimers() {
Logger.log("_buildLiveTimers")
// Logger.log("_buildLiveTimers")
let liveCountdowns = self.currentCountdowns.map {
return LiveTimer(id: $0, date: $1.end)
@ -127,28 +126,6 @@ class Conductor: ObservableObject {
// MARK: - Countdown
// func startCountdown(_ date: Date, countdown: Countdown) {
//// DispatchQueue.main.async {
//
// Logger.log("Starts countdown: \(countdown.displayName)")
//
// // cleanup existing countdowns
// self.removeLiveTimer(id: countdown.stringId)
//
//// self._cleanupTimers.removeValue(forKey: countdown.stringId)
//
// let dateInterval = DateInterval(start: Date(), end: date)
// self.currentCountdowns[countdown.stringId] = dateInterval
//
//// self._launchLiveActivity(countdown: countdown, endDate: date)
//
//// self._createTimerIntent(countdown)
//
//// Logger.log("countdowns count = \(self.currentCountdowns.count)")
//
//// }
// }
func cancelCountdown(id: TimerID) {
CountdownScheduler.master.cancelCurrentNotifications(countdownId: id)
self.cancelSoundPlayer(id: id)
@ -169,7 +146,7 @@ class Conductor: ObservableObject {
}
}
func prepareAlarm(countdown: Countdown, handler: @escaping (Result<Date?, Error>) -> Void) {
func startCountdown(countdown: Countdown, handler: @escaping (Result<Date?, Error>) -> Void) {
DispatchQueue.main.async {
@ -179,8 +156,7 @@ class Conductor: ObservableObject {
self.removeLiveTimer(id: countdown.stringId)
let sound = countdown.someSound
let soundFile = try SoundFile(fullName: sound.fileName)
let soundPlayer = try DelaySoundPlayer(timerID: countdown.stringId, soundFile: soundFile)
let soundPlayer = try DelaySoundPlayer(timerID: countdown.stringId, sound: sound)
self._delayedSoundPlayers[countdown.stringId] = soundPlayer
try soundPlayer.start(in: countdown.duration,
repeatCount: Int(countdown.repeatCount))
@ -240,8 +216,7 @@ class Conductor: ObservableObject {
do {
let sound: Sound = countdown.someSound
let soundFile: SoundFile = try SoundFile(fullName: sound.fileName)
let soundPlayer = try DelaySoundPlayer(timerID: countdownId, soundFile: soundFile)
let soundPlayer = try DelaySoundPlayer(timerID: countdownId, sound: sound)
self._delayedSoundPlayers[countdown.stringId] = soundPlayer
try soundPlayer.restore(for: interval.end, repeatCount: Int(countdown.repeatCount))
} catch {

@ -16,7 +16,7 @@ class CountdownScheduler {
func scheduleIfPossible(countdown: Countdown, handler: @escaping (Result<Date?, Error>) -> Void) {
self.cancelCurrentNotifications(countdownId: countdown.stringId)
Conductor.maestro.prepareAlarm(countdown: countdown, handler: handler)
Conductor.maestro.startCountdown(countdown: countdown, handler: handler)
self._scheduleCountdownNotification(countdown: countdown, handler: handler)
}

@ -40,9 +40,8 @@ struct LeCountdownApp: App {
var body: some Scene {
WindowGroup {
Group {
ZStack {
#if os(iOS)
if UIDevice.isPhoneIdiom {
CompactHomeView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
@ -55,9 +54,6 @@ struct LeCountdownApp: App {
.environment(\.managedObjectContext, persistenceController.container.viewContext)
#endif
}
// .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
// self._willEnterForegroundNotification()
// }
.onAppear {
self._onAppear()
}
@ -82,7 +78,6 @@ struct LeCountdownApp: App {
Logger.log("preferredLanguages = \(String(describing: Locale.preferredLanguages))")
self._patch()
// let voices = AVSpeechSynthesisVoice.speechVoices()

@ -1,5 +1,5 @@
//
// BackgroundSoundPlayer.swift
// DelaySoundPlayer.swift
// LeCountdown
//
// Created by Laurent Morvillier on 08/03/2023.
@ -14,9 +14,16 @@ import AVFoundation
fileprivate var _timerID: TimerID
init(timerID: TimerID, soundFile: SoundFile) throws {
fileprivate var _soundDuration: TimeInterval?
fileprivate var _timer: Timer? = nil
init(timerID: TimerID, sound: Sound) throws {
self._timerID = timerID
self._soundDuration = Preferences.soundDurations[sound.fileName]
let soundFile = try sound.soundFile()
guard let url = soundFile.url else {
throw SoundPlayerError.missingResourceError(file: soundFile)
}
@ -46,13 +53,33 @@ import AVFoundation
Logger.log("self._player.deviceCurrentTime = \(self._player.deviceCurrentTime)")
self._player.play(atTime: self._player.deviceCurrentTime + duration)
if repeatCount == 0 {
self._scheduleFadeOut(duration: duration)
}
}
func stop() {
self._player.stop()
}
fileprivate func _scheduleFadeOut(duration: TimeInterval) {
// Logger.log("_scheduleFadeOut")
guard let soundDuration = self._soundDuration, soundDuration > 1.0 else {
return
}
let interval = duration + soundDuration - 1.0
// Logger.log("Fade in \(interval)")
let date = Date(timeIntervalSinceNow: interval)
self._timer = Timer(fire: date, interval: 0.0, repeats: false) { _ in
// Logger.log("FADEOUT!")
self._player.setVolume(0.0, fadeDuration: 1.0)
}
self._timer?.fire()
}
// MARK: - Delegate
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {

@ -59,11 +59,11 @@ enum SoundPlayerError : Error {
player.prepareToPlay()
player.volume = 1.0
player.delegate = self
self._player = player
Logger.log("Plays \(url) on player: \(String(describing: self._player))")
Logger.log("SoundPlayer > .deviceCurrentTime = \(player.deviceCurrentTime)")
// Logger.log("Plays \(url) on player: \(String(describing: self._player))")
// Logger.log("SoundPlayer > .deviceCurrentTime = \(player.deviceCurrentTime)")
player.play()
}

@ -81,7 +81,8 @@ struct ContentView<T : AbstractTimer>: View {
SiriTimerView(timer: self.boringContext.siriTimer, isVisible: self.$siriTipShown)
HStack(alignment: .center) {
VolumeView().padding(12.0)
VolumeView()
.padding(12.0)
}.frame(width: 300.0, height: 40.0)
.background(Color(white: 0.9))
.cornerRadius(16.0)

@ -10,28 +10,37 @@ import MediaPlayer
import UIKit
struct VolumeView: UIViewRepresentable {
var changeVolume: Bool
init(changeVolume: Bool = false) {
self.changeVolume = changeVolume
}
func makeUIView(context: Context) -> MPVolumeView {
let volumeView = MPVolumeView(frame: .zero)
// volumeView.showsLargeContentViewer = false
volumeView.isHidden = self.changeVolume
// if let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider {
// slider.setValue(0.15, animated: false)
// }
self._setVolume(volumeView: volumeView)
if self.changeVolume {
self._setVolume(volumeView: volumeView)
}
return volumeView
}
func updateUIView(_ view: MPVolumeView, context: Context) {
Logger.log("update volume view")
// Logger.log("update volume view")
if self.changeVolume {
self._setVolume(volumeView: view)
}
}
fileprivate func _setVolume(volumeView: MPVolumeView) {
if let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
// Logger.log("update volume view")
slider.setValue(Preferences.defaultVolume, animated: false)
}
}

Loading…
Cancel
Save