faiface / beep

A little package that brings sound to any Go application. Suitable for playback and audio-processing.
MIT License
2.03k stars 150 forks source link

Setting Streamer to nil not stopping sound #153

Open assemblaj opened 1 year ago

assemblaj commented 1 year ago

Hello, I'm from the IKEMEN-Go project. On our save-state branch, we are having an issue where setting the ctrl.Streamer instance to nilisn't stopping sound. Setting ctrl.Paused = true stops the sound, though. Any suggestions as to what could be wrong and how to pin down this issue? Here is the code in our library:

Our custom streamer for handling Panning and Volume

type SoundEffect struct {
    streamer beep.Streamer
    volume   float32
    ls, p    float32
    x        *float32
}

// sys is our global Game object 
func (s *SoundEffect) Stream(samples [][2]float64) (n int, ok bool) {
    lv, rv := s.volume, s.volume
    if sys.stereoEffects && (s.x != nil || s.p != 0) {
        var r float32
        if s.x != nil { // pan
            r = ((sys.xmax - s.ls**s.x) - s.p) / (sys.xmax - sys.xmin)
        } else { // abspan
            r = ((sys.xmax-sys.xmin)/2 - s.p) / (sys.xmax - sys.xmin)
        }
        sc := sys.panningRange / 100
        of := (100 - sys.panningRange) / 200
        lv = s.volume * 2 * (r*sc + of)
        rv = s.volume * 2 * ((1-r)*sc + of)
        if lv > 512 {
            lv = 512
        } else if lv < 0 {
            lv = 0
        }
        if rv > 512 {
            rv = 512
        } else if rv < 0 {
            rv = 0
        }
    }

    n, ok = s.streamer.Stream(samples)
    for i := range samples[:n] {
        samples[i][0] *= float64(lv / 256)
        samples[i][1] *= float64(rv / 256)
    }
    return n, ok
}

func (s *SoundEffect) Err() error {
    return s.streamer.Err()
}

How we play sound

func (s *SoundChannel) Play(sound *Sound, loop bool, freqmul float32) {
    if sound == nil {
        return
    }
    s.sound = sound
    s.streamer = s.sound.GetStreamer()
    loopCount := int(1)
    if loop {
        loopCount = -1
    }
    looper := beep.Loop(loopCount, s.streamer)
    s.sfx = &SoundEffect{streamer: looper, volume: 256}
    srcRate := s.sound.format.SampleRate
    dstRate := beep.SampleRate(audioFrequency / freqmul)
    resampler := beep.Resample(audioResampleQuality, srcRate, dstRate, s.sfx)
    s.ctrl = &beep.Ctrl{Streamer: resampler}
    sys.soundMixer.Add(s.ctrl)
}

How we are stopping sound

func (s *SoundChannel) Stop() {
    if s.ctrl != nil {
        speaker.Lock()
        s.ctrl.Streamer = nil
        speaker.Unlock()
    }
    s.sound = nil
}