diff options
Diffstat (limited to 'pkg/controller')
-rw-r--r-- | pkg/controller/controller.go | 119 |
1 files changed, 116 insertions, 3 deletions
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index b8d04e7..ab04fcc 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -22,17 +22,130 @@ package controller +import ( + "errors" + "fmt" + "log" + "strings" + + "github.com/scgolang/midi" +) + +const ( + BUTTON_ON = byte(0x90) + BUTTON_OFF = byte(0x80) + NOTE_OFFSET_BUTTON = byte(0x00) + NUM_BUTTONS = 4 + + LED_CC = byte(0xB0) + NOTE_OFFSET_LED = byte(0x00) + NUM_LEDS = 4 + LED_OFF = byte(0x00) + LED_ON = byte(0x01) + LED_TOGGLE = byte(0x02) + LED_BLINK_MIN = byte(0x03) + LED_BLINK_MAX = byte(0x7f) +) + type Controller struct { + Dev *midi.Device +} + +func openDevice(devices []*midi.Device, prefix string) (d *midi.Device, err error) { + for _, device := range devices { + if strings.HasPrefix(device.Name, prefix) { + d = device + } + } + if d == nil { + return nil, errors.New("could not find device with prefix: " + prefix) + } + return d, d.Open() } func NewController(c Config) (*Controller, error) { - return &Controller{}, nil + devices, err := midi.Devices() + if err != nil { + return nil, err + } + + ctrl := &Controller{} + if ctrl.Dev, err = openDevice(devices, c.Dev); err != nil { + return nil, err + } + ctrl.Dev.QueueSize = 100 + + return ctrl, nil +} + +func (c *Controller) handleMidiPacket(p midi.Packet) { + num := p.Data[1] + switch p.Data[0] { + case BUTTON_ON: + log.Printf("controller: button %d pressed", num) + case BUTTON_OFF: + log.Printf("controller: button %d released", num) + default: + // ignore all other events + return + } } -func (m *Controller) Init() error { +func (c *Controller) Init() error { + ch, err := c.Dev.Packets() + if err != nil { + return err + } + + go func() { + for { + // TODO: handle Errors (reopen the device!) + c.handleMidiPacket(<-ch) + } + }() return nil } -func (m *Controller) Shutdown() error { +func (c *Controller) Shutdown() error { + if c.Dev != nil { + c.Dev.Close() + } + // TODO: also close all subscribed channels + // terminate go-routine started by Init() return nil } + +func (c *Controller) setLed(num byte, value byte) error { + if num >= NUM_LEDS { + return fmt.Errorf("this controller has only %d leds.", NUM_LEDS) + } + + n, err := c.Dev.Write([]byte{LED_CC, NOTE_OFFSET_LED + num, value}) + if err != nil { + // reopen device? + return err + } + if n != 3 { + return errors.New("sending LED command failed.") + } + return nil +} + +func (c *Controller) LedOff(num byte) error { + return c.setLed(num, LED_OFF) +} + +func (c *Controller) LedOn(num byte) error { + return c.setLed(num, LED_ON) +} + +func (c *Controller) LedToggle(num byte) error { + return c.setLed(num, LED_TOGGLE) +} + +func (c *Controller) LedBlink(num, wait byte) error { + if (wait + LED_BLINK_MIN) > LED_BLINK_MAX { + return fmt.Errorf("blink wait must be between 0 and %d.", LED_BLINK_MAX-LED_BLINK_MIN) + } + return c.setLed(num, wait+LED_BLINK_MIN) +} |