1
1
mirror of https://github.com/wader/fq.git synced 2024-11-29 04:10:01 +03:00
fq/format/midi/sysex.go
twystd 9c7f7f961a midi: fixes for PR comments:
- Renamed 'tracks' section to 'content' (cf. https://github.com/wader/fq/pull/1004#discussion_r1746651234)
- Removed 'validation only' errors (cf. https://github.com/wader/fq/pull/1004#issuecomment-2333464662)
- Decoded MThd divisions field with SMPTE timecode
2024-09-06 15:41:57 -07:00

129 lines
2.6 KiB
Go

package midi
import (
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/scalar"
)
var sysex = scalar.UintMapSymStr{
0xf0: "sysex_message",
0xf7: "sysex_escape",
}
var sysex_extensions = scalar.UintMapSymStr{
0xf7: "sysex_continuation",
}
func decodeSysExEvent(d *decode.D, status uint8, ctx *context) {
ctx.running = 0x00
delta := func(d *decode.D) {
ctx.tick += d.FieldUintFn("delta", vlq)
d.FieldValueUint("tick", ctx.tick)
}
switch {
case status == 0xf0:
d.FieldStruct("sysex_event", func(d *decode.D) {
d.FieldStruct("time", delta)
d.FieldU8("event", sysex)
decodeSysExMessage(d, ctx)
})
case status == 0xf7 && ctx.casio:
d.FieldStruct("sysex_event", func(d *decode.D) {
d.FieldStruct("time", delta)
d.FieldU8("event", sysex_extensions)
decodeSysExContinuation(d, ctx)
})
case status == 0xf7:
d.FieldStruct("sysex_event", func(d *decode.D) {
d.FieldStruct("time", delta)
d.FieldU8("event", sysex)
decodeSysExEscape(d, ctx)
})
default:
flush(d, "unknown SysEx event (%02x)", status)
}
}
func decodeSysExMessage(d *decode.D, ctx *context) {
length := d.FieldUintFn("length", vlq)
if length*8 > uint64(d.BitsLeft()) {
d.Fatalf("invalid field length")
}
d.FieldStruct("message", func(d *decode.D) {
d.FieldU8("manufacturer", manufacturers)
if length < 1 {
ctx.casio = true
d.FieldValueBool("continued", true)
} else {
bytes := d.PeekBytes(int(length - 1))
N := len(bytes)
if N > 0 && bytes[N-1] == 0xf7 {
ctx.casio = false
} else {
ctx.casio = true
}
if N > 0 && bytes[N-1] == 0xf7 {
d.FieldRawLen("data", int64(8*(N-1)))
d.FieldU8("end_of_message")
} else {
d.FieldRawLen("data", int64(8*N))
d.FieldValueBool("continued", true)
}
}
})
}
func decodeSysExContinuation(d *decode.D, ctx *context) {
length := d.FieldUintFn("length", vlq)
if length*8 > uint64(d.BitsLeft()) {
d.Fatalf("invalid field length")
}
d.FieldStruct("continuation", func(d *decode.D) {
if length > 0 {
bytes := d.PeekBytes(int(length))
N := len(bytes)
if N > 0 && bytes[N-1] == 0xf7 {
ctx.casio = false
} else {
ctx.casio = true
}
if N > 0 && bytes[N-1] == 0xf7 {
d.FieldRawLen("data", int64(8*(N-1)))
d.FieldU8("end_of_message")
} else {
d.FieldRawLen("data", int64(8*N))
d.FieldValueBool("continued", true)
}
}
})
}
func decodeSysExEscape(d *decode.D, ctx *context) {
length := d.FieldUintFn("length", vlq)
if length*8 > uint64(d.BitsLeft()) {
d.Fatalf("invalid field length")
}
d.FieldStruct("escape", func(d *decode.D) {
d.FieldRawLen("data", int64(8*length))
})
ctx.casio = false
}