feat(GamePad): Implemented mappings
This commit is contained in:
@@ -1,25 +1,31 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"gitlab.com/gomidi/midi/v2"
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
"github.com/bendahl/uinput"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
midiInput *MidiInput
|
midiInput *MidiInput
|
||||||
mappings []Mapping
|
mappings []Mapping
|
||||||
abortChan chan interface{}
|
abortChan chan interface{}
|
||||||
|
virtGamepad uinput.Gamepad
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewController(portName string) (*Controller, error) {
|
func NewController(portName string, vendorID, productID uint16) (*Controller, error) {
|
||||||
midiInput, err := NewMidiInput(portName)
|
midiInput, err := NewMidiInput(portName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtGamepad, err := uinput.CreateGamepad("/dev/uinput", []byte(portName), vendorID, productID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
abortChan := make(chan interface{})
|
abortChan := make(chan interface{})
|
||||||
|
|
||||||
controller := &Controller{midiInput, nil, abortChan}
|
controller := &Controller{midiInput, nil, abortChan, virtGamepad}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@@ -42,12 +48,11 @@ func (c *Controller) AddMapping(mapping Mapping) {
|
|||||||
func (c Controller) Stop() {
|
func (c Controller) Stop() {
|
||||||
c.midiInput.Stop()
|
c.midiInput.Stop()
|
||||||
c.abortChan <- struct{}{}
|
c.abortChan <- struct{}{}
|
||||||
|
c.virtGamepad.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Controller) update(msg midi.Message) {
|
func (c Controller) update(msg midi.Message) {
|
||||||
for _, mapping := range c.mappings {
|
for _, mapping := range c.mappings {
|
||||||
if mapping.Is(msg) {
|
mapping.TriggerIfMatch(msg, c.virtGamepad)
|
||||||
log.Println("Mapping triggered!\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
go.mod
5
go.mod
@@ -2,4 +2,7 @@ module datalore/midi-hid
|
|||||||
|
|
||||||
go 1.24.5
|
go 1.24.5
|
||||||
|
|
||||||
require gitlab.com/gomidi/midi/v2 v2.3.16
|
require (
|
||||||
|
github.com/bendahl/uinput v1.7.0
|
||||||
|
gitlab.com/gomidi/midi/v2 v2.3.16
|
||||||
|
)
|
||||||
|
2
go.sum
2
go.sum
@@ -1,2 +1,4 @@
|
|||||||
|
github.com/bendahl/uinput v1.7.0 h1:nA4fm8Wu8UYNOPykIZm66nkWEyvxzfmJ8YC02PM40jg=
|
||||||
|
github.com/bendahl/uinput v1.7.0/go.mod h1:Np7w3DINc9wB83p12fTAM3DPPhFnAKP0WTXRqCQJ6Z8=
|
||||||
gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c=
|
gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c=
|
||||||
gitlab.com/gomidi/midi/v2 v2.3.16/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
|
gitlab.com/gomidi/midi/v2 v2.3.16/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
|
||||||
|
12
main.go
12
main.go
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitlab.com/gomidi/midi/v2"
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
"github.com/bendahl/uinput"
|
||||||
)
|
)
|
||||||
|
|
||||||
func must[T any](obj T, err error) T {
|
func must[T any](obj T, err error) T {
|
||||||
@@ -19,12 +20,11 @@ func main() {
|
|||||||
defer midi.CloseDriver()
|
defer midi.CloseDriver()
|
||||||
|
|
||||||
log.Println("Starting...")
|
log.Println("Starting...")
|
||||||
controller := must(NewController("DJControl Inpulse 500 MIDI 1"))
|
controller := must(NewController("DJControl Inpulse 500 MIDI 1", 0x45e, 0x285)) // mimics xbox 360 controller
|
||||||
controller.AddMapping(ButtonMapping{1, 7}) // play left
|
defer controller.Stop()
|
||||||
controller.AddMapping(ControlMapping{1, 0}) // volume left
|
|
||||||
|
controller.AddMapping(ButtonMapping{"Play left", 1, 7, uinput.ButtonSouth})
|
||||||
|
controller.AddMapping(ControlMapping{"Volume left", 1, 0, LeftY, false})
|
||||||
|
|
||||||
time.Sleep(time.Second * 20)
|
time.Sleep(time.Second * 20)
|
||||||
log.Println("Stopping...")
|
|
||||||
controller.Stop()
|
|
||||||
log.Println("Stopped.")
|
|
||||||
}
|
}
|
||||||
|
64
mapping.go
64
mapping.go
@@ -1,16 +1,22 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gitlab.com/gomidi/midi/v2"
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
"github.com/bendahl/uinput"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mapping interface {
|
type Mapping interface {
|
||||||
Is(midi.Message) bool
|
Is(midi.Message) bool
|
||||||
|
TriggerIfMatch(midi.Message, uinput.Gamepad) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ButtonMapping struct {
|
type ButtonMapping struct {
|
||||||
|
comment string
|
||||||
midiChannel uint8
|
midiChannel uint8
|
||||||
midiKey uint8
|
midiKey uint8
|
||||||
|
gamepadKey int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ButtonMapping) Is(msg midi.Message) bool {
|
func (m ButtonMapping) Is(msg midi.Message) bool {
|
||||||
@@ -24,9 +30,36 @@ func (m ButtonMapping) Is(msg midi.Message) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m ButtonMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Gamepad) error {
|
||||||
|
if m.Is(msg) {
|
||||||
|
switch msg.Type() {
|
||||||
|
case midi.NoteOnMsg:
|
||||||
|
return virtGamepad.ButtonDown(m.gamepadKey)
|
||||||
|
case midi.NoteOffMsg:
|
||||||
|
return virtGamepad.ButtonUp(m.gamepadKey)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Invalid message type triggered ButtonMapping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControllerAxis int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LeftX ControllerAxis = iota
|
||||||
|
LeftY
|
||||||
|
RightX
|
||||||
|
RightY
|
||||||
|
)
|
||||||
|
|
||||||
type ControlMapping struct {
|
type ControlMapping struct {
|
||||||
|
comment string
|
||||||
midiChannel uint8
|
midiChannel uint8
|
||||||
midiController uint8
|
midiController uint8
|
||||||
|
axis ControllerAxis
|
||||||
|
isSigned bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ControlMapping) Is(msg midi.Message) bool {
|
func (m ControlMapping) Is(msg midi.Message) bool {
|
||||||
@@ -38,3 +71,34 @@ func (m ControlMapping) Is(msg midi.Message) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m ControlMapping) TriggerIfMatch(msg midi.Message, virtGamepad uinput.Gamepad) error {
|
||||||
|
if m.Is(msg) {
|
||||||
|
var (
|
||||||
|
valueAbsolute uint8
|
||||||
|
valueNormalised float32
|
||||||
|
)
|
||||||
|
|
||||||
|
msg.GetControlChange(nil, nil, &valueAbsolute)
|
||||||
|
|
||||||
|
// value is 0-127, normalise
|
||||||
|
valueNormalised = float32(valueAbsolute) / 127
|
||||||
|
if m.isSigned {
|
||||||
|
valueNormalised *= 2
|
||||||
|
valueNormalised -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch m.axis {
|
||||||
|
case LeftX:
|
||||||
|
return virtGamepad.LeftStickMoveX(valueNormalised)
|
||||||
|
case LeftY:
|
||||||
|
return virtGamepad.LeftStickMoveY(valueNormalised)
|
||||||
|
case RightX:
|
||||||
|
return virtGamepad.RightStickMoveX(valueNormalised)
|
||||||
|
case RightY:
|
||||||
|
return virtGamepad.RightStickMoveY(valueNormalised)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user