Skip to content

Commit

Permalink
Play sfx in a loop
Browse files Browse the repository at this point in the history
  • Loading branch information
elgopher committed Sep 3, 2023
1 parent fc0fcc4 commit 073b851
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 82 deletions.
12 changes: 11 additions & 1 deletion audio/audio.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package audio
//
// offset is the note position to start playing (0-31). Offset is clamped to [0,31].
//
// length is the number of notes to play (1-32). Length <= 0 is automatically updated to 32.
// length is the number of notes to play. If length <= 0 and sfx has no loop
// then entire sfx is played. If length < sfx length then only fraction of sfx is
// played. If length <= 0 and sfx has loop then sfx is played infinitely.
func Sfx(sfxNo int, channel Channel, offset, length int) {
system.Sfx(sfxNo, channel, offset, length)
}
Expand Down Expand Up @@ -118,6 +120,14 @@ type SoundEffect struct {
Buzz bool
}

func (s SoundEffect) noteAt(no int) Note {
var note Note
if no < len(s.Notes) {
note = s.Notes[no]
}
return note
}

type Note struct {
Pitch Pitch // 0-63
Instrument Instrument // 0-15
Expand Down
21 changes: 16 additions & 5 deletions audio/synth.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (c *channel) readSample(sfx SoundEffect) float64 {

var sample float64

volume := float64(sfx.Notes[c.noteNo].Volume) / 7
volume := float64(sfx.noteAt(c.noteNo).Volume) / 7
sample = c.oscillator.NextSample() * volume

c.sampleNo += 1
Expand All @@ -72,16 +72,25 @@ func (c *channel) readSample(sfx SoundEffect) float64 {
}

func (c *channel) moveToNextNote(sfx SoundEffect) {
c.notesToGo--
c.noteNo++

if c.noteNo == c.lastNoteNo {
if c.noteNo == int(sfx.LoopStop) {
c.noteNo = int(sfx.LoopStart)
}

maxLenReached := sfx.LoopStop == 0 && int(sfx.LoopStart) == c.noteNo
hasLoop := sfx.LoopStop > 0 // TODO sfx.LoopStart must be != sfx.LoopStop
infiniteLoop := hasLoop && c.infiniteLoop
if (c.notesToGo == 0 && !infiniteLoop) || maxLenReached {
c.playing = false
return
}

c.noteEndSample += singleNoteSamples(sfx.Speed)

note := sfx.Notes[c.noteNo]
note := sfx.noteAt(c.noteNo)

c.oscillator.Func = oscillatorFunc(note.Instrument)
c.oscillator.FreqHz = pitchToFreq(note.Pitch)
}
Expand All @@ -102,6 +111,7 @@ func (s *Synthesizer) Sfx(sfxNo int, ch Channel, offset, length int) {

if length <= 0 {
length = 32
s.channels[ch].infiniteLoop = true
}

s.channels[ch].playing = true
Expand All @@ -110,7 +120,7 @@ func (s *Synthesizer) Sfx(sfxNo int, ch Channel, offset, length int) {

s.channels[ch].sampleNo = 0
s.channels[ch].noteNo = offset
s.channels[ch].lastNoteNo = length
s.channels[ch].notesToGo = length

s.channels[ch].noteEndSample = singleNoteSamples(sfx.Speed)

Expand Down Expand Up @@ -325,7 +335,8 @@ func boolToByte(b bool) byte {
type channel struct {
sfxNo int
noteNo int
lastNoteNo int
notesToGo int
infiniteLoop bool
sampleNo int
noteEndSample int
oscillator internal.Oscillator
Expand Down
Loading

0 comments on commit 073b851

Please sign in to comment.