diff --git a/internal/processor/midi-message-filter.go b/internal/processor/midi-message-filter.go new file mode 100644 index 0000000..9c76764 --- /dev/null +++ b/internal/processor/midi-message-filter.go @@ -0,0 +1,55 @@ +//go:build cgo + +package processor + +import ( + "context" + "fmt" + + "github.com/jwetzell/showbridge-go/internal/config" + "gitlab.com/gomidi/midi/v2" +) + +type MIDIMessageFilter struct { + config config.ProcessorConfig + MIDIType string +} + +func (mmf *MIDIMessageFilter) Process(ctx context.Context, payload any) (any, error) { + payloadMessage, ok := payload.(midi.Message) + + if !ok { + return nil, fmt.Errorf("midi.message.filter processor only accepts an midi.Message") + } + + if payloadMessage.Type().String() != mmf.MIDIType { + return nil, nil + } + + return payloadMessage, nil +} + +func (mmf *MIDIMessageFilter) Type() string { + return mmf.config.Type +} + +func init() { + RegisterProcessor(ProcessorRegistration{ + Type: "midi.message.filter", + New: func(config config.ProcessorConfig) (Processor, error) { + params := config.Params + midiType, ok := params["type"] + + if !ok { + return nil, fmt.Errorf("midi.message.filter requires a type parameter") + } + midiTypeString, ok := midiType.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.filter type must be a string") + } + + return &MIDIMessageFilter{config: config, MIDIType: midiTypeString}, nil + }, + }) +} diff --git a/internal/processor/midi-message-unpack.go b/internal/processor/midi-message-unpack.go new file mode 100644 index 0000000..5933f9e --- /dev/null +++ b/internal/processor/midi-message-unpack.go @@ -0,0 +1,90 @@ +//go:build cgo + +package processor + +import ( + "context" + "fmt" + + "github.com/jwetzell/showbridge-go/internal/config" + "gitlab.com/gomidi/midi/v2" +) + +type MIDIMessageUnpack struct { + config config.ProcessorConfig +} + +type MIDINoteOn struct { + Channel uint8 + Note uint8 + Velocity uint8 +} + +type MIDINoteOff struct { + Channel uint8 + Note uint8 + Velocity uint8 +} + +type MIDIControlChange struct { + Channel uint8 + Control uint8 + Value uint8 +} + +type MIDIProgramChange struct { + Channel uint8 + Program uint8 +} + +type MIDIPitchBend struct { + Channel uint8 + Relative int16 + Absolute uint16 +} + +func (mmu *MIDIMessageUnpack) Process(ctx context.Context, payload any) (any, error) { + payloadMidi, ok := payload.(midi.Message) + + if !ok { + return nil, fmt.Errorf("midi.message.unpack processor only accepts a midi.Message") + } + + switch payloadMidi.Type() { + case midi.NoteOnMsg: + noteOnMsg := MIDINoteOn{} + payloadMidi.GetNoteOn(¬eOnMsg.Channel, ¬eOnMsg.Note, ¬eOnMsg.Velocity) + return noteOnMsg, nil + case midi.NoteOffMsg: + noteOffMsg := MIDINoteOff{} + payloadMidi.GetNoteOff(¬eOffMsg.Channel, ¬eOffMsg.Note, ¬eOffMsg.Velocity) + return noteOffMsg, nil + case midi.ControlChangeMsg: + controlChangeMsg := MIDIControlChange{} + payloadMidi.GetControlChange(&controlChangeMsg.Channel, &controlChangeMsg.Control, &controlChangeMsg.Value) + return controlChangeMsg, nil + case midi.ProgramChangeMsg: + programChangeMsg := MIDIProgramChange{} + payloadMidi.GetProgramChange(&programChangeMsg.Channel, &programChangeMsg.Program) + return programChangeMsg, nil + case midi.PitchBendMsg: + pitchBendMsg := MIDIPitchBend{} + payloadMidi.GetPitchBend(&pitchBendMsg.Channel, &pitchBendMsg.Relative, &pitchBendMsg.Absolute) + return pitchBendMsg, nil + default: + return nil, fmt.Errorf("midi.message.unpack message type not supported %v", payloadMidi.Type()) + } +} + +func (mmu *MIDIMessageUnpack) Type() string { + return mmu.config.Type +} + +func init() { + RegisterProcessor(ProcessorRegistration{ + Type: "midi.message.unpack", + New: func(config config.ProcessorConfig) (Processor, error) { + return &MIDIMessageUnpack{config: config}, nil + }, + }) +}