diff --git a/format/midi/TODO.md b/format/midi/TODO.md index 3dfe4def..182e03e4 100644 --- a/format/midi/TODO.md +++ b/format/midi/TODO.md @@ -1,6 +1,6 @@ # TODO -- [ ] update fork from master +- [x] update forked master branch - [ ] discard unknown chunks - [ ] tests - [ ] format 0 @@ -17,25 +17,26 @@ - [ ] format 2 - meta events - - [ ] sequence number - - [ ] text - - [ ] copyright + - [x] sequence number + - [x] text + - [x] copyright - [x] track name - - [ ] instrument name - - [ ] lyric - - [ ] marker - - [ ] cue point - - [ ] program name - - [ ] device name - - [ ] MIDI channel prefix - - [ ] MIDI port - - [ ] end of track + - [x] instrument name + - [x] lyric + - [x] marker + - [x] cue point + - [x] program name + - [x] device name + - [x] MIDI channel prefix + - [x] MIDI port + - [x] end of track - [x] tempo - - [ ] SMPTE offset + - [x] SMPTE offset - [x] key signature - [ ] check key mappings - [x] time signature - [ ] sequencer specific event + - [ ] map manufacturer - midi events - [x] note off @@ -44,7 +45,7 @@ - [ ] map note name - [ ] polyphonic pressure - [x] controller - - [ ] program change + - [x] program change - [ ] channel pressure - [ ] pitch bend diff --git a/format/midi/metaevents.go b/format/midi/metaevents.go index dec71218..9347ff63 100644 --- a/format/midi/metaevents.go +++ b/format/midi/metaevents.go @@ -140,6 +140,14 @@ func decodeMetaEvent(d *decode.D, event uint8) { d.FieldStruct("DeviceName", decodeDeviceName) return + case TypeMIDIChannelPrefix: + d.FieldStruct("TypeMIDIChannelPrefix", decodeMIDIChannelPrefix) + return + + case TypeMIDIPort: + d.FieldStruct("TypeMIDIPort", decodeMIDIPort) + return + case TypeTempo: d.FieldStruct("Tempo", decodeTempo) return @@ -160,9 +168,9 @@ func decodeMetaEvent(d *decode.D, event uint8) { d.FieldStruct("EndOfTrack", decodeEndOfTrack) return - // TypeMIDIChannelPrefix MetaEventType = 0x20 - // TypeMIDIPort MetaEventType = 0x21 - // TypeSequencerSpecificEvent MetaEventType = 0x7f + case TypeSequencerSpecificEvent: + d.FieldStruct("SequencerSpecificEvent", decodeSequencerSpecificEvent) + return } // ... unknown event - flush remaining data @@ -275,6 +283,40 @@ func decodeDeviceName(d *decode.D) { }) } +func decodeMIDIChannelPrefix(d *decode.D) { + d.FieldUintFn("delta", vlq) + d.FieldU8("status") + d.FieldU8("event") + d.FieldUintFn("channel", func(d *decode.D) uint64 { + channel := uint64(0) + data := vlf(d) + + for _, b := range data { + channel <<= 8 + channel |= uint64(b & 0x00ff) + } + + return channel + }) +} + +func decodeMIDIPort(d *decode.D) { + d.FieldUintFn("delta", vlq) + d.FieldU8("status") + d.FieldU8("event") + d.FieldUintFn("port", func(d *decode.D) uint64 { + channel := uint64(0) + data := vlf(d) + + for _, b := range data { + channel <<= 8 + channel |= uint64(b & 0x00ff) + } + + return channel + }) +} + func decodeTempo(d *decode.D) { d.FieldUintFn("delta", vlq) d.FieldU8("status") @@ -377,10 +419,10 @@ func decodeKeySignature(d *decode.D) { 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 + data := vlf(d) + if len(data) > 1 { + key := (uint64(data[0]) << 8) & 0xff00 + key |= (uint64(data[1]) << 0) & 0x00ff d.FieldValueUint("key", key, keys) } @@ -393,3 +435,24 @@ func decodeEndOfTrack(d *decode.D) { vlf(d) } + +func decodeSequencerSpecificEvent(d *decode.D) { + d.FieldUintFn("delta", vlq) + d.FieldU8("status") + d.FieldU8("event") + + data := vlf(d) + if len(data) > 2 && data[0] == 0x00 { + d.FieldValueStr("manufacturer", fmt.Sprintf("%02X%02X%02X", data[0], data[1], data[2])) + + if len(data) > 3 { + d.FieldValueStr("data", fmt.Sprintf("%v", data[3:])) + } + + } else if len(data) > 0 { + d.FieldValueStr("manufacturer", fmt.Sprintf("%02x", data[0])) + if len(data) > 1 { + d.FieldValueStr("data", fmt.Sprintf("%v", data[1:])) + } + } +} diff --git a/format/midi/midi.go b/format/midi/midi.go index a69789fe..7004ec28 100644 --- a/format/midi/midi.go +++ b/format/midi/midi.go @@ -5,7 +5,6 @@ package midi import ( "bytes" "embed" - "fmt" "github.com/wader/fq/format" "github.com/wader/fq/pkg/decode" @@ -101,8 +100,6 @@ func decodeMTrk(d *decode.D) { func decodeEvent(d *decode.D) { _, status, event := peekEvent(d) - fmt.Printf(">> status:%02x event:%02x\n", status, event) - // ... meta event? if status == 0xff { decodeMetaEvent(d, event) diff --git a/format/midi/midievents.go b/format/midi/midievents.go index 7455fd8c..95d43a34 100644 --- a/format/midi/midievents.go +++ b/format/midi/midievents.go @@ -116,6 +116,10 @@ func decodeMIDIEvent(d *decode.D, status uint8) { d.FieldStruct("NoteOn", decodeNoteOn) return + case TypePolyphonicPressure: + d.FieldStruct("PolyphonicPressure", decodePolyphonicPressure) + return + case TypeController: d.FieldStruct("Controller", decodeController) return @@ -124,7 +128,6 @@ func decodeMIDIEvent(d *decode.D, status uint8) { d.FieldStruct("ProgramChange", decodeProgramChange) return - // TypePolyphonicPressure MidiEventType = 0xa0 // TypeProgramChange MidiEventType = 0xc0 // TypeChannelPressure MidiEventType = 0xd0 // TypePitchBend MidiEventType = 0xe0 @@ -162,6 +165,17 @@ func decodeNoteOn(d *decode.D) { d.FieldU8("velocity") } +func decodePolyphonicPressure(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("pressure") +} + func decodeController(d *decode.D) { d.FieldUintFn("delta", vlq) d.FieldUintFn("channel", func(d *decode.D) uint64 {