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, &params);
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