102 lines
2.2 KiB
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
|
|
}
|