// NewGroup creates a group func (self *Client) NewGroup(id, action, target int32) error { dumpReq := osc.NewMessage("/g_new") dumpReq.Append(id) dumpReq.Append(action) dumpReq.Append(target) return self.oscServer.SendTo(self.addr, dumpReq) }
// SendDef sends a synthdef to scsynth. // This method blocks until a /done message is received // indicating that the synthdef was loaded func (self *Client) SendDef(def *Synthdef) error { msg := osc.NewMessage("/d_recv") db, err := def.Bytes() if err != nil { return err } msg.Append(db) self.oscServer.SendTo(self.addr, msg) var done *osc.Message select { case done = <-self.doneChan: goto ParseMessage case err = <-self.oscErrChan: return err } ParseMessage: // error if this message was not an ack of the synthdef errmsg := "expected /done with /d_recv argument" if done.CountArguments() != 1 { return fmt.Errorf(errmsg) } if addr, isString := done.Arguments[0].(string); !isString || addr != "/d_recv" { return fmt.Errorf(errmsg) } return nil }
// Send a /quit message to scsynth func main() { addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:57130") if err != nil { log.Fatal(err) } oscServer := osc.NewServer(listenAddr, listenPort) errChan := make(chan error) doneChan := make(chan *osc.Message) err = oscServer.AddMsgHandler("/done", func(msg *osc.Message) { doneChan <- msg }) if err != nil { log.Println("could not send quit message") log.Fatal(err) } go func() { errChan <- oscServer.ListenAndDispatch() }() err = <-oscServer.Listening if err != nil { log.Fatal(err) } log.Println("sending quit request") quitReq := osc.NewMessage("/quit") err = oscServer.SendTo(addr, quitReq) if err != nil { log.Fatal(err) } select { case quitResp := <-doneChan: osc.PrintMessage(quitResp) case err := <-errChan: log.Fatal(err) } }
// FreeAll frees all nodes in a group func (self *Client) FreeAll(gids ...int32) error { freeReq := osc.NewMessage(groupFreeAllAddress) for _, gid := range gids { freeReq.Append(gid) } return self.oscServer.SendTo(self.conn, freeReq) }
// Gen generates a buffer using a routine. // A runtime panic will occur if routine is not one of the // BufferRoutine constants. func (self *Buffer) Gen(routine string, flags int, args ...float32) error { if err := checkBufferRoutine(routine); err != nil { return err } if err := checkBufferGenFlags(flags); err != nil { return err } pat := bufferGenAddress gen, err := osc.NewMessage(pat) if err != nil { return err } if err := gen.WriteInt32(self.Num); err != nil { return err } if err := gen.WriteString(routine); err != nil { return err } if err := gen.WriteInt32(int32(flags)); err != nil { return err } for _, arg := range args { if err := gen.WriteFloat32(arg); err != nil { return err } } if err := self.client.oscConn.Send(gen); err != nil { return err } var done *osc.Message select { case done = <-self.client.doneChan: case err = <-self.client.oscErrChan: return err } if done.CountArguments() != 2 { return errors.New("expected two arguments to /done message") } _, err = done.ReadString() if err != nil { return err } bufnum, err := done.ReadInt32() if err != nil { return err } // TODO: // Don't error if we get a done message for a different buffer. // We should probably requeue this particular done message on doneChan. if bufnum != self.Num { m := "expected done message for buffer %d, but got one for buffer %d" return fmt.Errorf(m, self.Num, bufnum) } return nil }
// Synth creates a synth node. func (self *Client) Synth(defName string, id, action, target int32, ctls map[string]float32) (*Synth, error) { synthReq, err := osc.NewMessage(synthNewAddress) if err != nil { return nil, err } if err := synthReq.WriteString(defName); err != nil { return nil, err } if err := synthReq.WriteInt32(id); err != nil { return nil, err } if err := synthReq.WriteInt32(action); err != nil { return nil, err } if err := synthReq.WriteInt32(target); err != nil { return nil, err } if ctls != nil { for k, v := range ctls { if err := synthReq.WriteString(k); err != nil { return nil, err } if err := synthReq.WriteFloat32(v); err != nil { return nil, err } } } if err := self.oscConn.Send(synthReq); err != nil { return nil, err } return newSynth(self, defName, id), nil }
// FreeAll frees all nodes in a group func (self *Client) FreeAll(gids ...int32) error { freeReq := osc.NewMessage("/g_freeAll") for _, gid := range gids { freeReq.Append(gid) } return self.oscServer.SendTo(self.addr, freeReq) }
// Set the value of a synth control. func (self *Synth) Set(ctls map[string]float32) error { set := osc.NewMessage(setSynthNodeAddress) set.Append(self.id) for name, value := range ctls { set.Append(name, value) } return self.client.oscServer.SendTo(self.client.conn, set) }
// NewSynth creates a synth func (self *Client) NewSynth(name string, id, action, target int32) error { synthReq := osc.NewMessage("/s_new") synthReq.Append(name) synthReq.Append(id) synthReq.Append(action) synthReq.Append(target) synthReq.Append(int32(0)) return self.oscServer.SendTo(self.addr, synthReq) }
// Free a synth node. func (self *Synth) Free() error { free, err := osc.NewMessage(freeSynthNodeAddress) if err != nil { return err } if err := free.WriteInt32(self.id); err != nil { return err } return self.client.oscConn.Send(free) }
// DumpOSC sends a /dumpOSC message to scsynth // level should be DumpOff, DumpParsed, DumpContents, DumpAll func (self *Client) DumpOSC(level int32) error { dumpReq, err := osc.NewMessage(dumpOscAddress) if err != nil { return err } if err := dumpReq.WriteInt32(level); err != nil { return err } return self.oscConn.Send(dumpReq) }
// NewGroup creates a group func (self *Client) Group(id, action, target int32) (*Group, error) { dumpReq := osc.NewMessage(groupNewAddress) dumpReq.Append(id) dumpReq.Append(action) dumpReq.Append(target) err := self.oscServer.SendTo(self.conn, dumpReq) if err != nil { return nil, err } return newGroup(self, id), nil }
// QueryGroup g_queryTree for a particular group func (self *Client) QueryGroup(id int32) (*group, error) { addr := "/g_queryTree" gq := osc.NewMessage(addr) gq.Append(int32(RootNodeID)) err := self.oscServer.SendTo(self.addr, gq) if err != nil { return nil, err } // wait for response resp := <-self.gqueryTreeChan return parseGroup(resp) }
// FreeAll frees all nodes in a group func (self *Client) FreeAll(gids ...int32) error { freeReq, err := osc.NewMessage(groupFreeAllAddress) if err != nil { return err } for _, gid := range gids { if err := freeReq.WriteInt32(gid); err != nil { return err } } return self.oscConn.Send(freeReq) }
// AllocBuffer allocates a buffer on the server func (self *Client) AllocBuffer(frames, channels int) (*Buffer, error) { buf := newBuffer(self) pat := bufferAllocAddress alloc, err := osc.NewMessage(pat) if err != nil { return nil, err } if err := alloc.WriteInt32(buf.Num); err != nil { return nil, err } if err := alloc.WriteInt32(int32(frames)); err != nil { return nil, err } if err := alloc.WriteInt32(int32(channels)); err != nil { return nil, err } if err := self.oscConn.Send(alloc); err != nil { return nil, err } var done *osc.Message select { case done = <-self.doneChan: break case err = <-self.oscErrChan: return nil, err } // error if this message was not an ack of the synthdef if done.CountArguments() != 2 { return nil, fmt.Errorf("expected two arguments to /done message") } addr, err := done.ReadString() if err != nil { return nil, err } if addr != pat { return nil, fmt.Errorf("expected first argument to be %s but got %s", pat, addr) } bufnum, err := done.ReadInt32() if err != nil { return nil, err } // TODO: // Don't error if we get a done message for a different buffer. // We should probably requeue this particular done message on doneChan. if bufnum != buf.Num { m := "expected done message for buffer %d, but got one for buffer %d" return nil, fmt.Errorf(m, buf.Num, bufnum) } return buf, nil }
// Status gets the status of scsynth func (self *Client) Status() (*ServerStatus, error) { statusReq := osc.NewMessage("/status") err := self.oscServer.SendTo(self.addr, statusReq) if err != nil { return nil, err } select { case msg := <-self.statusChan: return newStatus(msg) case err = <-self.oscErrChan: return nil, err } }
// ReadBuffer tells the server to read an audio file and // load it into a buffer func (self *Client) ReadBuffer(path string, num int32) (*Buffer, error) { allocRead, err := osc.NewMessage(bufferReadAddress) if err != nil { return nil, err } buf := newReadBuffer(path, num, self) if err := allocRead.WriteInt32(buf.Num); err != nil { return nil, err } if err := allocRead.WriteString(path); err != nil { return nil, err } if err := self.oscConn.Send(allocRead); err != nil { return nil, err } var done *osc.Message select { case done = <-self.doneChan: case err = <-self.oscErrChan: return nil, err } // error if this message was not an ack of the buffer read if done.CountArguments() != 2 { return nil, fmt.Errorf("expected two arguments to /done message") } addr, err := done.ReadString() if err != nil { return nil, err } if addr != bufferReadAddress { return nil, fmt.Errorf("expected first argument to be %s but got %s", bufferReadAddress, addr) } bufnum, err := done.ReadInt32() if err != nil { return nil, err } // TODO: // Don't error if we get a done message for a different buffer. // We should probably requeue this particular done message on doneChan. if bufnum != buf.Num { m := "expected done message for buffer %d, but got one for buffer %d" return nil, fmt.Errorf(m, buf.Num, bufnum) } return buf, nil }
// QueryGroup g_queryTree for a particular group func (self *Client) QueryGroup(id int32) (*Group, error) { addr := gqueryTreeAddress gq, err := osc.NewMessage(addr) if err != nil { return nil, err } if err := gq.WriteInt32(int32(RootNodeID)); err != nil { return nil, err } if err := self.oscConn.Send(gq); err != nil { return nil, err } // wait for response resp := <-self.gqueryTreeChan return parseGroup(resp) }
// defaultGroupExists figures out whether or not the default group exists func (self *Client) defaultGroupExists() (bool, error) { addr := "/g_queryTree" gq := osc.NewMessage(addr) gq.Append(int32(RootNodeID)) err := self.oscServer.SendTo(self.addr, gq) if err != nil { return false, err } // wait for response resp := <-self.gqueryTreeChan _, err = parseGroup(resp) if err != nil { return false, err } return false, nil }
// Gen generates a buffer using a routine. // A runtime panic will occur if routine is not one of the // BufferRoutine constants. func (self *buffer) Gen(routine string, flags int, args ...float32) error { checkBufferRoutine(routine) checkBufferGenFlags(flags) pat := bufferGenAddress gen := osc.NewMessage(pat) gen.Append(self.Num()) gen.Append(routine) gen.Append(int32(flags)) for _, arg := range args { gen.Append(arg) } err := self.c.oscServer.SendTo(self.c.conn, gen) if err != nil { return err } var done *osc.Message select { case done = <-self.c.doneChan: break case err = <-self.c.oscErrChan: return err } if done.CountArguments() != 2 { return fmt.Errorf("expected two arguments to /done message") } if addr, isString := done.Arguments[0].(string); !isString || addr != pat { return fmt.Errorf("expected first argument to be %s but got %s", pat, addr) } var bufnum int32 var isInt32 bool if bufnum, isInt32 = done.Arguments[1].(int32); !isInt32 { m := "expected int32 as second argument, but got %s (%v)" return fmt.Errorf(m, reflect.TypeOf(done.Arguments[1]), done.Arguments[1]) } // TODO: // Don't error if we get a done message for a different buffer. // We should probably requeue this particular done message on doneChan. if bufnum != self.Num() { m := "expected done message for buffer %d, but got one for buffer %d" return fmt.Errorf(m, self.Num(), bufnum) } return nil }
// NewSynth creates a synth func (self *Client) Synth(defName string, id, action, target int32, ctls map[string]float32) (*Synth, error) { synthReq := osc.NewMessage(synthNewAddress) synthReq.Append(defName) synthReq.Append(id) synthReq.Append(action) synthReq.Append(target) if ctls != nil { for k, v := range ctls { synthReq.Append(k) synthReq.Append(v) } } err := self.oscServer.SendTo(self.conn, synthReq) if err != nil { return nil, err } return newSynth(self, defName, id), nil }
// Set the value of a synth control. func (self *Synth) Set(ctls map[string]float32) error { set, err := osc.NewMessage(setSynthNodeAddress) if err != nil { return err } if err := set.WriteInt32(self.id); err != nil { return err } for name, value := range ctls { if err := set.WriteString(name); err != nil { return err } if err := set.WriteFloat32(value); err != nil { return err } } return self.client.oscConn.Send(set) }
// NewGroup creates a group func (self *Client) Group(id, action, target int32) (*Group, error) { dumpReq, err := osc.NewMessage(groupNewAddress) if err != nil { return nil, err } if err := dumpReq.WriteInt32(id); err != nil { return nil, err } if err := dumpReq.WriteInt32(action); err != nil { return nil, err } if err := dumpReq.WriteInt32(target); err != nil { return nil, err } if err := self.oscConn.Send(dumpReq); err != nil { return nil, err } return newGroup(self, id), nil }
// AllocBuffer allocates a buffer on the server func (self *Client) AllocBuffer(frames, channels int) (Buffer, error) { buf := newBuffer(self) pat := bufferAllocAddress alloc := osc.NewMessage(pat) alloc.Append(buf.Num()) alloc.Append(int32(frames)) alloc.Append(int32(channels)) err := self.oscServer.SendTo(self.conn, alloc) if err != nil { return nil, err } var done *osc.Message select { case done = <-self.doneChan: break case err = <-self.oscErrChan: return nil, err } // error if this message was not an ack of the synthdef if done.CountArguments() != 2 { return nil, fmt.Errorf("expected two arguments to /done message") } if addr, isString := done.Arguments[0].(string); !isString || addr != pat { return nil, fmt.Errorf("expected first argument to be %s but got %s", pat, addr) } var bufnum int32 var isInt32 bool if bufnum, isInt32 = done.Arguments[1].(int32); !isInt32 { m := "expected int32 as second argument, but got %s (%v)" return nil, fmt.Errorf(m, reflect.TypeOf(done.Arguments[1]), done.Arguments[1]) } // TODO: // Don't error if we get a done message for a different buffer. // We should probably requeue this particular done message on doneChan. if bufnum != buf.Num() { m := "expected done message for buffer %d, but got one for buffer %d" return nil, fmt.Errorf(m, buf.Num(), bufnum) } return buf, nil }
// SendDef sends a synthdef to scsynth. // This method blocks until a /done message is received // indicating that the synthdef was loaded func (self *Client) SendDef(def *Synthdef) error { msg, err := osc.NewMessage(synthdefReceiveAddress) if err != nil { return err } db, err := def.Bytes() if err != nil { return err } if err := msg.WriteBlob(db); err != nil { return err } if err := self.oscConn.Send(msg); err != nil { return err } var done *osc.Message select { case done = <-self.doneChan: goto ParseMessage case err = <-self.oscErrChan: return err } ParseMessage: // error if this message was not an ack of the synthdef errmsg := "expected /done with /d_recv argument" if done.CountArguments() != 1 { return fmt.Errorf(errmsg) } addr, err := done.ReadString() if err != nil { return err } if addr != synthdefReceiveAddress { return errors.New(errmsg) } return nil }
// ClearSched causes scsynth to clear all scheduled bundles func (self *Client) ClearSched() error { clear := osc.NewMessage("/clearSched") return self.oscServer.SendTo(self.addr, clear) }
// DumpOSC sends a /dumpOSC message to scsynth // level should be DumpOff, DumpParsed, DumpContents, DumpAll func (self *Client) DumpOSC(level int32) error { dumpReq := osc.NewMessage(dumpOscAddress) dumpReq.Append(level) return self.oscServer.SendTo(self.conn, dumpReq) }
// DumpOSC sends a /dumpOSC message to scsynth // level should be DumpOff, DumpParsed, DumpContents, DumpAll func (self *Client) DumpOSC(level int32) error { dumpReq := osc.NewMessage("/dumpOSC") dumpReq.Append(level) return self.oscServer.SendTo(self.addr, dumpReq) }
// Free a synth node. func (self *Synth) Free() error { free := osc.NewMessage(freeSynthNodeAddress) free.Append(self.id) return self.client.oscServer.SendTo(self.client.conn, free) }