Search code examples
swiftswiftuiavaudioplayeraudio-playertogglebutton

Toggle sound off straight away


I have created a toggle button to turn off/on the music. This problem is i have to close the application for it to take effect.

This is what i use to begin the music:

.onAppear(perform: {self.musicM.playSoundBand(sound: "Band", type: "wav")})

Here is my toggle button:

 Toggle(isOn: self.$musicM.mOn) {
                    ZStack {
                        Image("Button")
                            .renderingMode(.original)
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .rotationEffect(Angle(degrees: 180))
                            .padding([.leading, .trailing], 40);
                        Text("Music")
                            .padding(.all, 20)
                            .padding([.leading, .trailing], 40)
                            .font(.largeTitle)
                            .foregroundColor(.black)
                    }
                    Spacer()
                }.onTapGesture(perform: {if self.musicM.mOn == false { self.musicM.pauseMusicBand(); self.soundEffectsM.playSound(sound: "GunCock", type: "wav")}})

I have tried variations and utilising .stop() but still wont work. If it helps here is my soundmanager class also:

class musicModel: ObservableObject {
    var audioPlayerBand:AVAudioPlayer?
    @Published var mOn: Bool = UserDefaults.standard.bool(forKey: "mOn") {
        didSet {
            UserDefaults.standard.set(self.mOn, forKey: "mOn")
        }
    }
    func pauseMusicBand() {
        UserDefaults.standard.set(false, forKey: "mOn"); audioPlayerBand?.pause()
    }
    func setVolume(volume: Float) {
        audioPlayerBand?.volume = volume
    }
    func playSoundBand(sound: String, type: String) {
        if let path = Bundle.main.path(forResource: sound, ofType: type) {
            do {
                audioPlayerBand = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
                audioPlayerBand?.numberOfLoops =  -1
                audioPlayerBand?.play()
            } catch {
                print("ERROR: Could not find sound file!")
            }; if self.mOn == false { pauseMusicBand() }
        }
    }
}

Solution

  • This test code shows how you can toggle your sound off straight away:

    import SwiftUI
    import Foundation
    import AVFoundation
    
    struct ContentView: View {
    
    @ObservedObject var musicM = musicModel()
    
    var body: some View {
            Toggle(isOn: Binding<Bool>(
                get: { self.musicM.mOn },
                set: { self.musicM.mOn = $0; self.doMusic() })) {
                ZStack {
                    Image("Button")
                        .renderingMode(.original)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .rotationEffect(Angle(degrees: 180))
                        .padding([.leading, .trailing], 40);
                    Text("Music")
                        .padding(.all, 20)
                        .padding([.leading, .trailing], 40)
                        .font(.largeTitle)
                        .foregroundColor(.black)
                }
                Spacer()
        }.onAppear(perform: self.startBackgroundMusic)
    }
    
    func startBackgroundMusic() {
        // if you want to always start the background music, then toggle should be set
    //        self.musicM.mOn = true
    //        self.musicM.playSoundBand(sound: "Band", type: "wav")
    
        // if you want to play the background music only if the user has set it last time
        if self.musicM.mOn {
            self.musicM.playSoundBand(sound: "Band", type: "wav")
        }
    }
    
    func doMusic() {
        if self.musicM.mOn {
            self.musicM.playSoundBand(sound: "Band", type: "wav")
        } else {
            self.musicM.audioPlayerBand?.pause()
         //   self.soundEffectsM.playSound(sound: "GunCock", type: "wav")
        }
    }
    }
    
    class musicModel: ObservableObject {
    var audioPlayerBand: AVAudioPlayer?
    
    @Published var mOn: Bool = UserDefaults.standard.bool(forKey: "mOn") {
        didSet {
            UserDefaults.standard.set(self.mOn, forKey: "mOn")
        }
    }
    func pauseMusicBand() {
        UserDefaults.standard.set(false, forKey: "mOn")
        audioPlayerBand?.pause()
    }
    func setVolume(volume: Float) {
        audioPlayerBand?.volume = volume
    }
    func playSoundBand(sound: String, type: String) {
        if let path = Bundle.main.path(forResource: sound, ofType: type) {
            do {
                audioPlayerBand = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
                audioPlayerBand?.numberOfLoops =  -1
                audioPlayerBand?.play()
            } catch {
                print("ERROR: Could not find sound file!")
            }
        }
    }
    }