diff --git a/go.mod b/go.mod index f414092..32d2b9e 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( require ( github.com/gorilla/websocket v1.5.3 // indirect + gitlab.com/gomidi/midi/v2 v2.3.16 // indirect golang.org/x/net v0.44.0 // indirect golang.org/x/sync v0.17.0 // indirect ) diff --git a/go.sum b/go.sum index 49a4f68..a32dd2f 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/urfave/cli/v3 v3.6.0 h1:oIdArVjkdIXHWg3iqxgmqwQGC8NM0JtdgwQAj2sRwFo= github.com/urfave/cli/v3 v3.6.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c= +gitlab.com/gomidi/midi/v2 v2.3.16/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw= golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= diff --git a/midi-client.go b/midi-client.go new file mode 100644 index 0000000..ac0a9da --- /dev/null +++ b/midi-client.go @@ -0,0 +1,114 @@ +package showbridge + +import ( + "fmt" + "log/slog" + + "gitlab.com/gomidi/midi/v2" + _ "gitlab.com/gomidi/midi/v2/drivers/rtmididrv" // autoregisters driver +) + +type MIDIClient struct { + config ModuleConfig + router *Router + InputPort string + OutputPort string + SendFunc func(midi.Message) error +} + +func init() { + RegisterModule(ModuleRegistration{ + Type: "misc.midi.client", + New: func(config ModuleConfig) (Module, error) { + params := config.Params + input, ok := params["input"] + + if !ok { + return nil, fmt.Errorf("net.mqtt.client requires a input parameter") + } + + inputString, ok := input.(string) + + if !ok { + return nil, fmt.Errorf("misc.midi.client input must be a string") + } + + output, ok := params["output"] + + if !ok { + return nil, fmt.Errorf("net.mqtt.client requires a output parameter") + } + + outputString, ok := output.(string) + + if !ok { + return nil, fmt.Errorf("misc.midi.client output must be a string") + } + + return &MIDIClient{config: config, InputPort: inputString, OutputPort: outputString}, nil + }, + }) +} + +func (mc *MIDIClient) Id() string { + return mc.config.Id +} + +func (mc *MIDIClient) Type() string { + return mc.config.Type +} + +func (mc *MIDIClient) RegisterRouter(router *Router) { + mc.router = router +} + +func (mc *MIDIClient) Run() error { + defer midi.CloseDriver() + + in, err := midi.FindInPort(mc.InputPort) + if err != nil { + return fmt.Errorf("misc.midi.client can't find input port: %s", mc.InputPort) + } + + stop, err := midi.ListenTo(in, func(msg midi.Message, timestampms int32) { + if mc.router != nil { + mc.router.HandleInput(mc.Id(), msg) + } + }, midi.UseSysEx()) + defer stop() + + out, err := midi.FindOutPort(mc.OutputPort) + + if err != nil { + return fmt.Errorf("misc.midi.client can't find output port: %s", mc.OutputPort) + } + + send, err := midi.SendTo(out) + if err != nil { + return err + } + + mc.SendFunc = send + + if err != nil { + return err + } + + <-mc.router.Context.Done() + slog.Debug("router context done in module", "id", mc.config.Id) + return nil +} + +func (mc *MIDIClient) Output(payload any) error { + if mc.SendFunc == nil { + return fmt.Errorf("misc.midi.client output is not setup") + } + + payloadMessage, ok := payload.(midi.Message) + + if !ok { + return fmt.Errorf("misc.midi.client can only ouptut midi.Message") + } + + return mc.SendFunc(payloadMessage) +}