housekeeping: Refactored API to separate packages
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
package main
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"git.datalore.sh/datalore/midi-hid/translation"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/bendahl/uinput"
|
"github.com/bendahl/uinput"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
@@ -84,8 +86,8 @@ func ParseConfig(path string) (Config, error) {
|
|||||||
|
|
||||||
// Construct iterates over all ControllerConfigs and constructs the Controller objects.
|
// Construct iterates over all ControllerConfigs and constructs the Controller objects.
|
||||||
// In case of a failure, it aborts and returns an error.
|
// In case of a failure, it aborts and returns an error.
|
||||||
func (config Config) Construct() (ControllerList, error) {
|
func (config Config) Construct() (translation.ControllerList, error) {
|
||||||
var controllerList ControllerList
|
var controllerList translation.ControllerList
|
||||||
|
|
||||||
for _, controllerConfig := range config.Controller {
|
for _, controllerConfig := range config.Controller {
|
||||||
actualController, err := controllerConfig.Construct()
|
actualController, err := controllerConfig.Construct()
|
||||||
@@ -102,8 +104,8 @@ func (config Config) Construct() (ControllerList, error) {
|
|||||||
// Construct builds a Controller object and its corresponding mappings.
|
// Construct builds a Controller object and its corresponding mappings.
|
||||||
// Aborts and returns an error if the midi port was not found or one of
|
// Aborts and returns an error if the midi port was not found or one of
|
||||||
// the Mappings is invalid.
|
// the Mappings is invalid.
|
||||||
func (cc ControllerConfig) Construct() (*Controller, error) {
|
func (cc ControllerConfig) Construct() (*translation.Controller, error) {
|
||||||
actualController, err := NewController(cc.PortName, cc.VendorID, cc.ProductID)
|
actualController, err := translation.NewController(cc.PortName, cc.VendorID, cc.ProductID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return actualController, err
|
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.
|
// 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 {
|
switch mc.Type {
|
||||||
case ButtonMappingType:
|
case ButtonMappingType:
|
||||||
button, err := mc.Button.Construct()
|
button, err := mc.Button.Construct()
|
||||||
if err != nil {
|
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)
|
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:
|
case ControlMappingType:
|
||||||
axis, err := mc.Axis.Construct()
|
axis, err := mc.Axis.Construct()
|
||||||
if err != nil {
|
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)
|
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:
|
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.
|
// Construct converts an AxisName into the internal representation for a ControllerAxis.
|
||||||
// Returns an error if AxisName is invalid.
|
// Returns an error if AxisName is invalid.
|
||||||
func (an AxisName) Construct() (ControllerAxis, error) {
|
func (an AxisName) Construct() (translation.ControllerAxis, error) {
|
||||||
switch an {
|
switch an {
|
||||||
case AxisLeftX:
|
case AxisLeftX:
|
||||||
return LeftX, nil
|
return translation.LeftX, nil
|
||||||
case AxisLeftY:
|
case AxisLeftY:
|
||||||
return LeftY, nil
|
return translation.LeftY, nil
|
||||||
case AxisRightX:
|
case AxisRightX:
|
||||||
return RightX, nil
|
return translation.RightX, nil
|
||||||
case AxisRightY:
|
case AxisRightY:
|
||||||
return RightY, nil
|
return translation.RightY, nil
|
||||||
default:
|
default:
|
||||||
return -1, fmt.Errorf("Invalid axis name \"%s\"", an)
|
return -1, fmt.Errorf("Invalid axis name \"%s\"", an)
|
||||||
}
|
}
|
6
main.go
6
main.go
@@ -5,6 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
|
"git.datalore.sh/datalore/midi-hid/config"
|
||||||
|
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"gitlab.com/gomidi/midi/v2"
|
"gitlab.com/gomidi/midi/v2"
|
||||||
)
|
)
|
||||||
@@ -34,8 +36,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Starting...")
|
log.Info("Starting...")
|
||||||
config := must(ParseConfig(configPath))
|
conf := must(config.ParseConfig(configPath))
|
||||||
controllerList := must(config.Construct())
|
controllerList := must(conf.Construct())
|
||||||
defer controllerList.Stop()
|
defer controllerList.Stop()
|
||||||
|
|
||||||
// wait for SIGINT
|
// wait for SIGINT
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package translation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package translation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -18,10 +18,10 @@ type Mapping interface {
|
|||||||
|
|
||||||
// A ButtonMapping maps a MIDI Note to a gamepad button.
|
// A ButtonMapping maps a MIDI Note to a gamepad button.
|
||||||
type ButtonMapping struct {
|
type ButtonMapping struct {
|
||||||
comment string
|
CommentStr string
|
||||||
midiChannel uint8
|
MidiChannel uint8
|
||||||
midiKey uint8
|
MidiKey uint8
|
||||||
gamepadKey int
|
GamepadKey int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is checks if the MIDI message msg triggers this Mapping, without actually triggering it.
|
// 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 {
|
switch {
|
||||||
case msg.GetNoteOn(&channel, &key, nil), msg.GetNoteOff(&channel, &key, nil):
|
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:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -45,13 +45,13 @@ func (m ButtonMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Gamep
|
|||||||
switch msg.Type() {
|
switch msg.Type() {
|
||||||
case midi.NoteOnMsg:
|
case midi.NoteOnMsg:
|
||||||
if velocity != 0 {
|
if velocity != 0 {
|
||||||
log.Debug(m.comment, "status", "down")
|
log.Debug(m.CommentStr, "status", "down")
|
||||||
return virtGamepad.ButtonDown(m.gamepadKey)
|
return virtGamepad.ButtonDown(m.GamepadKey)
|
||||||
}
|
}
|
||||||
fallthrough // if reached here, velocity is 0 -> NoteOff
|
fallthrough // if reached here, velocity is 0 -> NoteOff
|
||||||
case midi.NoteOffMsg:
|
case midi.NoteOffMsg:
|
||||||
log.Debug(m.comment, "status", "up")
|
log.Debug(m.CommentStr, "status", "up")
|
||||||
return virtGamepad.ButtonUp(m.gamepadKey)
|
return virtGamepad.ButtonUp(m.GamepadKey)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Invalid message type triggered ButtonMapping")
|
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.
|
// Comment returns the Mappings comment.
|
||||||
func (m ButtonMapping) Comment() string {
|
func (m ButtonMapping) Comment() string {
|
||||||
return m.comment
|
return m.CommentStr
|
||||||
}
|
}
|
||||||
|
|
||||||
type ControllerAxis int
|
type ControllerAxis int
|
||||||
@@ -75,12 +75,12 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ControlMapping struct {
|
type ControlMapping struct {
|
||||||
comment string
|
CommentStr string
|
||||||
midiChannel uint8
|
MidiChannel uint8
|
||||||
midiController uint8
|
MidiController uint8
|
||||||
axis ControllerAxis
|
Axis ControllerAxis
|
||||||
isSigned bool
|
IsSigned bool
|
||||||
deadzone float64
|
Deadzone float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is checks if the MIDI message msg triggers this Mapping, without actually triggering it.
|
// 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
|
var channel, controller uint8
|
||||||
|
|
||||||
if msg.GetControlChange(&channel, &controller, nil) {
|
if msg.GetControlChange(&channel, &controller, nil) {
|
||||||
return (m.midiChannel == channel && m.midiController == controller)
|
return (m.MidiChannel == channel && m.MidiController == controller)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -107,18 +107,18 @@ func (m ControlMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Game
|
|||||||
|
|
||||||
// value is 0-127, normalise
|
// value is 0-127, normalise
|
||||||
valueNormalised = float64(valueAbsolute) / 127
|
valueNormalised = float64(valueAbsolute) / 127
|
||||||
if m.isSigned {
|
if m.IsSigned {
|
||||||
valueNormalised *= 2
|
valueNormalised *= 2
|
||||||
valueNormalised -= 1
|
valueNormalised -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if math.Abs(valueNormalised) < m.deadzone {
|
if math.Abs(valueNormalised) < m.Deadzone {
|
||||||
valueNormalised = 0
|
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:
|
case LeftX:
|
||||||
return virtGamepad.LeftStickMoveX(float32(valueNormalised))
|
return virtGamepad.LeftStickMoveX(float32(valueNormalised))
|
||||||
case LeftY:
|
case LeftY:
|
||||||
@@ -135,5 +135,5 @@ func (m ControlMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Game
|
|||||||
|
|
||||||
// Comment returns the Mappings comment.
|
// Comment returns the Mappings comment.
|
||||||
func (m ControlMapping) Comment() string {
|
func (m ControlMapping) Comment() string {
|
||||||
return m.comment
|
return m.CommentStr
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package translation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitlab.com/gomidi/midi/v2"
|
"gitlab.com/gomidi/midi/v2"
|
Reference in New Issue
Block a user