-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
339 lines (287 loc) · 10.6 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
package jamyxgo
import (
"fmt"
"encoding/json"
"net"
"strconv"
"log"
)
type Command struct {
Target string `json:"target"`
Cmd string `json:"cmd"`
Opts []string `json:"opts"`
}
// Target holds the connection to the server.
type Target struct {
ip string
port int
}
// Constructor for Target
func NewTarget(ip string, port int) (*Target) {
return &Target { ip, port, }
}
// Return connection to the jamyxer server.
func (target* Target) GetConnection() (net.Conn) {
conn, err := net.Dial("tcp", target.ip+":"+strconv.Itoa(target.port))
if err != nil {
log.Fatal(err)
}
return conn
}
// Send a command to the jamyxer server.
func (target* Target) SendCommand(cmd Command) (reply interface {}) {
conn := target.GetConnection()
cmd_b, _ := json.Marshal(cmd)
log.Println("Sending command:", string(cmd_b))
_, err := conn.Write(cmd_b)
if err != nil {
log.Fatal(err)
}
reply_b := make([]byte, 1024)
numbytes, err := conn.Read(reply_b)
if err != nil {
log.Fatal(err)
}
if numbytes == 0 {
log.Fatal("Numbytes is 0!")
}
var r interface {}
err = json.Unmarshal(reply_b[:numbytes], &r)
if err != nil {
fmt.Println("error:", err)
}
log.Println("Reply:", string(reply_b[:numbytes]), r)
log.Print("\n\n--\n\n")
return r
}
func getTargetType(isinput bool) string {
if isinput { return "i" }
return "o"
}
func toStringArr(in []interface{}) ([]string) {
result := make([]string, len(in))
for i, e := range in{
if e == nil {
continue
}
result[i] = e.(string)
}
return result
}
// ==== Set Volume ====
// Set volume for specified input/output channel.
func (target *Target) VolumeSet(isinput bool, channel string, volume float32) {
// target.SendCommand("v%ss \"%s\" %f\n", getTargetType(isinput), channel, volume)
target.SendCommand(Command {
Target: "myx",
Cmd: "set",
Opts: []string{"v", getTargetType(isinput), channel, fmt.Sprintf("%f", volume)}})
}
// Set volume for specified input channel.
func (target *Target) VolumeInputSet(input string, volume float32) { target.VolumeSet(true, input, volume) }
// Set volume for specified output channel.
func (target *Target) VolumeOutputSet(output string, volume float32) { target.VolumeSet(false, output, volume) }
// ==== Set Balance ====
// Set balance for specified input/output channel.
func (target *Target) BalanceSet(isinput bool, channel string, balance float32) {
// target.SendCommand("v%ss \"%s\" %f\n", getTargetType(isinput), channel, balance)
target.SendCommand(Command {
Target: "myx",
Cmd: "set",
Opts: []string{"b", getTargetType(isinput), channel, fmt.Sprintf("%f", balance)}})
}
// Set balance for specified input channel.
func (target *Target) BalanceInputSet(input string, balance float32) { target.BalanceSet(true, input, balance) }
// Set balance for specified output channel.
func (target *Target) BalanceOutputSet(output string, balance float32) { target.BalanceSet(false, output, balance) }
// ==== Get Port ====
// Port object that holds all port info
type Port struct {
Port string
Ptype string
IsInput bool
IsMono bool
Vol float32
Bal float32
Cons []string
target *Target
}
// Extract Port from interface
func (target *Target) GetPortFromInterface(port map[string]interface{}) Port {
return Port{
Port: port["port"].(string),
Ptype: port["ptype"].(string),
IsInput: port["ptype"].(string) == "in",
IsMono: port["ismono"].(bool),
Vol: float32(port["vol"].(float64)),
Bal: float32(port["bal"].(float64)),
Cons: toStringArr(port["cons"].([]interface{})),
target: target,
}
}
// Extract Port object from a command reply
func (target *Target) GetPortFromReply(reply map[string]interface{}) (Port) {
port := reply["obj"].(map[string]interface{})
return target.GetPortFromInterface(port)
}
// Get Port object for specified input/output channel.
func (target *Target) GetPort(isinput bool, channel string) (Port) {
reply := target.SendCommand(Command {
Target: "myx",
Cmd: "get",
Opts: []string{getTargetType(isinput), channel},
})
return target.GetPortFromReply(reply.(map[string]interface{}))
}
// Return true is channel name was found in connections
func (port *Port) IsConnectedToChannel(channel string) bool {
for _, i := range port.Cons {
if i == channel { return true }
}
return false
}
// Return true is port was found in connections
func (port *Port) IsConnectedToPort(other Port) bool {
return port.IsConnectedToChannel(other.Port)
}
// Update the port's properties in place
func (port *Port) Update() {
*port = port.target.GetPort(port.IsInput, port.Port)
}
// Set the volume of port
func (port *Port) SetVol(vol float32) {
port.target.VolumeSet(port.IsInput, port.Port, vol)
port.Update()
}
// Set the balance of port
func (port *Port) SetBal(vol float32) {
port.target.BalanceSet(port.IsInput, port.Port, vol)
port.Update()
}
// Wait for volume of port to change and then return vol
func (port* Port) ListenVol() {
*port = port.target.VolumeListen(port.IsInput, port.Port)
}
// Wait for balance of port to change and then return bal
func (port* Port) ListenBal() {
*port = port.target.BalanceListen(port.IsInput, port.Port)
}
// Connect port with channel (other port name)
func (port *Port) ConnectToChannel(channel string) {
if port.IsInput {
port.target.ConnectIO(port.Port, channel)
} else {
port.target.ConnectIO(channel, port.Port)
}
port.Update()
}
// Connect two ports together
func (port *Port) ConnectToPort(other Port) {
port.ConnectToChannel(other.Port)
port.Update()
other.Update() // might not do anything here since other is passed by value
}
// Disconnect port from channel (other port name)
func (port *Port) DisconnectFromChannel(channel string) {
if port.IsInput {
port.target.DisconnectIO(port.Port, channel)
} else {
port.target.DisconnectIO(channel, port.Port)
}
}
// Disconnect two ports from eachother
func (port *Port) DisconnectFromPort(other Port) {
port.DisconnectFromChannel(other.Port)
}
// Toggle Connection with channel (other port name)
func (port *Port) ToggleConnectionWithChannel(channel string) {
if port.IsInput {
port.target.ToggleConnectionIO(port.Port, channel)
} else {
port.target.ToggleConnectionIO(channel, port.Port)
}
}
// Toggle Connection between two ports
func (port *Port) ToggleConnectionWithPort(other Port) {
port.ToggleConnectionWithChannel(other.Port)
}
func (port *Port) SetMonitored() {
port.target.SetMonitor(port.IsInput, port.Port)
port.Update()
}
// ==== Get Channels ====
type Ports struct {
Inputs []Port
Outputs []Port
}
// Returns an array of strings representing the names of the input/output channels.
func (target *Target) GetPorts() Ports {
reply := target.SendCommand(Command { Target: "myx", Cmd: "get", Opts: []string{"channels"} })
all_ports := make(map[string][]Port)
all_unconverted_ports := reply.(map[string]interface{})["obj"].(map[string]interface{})
for k, v := range all_unconverted_ports {
ports := make([]Port, len(v.([]interface{})))
for i, e := range v.([]interface{}) {
ports[i] = target.GetPortFromInterface(e.(map[string]interface{}))
}
all_ports[k] = ports
}
return Ports { Inputs: all_ports["inputs"], Outputs: all_ports["outputs"] }
}
// ==== Set Connected ====
// Connect input with output
func (target *Target) ConnectIO(input, output string) {
target.SendCommand(Command { Target: "myx", Cmd: "con", Opts: []string{input, output} })
}
// Toggle connection between input and output
func (target *Target) ToggleConnectionIO(input, output string) {
target.SendCommand(Command { Target: "myx", Cmd: "tog", Opts: []string{input, output} })
}
// Disconnect input and output
func (target *Target) DisconnectIO(input, output string) {
target.SendCommand(Command { Target: "myx", Cmd: "dis", Opts: []string{input, output} })
}
// ==== Get Connected ====
// Return true if output & input are connected
func (target *Target) GetConnectedIO(input, output string) bool {
for _, i := range target.GetPort(false, output).Cons {
if i == input { return true }
}
return false
}
// ==== Set Monitor ====
func (target *Target) SetMonitor(isinput bool, channel string) {
target.SendCommand(Command { Target: "myx", Cmd: "set", Opts: []string{"monitor", getTargetType(isinput), channel}})
}
// ==== Get Monitor ====
func (target *Target) GetMonitorPort() Port {
reply := target.SendCommand(Command { Target: "myx", Cmd: "get", Opts: []string{"monitor"} })
return target.GetPortFromReply(reply.(map[string]interface{}))
}
// ==== Listeners ====
// Listen for volume change for specified channel.
// This is a blocking call waiting for a change in volume and returning it.
func (target *Target) VolumeListen(isinput bool, channel string) Port {
reply := target.SendCommand(Command {Target: "myx", Cmd: "mon", Opts: []string{"vol", getTargetType(isinput), channel}})
var port Port = target.GetPortFromReply(reply.(map[string]interface{}))
return port
}
// Listen for volume for specified input channel.
// This is a blocking call waiting for a change in volume and returning it.
func (target *Target) VolumeInputListen(input string) Port { return target.VolumeListen(true, input) }
// Listen for volume for specified output channel.
// This is a blocking call waiting for a change in volume and returning it.
func (target *Target) VolumeOutputListen(output string) Port { return target.VolumeListen(false, output) }
// Listen for balance change for specified channel.
// This is a blocking call waiting for a change in balance and returning it.
func (target *Target) BalanceListen(isinput bool, channel string) Port {
reply := target.SendCommand(Command {Target: "myx", Cmd: "mon", Opts: []string{"bal", getTargetType(isinput), channel}})
var port Port = target.GetPortFromReply(reply.(map[string]interface{}))
return port
}
// Listen for balance for specified input channel.
// This is a blocking call waiting for a change in balance and returning it.
func (target *Target) BalanceInputListen(input string) Port { return target.BalanceListen(true, input) }
// Listen for balance for specified output channel.
// This is a blocking call waiting for a change in balance and returning it.
func (target *Target) BalanceOutputListen(output string) Port { return target.BalanceListen(false, output) }