Skip to content

Commit 5ecc9d6

Browse files
committed
Add more info to Sfx stat
Add additional information about remaining notes
1 parent 287c46e commit 5ecc9d6

File tree

5 files changed

+162
-16
lines changed

5 files changed

+162
-16
lines changed

audio/audio.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,16 @@ func GetStat() Stat {
6868
var system System = &Synthesizer{}
6969

7070
type Stat struct {
71-
Sfx [4]int // -1 means no sfx on channel
72-
Note [4]int // -1 means no sfx on channel. Not implemented yet.
73-
Pattern int // currently played music pattern. Not implemented yet.
74-
PatternsCount int // the number of music patterns played since the most recent call to Music(). Not implemented yet.
75-
TicksCount int // the number of ticks (notes or rests) played on the current pattern. Not implemented yet.
71+
Sfx [4]SfxStat
72+
Pattern int // currently played music pattern. Not implemented yet.
73+
PatternsCount int // the number of music patterns played since the most recent call to Music(). Not implemented yet.
74+
TicksCount int // the number of ticks (notes or rests) played on the current pattern. Not implemented yet.
75+
}
76+
77+
type SfxStat struct {
78+
SfxNo int // -1 means no sfx on channel
79+
Note int // current note in sfx
80+
Remaining int // number of remaining notes in sfx. -1 if loop
7681
}
7782

7883
type SoundEffect struct {
@@ -101,6 +106,18 @@ func (s SoundEffect) noteAt(no int) Note {
101106
return note
102107
}
103108

109+
func (s SoundEffect) hasLoop() bool {
110+
return s.LoopStop > s.LoopStart
111+
}
112+
113+
func (s SoundEffect) hasLength() bool {
114+
return s.LoopStart > s.LoopStop
115+
}
116+
117+
func (s SoundEffect) length() int {
118+
return int(s.LoopStart - s.LoopStop)
119+
}
120+
104121
type Note struct {
105122
Pitch Pitch // 0-63
106123
Instrument Instrument // 0-15

audio/synth.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ func (s *Synthesizer) Play(sfxNo, ch, offset, length int) {
115115
s.channels[ch].sfxNo = sfxNo
116116
s.channels[ch].frame = 0
117117
s.channels[ch].noteNo = offset
118+
if length <= 0 && sfx.LoopStop <= sfx.LoopStart {
119+
length = 32
120+
}
121+
if length > 32 {
122+
length = 32
123+
}
118124
s.channels[ch].notesToGo = length
119125
s.channels[ch].loopingDisabled = false
120126

@@ -183,14 +189,29 @@ func (s *Synthesizer) Music(patterNo int, fadeMs int, channelMask byte) {
183189
}
184190

185191
func (s *Synthesizer) Stat() Stat {
186-
fmt.Println("Stat is not implemented yet. Sorry...")
192+
fmt.Println("Stat is not fully implemented yet. Sorry...")
187193

188194
stat := Stat{}
189195
for i, c := range s.channels {
190196
if c.playing {
191-
stat.Sfx[i] = c.sfxNo
197+
sfxStat := SfxStat{
198+
SfxNo: c.sfxNo,
199+
Note: c.noteNo,
200+
Remaining: c.notesToGo,
201+
}
202+
sfx := s.GetSfx(c.sfxNo)
203+
if sfx.hasLoop() {
204+
sfxStat.Remaining = -1
205+
} else if sfx.hasLength() {
206+
sfxStat.Remaining = minInt(sfx.length(), c.notesToGo)
207+
}
208+
stat.Sfx[i] = sfxStat
192209
} else {
193-
stat.Sfx[i] = -1
210+
stat.Sfx[i] = SfxStat{
211+
SfxNo: -1,
212+
Note: -1,
213+
Remaining: 0,
214+
}
194215
}
195216
}
196217
return stat

audio/synth_test.go

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
353353
assertSilence(t, buffer)
354354

355355
t.Run("and next note with max volume should be played", func(t *testing.T) {
356+
assert.Equal(t, 2, synth.Stat().Sfx[0].Note)
356357
synth.ReadSamples(buffer)
357358
assertNotSilence(t, buffer)
358359
})
@@ -415,7 +416,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
415416
synth.Play(sfxNo, -1, 0, 1)
416417
// then
417418
stat := synth.Stat()
418-
assert.Equal(t, sfxNo, stat.Sfx[3])
419+
assert.Equal(t, sfxNo, stat.Sfx[3].SfxNo)
419420
assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne))
420421
})
421422

@@ -435,7 +436,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
435436
synth.Play(sfxNo, -1, 0, 1)
436437
// then
437438
stat := synth.Stat()
438-
assert.Equal(t, sfxNo, stat.Sfx[3])
439+
assert.Equal(t, sfxNo, stat.Sfx[3].SfxNo)
439440
assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne))
440441
})
441442

@@ -451,8 +452,8 @@ func TestSynthesizer_PlayStop(t *testing.T) {
451452
synth.Play(0, 1, 0, 1)
452453
// then
453454
stat := synth.Stat()
454-
assert.Equal(t, -1, stat.Sfx[0])
455-
assert.Equal(t, 0, stat.Sfx[1])
455+
assert.Equal(t, -1, stat.Sfx[0].SfxNo)
456+
assert.Equal(t, 0, stat.Sfx[1].SfxNo)
456457
// and
457458
signal := readSamples(synth, durationOfNoteWhenSpeedIsOne)
458459
expectedSignal := generateSamples(e, durationOfNoteWhenSpeedIsOne)
@@ -477,7 +478,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
477478
synth.Stop(-1)
478479
// then
479480
stat := synth.Stat()
480-
assert.Equal(t, -1, stat.Sfx[0])
481+
assert.Equal(t, -1, stat.Sfx[0].SfxNo)
481482
// and
482483
assertSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne))
483484
})
@@ -500,7 +501,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
500501
synth.StopChan(-1)
501502
// then
502503
stat := synth.Stat()
503-
assert.Equal(t, -1, stat.Sfx[0])
504+
assert.Equal(t, -1, stat.Sfx[0].SfxNo)
504505
// and
505506
assertSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne))
506507
})
@@ -522,7 +523,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
522523
synth.Play(0, ch, 0, 1)
523524
// then
524525
stat := synth.Stat()
525-
assert.Equal(t, 0, stat.Sfx[0])
526+
assert.Equal(t, 0, stat.Sfx[0].SfxNo)
526527
// and
527528
assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne))
528529
})
@@ -546,7 +547,7 @@ func TestSynthesizer_PlayStop(t *testing.T) {
546547
synth.Play(sfxNo, 0, 0, 1)
547548
// then
548549
stat := synth.Stat()
549-
assert.Equal(t, 0, stat.Sfx[0])
550+
assert.Equal(t, 0, stat.Sfx[0].SfxNo)
550551
// and
551552
assertNotSilence(t, readSamples(synth, durationOfNoteWhenSpeedIsOne))
552553
})
@@ -928,6 +929,107 @@ func sfxLengthTest(t *testing.T) {
928929
})
929930
}
930931

932+
func TestSynthesizer_Stat(t *testing.T) {
933+
t.Run("should return sfx stat when no sfx were played", func(t *testing.T) {
934+
var synth audio.Synthesizer
935+
expected := audio.SfxStat{
936+
SfxNo: -1,
937+
Note: -1,
938+
Remaining: 0,
939+
}
940+
stat := synth.Stat()
941+
for i := 0; i < maxChannels; i++ {
942+
assert.Equal(t, expected, stat.Sfx[i])
943+
}
944+
})
945+
946+
t.Run("should return issued note", func(t *testing.T) {
947+
for note := 0; note < 2; note++ {
948+
var synth audio.Synthesizer
949+
synth.Play(0, 0, note, 0)
950+
assert.Equal(t, note, synth.Stat().Sfx[0].Note)
951+
}
952+
})
953+
954+
t.Run("should return issued remaining notes", func(t *testing.T) {
955+
for length := 1; length < 3; length++ {
956+
var synth audio.Synthesizer
957+
synth.Play(0, 0, 0, length)
958+
assert.Equal(t, length, synth.Stat().Sfx[0].Remaining)
959+
}
960+
})
961+
962+
t.Run("should return 32 when issued length was 0", func(t *testing.T) {
963+
var synth audio.Synthesizer
964+
synth.Play(0, 0, 0, 0)
965+
assert.Equal(t, 32, synth.Stat().Sfx[0].Remaining)
966+
})
967+
968+
t.Run("should return -1 when sfx has loop", func(t *testing.T) {
969+
var synth audio.Synthesizer
970+
synth.SetSfx(0, audio.SoundEffect{
971+
LoopStart: 0,
972+
LoopStop: 1,
973+
})
974+
synth.Play(0, 0, 0, 0)
975+
assert.Equal(t, -1, synth.Stat().Sfx[0].Remaining)
976+
})
977+
978+
t.Run("should return -1 when sfx was updated after played", func(t *testing.T) {
979+
var synth audio.Synthesizer
980+
synth.Play(0, 0, 0, 0)
981+
synth.SetSfx(0, audio.SoundEffect{
982+
LoopStart: 0,
983+
LoopStop: 1,
984+
})
985+
assert.Equal(t, -1, synth.Stat().Sfx[0].Remaining)
986+
})
987+
988+
t.Run("should return length when sfx.LoopStart > sfx.LoopStop", func(t *testing.T) {
989+
var synth audio.Synthesizer
990+
synth.SetSfx(0, audio.SoundEffect{
991+
LoopStart: 1, // len=1
992+
LoopStop: 0,
993+
})
994+
synth.Play(0, 0, 0, 0)
995+
assert.Equal(t, 1, synth.Stat().Sfx[0].Remaining)
996+
})
997+
998+
t.Run("should return min length when sfx.LoopStart > sfx.LoopStop", func(t *testing.T) {
999+
var synth audio.Synthesizer
1000+
synth.SetSfx(0, audio.SoundEffect{
1001+
LoopStart: 3, // len=3
1002+
LoopStop: 0,
1003+
})
1004+
synth.Play(0, 0, 0, 2) // len=2
1005+
assert.Equal(t, 2, synth.Stat().Sfx[0].Remaining)
1006+
})
1007+
1008+
t.Run("should return remaining notes after one note was played", func(t *testing.T) {
1009+
var synth audio.Synthesizer
1010+
synth.Play(0, 0, 0, 2)
1011+
readSamples(&synth, durationOfNoteWhenSpeedIsOne)
1012+
assert.Equal(t, 1, synth.Stat().Sfx[0].Remaining)
1013+
})
1014+
1015+
t.Run("should return 32 when length higher than 32", func(t *testing.T) {
1016+
var synth audio.Synthesizer
1017+
synth.Play(0, 0, 0, 33)
1018+
assert.Equal(t, 32, synth.Stat().Sfx[0].Remaining)
1019+
})
1020+
1021+
t.Run("should return remaining notes when sfx has length (loop start > loop stop) and one was played", func(t *testing.T) {
1022+
var synth audio.Synthesizer
1023+
synth.SetSfx(0, audio.SoundEffect{
1024+
LoopStart: 3, // len=3
1025+
LoopStop: 0,
1026+
})
1027+
synth.Play(0, 0, 0, 2)
1028+
readSamples(&synth, durationOfNoteWhenSpeedIsOne)
1029+
assert.Equal(t, 1, synth.Stat().Sfx[0].Remaining)
1030+
})
1031+
}
1032+
9311033
func readSamples(synth *audio.Synthesizer, size int) []float64 {
9321034
buffer := make([]float64, size)
9331035
synth.ReadSamples(buffer)

ebitengine/audio.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ func startAudio() (stop func(), ready <-chan struct{}, _ error) {
5757
audioSystem: synth,
5858
readSamples: liveReader.ReadSamples,
5959
}
60+
stat := audio.GetStat()
6061
audio.SetSystem(audioSystem) // make audio system concurrency-safe
6162
audio.Sync()
63+
for channel, sfx := range stat.Sfx {
64+
audioSystem.Play(sfx.SfxNo, channel, sfx.Note, sfx.Remaining)
65+
}
6266
AudioStream = audioSystem
6367
}
6468

examples/audio/audio.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ func main() {
1717

1818
sfxNote0 := &audio.Sfx[0].Notes[0]
1919

20+
audio.Play(0, 0, 0, 0)
21+
2022
pi.Update = func() {
2123
if pi.Btnp(pi.X) {
2224
audio.Play(0, 0, 0, 0)

0 commit comments

Comments
 (0)