1 /************************************************************************
3 IMPORTANT NOTE : this file contains two clearly delimited sections :
4 the ARCHITECTURE section (in two parts) and the USER section. Each section
5 is governed by its own copyright and license. Please check individually
6 each section for license and copyright information.
7 *************************************************************************/
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
14 ---------------------------------------------------------------------
15 This Architecture section is free software; you can redistribute it
16 and/or modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version 3 of
18 the License, or (at your option) any later version.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; If not, see <http://www.gnu.org/licenses/>.
28 EXCEPTION : As a special exception, you may create a larger work
29 that contains this FAUST architecture section and distribute
30 that work under terms of your choice, so long as this FAUST
31 architecture section is not modified.
34 ************************************************************************
35 ************************************************************************/
54 #include <jack/jack.h>
55 #include <jack/jslist.h>
59 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
60 // flags to avoid costly denormals
62 #include <xmmintrin.h>
64 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
66 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
69 #define AVOIDDENORMALS
72 struct Meta
: map
<const char*, const char*>
74 void declare (const char* key
, const char* value
) { (*this)[key
]=value
; }
77 #define max(x,y) (((x)>(y)) ? (x) : (y))
78 #define min(x,y) (((x)<(y)) ? (x) : (y))
80 // abs is now predefined
81 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
83 inline int lsr (int x
, int n
) { return int(((unsigned int)x
) >> n
); }
85 /******************************************************************************
86 *******************************************************************************
90 *******************************************************************************
91 *******************************************************************************/
93 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
94 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
99 /******************************************************************************
100 *******************************************************************************
102 GRAPHIC USER INTERFACE (v2)
105 *******************************************************************************
106 *******************************************************************************/
112 typedef void (*uiCallback
)(float val
, void* data
);
115 * Graphic User Interface : abstract definition
120 typedef list
<uiItem
*> clist
;
121 typedef map
<float*, clist
*> zmap
;
124 static list
<UI
*> fGuiList
;
130 UI() : fStopped(false) {
131 fGuiList
.push_back(this);
135 // suppression de this dans fGuiList
138 // -- zone management
140 void registerZone(float* z
, uiItem
* c
)
142 if (fZoneMap
.find(z
) == fZoneMap
.end()) fZoneMap
[z
] = new clist();
143 fZoneMap
[z
]->push_back(c
);
146 void updateAllZones();
148 void updateZone(float* z
);
150 static void updateAllGuis()
152 list
<UI
*>::iterator g
;
153 for (g
= fGuiList
.begin(); g
!= fGuiList
.end(); g
++) {
154 (*g
)->updateAllZones();
160 virtual void addButton(const char* label
, float* zone
) = 0;
161 virtual void addToggleButton(const char* label
, float* zone
) = 0;
162 virtual void addCheckButton(const char* label
, float* zone
) = 0;
163 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
164 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
165 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
167 // -- passive widgets
169 virtual void addNumDisplay(const char* label
, float* zone
, int precision
) = 0;
170 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
) = 0;
171 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
) = 0;
172 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
) = 0;
174 void addCallback(float* zone
, uiCallback foo
, void* data
);
176 // -- widget's layouts
178 virtual void openFrameBox(const char* label
) = 0;
179 virtual void openTabBox(const char* label
) = 0;
180 virtual void openHorizontalBox(const char* label
) = 0;
181 virtual void openVerticalBox(const char* label
) = 0;
182 virtual void closeBox() = 0;
184 virtual void declare(float* zone
, const char* key
, const char* value
) {}
187 class OSCUI
: public UI
195 // suppression de this dans fGuiList
201 virtual void addButton(const char* label
, float* zone
) {}
202 virtual void addToggleButton(const char* label
, float* zone
) {}
203 virtual void addCheckButton(const char* label
, float* zone
) {}
204 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) {}
205 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) {}
206 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
) {}
208 // -- passive widgets
210 virtual void addNumDisplay(const char* label
, float* zone
, int precision
) {}
211 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
) {}
212 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
) {}
213 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
) {}
215 void addCallback(float* zone
, uiCallback foo
, void* data
);
217 // -- widget's layouts
219 virtual void openFrameBox(const char* label
) {}
220 virtual void openTabBox(const char* label
) {}
221 virtual void openHorizontalBox(const char* label
) {}
222 virtual void openVerticalBox(const char* label
) {}
223 virtual void closeBox() {}
225 virtual void declare(float* zone
, const char* key
, const char* value
) {}
228 list
<UI
*> UI::fGuiList
;
231 * User Interface Item: abstract definition
242 uiItem (UI
* ui
, float* zone
) : fGUI(ui
), fZone(zone
), fCache(-123456.654321)
244 ui
->registerZone(zone
, this);
251 void modifyZone(float v
)
256 fGUI
->updateZone(fZone
);
260 float cache() { return fCache
; }
261 virtual void reflectZone() = 0;
269 struct uiCallbackItem
: public uiItem
271 uiCallback fCallback
;
274 uiCallbackItem(UI
* ui
, float* zone
, uiCallback foo
, void* data
)
275 : uiItem(ui
, zone
), fCallback(foo
), fData(data
) {}
277 virtual void reflectZone() {
285 * Update all user items reflecting zone z
288 inline void UI::updateZone(float* z
)
291 clist
* l
= fZoneMap
[z
];
292 for (clist::iterator c
= l
->begin(); c
!= l
->end(); c
++) {
293 if ((*c
)->cache() != v
) (*c
)->reflectZone();
298 * Update all user items not up to date
301 inline void UI::updateAllZones()
303 for (zmap::iterator m
= fZoneMap
.begin(); m
!= fZoneMap
.end(); m
++) {
305 clist
* l
= m
->second
;
307 for (clist::iterator c
= l
->begin(); c
!= l
->end(); c
++) {
308 if ((*c
)->cache() != v
) (*c
)->reflectZone();
313 inline void UI::addCallback(float* zone
, uiCallback foo
, void* data
)
315 new uiCallbackItem(this, zone
, foo
, data
);
318 //----------------------------------------------------------------
319 // definition du processeur de signal
320 //----------------------------------------------------------------
329 virtual int getNumInputs() = 0;
330 virtual int getNumOutputs() = 0;
331 virtual void buildUserInterface(UI
* interface
) = 0;
332 virtual void init(int samplingRate
) = 0;
333 virtual void compute(int len
, float** inputs
, float** outputs
) = 0;
334 virtual void conclude() {}
338 /********************END ARCHITECTURE SECTION (part 1/2)****************/
340 /**************************BEGIN USER SECTION **************************/
344 /***************************END USER SECTION ***************************/
346 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
349 /******************************************************************************
350 *******************************************************************************
354 *******************************************************************************
355 *******************************************************************************/
357 #define JACK_DRIVER_NAME_MAX 15
358 #define JACK_DRIVER_PARAM_NAME_MAX 15
359 #define JACK_DRIVER_PARAM_STRING_MAX 63
360 #define JACK_DRIVER_PARAM_DESC 255
361 #define JACK_PATH_MAX 511
363 /** Driver parameter types */
366 JackDriverParamInt
= 1,
369 JackDriverParamString
,
371 } jack_driver_param_type_t
;
373 /** Driver parameter value */
379 char str
[JACK_DRIVER_PARAM_STRING_MAX
+ 1];
380 } jack_driver_param_value_t
;
383 /** A driver parameter descriptor */
385 char name
[JACK_DRIVER_NAME_MAX
+ 1]; /**< The parameter's name */
386 char character
; /**< The parameter's character (for getopt, etc) */
387 jack_driver_param_type_t type
; /**< The parameter's type */
388 jack_driver_param_value_t value
; /**< The parameter's (default) value */
389 char short_desc
[64]; /**< A short (~30 chars) description for the user */
390 char long_desc
[1024]; /**< A longer description for the user */
392 jack_driver_param_desc_t
;
394 /** A driver parameter */
397 jack_driver_param_value_t value
;
401 /** A struct for describing a jack driver */
403 char name
[JACK_DRIVER_NAME_MAX
+ 1]; /**< The driver's canonical name */
404 char desc
[JACK_DRIVER_PARAM_DESC
+ 1]; /**< The driver's extended description */
405 char file
[JACK_PATH_MAX
+ 1]; /**< The filename of the driver's shared object file */
406 uint32_t nparams
; /**< The number of parameters the driver has */
407 jack_driver_param_desc_t
* params
; /**< An array of parameter descriptors */
411 // class JackArgParser ***************************************************
416 std::string fArgString
;
418 std::vector
<std::string
> fArgv
;
422 JackArgParser (const char* arg
);
424 std::string
GetArgString();
427 int GetArgv (std::vector
<std::string
>& argv
);
428 int GetArgv (char** argv
);
429 void DeleteArgv (const char** argv
);
430 void ParseParams (jack_driver_desc_t
* desc
, JSList
** param_list
);
431 void FreeParams (JSList
* param_list
);
434 JackArgParser::JackArgParser (const char* arg
)
436 printf ("JackArgParser::JackArgParser, arg_string : '%s' \n", arg
);
440 if (strlen(arg
) == 0)
442 fArgString
= string(arg
);
443 //else parse the arg string
444 const size_t arg_len
= fArgString
.length();
448 size_t copy_start
= 0;
449 size_t copy_length
= 0;
450 //we need a 'space terminated' string
452 //first fill a vector with args
454 //find the first non-space character from the actual position
455 start
= fArgString
.find_first_not_of (' ', start
);
456 //get the next quote or space position
457 pos
= fArgString
.find_first_of (" \"" , start
);
458 //no more quotes or spaces, consider the end of the string
459 if (pos
== string::npos
)
462 if (fArgString
[pos
] == '\"') {
463 //first character : copy the substring
465 copy_start
= start
+ 1;
466 pos
= fArgString
.find ('\"', ++pos
);
467 copy_length
= pos
- copy_start
;
470 //else there is someting before the quote, first copy that
473 copy_length
= pos
- copy_start
;
478 if (fArgString
[pos
] == ' ') {
479 //short option descriptor
480 if ((fArgString
[start
] == '-') && (fArgString
[start
+ 1] != '-')) {
483 start
+= copy_length
;
485 //else copy all the space delimitated string
488 copy_length
= pos
- copy_start
;
492 //then push the substring to the args vector
493 fArgv
.push_back (fArgString
.substr (copy_start
, copy_length
));
494 printf("JackArgParser::JackArgParser, add : '%s' \n", (*fArgv
.rbegin()).c_str());
495 } while (start
< arg_len
);
497 //finally count the options
498 for (i
= 0; i
< fArgv
.size(); i
++)
499 if (fArgv
[i
].at(0) == '-')
503 JackArgParser::~JackArgParser()
506 string
JackArgParser::GetArgString()
511 int JackArgParser::GetNumArgv()
516 int JackArgParser::GetArgc()
521 int JackArgParser::GetArgv(vector
<string
>& argv
)
527 int JackArgParser::GetArgv(char** argv
)
532 //else allocate and fill it
533 argv
= (char**)calloc(fArgv
.size(), sizeof(char*));
534 for (unsigned int i
= 0; i
< fArgv
.size(); i
++) {
535 argv
[i
] = (char*)calloc(fArgv
[i
].length(), sizeof(char));
536 fill_n(argv
[i
], fArgv
[i
].length() + 1, 0);
537 fArgv
[i
].copy(argv
[i
], fArgv
[i
].length());
542 void JackArgParser::DeleteArgv(const char** argv
)
545 for (i
= 0; i
< fArgv
.size(); i
++)
546 free((void*)argv
[i
]);
550 void JackArgParser::ParseParams(jack_driver_desc_t
* desc
, JSList
** param_list
)
554 unsigned int param
= 0;
556 JSList
* params
= NULL
;
557 jack_driver_param_t
* intclient_param
;
559 for (i
= 0; i
< desc
->nparams
; i
++)
560 options_list
+= desc
->params
[i
].character
;
562 for (param
= 0; param
< fArgv
.size(); param
++)
564 if (fArgv
[param
][0] == '-')
567 if ((param_id
= options_list
.find_first_of(fArgv
[param
].at(1))) != string::npos
)
569 intclient_param
= static_cast<jack_driver_param_t
*>(calloc(1, sizeof(jack_driver_param_t
)));
570 intclient_param
->character
= desc
->params
[param_id
].character
;
572 switch (desc
->params
[param_id
].type
)
574 case JackDriverParamInt
:
575 if (param
+ 1 < fArgv
.size()) // something to parse
576 intclient_param
->value
.i
= atoi(fArgv
[param
+ 1].c_str());
579 case JackDriverParamUInt
:
580 if (param
+ 1 < fArgv
.size()) // something to parse
581 intclient_param
->value
.ui
= strtoul(fArgv
[param
+ 1].c_str(), NULL
, 10);
584 case JackDriverParamChar
:
585 if (param
+ 1 < fArgv
.size()) // something to parse
586 intclient_param
->value
.c
= fArgv
[param
+ 1][0];
589 case JackDriverParamString
:
590 if (param
+ 1 < fArgv
.size()) // something to parse
591 fArgv
[param
+ 1].copy(intclient_param
->value
.str
, min(static_cast<int>(fArgv
[param
+ 1].length()), JACK_DRIVER_PARAM_STRING_MAX
));
594 case JackDriverParamBool
:
595 intclient_param
->value
.i
= true;
599 params
= jack_slist_append(params
, intclient_param
);
603 printf("Invalid option '%c'\n", fArgv
[param
][1]);
608 *param_list
= params
;
611 void JackArgParser::FreeParams(JSList
* param_list
)
613 JSList
*node_ptr
= param_list
;
614 JSList
*next_node_ptr
;
617 next_node_ptr
= node_ptr
->next
;
618 free(node_ptr
->data
);
620 node_ptr
= next_node_ptr
;
624 struct JackFaustInternal
{
626 //----------------------------------------------------------------------------
627 // number of input and output channels
628 //----------------------------------------------------------------------------
633 //----------------------------------------------------------------------------
635 //----------------------------------------------------------------------------
637 jack_port_t
* fInputPorts
[256];
638 jack_port_t
* fOutputPorts
[256];
640 //----------------------------------------------------------------------------
641 // tables of noninterleaved input and output channels for FAUST
642 //----------------------------------------------------------------------------
644 float* fInChannel
[256];
645 float* fOutChannel
[256];
647 jack_client_t
* fClient
;
651 JackFaustInternal(jack_client_t
* client
, const JSList
* params
)
662 char** physicalInPorts
;
663 char** physicalOutPorts
;
665 fInterface
= new OSCUI();
666 fDSP
.buildUserInterface(fInterface
);
668 jack_set_process_callback(fClient
, process
, this);
669 jack_set_sample_rate_callback(fClient
, srate
, this);
671 fNumInChans
= fDSP
.getNumInputs();
672 fNumOutChans
= fDSP
.getNumOutputs();
674 for (int i
= 0; i
< fNumInChans
; i
++) {
676 snprintf(buf
, 256, "in_%d", i
);
677 fInputPorts
[i
] = jack_port_register(fClient
, buf
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0);
679 for (int i
= 0; i
< fNumOutChans
; i
++) {
681 snprintf(buf
, 256, "out_%d", i
);
682 fOutputPorts
[i
] = jack_port_register(fClient
, buf
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
685 fDSP
.init(jack_get_sample_rate(fClient
));
687 physicalInPorts
= (char **)jack_get_ports(fClient
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsInput
);
688 physicalOutPorts
= (char **)jack_get_ports(fClient
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsOutput
);
690 if (jack_activate(fClient
)) {
691 fprintf(stderr
, "cannot activate client");
695 if (physicalOutPorts
!= NULL
) {
696 for (int i
= 0; i
< fNumInChans
&& physicalOutPorts
[i
]; i
++) {
697 jack_connect(fClient
, physicalOutPorts
[i
], jack_port_name(fInputPorts
[i
]));
701 if (physicalInPorts
!= NULL
) {
702 for (int i
= 0; i
< fNumOutChans
&& physicalInPorts
[i
]; i
++) {
703 jack_connect(fClient
, jack_port_name(fOutputPorts
[i
]), physicalInPorts
[i
]);
710 //----------------------------------------------------------------------------
712 //----------------------------------------------------------------------------
714 static int srate(jack_nframes_t nframes
, void *arg
)
716 printf("the sample rate is now %u/sec\n", nframes
);
720 static int process(jack_nframes_t nframes
, void *arg
)
722 JackFaustInternal
* obj
= (JackFaustInternal
*)arg
;
725 for (int i
= 0; i
< obj
->fNumInChans
; i
++) {
726 obj
->fInChannel
[i
] = (float *)jack_port_get_buffer(obj
->fInputPorts
[i
], nframes
);
728 for (int i
= 0; i
< obj
->fNumOutChans
; i
++) {
729 obj
->fOutChannel
[i
] = (float *)jack_port_get_buffer(obj
->fOutputPorts
[i
], nframes
);
731 obj
->fDSP
.compute(nframes
, obj
->fInChannel
, obj
->fOutChannel
);
743 jack_driver_desc_t
* jack_get_descriptor()
745 jack_driver_desc_t
*desc
;
747 desc
= (jack_driver_desc_t
*)calloc(1, sizeof(jack_driver_desc_t
));
749 strcpy(desc
->name
, "faust"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
750 strcpy(desc
->desc
, " Faust generated internal"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
755 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
758 strcpy(desc->params[i].name, "channels");
759 desc->params[i].character = 'c';
760 desc->params[i].type = JackDriverParamInt;
761 desc->params[i].value.ui = 0;
762 strcpy(desc->params[i].short_desc, "Maximum number of channels");
763 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
766 strcpy(desc->params[i].name, "inchannels");
767 desc->params[i].character = 'i';
768 desc->params[i].type = JackDriverParamInt;
769 desc->params[i].value.ui = 0;
770 strcpy(desc->params[i].short_desc, "Maximum number of input channels");
771 strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
777 int jack_internal_initialize(jack_client_t
* client
, const JSList
* params
)
781 JackFaustInternal
* internal
= new JackFaustInternal(client
, params
);
782 if (internal
->Open() == 0) {
794 int jack_initialize(jack_client_t
* client
, const char* load_init
)
796 JSList
* params
= NULL
;
797 jack_driver_desc_t
*desc
= jack_get_descriptor();
799 JackArgParser
parser(load_init
);
800 if (parser
.GetArgc() > 0)
801 parser
.ParseParams(desc
, ¶ms
);
803 int res
= jack_internal_initialize(client
, params
);
804 parser
.FreeParams(params
);
808 void jack_finish(void* arg
)
810 JackFaustInternal
* internal
= static_cast<JackFaustInternal
*>(arg
);
813 printf("Unloading internal\n");
823 /********************END ARCHITECTURE SECTION (part 2/2)****************/