Skip to content

Commit

Permalink
midi: Decoded MIDIChannelPrefix, MIDIPort and SequencerSpecific metae…
Browse files Browse the repository at this point in the history
…vents
  • Loading branch information
twystd committed Aug 17, 2024
1 parent 2a16748 commit 109719f
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 26 deletions.
31 changes: 16 additions & 15 deletions format/midi/TODO.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TODO

- [ ] update fork from master
- [x] update forked master branch
- [ ] discard unknown chunks
- [ ] tests
- [ ] format 0
Expand All @@ -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
Expand All @@ -44,7 +45,7 @@
- [ ] map note name
- [ ] polyphonic pressure
- [x] controller
- [ ] program change
- [x] program change
- [ ] channel pressure
- [ ] pitch bend

Expand Down
77 changes: 70 additions & 7 deletions format/midi/metaevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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)
}
Expand All @@ -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:]))
}
}
}
3 changes: 0 additions & 3 deletions format/midi/midi.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package midi
import (
"bytes"
"embed"
"fmt"

"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
Expand Down Expand Up @@ -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)
Expand Down
16 changes: 15 additions & 1 deletion format/midi/midievents.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 109719f

Please sign in to comment.