func parse(msg *osc.Message) (*venue.Packet, error) { req := request{msg: msg, x: -1, y: -1} l := lex("OSC", msg.Address) Parsing: for { item := l.nextItem() fmt.Printf("item: %v\n", item) switch item.typ { case itemCommand: req.command = item.val case itemControl: req.control = item.val case itemLabel: req.label = true case itemLayout: dev, orient, err := layout(item.val) if err != nil { return nil, err } req.dev, req.orient = dev, orient case itemPage: req.page = item.val case itemPositionX: req.x = venuelib.ToInt(item.val) case itemPositionY: req.y = venuelib.ToInt(item.val) case itemVersion: req.version = item.val case itemError: return nil, errors.New(fmt.Sprintf("unable to parse item %v", item)) case itemEOF: break Parsing } } packer, ok := packers[req.version] if !ok { return nil, errors.New(fmt.Sprintf("unable to pack version %s", req.version)) } packer.init(req) for packer.setPacker(packer.packer()); !packer.done(); { packer.pack() } if err := packer.error(); err != nil { return nil, err } return packer.packet(), nil }
func (s *state) handleMessage(v *venue.Venue, msg *osc.Message, remote net.Addr) { const ( vertical = iota horizontal ) var ( // The dx and dy vars are always based on a vertical orientation. dxInput, dyInput int dxOutput int orientation int ) // The address is expected to be in this format: // /version/layout/page/control/command[/num1][/num2][/label] addr := msg.Address log.Printf("OSC Message from %v: %v", remote, addr) version, addr := car(addr), cdr(addr) switch version { case "ping": v.Ping() return case "0.1": case "0.0": log.Printf("Unsupported version.") return default: log.Printf("Unsupported message.") return } log.Printf("Version: %v", version) layout, addr := car(addr), cdr(addr) switch layout { case "pv": dxInput, dyInput = 8, 4 dxOutput = 6 case "th": dxInput, dyInput = 12, 4 dxOutput = 12 orientation = horizontal } log.Printf("Layout: %v", layout) page, addr := car(addr), cdr(addr) log.Printf("Page: %v", page) control, addr := car(addr), cdr(addr) log.Printf("Control: %v", control) switch control { case "input": command, addr := car(addr), cdr(addr) log.Printf("Command: %v", command) switch command { case "bank": // Only present on the phone layout. bank := car(addr) log.Printf("Input bank %v selected.", bank) switch bank { case "a": s.inputBank = 1 case "b": s.inputBank = 2 } case "gain": val := msg.Arguments[0].(float32) if val == 0 { // Only handle presses, not releases. log.Println("Ignoring release.") break } log.Printf("addr:%v", addr) x, y, dx, dy, bank := venuelib.ToInt(car(addr)), venuelib.ToInt(cadr(addr)), 1, 4, 1 log.Printf("x:%v y:%v dx:%v dy:%v bank:%v", x, y, dx, dy, bank) if orientation == horizontal { x, y = multiRotate(x, y, dy) } pos := multiPosition(x, y, dx, dy, bank) log.Printf("pos: %v", pos) var clicks int switch pos { case 1: clicks = 5 // +5 dB case 2: clicks = 1 // +1 dB case 3: clicks = -1 // -1 dB case 4: clicks = -5 // -5 dB } name := "gain" // Adjust gain value of input. log.Printf("Adjusting %v value of input by %v clicks.", name, clicks) widget := v.VNC.Widget(vnc.InputsPage, name) if err := widget.(*vnc.Encoder).Adjust(v.VNC, clicks); err != nil { // Ignoring error for now. } case "select": val := msg.Arguments[0].(float32) if val == 0 { // Only handle presses, not releases. log.Println("Ignoring release.") break } x, y := venuelib.ToInt(car(addr)), venuelib.ToInt(cadr(addr)) if orientation == horizontal { x, y = multiRotate(x, y, dyInput) } input := multiPosition(x, y, dxInput, dyInput, s.inputBank) v.VNC.SelectInput(uint16(input)) s.input = input default: log.Printf("Unrecognized command: %v", command) } case "output": command, addr := car(addr), cdr(addr) log.Printf("Command: %v", command) switch command { case "bank": // Only present on the phone layout. bank := car(addr) log.Printf("Output bank %v selected.", bank) switch bank { case "a": s.outputBank = 1 case "b": s.outputBank = 2 case "c": s.outputBank = 3 } case "level": val := msg.Arguments[0].(float32) if val == 0 { // Only handle presses, not releases. log.Println("Ignoring release.") break } // Determine output number and UI control name. x, y := venuelib.ToInt(car(addr)), venuelib.ToInt(cadr(addr)) if orientation == horizontal { x, y = multiRotate(x, y, 4) // TODO(kward): 4 should be a constant. } output := x*2 - 1 var name string if output < 16 { name = fmt.Sprintf("aux%d", output) // TOOD(kward): replace aux with constant. } else { name = fmt.Sprintf("grp%d", output-16) } log.Printf("Setting %v output level.", name) if s.output != output { v.VNC.SelectOutput(name) s.output = output } var clicks int switch y { case 1: clicks = 5 // +5 dB case 2: clicks = 1 // +1 dB case 3: clicks = -1 // -1 dB case 4: clicks = -5 // -5 dB } // Adjust output value of input send. log.Printf("Adjusting %v output value of input by %v clicks.", name, clicks) widget := v.VNC.Widget(vnc.InputsPage, name) if err := widget.(*vnc.Encoder).Adjust(v.VNC, clicks); err != nil { // Ignoring error for now. } case "select": val := msg.Arguments[0].(float32) if val == 0 { // Only handle presses, not releases. break } // Determine output number and UI control name. x, y, dy := venuelib.ToInt(car(addr)), venuelib.ToInt(cadr(addr)), 1 if orientation == horizontal { x, y = multiRotate(x, y, dy) } output := multiPosition(x, y, dxOutput, dy, s.outputBank)*2 - 1 var name string if output < 16 { name = fmt.Sprintf("aux%d", output) // TOOD(kward): replace aux with constant. } else { name = fmt.Sprintf("grp%d", output-16) } log.Printf("Selecting %v output.", name) if s.output != output { v.VNC.SelectOutput(name) s.output = output // Click output meter to update selected channel. // TODO(kward): Do following only in "input follows solo" mode. widget := v.VNC.Widget(vnc.OutputsPage, name+"meter") if err := widget.Press(v.VNC); err != nil { // Ignoring error for now. } } v.VNC.SetPage(vnc.InputsPage) case "pan": log.Printf("Pan unimplemented.") return val := int(msg.Arguments[0].(float32)) output := s.output if output == 0 { log.Print("Output not selected yet. Doing nothing.") return } var name string if output < 16 { name = fmt.Sprintf("aux%d", output) // TOOD(kward): replace aux with constant. } else { name = fmt.Sprintf("grp%d", output-16) } log.Printf("Setting %v pan position to %v.", name, val) // Adjust pan value of output. widget := v.VNC.Widget(vnc.InputsPage, name+"pan") if err := widget.Update(v.VNC, val); err != nil { // Ignore errors for now. } default: log.Printf("Unrecognized command: %v", command) } } }