mirror of
https://github.com/wader/fq.git
synced 2024-11-23 00:57:15 +03:00
midi: Decoded KeySignature, NoteOn and Controller events
This commit is contained in:
parent
a1385caf36
commit
3276641208
@ -3,6 +3,7 @@
|
||||
- [ ] add to probe group
|
||||
- [x] move delta into events
|
||||
- [ ] tests
|
||||
- [ ] discard unknown chunks
|
||||
|
||||
- formats
|
||||
- [ ] format 0
|
||||
@ -25,15 +26,16 @@
|
||||
- [ ] end of track
|
||||
- [x] tempo
|
||||
- [ ] SMPTE offset
|
||||
- [ ] key signature
|
||||
- [x] key signature
|
||||
- [ ] check key mappings
|
||||
- [ ] time signature
|
||||
- [ ] sequencer specific event
|
||||
|
||||
- midi events
|
||||
- [ ] note off
|
||||
- [ ] note on
|
||||
- [x] note on
|
||||
- [ ] polyphonic pressure
|
||||
- [ ] controller
|
||||
- [x] controller
|
||||
- [ ] program change
|
||||
- [ ] channel pressure
|
||||
- [ ] pitch bend
|
||||
|
@ -1,7 +1,10 @@
|
||||
package midi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wader/fq/pkg/decode"
|
||||
"github.com/wader/fq/pkg/scalar"
|
||||
)
|
||||
|
||||
type MetaEventType uint8
|
||||
@ -27,6 +30,119 @@ const (
|
||||
TypeSequencerSpecificEvent MetaEventType = 0x7f
|
||||
)
|
||||
|
||||
const (
|
||||
keyCMajor = 0x0001
|
||||
keyGMajor = 0x0101
|
||||
keyDMajor = 0x0201
|
||||
keyAMajor = 0x0301
|
||||
keyEMajor = 0x0401
|
||||
keyBMajor = 0x0501
|
||||
keyFSharpMajor = 0x0601
|
||||
keyCSharpMajor = 0x0701
|
||||
keyFMajor = 0x0801
|
||||
keyBFlatMajor = 0x0901
|
||||
keyEFlatMajor = 0x0a01
|
||||
keyAFlatMajor = 0x0b01
|
||||
keyDFlatMajor = 0x0c01
|
||||
keyGFlatMajor = 0x0d01
|
||||
keyCFlatMajor = 0x0e01
|
||||
|
||||
keyAMinor = 0x0000
|
||||
keyEMinor = 0x0100
|
||||
keyBMinor = 0x0200
|
||||
keyASharpMinor = 0x0300
|
||||
keyDSharpMinor = 0x0400
|
||||
keyGSharpMinor = 0x0500
|
||||
keyCSharpMinor = 0x0600
|
||||
keyFSharpMinor = 0x0700
|
||||
keyDMinor = 0x0800
|
||||
keyGMinor = 0x0900
|
||||
keyCMinor = 0x0a00
|
||||
keyFMinor = 0x0b00
|
||||
keyBFlatMinor = 0x0c00
|
||||
keyEFlatMinor = 0x0d00
|
||||
keyAFlatMinor = 0x0e00
|
||||
)
|
||||
|
||||
var keys = scalar.UintMapSymStr{
|
||||
keyCMajor: "C major",
|
||||
keyGMajor: "G major",
|
||||
keyDMajor: "D major",
|
||||
keyAMajor: "A major",
|
||||
keyEMajor: "E major",
|
||||
keyBMajor: "B major",
|
||||
keyFSharpMajor: "F♯ major",
|
||||
keyCSharpMajor: "C♯ major",
|
||||
keyFMajor: "F major",
|
||||
keyBFlatMajor: "B♭ major",
|
||||
keyEFlatMajor: "E♭ major",
|
||||
keyAFlatMajor: "A♭ major",
|
||||
keyDFlatMajor: "D♭ major",
|
||||
keyGFlatMajor: "G♭ major",
|
||||
keyCFlatMajor: "C♭ major",
|
||||
|
||||
keyAMinor: "A minor",
|
||||
keyEMinor: "E minor",
|
||||
keyBMinor: "B minor",
|
||||
keyASharpMinor: "A♯ minor",
|
||||
keyDSharpMinor: "D♯ minor",
|
||||
keyGSharpMinor: "G♯ minor",
|
||||
keyCSharpMinor: "C♯ minor",
|
||||
keyFSharpMinor: "F♯ minor",
|
||||
keyDMinor: "D minor",
|
||||
keyGMinor: "G minor",
|
||||
keyCMinor: "C minor",
|
||||
keyFMinor: "F minor",
|
||||
keyBFlatMinor: "B♭ minor",
|
||||
keyEFlatMinor: "E♭ minor",
|
||||
keyAFlatMinor: "A♭ minor",
|
||||
}
|
||||
|
||||
func decodeMetaEvent(d *decode.D, event uint8) {
|
||||
switch MetaEventType(event) {
|
||||
case TypeTrackName:
|
||||
d.FieldStruct("TrackName", decodeTrackName)
|
||||
return
|
||||
|
||||
case TypeTempo:
|
||||
d.FieldStruct("Tempo", decodeTempo)
|
||||
return
|
||||
|
||||
case TypeTimeSignature:
|
||||
d.FieldStruct("TimeSignature", decodeTimeSignature)
|
||||
return
|
||||
|
||||
case TypeKeySignature:
|
||||
d.FieldStruct("KeySignature", decodeKeySignature)
|
||||
return
|
||||
|
||||
case TypeEndOfTrack:
|
||||
d.FieldStruct("EndOfTrack", decodeEndOfTrack)
|
||||
return
|
||||
|
||||
// TypeSequenceNumber MetaEventType = 0x00
|
||||
// TypeText MetaEventType = 0x01
|
||||
// TypeCopyright MetaEventType = 0x02
|
||||
// TypeInstrumentName MetaEventType = 0x04
|
||||
// TypeLyric MetaEventType = 0x05
|
||||
// TypeMarker MetaEventType = 0x06
|
||||
// TypeCuePoint MetaEventType = 0x07
|
||||
// TypeProgramName MetaEventType = 0x08
|
||||
// TypeDeviceName MetaEventType = 0x09
|
||||
// TypeMIDIChannelPrefix MetaEventType = 0x20
|
||||
// TypeMIDIPort MetaEventType = 0x21
|
||||
// TypeSMPTEOffset MetaEventType = 0x54
|
||||
// TypeSequencerSpecificEvent MetaEventType = 0x7f
|
||||
}
|
||||
|
||||
// ... unknown event - flush remaining data
|
||||
fmt.Printf("UNKNOWN META EVENT:%02x\n", event)
|
||||
|
||||
var N int = int(d.BitsLeft())
|
||||
|
||||
d.Bits(N)
|
||||
}
|
||||
|
||||
func decodeTrackName(d *decode.D) {
|
||||
d.FieldUintFn("delta", vlq)
|
||||
d.FieldU8("status")
|
||||
@ -84,6 +200,20 @@ func decodeTimeSignature(d *decode.D) {
|
||||
})
|
||||
}
|
||||
|
||||
func decodeKeySignature(d *decode.D) {
|
||||
d.FieldUintFn("delta", vlq)
|
||||
d.FieldU8("status")
|
||||
d.FieldU8("event")
|
||||
|
||||
bytes := vlf(d)
|
||||
if len(bytes) > 1 {
|
||||
key := (uint64(bytes[0]) << 8) & 0xff00
|
||||
key |= (uint64(bytes[1]) << 0) & 0x00ff
|
||||
|
||||
d.FieldValueUint("key", key, keys)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeEndOfTrack(d *decode.D) {
|
||||
d.FieldUintFn("delta", vlq)
|
||||
d.FieldU8("status")
|
||||
|
@ -106,61 +106,14 @@ func decodeEvent(d *decode.D) {
|
||||
|
||||
// ... meta event?
|
||||
if status == 0xff {
|
||||
switch MetaEventType(event) {
|
||||
case TypeTrackName:
|
||||
d.FieldStruct("TrackName", decodeTrackName)
|
||||
return
|
||||
|
||||
case TypeTempo:
|
||||
d.FieldStruct("Tempo", decodeTempo)
|
||||
return
|
||||
|
||||
case TypeTimeSignature:
|
||||
d.FieldStruct("TimeSignature", decodeTimeSignature)
|
||||
return
|
||||
|
||||
case TypeEndOfTrack:
|
||||
d.FieldStruct("EndOfTrack", decodeEndOfTrack)
|
||||
return
|
||||
|
||||
// TypeSequenceNumber MetaEventType = 0x00
|
||||
// TypeText MetaEventType = 0x01
|
||||
// TypeCopyright MetaEventType = 0x02
|
||||
// TypeInstrumentName MetaEventType = 0x04
|
||||
// TypeLyric MetaEventType = 0x05
|
||||
// TypeMarker MetaEventType = 0x06
|
||||
// TypeCuePoint MetaEventType = 0x07
|
||||
// TypeProgramName MetaEventType = 0x08
|
||||
// TypeDeviceName MetaEventType = 0x09
|
||||
// TypeMIDIChannelPrefix MetaEventType = 0x20
|
||||
// TypeMIDIPort MetaEventType = 0x21
|
||||
// TypeSMPTEOffset MetaEventType = 0x54
|
||||
// TypeKeySignature MetaEventType = 0x59
|
||||
// TypeSequencerSpecificEvent MetaEventType = 0x7f
|
||||
}
|
||||
decodeMetaEvent(d, event)
|
||||
return
|
||||
}
|
||||
|
||||
// ... sysex event
|
||||
|
||||
// ... midi event?
|
||||
switch MidiEventType(status & 0xf0) {
|
||||
case TypeProgramChange:
|
||||
d.FieldStruct("ProgramChange", decodeProgramChange)
|
||||
return
|
||||
|
||||
// TypeNoteOff MidiEventType = 0x80
|
||||
// TypeNoteOn MidiEventType = 0x90
|
||||
// TypePolyphonicPressure MidiEventType = 0xa0
|
||||
// TypeController MidiEventType = 0xb0
|
||||
// TypeProgramChange MidiEventType = 0xc0
|
||||
// TypeChannelPressure MidiEventType = 0xd0
|
||||
// TypePitchBend MidiEventType = 0xe0
|
||||
}
|
||||
|
||||
fmt.Printf(">>>>>>>>>>> UNKNOWN: %02x %02x\n", status, event)
|
||||
|
||||
// ... unknown event - flush remaining data
|
||||
var N int = int(d.BitsLeft())
|
||||
|
||||
d.Bits(N)
|
||||
decodeMIDIEvent(d, status)
|
||||
}
|
||||
|
||||
func peekEvent(d *decode.D) (uint64, uint8, uint8) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
package midi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wader/fq/pkg/decode"
|
||||
"github.com/wader/fq/pkg/scalar"
|
||||
)
|
||||
|
||||
type MidiEventType byte
|
||||
@ -16,6 +19,146 @@ const (
|
||||
TypePitchBend MidiEventType = 0xe0
|
||||
)
|
||||
|
||||
var controllers = scalar.UintMapSymStr{
|
||||
// High resolution continuous controllers (MSB)
|
||||
0: "Bank Select (MSB)",
|
||||
1: "Modulation Wheel (MSB)",
|
||||
2: "Breath Controller (MSB)",
|
||||
4: "Foot Controller (MSB)",
|
||||
5: "Portamento Time (MSB)",
|
||||
6: "Data Entry (MSB)",
|
||||
7: "Channel Volume (MSB)",
|
||||
8: "Balance (MSB)",
|
||||
10: "Pan (MSB)",
|
||||
11: "Expression Controller (MSB)",
|
||||
12: "Effect Control 1 (MSB)",
|
||||
13: "Effect Control 2 (MSB)",
|
||||
16: "General Purpose Controller 1 (MSB)",
|
||||
17: "General Purpose Controller 2 (MSB)",
|
||||
18: "General Purpose Controller 3 (MSB)",
|
||||
19: "General Purpose Controller 4 (MSB)",
|
||||
|
||||
// High resolution continuous controllers (LSB)
|
||||
32: "Bank Select (LSB)",
|
||||
33: "Modulation Wheel (LSB)",
|
||||
34: "Breath Controller (LSB)",
|
||||
36: "Foot Controller (LSB)",
|
||||
37: "Portamento Time (LSB)",
|
||||
38: "Data Entry (LSB)",
|
||||
39: "Channel Volume (LSB)",
|
||||
40: "Balance (LSB)",
|
||||
42: "Pan (LSB)",
|
||||
43: "Expression Controller (LSB)",
|
||||
44: "Effect Control 1 (LSB)",
|
||||
45: "Effect Control 2 (LSB)",
|
||||
48: "General Purpose Controller 1 (LSB)",
|
||||
49: "General Purpose Controller 2 (LSB)",
|
||||
50: "General Purpose Controller 3 (LSB)",
|
||||
51: "General Purpose Controller 4 (LSB)",
|
||||
|
||||
// Switches
|
||||
64: "Sustain On/Off",
|
||||
65: "Portamento On/Off",
|
||||
66: "Sostenuto On/Off",
|
||||
67: "Soft Pedal On/Off",
|
||||
68: "Legato On/Off",
|
||||
69: "Hold 2 On/Off",
|
||||
|
||||
// Low resolution continuous controllers
|
||||
70: "Sound Controller 1 (TG: Sound Variation; FX: Exciter On/Off)",
|
||||
71: "Sound Controller 2 (TG: Harmonic Content; FX: Compressor On/Off)",
|
||||
72: "Sound Controller 3 (TG: Release Time; FX: Distortion On/Off)",
|
||||
73: "Sound Controller 4 (TG: Attack Time; FX: EQ On/Off)",
|
||||
74: "Sound Controller 5 (TG: Brightness; FX: Expander On/Off)",
|
||||
75: "Sound Controller 6 (TG: Decay Time; FX: Reverb On/Off)",
|
||||
76: "Sound Controller 7 (TG: Vibrato Rate; FX: Delay On/Off)",
|
||||
77: "Sound Controller 8 (TG: Vibrato Depth; FX: Pitch Transpose On/Off)",
|
||||
78: "Sound Controller 9 (TG: Vibrato Delay; FX: Flange/Chorus On/Off)",
|
||||
79: "Sound Controller 10 (TG: Undefined; FX: Special Effects On/Off)",
|
||||
80: "General Purpose Controller 5",
|
||||
81: "General Purpose Controller 6",
|
||||
82: "General Purpose Controller 7",
|
||||
83: "General Purpose Controller 8",
|
||||
84: "Portamento Control",
|
||||
88: "High Resolution Velocity Prefix",
|
||||
91: "Effects 1 Depth (Reverb Send Level)",
|
||||
92: "Effects 2 Depth (Tremelo Depth)",
|
||||
93: "Effects 3 Depth (Chorus Send Level)",
|
||||
94: "Effects 4 Depth (Celeste Depth)",
|
||||
95: "Effects 5 Depth (Phaser Depth)",
|
||||
|
||||
// RPNs / NRPNs
|
||||
96: "Data Increment",
|
||||
97: "Data Decrement",
|
||||
98: "Non-Registered Parameter Number (LSB)",
|
||||
99: "Non-Registered Parameter Number (MSB)",
|
||||
100: "Registered Parameter Number (LSB)",
|
||||
101: "Registered Parameter Number (MSB)",
|
||||
|
||||
// Channel Mode messages
|
||||
120: "All Sound Off",
|
||||
121: "Reset All Controllers",
|
||||
122: "Local Control On/Off",
|
||||
123: "All Notes Off",
|
||||
124: "Omni Mode Off",
|
||||
125: "Omni Mode On ",
|
||||
126: "Mono Mode On",
|
||||
127: "Poly Mode On",
|
||||
}
|
||||
|
||||
func decodeMIDIEvent(d *decode.D, status uint8) {
|
||||
switch MidiEventType(status & 0xf0) {
|
||||
case TypeNoteOn:
|
||||
d.FieldStruct("NoteOn", decodeNoteOn)
|
||||
return
|
||||
|
||||
case TypeController:
|
||||
d.FieldStruct("Controller", decodeController)
|
||||
return
|
||||
|
||||
case TypeProgramChange:
|
||||
d.FieldStruct("ProgramChange", decodeProgramChange)
|
||||
return
|
||||
|
||||
// TypeNoteOff MidiEventType = 0x80
|
||||
// TypePolyphonicPressure MidiEventType = 0xa0
|
||||
// TypeProgramChange MidiEventType = 0xc0
|
||||
// TypeChannelPressure MidiEventType = 0xd0
|
||||
// TypePitchBend MidiEventType = 0xe0
|
||||
}
|
||||
|
||||
// ... unknown event - flush remaining data
|
||||
fmt.Printf("UNKNOWN MIDI EVENT: %02x\n", status)
|
||||
|
||||
var N int = int(d.BitsLeft())
|
||||
|
||||
d.Bits(N)
|
||||
}
|
||||
|
||||
func decodeNoteOn(d *decode.D) {
|
||||
d.FieldUintFn("delta", vlq)
|
||||
d.FieldUintFn("channel", func(d *decode.D) uint64 {
|
||||
b := d.BytesLen(1)
|
||||
|
||||
return uint64(b[0] & 0x0f)
|
||||
})
|
||||
|
||||
d.FieldU8("note")
|
||||
d.FieldU8("velocity")
|
||||
}
|
||||
|
||||
func decodeController(d *decode.D) {
|
||||
d.FieldUintFn("delta", vlq)
|
||||
d.FieldUintFn("channel", func(d *decode.D) uint64 {
|
||||
b := d.BytesLen(1)
|
||||
|
||||
return uint64(b[0] & 0x0f)
|
||||
})
|
||||
|
||||
d.FieldU8("controller", controllers)
|
||||
d.FieldU8("value")
|
||||
}
|
||||
|
||||
func decodeProgramChange(d *decode.D) {
|
||||
d.FieldUintFn("delta", vlq)
|
||||
d.FieldUintFn("channel", func(d *decode.D) uint64 {
|
||||
|
14
format/midi/testdata/reference.mid
vendored
14
format/midi/testdata/reference.mid
vendored
@ -35,8 +35,16 @@ ff
|
||||
03
|
||||
0f 41 63 6f 75 73 74 69 63 20 47 75 69 74 61 72
|
||||
|
||||
00 c0 19 00 90 30 48
|
||||
00ff 5902 0001 00b0
|
||||
6500 00b0 6400 00b0 0606 8360 8030 4000
|
||||
00 c0 19
|
||||
|
||||
00 90 30 48
|
||||
|
||||
00
|
||||
ff
|
||||
59
|
||||
02 00 01
|
||||
|
||||
00 b0 65 00
|
||||
00b0 6400 00b0 0606 8360 8030 4000
|
||||
9032 4883 6080 3240 0090 3448 8360 8034
|
||||
4000 9035 4883 6080 3540 00ff 2f00
|
Loading…
Reference in New Issue
Block a user