-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
tabs_parser.go
125 lines (117 loc) · 2.25 KB
/
tabs_parser.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package core
import (
"fmt"
"strconv"
"strings"
)
var allowedTabnoteNames = "EADGeadg="
type tabnoteSTM struct {
fraction float32
dotted bool
name string
accidental int
fret int
velocity string
}
func newTabNoteSTM() *tabnoteSTM {
s := new(tabnoteSTM)
s.reset()
return s
}
func (s *tabnoteSTM) reset() {
s.dotted = false
s.fraction = 0.25
s.name = ""
s.fret = 0
s.velocity = ""
}
func (s *tabnoteSTM) accept(lit string) error {
if len(lit) == 0 {
return nil
}
if strings.HasSuffix(lit, ".") {
// without dot
if err := s.accept(lit[0 : len(lit)-1]); err != nil {
return err
}
lit = "."
// proceed
}
if len(s.name) == 0 {
if strings.ContainsAny(lit, allowedTabnoteNames) {
if len(lit) != 1 {
return fmt.Errorf("invalid note name, must be one character, got:%s", lit)
}
s.name = strings.ToUpper(lit)
return nil
}
// fraction or dotted
if lit == "." {
if s.dotted {
return fmt.Errorf("duration already known, got:%s", lit)
}
s.dotted = true
return nil
}
var f float32
switch lit {
case "16":
f = 0.0625
case "8":
f = 0.125
case "4":
f = 0.25
case "2":
f = 0.5
case "1":
f = 1
default:
return fmt.Errorf("invalid fraction or illegal note name, got:%s", lit)
}
if s.fraction != 0.25 {
return fmt.Errorf("fraction already known, got:%s", lit)
}
s.fraction = f
return nil
} else {
// name is set
if strings.ContainsAny(lit, allowedNoteNames) {
return fmt.Errorf("name already known, got:%s", lit)
}
// velocity
if strings.ContainsAny(lit, "-o+") {
s.velocity += lit
return nil
}
// fret
if i, err := strconv.Atoi(lit); err != nil {
return fmt.Errorf("invalid fret, unexpected:%s", lit)
} else {
s.fret = i
}
}
return nil
}
func (s *tabnoteSTM) currentNote() (TabNote, error) {
vel := Normal
if len(s.velocity) > 0 {
vel = ParseVelocity(s.velocity)
if vel == -1 {
return TabNote{}, fmt.Errorf("invalid dynamic, unexpected:%s", s.velocity)
}
}
return TabNote{
Name: s.name,
Fret: s.fret,
Velocity: vel,
fraction: s.fraction,
Dotted: s.dotted,
}, nil
}
func (s *tabnoteSTM) note() (TabNote, error) {
c, err := s.currentNote()
if err != nil {
return TabNote{}, err
}
return c, nil
}