examples/pcm: Refactoring

This commit is contained in:
Hajime Hoshi 2018-01-30 01:13:39 +09:00
parent 35b7375e69
commit c4faf5b12c

View File

@ -19,6 +19,7 @@ package main
import ( import (
"log" "log"
"math" "math"
"strings"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/audio" "github.com/hajimehoshi/ebiten/audio"
@ -41,8 +42,6 @@ func init() {
} }
} }
var frames = 0
const ( const (
freqA = 440.0 freqA = 440.0
freqAS = 466.2 freqAS = 466.2
@ -59,10 +58,11 @@ const (
) )
// Twinkle, Twinkle, Little Star // Twinkle, Twinkle, Little Star
const score = `CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR` var score = strings.Replace(
`CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR`,
var scoreIndex = 0 " ", "", -1)
// square fills out with square wave values with the specified volume, frequency and sequence.
func square(out []int16, volume float64, freq float64, sequence float64) { func square(out []int16, volume float64, freq float64, sequence float64) {
if freq == 0 { if freq == 0 {
for i := 0; i < len(out); i++ { for i := 0; i < len(out); i++ {
@ -83,6 +83,7 @@ func square(out []int16, volume float64, freq float64, sequence float64) {
} }
} }
// toBytes returns the 2ch little endian 16bit byte sequence with the given left/right sequence.
func toBytes(l, r []int16) []byte { func toBytes(l, r []int16) []byte {
if len(l) != len(r) { if len(l) != len(r) {
panic("len(l) must equal to len(r)") panic("len(l) must equal to len(r)")
@ -97,50 +98,60 @@ func toBytes(l, r []int16) []byte {
return b return b
} }
func addNote() rune { // playNote plays the note at scoreIndex of the score.
size := sampleRate / ebiten.FPS func playNote(scoreIndex int) rune {
notes := []float64{freqC, freqD, freqE, freqF, freqG, freqA * 2, freqB * 2}
defer func() {
scoreIndex++
scoreIndex %= len(score)
}()
l := make([]int16, size*30)
r := make([]int16, size*30)
note := score[scoreIndex] note := score[scoreIndex]
for note == ' ' {
scoreIndex++ // If the note is 'rest', play nothing.
scoreIndex %= len(score) if note == 'R' {
note = score[scoreIndex]
}
freq := 0.0
switch {
case note == 'R':
freq = 0
case note <= 'B':
freq = notes[int(note)+len(notes)-int('C')]
default:
freq = notes[note-'C']
}
vol := 1.0 / 16.0
square(l, vol, freq, 0.25)
square(r, vol, freq, 0.25)
b := toBytes(l, r)
p, _ := audio.NewPlayerFromBytes(audioContext, b)
p.Play()
return rune(note) return rune(note)
} }
var currentNote rune freqs := []float64{freqC, freqD, freqE, freqF, freqG, freqA * 2, freqB * 2}
freq := 0.0
switch {
case 'A' <= note && note <= 'B':
freq = freqs[int(note)+len(freqs)-int('C')]
case 'C' <= note && note <= 'G':
freq = freqs[note-'C']
default:
panic("note out of range")
}
const (
vol = 1.0 / 16.0
size = 30 * sampleRate / ebiten.FPS
)
l := make([]int16, size)
r := make([]int16, size)
square(l, vol, freq, 0.25)
square(r, vol, freq, 0.25)
p, _ := audio.NewPlayerFromBytes(audioContext, toBytes(l, r))
p.Play()
return rune(note)
}
var (
scoreIndex = 0
frames = 0
currentNote rune
)
func update(screen *ebiten.Image) error { func update(screen *ebiten.Image) error {
// Play notes for each half second.
if frames%30 == 0 { if frames%30 == 0 {
currentNote = addNote() currentNote = playNote(scoreIndex)
scoreIndex++
scoreIndex %= len(score)
} }
frames++ frames++
if ebiten.IsRunningSlowly() { if ebiten.IsRunningSlowly() {
return nil return nil
} }
msg := "Note: " msg := "Note: "
if currentNote == 'R' { if currentNote == 'R' {
msg += "-" msg += "-"