web-tuner/intervals.go

102 lines
2.2 KiB
Go

package main
import "strings"
type IntervalPair struct {
Strings [2]int `json:"strings"`
Name string `json:"name"`
Semitones int `json:"semitones"`
}
type IntervalData struct {
StringGroup []int `json:"string_group"`
FretPositions []int `json:"fret_positions"`
Intervals []IntervalPair `json:"intervals"`
}
var intervalNames = [12]string{
"P1", "m2", "M2", "m3", "M3", "P4",
"TT", "P5", "m6", "M6", "m7", "M7",
}
func intervalName(semitones int) string {
s := semitones % 12
if s < 0 {
s += 12
}
return intervalNames[s]
}
func generateIntervalPairs(cfg Config) []IntervalData {
tuning := cfg.Tuning
numStrings := len(tuning)
var result []IntervalData
for size := 2; size <= numStrings; size++ {
stringGroups := combinationsOf(numStrings, size)
for _, group := range stringGroups {
fretProduct := cartesianFrets(size, 6)
for _, frets := range fretProduct {
var pairs []IntervalPair
for i := 0; i < size; i++ {
for j := i + 1; j < size; j++ {
si, sj := group[i], group[j]
fi, fj := frets[i], frets[j]
sem := (NoteToSemitone[strings.TrimSpace(tuning[sj])] + fj -
NoteToSemitone[strings.TrimSpace(tuning[si])] - fi + 120) % 12
pairs = append(pairs, IntervalPair{
Strings: [2]int{si, sj},
Name: intervalName(sem),
Semitones: sem,
})
}
}
result = append(result, IntervalData{
StringGroup: group,
FretPositions: frets,
Intervals: pairs,
})
}
}
}
return result
}
func combinationsOf(n, k int) [][]int {
var results [][]int
combo := make([]int, k)
var gen func(start, depth int)
gen = func(start, depth int) {
if depth == k {
cp := make([]int, k)
copy(cp, combo)
results = append(results, cp)
return
}
for i := start; i < n; i++ {
combo[depth] = i
gen(i+1, depth+1)
}
}
gen(0, 0)
return results
}
func cartesianFrets(size, maxFret int) [][]int {
total := 1
for i := 0; i < size; i++ {
total *= maxFret
}
results := make([][]int, total)
for i := 0; i < total; i++ {
combo := make([]int, size)
tmp := i
for s := size - 1; s >= 0; s-- {
combo[s] = tmp % maxFret
tmp /= maxFret
}
results[i] = combo
}
return results
}