From ae28a4d385cd341059e6a07e5a925f90fdb0a0c9 Mon Sep 17 00:00:00 2001 From: datalore Date: Sat, 9 Aug 2025 17:43:55 +0200 Subject: [PATCH] housekeeping: Refactored API to separate packages --- config.go => config/config.go | 34 ++++++++-------- main.go | 6 ++- controller.go => translation/controller.go | 2 +- mapping.go => translation/mapping.go | 46 +++++++++++----------- midi.go => translation/midi.go | 2 +- 5 files changed, 47 insertions(+), 43 deletions(-) rename config.go => config/config.go (83%) rename controller.go => translation/controller.go (99%) rename mapping.go => translation/mapping.go (78%) rename midi.go => translation/midi.go (98%) diff --git a/config.go b/config/config.go similarity index 83% rename from config.go rename to config/config.go index 26f9d13..ade05ab 100644 --- a/config.go +++ b/config/config.go @@ -1,9 +1,11 @@ -package main +package config import ( "fmt" "os" + "git.datalore.sh/datalore/midi-hid/translation" + "github.com/goccy/go-yaml" "github.com/bendahl/uinput" "github.com/charmbracelet/log" @@ -84,8 +86,8 @@ func ParseConfig(path string) (Config, error) { // Construct iterates over all ControllerConfigs and constructs the Controller objects. // In case of a failure, it aborts and returns an error. -func (config Config) Construct() (ControllerList, error) { - var controllerList ControllerList +func (config Config) Construct() (translation.ControllerList, error) { + var controllerList translation.ControllerList for _, controllerConfig := range config.Controller { actualController, err := controllerConfig.Construct() @@ -102,8 +104,8 @@ func (config Config) Construct() (ControllerList, error) { // Construct builds a Controller object and its corresponding mappings. // Aborts and returns an error if the midi port was not found or one of // the Mappings is invalid. -func (cc ControllerConfig) Construct() (*Controller, error) { - actualController, err := NewController(cc.PortName, cc.VendorID, cc.ProductID) +func (cc ControllerConfig) Construct() (*translation.Controller, error) { + actualController, err := translation.NewController(cc.PortName, cc.VendorID, cc.ProductID) if err != nil { return actualController, err } @@ -121,28 +123,28 @@ func (cc ControllerConfig) Construct() (*Controller, error) { } // Construct builds the Mapping object. Returns an error if config is invalid. -func (mc MappingConfig) Construct() (Mapping, error) { +func (mc MappingConfig) Construct() (translation.Mapping, error) { switch mc.Type { case ButtonMappingType: button, err := mc.Button.Construct() if err != nil { - return ButtonMapping{}, err + return translation.ButtonMapping{}, err } log.Debug("Parsed button mapping", "comment", mc.Comment, "midiChannel", mc.MidiChannel, "midiKey", mc.MidiKey, "button", button) - return ButtonMapping{mc.Comment, mc.MidiChannel, mc.MidiKey, button}, nil + return translation.ButtonMapping{mc.Comment, mc.MidiChannel, mc.MidiKey, button}, nil case ControlMappingType: axis, err := mc.Axis.Construct() if err != nil { - return ControlMapping{}, err + return translation.ControlMapping{}, err } log.Debug("Parsed control mapping", "comment", mc.Comment, "midiChannel", mc.MidiChannel, "midiController", mc.MidiController, "axis", axis, "isSigned", mc.IsSigned, "deadzone", mc.Deadzone) - return ControlMapping{mc.Comment, mc.MidiChannel, mc.MidiController, axis, mc.IsSigned, mc.Deadzone}, nil + return translation.ControlMapping{mc.Comment, mc.MidiChannel, mc.MidiController, axis, mc.IsSigned, mc.Deadzone}, nil default: - return ButtonMapping{}, fmt.Errorf("Invalid mapping type") + return translation.ButtonMapping{}, fmt.Errorf("Invalid mapping type") } } @@ -189,16 +191,16 @@ func (bn ButtonName) Construct() (int, error) { // Construct converts an AxisName into the internal representation for a ControllerAxis. // Returns an error if AxisName is invalid. -func (an AxisName) Construct() (ControllerAxis, error) { +func (an AxisName) Construct() (translation.ControllerAxis, error) { switch an { case AxisLeftX: - return LeftX, nil + return translation.LeftX, nil case AxisLeftY: - return LeftY, nil + return translation.LeftY, nil case AxisRightX: - return RightX, nil + return translation.RightX, nil case AxisRightY: - return RightY, nil + return translation.RightY, nil default: return -1, fmt.Errorf("Invalid axis name \"%s\"", an) } diff --git a/main.go b/main.go index 4a1c6b9..bc6fd14 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,8 @@ import ( "os" "os/signal" + "git.datalore.sh/datalore/midi-hid/config" + "github.com/charmbracelet/log" "gitlab.com/gomidi/midi/v2" ) @@ -34,8 +36,8 @@ func main() { } log.Info("Starting...") - config := must(ParseConfig(configPath)) - controllerList := must(config.Construct()) + conf := must(config.ParseConfig(configPath)) + controllerList := must(conf.Construct()) defer controllerList.Stop() // wait for SIGINT diff --git a/controller.go b/translation/controller.go similarity index 99% rename from controller.go rename to translation/controller.go index 4f974e7..c33cacb 100644 --- a/controller.go +++ b/translation/controller.go @@ -1,4 +1,4 @@ -package main +package translation import ( "github.com/charmbracelet/log" diff --git a/mapping.go b/translation/mapping.go similarity index 78% rename from mapping.go rename to translation/mapping.go index 07c1a9e..9867695 100644 --- a/mapping.go +++ b/translation/mapping.go @@ -1,4 +1,4 @@ -package main +package translation import ( "fmt" @@ -18,10 +18,10 @@ type Mapping interface { // A ButtonMapping maps a MIDI Note to a gamepad button. type ButtonMapping struct { - comment string - midiChannel uint8 - midiKey uint8 - gamepadKey int + CommentStr string + MidiChannel uint8 + MidiKey uint8 + GamepadKey int } // Is checks if the MIDI message msg triggers this Mapping, without actually triggering it. @@ -30,7 +30,7 @@ func (m ButtonMapping) Is(msg midi.Message) bool { switch { case msg.GetNoteOn(&channel, &key, nil), msg.GetNoteOff(&channel, &key, nil): - return (m.midiChannel == channel && m.midiKey == key) + return (m.MidiChannel == channel && m.MidiKey == key) default: return false } @@ -45,13 +45,13 @@ func (m ButtonMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Gamep switch msg.Type() { case midi.NoteOnMsg: if velocity != 0 { - log.Debug(m.comment, "status", "down") - return virtGamepad.ButtonDown(m.gamepadKey) + log.Debug(m.CommentStr, "status", "down") + return virtGamepad.ButtonDown(m.GamepadKey) } fallthrough // if reached here, velocity is 0 -> NoteOff case midi.NoteOffMsg: - log.Debug(m.comment, "status", "up") - return virtGamepad.ButtonUp(m.gamepadKey) + log.Debug(m.CommentStr, "status", "up") + return virtGamepad.ButtonUp(m.GamepadKey) default: return fmt.Errorf("Invalid message type triggered ButtonMapping") } @@ -62,7 +62,7 @@ func (m ButtonMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Gamep // Comment returns the Mappings comment. func (m ButtonMapping) Comment() string { - return m.comment + return m.CommentStr } type ControllerAxis int @@ -75,12 +75,12 @@ const ( ) type ControlMapping struct { - comment string - midiChannel uint8 - midiController uint8 - axis ControllerAxis - isSigned bool - deadzone float64 + CommentStr string + MidiChannel uint8 + MidiController uint8 + Axis ControllerAxis + IsSigned bool + Deadzone float64 } // Is checks if the MIDI message msg triggers this Mapping, without actually triggering it. @@ -88,7 +88,7 @@ func (m ControlMapping) Is(msg midi.Message) bool { var channel, controller uint8 if msg.GetControlChange(&channel, &controller, nil) { - return (m.midiChannel == channel && m.midiController == controller) + return (m.MidiChannel == channel && m.MidiController == controller) } else { return false } @@ -107,18 +107,18 @@ func (m ControlMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Game // value is 0-127, normalise valueNormalised = float64(valueAbsolute) / 127 - if m.isSigned { + if m.IsSigned { valueNormalised *= 2 valueNormalised -= 1 } - if math.Abs(valueNormalised) < m.deadzone { + if math.Abs(valueNormalised) < m.Deadzone { valueNormalised = 0 } - log.Debug(m.comment, "value", valueNormalised, "deadzone", m.deadzone) + log.Debug(m.CommentStr, "value", valueNormalised, "deadzone", m.Deadzone) - switch m.axis { + switch m.Axis { case LeftX: return virtGamepad.LeftStickMoveX(float32(valueNormalised)) case LeftY: @@ -135,5 +135,5 @@ func (m ControlMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Game // Comment returns the Mappings comment. func (m ControlMapping) Comment() string { - return m.comment + return m.CommentStr } diff --git a/midi.go b/translation/midi.go similarity index 98% rename from midi.go rename to translation/midi.go index 923d74e..b06589c 100644 --- a/midi.go +++ b/translation/midi.go @@ -1,4 +1,4 @@ -package main +package translation import ( "gitlab.com/gomidi/midi/v2"