Exemplo n.º 1
0
Arquivo: parse.go Projeto: kward/venue
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
}
Exemplo n.º 2
0
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)
		}
	}
}