Initial commit
This commit is contained in:
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# midi-hid
|
||||||
|
|
||||||
|
This software allows mapping and translating of MIDI commands to HID inputs on Linux.
|
53
controller.go
Normal file
53
controller.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
midiInput *MidiInput
|
||||||
|
mappings []Mapping
|
||||||
|
abortChan chan interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController(portName string) (*Controller, error) {
|
||||||
|
midiInput, err := NewMidiInput(portName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
abortChan := make(chan interface{})
|
||||||
|
|
||||||
|
controller := &Controller{midiInput, nil, abortChan}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case midiMessage := <-midiInput.Messages:
|
||||||
|
controller.update(midiMessage)
|
||||||
|
case <-abortChan:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return controller, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) AddMapping(mapping Mapping) {
|
||||||
|
c.mappings = append(c.mappings, mapping)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Controller) Stop() {
|
||||||
|
c.midiInput.Stop()
|
||||||
|
c.abortChan <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Controller) update(msg midi.Message) {
|
||||||
|
for _, mapping := range c.mappings {
|
||||||
|
if mapping.Is(msg) {
|
||||||
|
log.Println("Mapping triggered!\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module datalore/midi-hid
|
||||||
|
|
||||||
|
go 1.24.5
|
||||||
|
|
||||||
|
require gitlab.com/gomidi/midi/v2 v2.3.16
|
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c=
|
||||||
|
gitlab.com/gomidi/midi/v2 v2.3.16/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
|
25
main.go
Normal file
25
main.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func must[T any](obj T, err error) T {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer midi.CloseDriver()
|
||||||
|
|
||||||
|
midiInput := must(NewMidiInput("DJControl Inpulse 500 MIDI 1"))
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 20)
|
||||||
|
midiInput.Stop()
|
||||||
|
}
|
40
mapping.go
Normal file
40
mapping.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mapping interface {
|
||||||
|
Is(midi.Message) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ButtonMapping struct {
|
||||||
|
midiChannel uint8
|
||||||
|
midiKey uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ButtonMapping) Is(msg midi.Message) bool {
|
||||||
|
var channel, key uint8
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case msg.GetNoteOn(&channel, &key, nil), msg.GetNoteOff(&channel, &key, nil):
|
||||||
|
return (m.midiChannel == channel && m.midiKey == key)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlMapping struct {
|
||||||
|
midiChannel uint8
|
||||||
|
midiController uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
35
midi.go
Normal file
35
midi.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
"gitlab.com/gomidi/midi/v2/drivers"
|
||||||
|
_ "gitlab.com/gomidi/midi/v2/drivers/rtmididrv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MidiInput struct {
|
||||||
|
input drivers.In
|
||||||
|
Messages chan midi.Message
|
||||||
|
Stop func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMidiInput(portName string) (*MidiInput, error) {
|
||||||
|
input, err := midi.FindInPort(portName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
messages := make(chan midi.Message)
|
||||||
|
|
||||||
|
midiListener := func(msg midi.Message, timestampMs int32) {
|
||||||
|
if msg.IsOneOf(midi.NoteOnMsg, midi.NoteOffMsg, midi.ControlChangeMsg) {
|
||||||
|
messages <- msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopFunc, err := midi.ListenTo(input, midiListener, midi.UseSysEx())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MidiInput{input, messages, stopFunc}, nil
|
||||||
|
}
|
Reference in New Issue
Block a user