diff --git a/audio/audio.go b/audio/audio.go index 28bd66c..f29b6ef 100644 --- a/audio/audio.go +++ b/audio/audio.go @@ -96,7 +96,7 @@ const ( Channel1 Channel = 1 Channel2 Channel = 2 Channel3 Channel = 3 - ChannelAny Channel = -1 + ChannelAny Channel = -1 // Rename - it means all channels for Sfx(-2, ...) ChannelStop Channel = -2 ) diff --git a/audio/synth.go b/audio/synth.go index 973a755..a2ca821 100644 --- a/audio/synth.go +++ b/audio/synth.go @@ -75,7 +75,7 @@ func (c *channel) moveToNextNote(sfx SoundEffect) { c.notesToGo-- c.noteNo++ - if c.noteNo == int(sfx.LoopStop) { + if c.noteNo == int(sfx.LoopStop) && !c.loopingDisabled { c.noteNo = int(sfx.LoopStart) } @@ -96,6 +96,11 @@ func (c *channel) moveToNextNote(sfx SoundEffect) { func (s *Synthesizer) Sfx(sfxNo int, ch Channel, offset, length int) { fmt.Println("Sfx is not implemented yet. Sorry...") + if sfxNo == -2 { + s.disableLooping(ch) + return + } + if ch >= ChannelStop && ch <= Channel3 { s.stopSfx(sfxNo) } @@ -131,6 +136,19 @@ func (s *Synthesizer) Sfx(sfxNo int, ch Channel, offset, length int) { s.channels[ch].oscillator.FreqHz = pitchToFreq(note0.Pitch) } +func (s *Synthesizer) disableLooping(ch Channel) { + if ch == ChannelAny || ch == ChannelStop { + for i := range s.channels { + s.channels[i].loopingDisabled = true + } + return + } + + if ch >= Channel0 && ch <= Channel3 { + s.channels[ch].loopingDisabled = true + } +} + func (s *Synthesizer) stopSfx(no int) { for i, c := range s.channels { if c.playing && c.sfxNo == no { @@ -364,11 +382,12 @@ func boolToByte(b bool) byte { } type channel struct { - sfxNo int - noteNo int - notesToGo int - frame int - noteEndFrame int - oscillator internal.Oscillator - playing bool + sfxNo int + noteNo int + notesToGo int + frame int + noteEndFrame int + oscillator internal.Oscillator + playing bool + loopingDisabled bool } diff --git a/audio/synth_test.go b/audio/synth_test.go index 0489bba..801971f 100644 --- a/audio/synth_test.go +++ b/audio/synth_test.go @@ -564,7 +564,6 @@ func TestSynthesizer_Sfx(t *testing.T) { assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne)) }) } - }) sfxOffsetLengthTest(t) @@ -820,6 +819,77 @@ func sfxLoopTest(t *testing.T) { }) } }) + + t.Run("should stop the loop on given channel", func(t *testing.T) { + channels := []audio.Channel{audio.Channel0, audio.Channel1, audio.Channel2, audio.Channel3} + + for _, ch := range channels { + testName := fmt.Sprintf("%d", ch) + + t.Run(testName, func(t *testing.T) { + var e audio.SoundEffect + e.Notes[0].Volume = audio.VolumeLoudest + e.Speed = 1 + e.LoopStart = 0 + e.LoopStop = 1 + + synth := &audio.Synthesizer{} + synth.SetSfx(0, e) + + synth.Sfx(0, ch, 0, 32) + // when + synth.Sfx(-2, ch, 0, 0) + // then + assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne)) // wait until entire sfx is played + assertSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne)) // wait until entire sfx is played + }) + } + }) + + t.Run("should stop the loop on all channels", func(t *testing.T) { + channels := []audio.Channel{audio.ChannelAny, audio.ChannelStop} + + for _, ch := range channels { + testName := fmt.Sprintf("%d", ch) + + t.Run(testName, func(t *testing.T) { + var e audio.SoundEffect + e.Notes[0].Volume = audio.VolumeLoudest + e.Speed = 1 + e.LoopStart = 0 + e.LoopStop = 1 + + synth := &audio.Synthesizer{} + synth.SetSfx(0, e) + + synth.Sfx(0, audio.Channel0, 0, 32) + synth.Sfx(0, audio.Channel1, 0, 32) + synth.Sfx(0, audio.Channel2, 0, 32) + synth.Sfx(0, audio.Channel3, 0, 32) + // when + synth.Sfx(-2, ch, 0, 0) + // then + assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne)) // wait until entire sfx is played + assertSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne)) // wait until entire sfx is played + }) + } + }) + + t.Run("should not panic when trying to stop the loop with invalid channel", func(t *testing.T) { + channels := []audio.Channel{-3, 4} + + for _, ch := range channels { + testName := fmt.Sprintf("%d", ch) + + t.Run(testName, func(t *testing.T) { + synth := &audio.Synthesizer{} + + assert.NotPanics(t, func() { + synth.Sfx(-2, ch, 0, 0) + }) + }) + } + }) } func sfxLengthTest(t *testing.T) {