-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchannel.go
140 lines (113 loc) · 3.99 KB
/
channel.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package midi
import (
"fmt"
"io"
)
// ChannelEvent represents channel voice and mode messages
type ChannelEvent struct {
coreEvent
Channel uint16
Value1 uint16
Value2 uint16
}
// String representation
func (e *ChannelEvent) String() string {
if e.eventType == PitchWheelChange || e.eventType == ProgramChange {
return fmt.Sprintf("%v: deltaTime %v, channel %v, value %v", eventTypeToString(e.eventType), e.deltaTime, e.Channel, e.Value1)
}
return fmt.Sprintf("%v: deltaTime %v, channel %v, value1 %v, value2 %v", eventTypeToString(e.eventType), e.deltaTime, e.Channel, e.Value1, e.Value2)
}
// WriteTo writer
func (e *ChannelEvent) WriteTo(w io.Writer) (int64, error) {
var totalBytesWritten int64
n, err := w.Write(writeVariableLengthInteger(e.deltaTime))
if err != nil {
return 0, err
}
totalBytesWritten += int64(n)
data := make([]byte, 3)
data[1] = byte(e.Value1)
data[2] = byte(e.Value2)
numBytes := 3
switch e.eventType {
case NoteOff:
data[0] = 0x8
case NoteOn:
data[0] = 0x9
case PolyphonicKeyPressure:
data[0] = 0xA
case ControlChange:
data[0] = 0xB
case ProgramChange:
data[0] = 0xC
numBytes = 2
case ChannelPressure:
data[0] = 0xD
numBytes = 2
case PitchWheelChange:
data[0] = 0xE
data[1] = byte(e.Value1 & 0x7F)
data[2] = byte(e.Value1 >> 7)
}
data[0] = (data[0] << 4) ^ byte(e.Channel)
n, err = w.Write(data[:numBytes])
if err != nil {
return 0, err
}
return totalBytesWritten + int64(n), nil
}
// parseChannelEvent parses a channel voice or mode event
func parseChannelEvent(statusByte uint8, deltaTime uint32, eventType EventType, numValues uint8, data []byte) (event Event, bytesRead uint32, err error) {
ce := &ChannelEvent{}
ce.deltaTime = deltaTime
ce.eventType = eventType
ce.Channel = uint16(statusByte & 0xF)
if len(data) < int(numValues) {
err = fmt.Errorf("channel event of type %v expects %v data bytes", eventTypeToString(eventType), numValues)
return
}
if numValues == 1 {
ce.Value1 = uint16(data[0])
} else if numValues == 2 {
ce.Value1 = uint16(data[0])
ce.Value2 = uint16(data[1])
}
bytesRead = uint32(numValues)
event = ce
return
}
// parseNoteOff parses a note off event
func parseNoteOff(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
return parseChannelEvent(statusByte, deltaTime, NoteOff, 2, data)
}
// parseNoteOn parses a note off event
func parseNoteOn(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
return parseChannelEvent(statusByte, deltaTime, NoteOn, 2, data)
}
// parsePolyphonicKeyPressure parses a polyphonic key pressure event
func parsePolyphonicKeyPressure(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
return parseChannelEvent(statusByte, deltaTime, PolyphonicKeyPressure, 2, data)
}
// parseControlChange parses a control change event
func parseControlChange(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
return parseChannelEvent(statusByte, deltaTime, ControlChange, 2, data)
}
// parseProgramChange parses a program change event
func parseProgramChange(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
return parseChannelEvent(statusByte, deltaTime, ProgramChange, 1, data)
}
// parseChannelPressure parses a channel pressure event
func parseChannelPressure(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
return parseChannelEvent(statusByte, deltaTime, ChannelPressure, 1, data)
}
// parsePitchWheelChange parses a pitch wheel change event
func parsePitchWheelChange(statusByte uint8, deltaTime uint32, data []byte) (event Event, bytesRead uint32, err error) {
event, bytesRead, err = parseChannelEvent(statusByte, deltaTime, PitchWheelChange, 2, data)
if err == nil {
// Get channel event
pw := event.(*ChannelEvent)
// Combine into single 14 bits pitch wheel value
pw.Value1 = (pw.Value2 << 7) ^ pw.Value1
}
return
}