diff --git a/internal/processor/midi-message-create.go b/internal/processor/midi-message-create.go new file mode 100644 index 0000000..fdb7ea7 --- /dev/null +++ b/internal/processor/midi-message-create.go @@ -0,0 +1,213 @@ +//go:build cgo + +package processor + +import ( + "bytes" + "context" + "fmt" + "strconv" + "text/template" + + "github.com/jwetzell/showbridge-go/internal/config" + "gitlab.com/gomidi/midi/v2" +) + +type MIDIMessageCreate struct { + config config.ProcessorConfig + ProcessFunc func(ctx context.Context, payload any) (any, error) +} + +func (mmd *MIDIMessageCreate) Process(ctx context.Context, payload any) (any, error) { + return mmd.ProcessFunc(ctx, payload) +} + +func (mmd *MIDIMessageCreate) Type() string { + return mmd.config.Type +} + +func newMidiNoteOnCreate(config config.ProcessorConfig) (Processor, error) { + + params := config.Params + + channel, ok := params["channel"] + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn requires a channel parameter") + } + + channelString, ok := channel.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn channel must be a string") + } + + channelTemplate, err := template.New("channel").Parse(channelString) + + if err != nil { + return nil, err + } + + note, ok := params["note"] + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn requires a note parameter") + } + + noteString, ok := note.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn note must be a string") + } + + noteTemplate, err := template.New("note").Parse(noteString) + + if err != nil { + return nil, err + } + + velocity, ok := params["velocity"] + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn requires a velocity parameter") + } + + velocityString, ok := velocity.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn velocity must be a string") + } + + velocityTemplate, err := template.New("velocity").Parse(velocityString) + + if err != nil { + return nil, err + } + + return &MIDIMessageCreate{config: config, ProcessFunc: func(ctx context.Context, payload any) (any, error) { + + var channelBuffer bytes.Buffer + err := channelTemplate.Execute(&channelBuffer, payload) + + if err != nil { + return nil, err + } + + channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8) + + var noteBuffer bytes.Buffer + err = noteTemplate.Execute(¬eBuffer, payload) + + if err != nil { + return nil, err + } + + noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8) + + var velocityBuffer bytes.Buffer + err = velocityTemplate.Execute(&velocityBuffer, payload) + + if err != nil { + return nil, err + } + + velocityValue, err := strconv.ParseUint(velocityBuffer.String(), 10, 8) + payloadMessage := midi.NoteOn(uint8(channelValue), uint8(noteValue), uint8(velocityValue)) + return payloadMessage, nil + }}, nil +} + +func newMidiNoteOffCreate(config config.ProcessorConfig) (Processor, error) { + + params := config.Params + + channel, ok := params["channel"] + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn requires a channel parameter") + } + + channelString, ok := channel.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn channel must be a string") + } + + channelTemplate, err := template.New("channel").Parse(channelString) + + if err != nil { + return nil, err + } + + note, ok := params["note"] + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn requires a note parameter") + } + + noteString, ok := note.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.create NoteOn note must be a string") + } + + noteTemplate, err := template.New("note").Parse(noteString) + + if err != nil { + return nil, err + } + + return &MIDIMessageCreate{config: config, ProcessFunc: func(ctx context.Context, payload any) (any, error) { + + var channelBuffer bytes.Buffer + err := channelTemplate.Execute(&channelBuffer, payload) + + if err != nil { + return nil, err + } + + channelValue, err := strconv.ParseUint(channelBuffer.String(), 10, 8) + + var noteBuffer bytes.Buffer + err = noteTemplate.Execute(¬eBuffer, payload) + + if err != nil { + return nil, err + } + + noteValue, err := strconv.ParseUint(noteBuffer.String(), 10, 8) + + payloadMessage := midi.NoteOff(uint8(channelValue), uint8(noteValue)) + return payloadMessage, nil + }}, nil +} + +func init() { + RegisterProcessor(ProcessorRegistration{ + Type: "midi.message.create", + New: func(config config.ProcessorConfig) (Processor, error) { + params := config.Params + + msgType, ok := params["type"] + + if !ok { + return nil, fmt.Errorf("midi.message.create requires a type parameter") + } + + msgTypeString, ok := msgType.(string) + + if !ok { + return nil, fmt.Errorf("midi.message.create type parameter must be a string") + } + + switch msgTypeString { + case "NoteOn": + return newMidiNoteOnCreate(config) + case "NoteOff": + return newMidiNoteOffCreate(config) + default: + return nil, fmt.Errorf("midi.message.create does not support type %s", msgTypeString) + } + }, + }) +}