mirror of
https://github.com/wader/fq.git
synced 2024-11-29 04:10:01 +03:00
9c7f7f961a
- 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
129 lines
2.6 KiB
Go
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
|
|
}
|