summaryrefslogtreecommitdiff
path: root/pkg/controller/controller.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/controller/controller.go')
-rw-r--r--pkg/controller/controller.go119
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)
+}