aboutsummaryrefslogtreecommitdiffstats
path: root/.config/SuperCollider/functions.scd
blob: d4dd058ca49d1e5956d0144553ec0e9df138715a (plain)
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
postln('Loading custom functions.');

/*
 * JACK specific helper functions
 * TODO: move to Quark
 */
// disconnect a port
~jackDisconnectPort = {
  arg source, sourceChannel, destination, destinationChannel;
  ("jack_disconnect "++source++":"++sourceChannel++" "++destination++":"++destinationChannel).unixCmd({
    arg exitCode;
    if(exitCode != 0, {
      postln("Disconnecting "++source++":"++sourceChannel++" from "++destination++":"++destinationChannel++" was unsuccessful!");
    });
  });
};

// connect a port
~jackConnectPort = {
  arg source, sourceChannel, destination, destinationChannel;
  ("jack_connect "++source++":"++sourceChannel++" "++destination++":"++destinationChannel).unixCmd({
    arg exitCode;
    if(exitCode != 0, {
      postln("Connecting "++source++":"++sourceChannel++" from "++destination++":"++destinationChannel++" was unsuccessful!");
    });
  });
};

// returns the amount of ports of a given client
~jackClientPorts = {
  arg clientName;
  ("jack_lsp "++clientName++"| wc -l").unixCmdGetStdOut.asInt;
};

/*
 * SuperCollider specific helper functions
 *
 */
// adds one or more channels to Server.local.options.num{In,Out}putBusChannels
// makes the tuple available in ~additionalChannels Dictionairy
~addAdditionalChannels = {
  arg type, name, channels;
  if( (name.isKindOf(Symbol) && channels.isArray), {
    switch (type,
      \input, {
        ~additionalChannels.at(\inputs).add(name -> channels);
        postln("Added additional input channels for '"++name++"': "++channels.asString);
        Server.local.options.numInputBusChannels = Server.local.options.numInputBusChannels + channels.size;
        postln("Setting numInputBusChannels to "++Server.local.options.numInputBusChannels);
      },
      \output, {
        ~additionalChannels.at(\outputs).add(name -> channels);
        postln("Added additional output channels for '"++name++"': "++channels.asString);
        Server.local.options.numOutputBusChannels = Server.local.options.numOutputBusChannels + channels.size;
        postln("Setting numOutputBusChannels to "++Server.local.options.numOutputBusChannels);
      },
      { error("Expecting \input or \output as type, got "++type.asString);
      });
  },{
    error('Expecting type Symbol for name and type Array for channels.');
  });
};

/*
 * SSR specific helper functions
 * TODO: move to Quark
 */

// sets up the necessary OSC connection for an existing local or remote SSR
// instance, subscribes to it and returns the NetAddr associated with it
~ssrSetupOSC = {
  arg host="localhost", port=50001;
  var ssr;
  // set ssr of the client instance
  ssr = NetAddr(host, port);
  // answer /poll messages with an /alive answer
  OSCdef(
    \pollreply,
    {
      arg msg, time, addr, recvPort;
      ~ssr.sendMsg("/alive");
    },
    '/poll',
    ssr
  );
  // subscribe to server with MessageLevel::SERVER
  ssr.sendMsg("/subscribe", $T, 2);
  ssr;
};

// clears the SSR scene, unsubscribes from the instance and removes alive
// answers OSCdef
~ssrDismantleOSC = {
  arg ssr;
  if (ssr.isKindOf(NetAddr), {
    // remove all sources
    ssr.sendMsg("/scene/clear");
    // unsubscribe from server
    ssr.sendMsg("/subscribe", $F);
    // disable alive answers
    OSCdef(\alive).disable;
  });
};

// adds a source to an SSR instance
~ssrAddSource = {
  arg ssr, name, model = "point", port, x = 0.0, y = 0.0, orientation = 0.0,
  gain = 1.0, movability = $F, orientationMovability = $F, mute = $F;
  if (ssr.isKindOf(NetAddr), {
    if (name.isString, {
      if (model.isString, {
        if (port.isString, {
          ssr.sendMsg("/source/new", name, model, port, x, y, orientation,
            gain, movability, orientationMovability, mute)
        },{
          error("The port argument is not of type String: "++port.class);
        });
      },{
        error("The model argument is not of type String: "++model.class);
      });
    },{
      error("The name argument is not of type String: "++name.class);
    });
  },{
    error("The ssr argument is not of type NetAddr: "++ssr.class);
  });
};

/*
 * MIDI specific helper functions
 * TODO: move to Quark
 */

// map inputs of a given MIDI device's control messages to the values on a
// control Bus
~midiControlToBus = {
  arg key, msgNum, chan, uid, bus;
  if(key.isKindOf(Symbol),{
    if((msgNum.isArray),{
      if (chan.isInteger, {
        if (uid.isInteger, {
          if (bus.isKindOf(Bus), {
            MIDIdef.new(
              key: key,
              func: {
                arg ...args;
                bus.setAt(
                  msgNum.indexOf(args[1].asInteger),
                  args[0].asInteger.lincurve(0, 127, 0.0, 1.0, 4, nil)
                );
              },
              msgNum: msgNum,
              chan: chan,
              msgType: \control,
              srcID: uid
            );
          },{
          error('Argument bus must be of type Bus: '++bus.class);
          });
        },{
        error('Argument uid must be of type Integer: '++uid.class);
        });
      },{
        error('Argument chan must be of type Integer: '++chan.class);
      });
    },{
      error('Argument msgNum must be of type Array: '++msgNum.class);
    });
  },{
    error('Argument key must be of type Symbol: '++key.class);
  });
};

// setting clock of ZZZES3 to bpm (in given range)
~midiControlToClockBPM = {
  arg key, msgNum, chan, uid, zzz, range;
  MIDIdef.new(
    key,
    {
      arg ...args;
      var bpm = args[0].linexp(0, 127, range[0], range[1]).asInteger;
      zzz.setClock(
        msgNum.indexOf(args[1].asInteger)+1,
        bpm/60
      );
    },
    msgNum,
    chan,
    \control,
    uid
  );
};