143 lines
2.6 KiB
Go
143 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"cart/w4"
|
|
"math/rand"
|
|
)
|
|
|
|
const (
|
|
C int = iota
|
|
Cs
|
|
D
|
|
Ds
|
|
E
|
|
F
|
|
Fs
|
|
G
|
|
Gs
|
|
A
|
|
As
|
|
B
|
|
)
|
|
|
|
var frequencies = []uint{262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494}
|
|
|
|
type Music struct {
|
|
KickProb [8]uint8
|
|
KickLine [8]bool
|
|
SnareProb [8]uint8
|
|
SnareLine [8]bool
|
|
LeadProb [8]uint8
|
|
LeadLine [8]uint
|
|
MainNoteIndex int
|
|
Frame uint64
|
|
CurrentPart uint8
|
|
CurrentLine uint8
|
|
Active bool
|
|
MutedFrames uint
|
|
}
|
|
|
|
func (m *Music) Start() {
|
|
m.GenLines()
|
|
m.Frame = 0
|
|
m.CurrentLine = 0
|
|
m.CurrentPart = 0
|
|
m.Active = true
|
|
}
|
|
func (m *Music) Pause() {
|
|
m.Active = false
|
|
}
|
|
func (m *Music) Resume() {
|
|
m.Active = true
|
|
m.MutedFrames = 0
|
|
}
|
|
|
|
func (m *Music) MuteFor(frames uint) {
|
|
m.MutedFrames = frames
|
|
}
|
|
|
|
var pentaScale = []int{0, 3, 5, 7, 10, 12}
|
|
|
|
func (m *Music) PentaNote(n int) uint {
|
|
pentaIndex := n % 6
|
|
octave := 1 + n/6
|
|
// w4.Trace("Octave: " + strconv.Itoa(octave))
|
|
noteIndex := (m.MainNoteIndex + pentaScale[pentaIndex]) % 12
|
|
return frequencies[noteIndex] * uint(octave)
|
|
}
|
|
|
|
func (m *Music) Update() {
|
|
if !m.Active {
|
|
return
|
|
}
|
|
if m.MutedFrames > 0 {
|
|
m.MutedFrames--
|
|
}
|
|
if m.Frame%15 == 0 {
|
|
if m.MutedFrames == 0 {
|
|
if m.KickLine[m.CurrentLine] {
|
|
w4.Tone(200|1<<16, 5, 60, w4.TONE_TRIANGLE)
|
|
}
|
|
if m.SnareLine[m.CurrentLine] {
|
|
w4.Tone(200|50<<16, 10<<8, 10, w4.TONE_NOISE)
|
|
}
|
|
if m.LeadLine[m.CurrentLine] != 0 {
|
|
w4.Tone(m.LeadLine[m.CurrentLine], 10|15<<8, 5, w4.TONE_MODE2|w4.TONE_PULSE2)
|
|
}
|
|
}
|
|
m.CurrentLine++
|
|
if m.CurrentLine == 8 {
|
|
m.CurrentLine = 0
|
|
m.CurrentPart++
|
|
if m.CurrentPart == 4 {
|
|
m.CurrentPart = 0
|
|
m.GenLines()
|
|
}
|
|
}
|
|
}
|
|
m.Frame++
|
|
}
|
|
|
|
func (m *Music) GenLines() {
|
|
m.KickLine = m.GenDrumLine(m.KickProb)
|
|
m.SnareLine = m.GenDrumLine(m.SnareProb)
|
|
m.LeadLine = m.GenLeadLine(m.LeadProb)
|
|
m.MainNoteIndex = rand.Intn(5)
|
|
}
|
|
|
|
func (m *Music) GenDrumLine(prob [8]uint8) [8]bool {
|
|
line := [8]bool{}
|
|
for i, p := range prob {
|
|
line[i] = rand.Intn(101) < int(p)
|
|
}
|
|
return line
|
|
}
|
|
|
|
func (m *Music) GenLeadLine(prob [8]uint8) [8]uint {
|
|
line := [8]uint{}
|
|
pattern := [8]int{}
|
|
offset := rand.Intn(6)
|
|
switch rand.Intn(4) {
|
|
case 0:
|
|
pattern = [8]int{0, 1, 2, 3, 0, 1, 2, 3}
|
|
case 1:
|
|
pattern = [8]int{3, 2, 1, 0, 3, 2, 1, 0}
|
|
case 2:
|
|
pattern = [8]int{7, 5, 6, 4, 5, 3, 4, 2}
|
|
case 3:
|
|
pattern = [8]int{0, 2, 1, 3, 2, 4, 3, 5}
|
|
case 4:
|
|
pattern = [8]int{0, 2, 4, 1, 3, 5, 2, 4}
|
|
case 5:
|
|
pattern = [8]int{4, 2, 5, 3, 1, 4, 2, 0}
|
|
}
|
|
for i, p := range prob {
|
|
if rand.Intn(101) < int(p) {
|
|
line[i] = m.PentaNote(pattern[i]+offset) / 2
|
|
continue
|
|
}
|
|
line[i] = 0
|
|
}
|
|
return line
|
|
}
|