1 /************************************************************************
2 IMPORTANT NOTE : this file contains two clearly delimited sections :
3 the ARCHITECTURE section (in two parts) and the USER section. Each section
4 is governed by its own copyright and license. Please check individually
5 each section for license and copyright information.
6 *************************************************************************/
7
8 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
9
10 /************************************************************************
11 FAUST Architecture File
12 Copyright (C) 2003-2019 GRAME, Centre National de Creation Musicale
13 ---------------------------------------------------------------------
14 This Architecture section is free software; you can redistribute it
15 and/or modify it under the terms of the GNU General Public License
16 as published by the Free Software Foundation; either version 3 of
17 the License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; If not, see <http://www.gnu.org/licenses/>.
26
27 EXCEPTION : As a special exception, you may create a larger work
28 that contains this FAUST architecture section and distribute
29 that work under terms of your choice, so long as this FAUST
30 architecture section is not modified.
31
32 ************************************************************************
33 ************************************************************************/
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <limits.h>
39 #include <math.h>
40 #include <errno.h>
41 #include <time.h>
42 #include <vector>
43 #include <stack>
44 #include <string>
45 #include <map>
46 #include <list>
47 #include <iostream>
48 #include <assert.h>
49
50 #include "faust/dsp/dsp.h"
51 #include "faust/gui/GUI.h"
52 #include "faust/gui/OSCUI.h"
53 #include "faust/misc.h"
54
55 #include <libgen.h>
56 #include <jack/jack.h>
57 #include <jack/jslist.h>
58
59 using namespace std;
60
61 /******************************************************************************
62 *******************************************************************************
63
64 VECTOR INTRINSICS
65
66 *******************************************************************************
67 *******************************************************************************/
68
69 <<includeIntrinsic>>
70
71 /********************END ARCHITECTURE SECTION (part 1/2)****************/
72
73 /**************************BEGIN USER SECTION **************************/
74
75 <<includeclass>>
76
77 /***************************END USER SECTION ***************************/
78
79 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
80
81 std::list<GUI*> GUI::fGuiList;
82 ztimedmap GUI::gTimedZoneMap;
83
84 /******************************************************************************
85 *******************************************************************************
86
87 JACK AUDIO INTERFACE
88
89 *******************************************************************************
90 *******************************************************************************/
91
92 #define JACK_DRIVER_NAME_MAX 15
93 #define JACK_DRIVER_PARAM_NAME_MAX 15
94 #define JACK_DRIVER_PARAM_STRING_MAX 63
95 #define JACK_DRIVER_PARAM_DESC 255
96 #define JACK_PATH_MAX 511
97
98 /** Driver parameter types */
99 typedef enum
100 {
101 JackDriverParamInt = 1,
102 JackDriverParamUInt,
103 JackDriverParamChar,
104 JackDriverParamString,
105 JackDriverParamBool
106 } jack_driver_param_type_t;
107
108 /** Driver parameter value */
109 typedef union
110 {
111 uint32_t ui;
112 int32_t i;
113 char c;
114 char str[JACK_DRIVER_PARAM_STRING_MAX + 1];
115 } jack_driver_param_value_t;
116
117
118 /** A driver parameter descriptor */
119 typedef struct {
120 char name[JACK_DRIVER_NAME_MAX + 1]; /**< The parameter's name */
121 char character; /**< The parameter's character (for getopt, etc) */
122 jack_driver_param_type_t type; /**< The parameter's type */
123 jack_driver_param_value_t value; /**< The parameter's (default) value */
124 char short_desc[64]; /**< A short (~30 chars) description for the user */
125 char long_desc[1024]; /**< A longer description for the user */
126 }
127 jack_driver_param_desc_t;
128
129 /** A driver parameter */
130 typedef struct {
131 char character;
132 jack_driver_param_value_t value;
133 }
134 jack_driver_param_t;
135
136 /** A struct for describing a jack driver */
137 typedef struct {
138 char name[JACK_DRIVER_NAME_MAX + 1]; /**< The driver's canonical name */
139 char desc[JACK_DRIVER_PARAM_DESC + 1]; /**< The driver's extended description */
140 char file[JACK_PATH_MAX + 1]; /**< The filename of the driver's shared object file */
141 uint32_t nparams; /**< The number of parameters the driver has */
142 jack_driver_param_desc_t * params; /**< An array of parameter descriptors */
143 }
144 jack_driver_desc_t;
145
146 // class JackArgParser ***************************************************
147 class JackArgParser
148 {
149 private:
150
151 std::string fArgString;
152 int fArgc;
153 std::vector<std::string> fArgv;
154
155 public:
156
157 JackArgParser (const char* arg);
158 ~JackArgParser();
159 std::string GetArgString();
160 int GetNumArgv();
161 int GetArgc();
162 int GetArgv (std::vector<std::string>& argv);
163 int GetArgv (char** argv);
164 void DeleteArgv (const char** argv);
165 void ParseParams (jack_driver_desc_t* desc, JSList** param_list);
166 void FreeParams (JSList* param_list);
167 };
168
JackArgParser(const char * arg)169 JackArgParser::JackArgParser (const char* arg)
170 {
171 printf ("JackArgParser::JackArgParser, arg_string : '%s' \n", arg);
172
173 fArgc = 0;
174 //if empty string
175 if (strlen(arg) == 0)
176 return;
177 fArgString = string(arg);
178 //else parse the arg string
179 const size_t arg_len = fArgString.length();
180 unsigned int i = 0;
181 size_t pos = 0;
182 size_t start = 0;
183 size_t copy_start = 0;
184 size_t copy_length = 0;
185 //we need a 'space terminated' string
186 fArgString += " ";
187 //first fill a vector with args
188 do {
189 //find the first non-space character from the actual position
190 start = fArgString.find_first_not_of (' ', start);
191 //get the next quote or space position
192 pos = fArgString.find_first_of (" \"" , start);
193 //no more quotes or spaces, consider the end of the string
194 if (pos == string::npos)
195 pos = arg_len;
196 //if double quote
197 if (fArgString[pos] == '\"') {
198 //first character : copy the substring
199 if (pos == start) {
200 copy_start = start + 1;
201 pos = fArgString.find ('\"', ++pos);
202 copy_length = pos - copy_start;
203 start = pos + 1;
204 }
205 //else there is someting before the quote, first copy that
206 else {
207 copy_start = start;
208 copy_length = pos - copy_start;
209 start = pos;
210 }
211 }
212 //if space
213 if (fArgString[pos] == ' ') {
214 //short option descriptor
215 if ((fArgString[start] == '-') && (fArgString[start + 1] != '-')) {
216 copy_start = start;
217 copy_length = 2;
218 start += copy_length;
219 }
220 //else copy all the space delimitated string
221 else {
222 copy_start = start;
223 copy_length = pos - copy_start;
224 start = pos + 1;
225 }
226 }
227 //then push the substring to the args vector
228 fArgv.push_back (fArgString.substr (copy_start, copy_length));
229 printf("JackArgParser::JackArgParser, add : '%s' \n", (*fArgv.rbegin()).c_str());
230 } while (start < arg_len);
231
232 //finally count the options
233 for (i = 0; i < fArgv.size(); i++) {
234 if (fArgv[i].at(0) == '-') {
235 fArgc++;
236 }
237 }
238 }
239
~JackArgParser()240 JackArgParser::~JackArgParser()
241 {}
242
GetArgString()243 string JackArgParser::GetArgString()
244 {
245 return fArgString;
246 }
247
GetNumArgv()248 int JackArgParser::GetNumArgv()
249 {
250 return fArgv.size();
251 }
252
GetArgc()253 int JackArgParser::GetArgc()
254 {
255 return fArgc;
256 }
257
GetArgv(vector<string> & argv)258 int JackArgParser::GetArgv(vector<string>& argv)
259 {
260 argv = fArgv;
261 return 0;
262 }
263
GetArgv(char ** argv)264 int JackArgParser::GetArgv(char** argv)
265 {
266 //argv must be NULL
267 if (argv)
268 return -1;
269 //else allocate and fill it
270 argv = (char**)calloc(fArgv.size(), sizeof(char*));
271 for (unsigned int i = 0; i < fArgv.size(); i++) {
272 argv[i] = (char*)calloc(fArgv[i].length(), sizeof(char));
273 fill_n(argv[i], fArgv[i].length() + 1, 0);
274 fArgv[i].copy(argv[i], fArgv[i].length());
275 }
276 return 0;
277 }
278
DeleteArgv(const char ** argv)279 void JackArgParser::DeleteArgv(const char** argv)
280 {
281 unsigned int i;
282 for (i = 0; i < fArgv.size(); i++)
283 free((void*)argv[i]);
284 free((void*)argv);
285 }
286
ParseParams(jack_driver_desc_t * desc,JSList ** param_list)287 void JackArgParser::ParseParams(jack_driver_desc_t* desc, JSList** param_list)
288 {
289 string options_list;
290 unsigned long i = 0;
291 unsigned int param = 0;
292 size_t param_id = 0;
293 JSList* params = NULL;
294 jack_driver_param_t* intclient_param;
295
296 for (i = 0; i < desc->nparams; i++) {
297 options_list += desc->params[i].character;
298 }
299
300 for (param = 0; param < fArgv.size(); param++)
301 {
302 if (fArgv[param][0] == '-')
303 {
304 //valid option
305 if ((param_id = options_list.find_first_of(fArgv[param].at(1))) != string::npos)
306 {
307 intclient_param = static_cast<jack_driver_param_t*>(calloc(1, sizeof(jack_driver_param_t)));
308 intclient_param->character = desc->params[param_id].character;
309
310 switch (desc->params[param_id].type)
311 {
312 case JackDriverParamInt:
313 if (param + 1 < fArgv.size()) // something to parse
314 intclient_param->value.i = atoi(fArgv[param + 1].c_str());
315 break;
316
317 case JackDriverParamUInt:
318 if (param + 1 < fArgv.size()) // something to parse
319 intclient_param->value.ui = strtoul(fArgv[param + 1].c_str(), NULL, 10);
320 break;
321
322 case JackDriverParamChar:
323 if (param + 1 < fArgv.size()) // something to parse
324 intclient_param->value.c = fArgv[param + 1][0];
325 break;
326
327 case JackDriverParamString:
328 if (param + 1 < fArgv.size()) // something to parse
329 fArgv[param + 1].copy(intclient_param->value.str, min(static_cast<int>(fArgv[param + 1].length()), JACK_DRIVER_PARAM_STRING_MAX));
330 break;
331
332 case JackDriverParamBool:
333 intclient_param->value.i = true;
334 break;
335 }
336 //add to the list
337 params = jack_slist_append(params, intclient_param);
338 }
339 //invalid option
340 else
341 printf("Invalid option '%c'\n", fArgv[param][1]);
342 }
343 }
344
345 assert(param_list);
346 *param_list = params;
347 }
348
FreeParams(JSList * param_list)349 void JackArgParser::FreeParams(JSList* param_list)
350 {
351 JSList *node_ptr = param_list;
352 JSList *next_node_ptr;
353
354 while (node_ptr) {
355 next_node_ptr = node_ptr->next;
356 free(node_ptr->data);
357 free(node_ptr);
358 node_ptr = next_node_ptr;
359 }
360 }
361
362 struct JackFaustInternal {
363
364 //----------------------------------------------------------------------------
365 // number of input and output channels
366 //----------------------------------------------------------------------------
367
368 int fNumInChans;
369 int fNumOutChans;
370
371 //----------------------------------------------------------------------------
372 // Jack ports
373 //----------------------------------------------------------------------------
374
375 jack_port_t* fInputPorts[256];
376 jack_port_t* fOutputPorts[256];
377
378 //----------------------------------------------------------------------------
379 // tables of noninterleaved input and output channels for FAUST
380 //----------------------------------------------------------------------------
381
382 float* fInChannel[256];
383 float* fOutChannel[256];
384
385 jack_client_t* fClient;
386 UI* fInterface;
387 mydsp fDSP;
388
JackFaustInternalJackFaustInternal389 JackFaustInternal(jack_client_t* client, const JSList* params)
390 :fClient(client)
391 {}
392
~JackFaustInternalJackFaustInternal393 ~JackFaustInternal()
394 {
395 delete fInterface;
396 }
397
OpenJackFaustInternal398 int Open()
399 {
400 char** physicalInPorts;
401 char** physicalOutPorts;
402
403 fInterface = new OSCUI(NULL, 0, NULL);
404 fDSP.buildUserInterface(fInterface);
405
406 jack_set_process_callback(fClient, process, this);
407 jack_set_sample_rate_callback(fClient, srate, this);
408
409 fNumInChans = fDSP.getNumInputs();
410 fNumOutChans = fDSP.getNumOutputs();
411
412 for (int i = 0; i < fNumInChans; i++) {
413 char buf[256];
414 snprintf(buf, 256, "in_%d", i);
415 fInputPorts[i] = jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
416 }
417 for (int i = 0; i < fNumOutChans; i++) {
418 char buf[256];
419 snprintf(buf, 256, "out_%d", i);
420 fOutputPorts[i] = jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
421 }
422
423 fDSP.init(jack_get_sample_rate(fClient));
424
425 physicalInPorts = (char **)jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
426 physicalOutPorts = (char **)jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical|JackPortIsOutput);
427
428 if (jack_activate(fClient)) {
429 fprintf(stderr, "cannot activate client");
430 return -1;
431 }
432
433 if (physicalOutPorts != NULL) {
434 for (int i = 0; i < fNumInChans && physicalOutPorts[i]; i++) {
435 jack_connect(fClient, physicalOutPorts[i], jack_port_name(fInputPorts[i]));
436 }
437 }
438
439 if (physicalInPorts != NULL) {
440 for (int i = 0; i < fNumOutChans && physicalInPorts[i]; i++) {
441 jack_connect(fClient, jack_port_name(fOutputPorts[i]), physicalInPorts[i]);
442 }
443 }
444
445 return 0;
446 }
447
448 //----------------------------------------------------------------------------
449 // Jack Callbacks
450 //----------------------------------------------------------------------------
451
srateJackFaustInternal452 static int srate(jack_nframes_t nframes, void *arg)
453 {
454 printf("the sample rate is now %u/sec\n", nframes);
455 return 0;
456 }
457
processJackFaustInternal458 static int process(jack_nframes_t nframes, void *arg)
459 {
460 JackFaustInternal* obj = (JackFaustInternal*)arg;
461 AVOIDDENORMALS;
462
463 for (int i = 0; i < obj->fNumInChans; i++) {
464 obj->fInChannel[i] = (float *)jack_port_get_buffer(obj->fInputPorts[i], nframes);
465 }
466 for (int i = 0; i < obj->fNumOutChans; i++) {
467 obj->fOutChannel[i] = (float *)jack_port_get_buffer(obj->fOutputPorts[i], nframes);
468 }
469 obj->fDSP.compute(nframes, obj->fInChannel, obj->fOutChannel);
470
471 return 0;
472 }
473
474 };
475
476 #ifdef __cplusplus
477 extern "C"
478 {
479 #endif
480
jack_get_descriptor()481 jack_driver_desc_t* jack_get_descriptor()
482 {
483 jack_driver_desc_t *desc;
484 unsigned int i;
485 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
486
487 strcpy(desc->name, "faust"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
488 strcpy(desc->desc, " Faust generated internal"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
489
490 desc->nparams = 0;
491 /*
492 desc->nparams = 2;
493 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
494
495 i = 0;
496 strcpy(desc->params[i].name, "channels");
497 desc->params[i].character = 'c';
498 desc->params[i].type = JackDriverParamInt;
499 desc->params[i].value.ui = 0;
500 strcpy(desc->params[i].short_desc, "Maximum number of channels");
501 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
502
503 i++;
504 strcpy(desc->params[i].name, "inchannels");
505 desc->params[i].character = 'i';
506 desc->params[i].type = JackDriverParamInt;
507 desc->params[i].value.ui = 0;
508 strcpy(desc->params[i].short_desc, "Maximum number of input channels");
509 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
510 */
511
512 return desc;
513 }
514
jack_internal_initialize(jack_client_t * client,const JSList * params)515 int jack_internal_initialize(jack_client_t* client, const JSList* params)
516 {
517 try {
518
519 JackFaustInternal* internal = new JackFaustInternal(client, params);
520 if (internal->Open() == 0) {
521 return 0;
522 } else {
523 delete internal;
524 return 1;
525 }
526
527 } catch (...) {
528 return 1;
529 }
530 }
531
jack_initialize(jack_client_t * client,const char * load_init)532 int jack_initialize(jack_client_t* client, const char* load_init)
533 {
534 JSList* params = NULL;
535 jack_driver_desc_t *desc = jack_get_descriptor();
536
537 JackArgParser parser(load_init);
538 if (parser.GetArgc() > 0)
539 parser.ParseParams(desc, ¶ms);
540
541 int res = jack_internal_initialize(client, params);
542 parser.FreeParams(params);
543 return res;
544 }
545
jack_finish(void * arg)546 void jack_finish(void* arg)
547 {
548 JackFaustInternal* internal = static_cast<JackFaustInternal*>(arg);
549
550 if (internal) {
551 printf("Unloading internal\n");
552 delete internal;
553 }
554 }
555
556 #ifdef __cplusplus
557 }
558 #endif
559
560 /********************END ARCHITECTURE SECTION (part 2/2)****************/
561