music - notes_gen.go
1 // +build ignore
2
3 package main
4
5 import (
6 "flag"
7 "fmt"
8 "math"
9 "os"
10 )
11
12 var notes = [...]string{
13 "C",
14 "Cs",
15 "D",
16 "Ds",
17 "E",
18 "F",
19 "Fs",
20 "G",
21 "Gs",
22 "A",
23 "As",
24 "B",
25 }
26
27 var same = map[string]string{
28 "Cs": "Db",
29 "Ds": "Eb",
30 "Fs": "Gb",
31 "As": "Bb",
32 }
33
34 func e(message string, err error) {
35 if err != nil {
36 fmt.Println(message, err)
37 os.Exit(1)
38 }
39 }
40
41 var spaces = " "
42
43 func main() {
44 var (
45 key uint
46 pitch float64
47 num uint
48 output string
49 )
50 flag.UintVar(&key, "k", 49, "reference key number")
51 flag.Float64Var(&pitch, "p", 440, "reference key pitch")
52 flag.StringVar(&output, "o", "notes.go", "output file")
53 flag.UintVar(&num, "n", 108, "number of notes")
54 flag.Parse()
55 f, err := os.Create(output)
56 e("unable to create output file:", err)
57 _, err = fmt.Fprintf(f, "//go:generate go run notes_gen.go -k %d -p %f -n %d\n"+
58 "// generated with notes_gen.go\n"+
59 "\n"+
60 "package music\n"+
61 "\n"+
62 "type Note float64\n"+
63 "\n"+
64 "const (\n",
65 key, pitch, num)
66 e("error writing file header", err)
67
68 spaces = spaces[:numSize(num)+1]
69
70 semitone := math.Pow(2, float64(1)/12)
71 keyF := float64(key)
72 for i := uint(0); i < num; i++ {
73 note := pitch * math.Pow(semitone, float64(i)-float64(keyF)-8)
74 _, err = fmt.Fprintf(f, " %s%d%sNote = %f\n", notes[i%12], i/12, spaces[uint(len(notes[i%12]))+numSize(i/12):], note)
75 e("error writing note", err)
76 if sn, ok := same[notes[i%12]]; ok {
77 _, err = fmt.Fprintf(f, " %s%d%sNote = %f\n", sn, i/12, spaces[uint(len(notes[i%12]))+numSize(i/12):], note)
78 e("error writing note", err)
79 }
80 }
81 _, err = f.WriteString(")\n")
82 e("error writing file trailer", err)
83 e("error closing file", f.Close())
84 }
85
86 func numSize(n uint) uint {
87 var m uint = 1
88 for n >= 10 {
89 n /= 10
90 m++
91 }
92 return m
93 }