-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdrum_machine.go
74 lines (58 loc) · 1.87 KB
/
drum_machine.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package main
// #cgo LDFLAGS: /usr/local/lib/libmetro.a /usr/local/lib64/libsoundio.a /usr/local/lib/libstk.a -lstdc++ -lasound -lpulse -ljack -lm
// #include <libmetro/cmetro.h>
import "C"
import (
"fmt"
"github.com/sevagh/drum_machine/internal"
"log"
"os"
"time"
)
func main() {
p := internal.NewParser(os.Stdin)
beats, err := p.Parse()
if err != nil {
log.Fatalf("parse err: %+v\n", err)
}
if len(beats) < 1 {
fmt.Printf("no beats in input file\n")
return
}
tempo, firstTimestampUs, song, err := internal.ValidateBeats(beats)
if err != nil {
log.Fatalf("song error: %+v\n", err)
}
bpm := C.int(tempo)
// this is libmetro's C code
metro := C.metronome_create(bpm)
defer C.metronome_destroy(metro)
var ret C.int
// build a repeating metronome from the first bar
// TODO: all bars are probably repeating since this is pop
// but more complicated bars can coexist by discovering their
// least common multiple and adjusting the bpm and adding silences
// accordingly. libmetro supports this - see
// https://github.com/sevagh/libmetro/blob/master/examples/poly_43.cpp#L39
downbeat := C.note_create_drum_downbeat_1()
defer C.note_destroy(downbeat)
beat := C.note_create_drum_beat_1()
defer C.note_destroy(beat)
measure := C.measure_create(C.int(song[0].NBeats))
defer C.measure_destroy(measure)
C.measure_set_note(measure, C.int(0), downbeat)
for i := 1; i < song[0].NBeats; i++ {
if ret = C.measure_set_note(measure, C.int(i), beat); ret != 0 {
log.Fatalf("error in libmetro C wrapper: %d\n", ret)
}
}
if ret = C.metronome_add_measure(metro, measure); ret != 0 {
log.Fatalf("error in libmetro C wrapper: %d\n", ret)
}
// do an initial sleep of the first timestamp
time.Sleep(firstTimestampUs)
fmt.Println("Ctrl-C to exit any time")
if ret = C.metronome_start_and_loop(metro); ret != 0 {
log.Fatalf("error in libmetro C wrapper: %d\n", ret)
}
}