1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <limits.h>
5 #include <math.h>
6 #include <errno.h>
7 #include <time.h>
8 #include <sys/ioctl.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 //#include <sys/soundcard.h>
12 #include <pwd.h>
13 #include <sys/types.h>
14 #include <assert.h>
15 #include <pthread.h>
16 #include <sys/wait.h>
17 #include <list>
18 #include <vector>
19 #include <stack>
20
21 #include "wx/wx.h"
22 #include "wx/statbox.h"
23 #include "wx/notebook.h"
24 #include "wx/spinctrl.h"
25
26 #include <libgen.h>
27 #include <jack/jack.h>
28
29 // linux : g++ -O3 -lm -ljack `wx-config --cflags --libs` ex2.cpp
30 // macosx: g++ karplus-strong.cpp -D__WXMAC__ -DWXMAKINGDLL -lwx_mac-2.4 -ljack -o karplus
31
32 using namespace std ;
33
34 // abs is now predefined
35 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
36
37
lsr(int x,int n)38 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
39
int2pow2(int x)40 inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
41
42
43 /******************************************************************************
44 *******************************************************************************
45
46 VECTOR INTRINSICS
47
48 *******************************************************************************
49 *******************************************************************************/
50
51 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
52 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
53
54 <<includeIntrinsic>>
55
56
57 /******************************************************************************
58 *******************************************************************************
59
60 USER INTERFACE
61
62 *******************************************************************************
63 *******************************************************************************/
64
65 class UI
66 {
67 bool fStopped;
68 public:
69
UI()70 UI() : fStopped(false) {}
~UI()71 virtual ~UI() {}
72
73 virtual void addButton(char* label, float* zone) = 0;
74 virtual void addToggleButton(char* label, float* zone) = 0;
75 virtual void addCheckButton(char* label, float* zone) = 0;
76 virtual void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step) = 0;
77 virtual void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step) = 0;
78 virtual void addNumEntry(char* label, float* zone, float init, float min, float max, float step) = 0;
79
80 virtual void openFrameBox(char* label) = 0;
81 virtual void openTabBox(char* label) = 0;
82 virtual void openHorizontalBox(char* label) = 0;
83 virtual void openVerticalBox(char* label) = 0;
84 virtual void closeBox() = 0;
85
run()86 virtual void run() {};
87
stop()88 void stop() { fStopped = true; }
stopped()89 bool stopped() { return fStopped; }
90 };
91
92
93
94 /******************************************************************************
95 *******************************************************************************
96
97 FAUST DSP
98
99 *******************************************************************************
100 *******************************************************************************/
101
102
103
104 //----------------------------------------------------------------
105 // définition du processeur de signal
106 //----------------------------------------------------------------
107
108 class dsp {
109 protected:
110 int fSamplingFreq;
111 public:
dsp()112 dsp() {}
113 virtual int getNumInputs() = 0;
114 virtual int getNumOutputs() = 0;
115 virtual void buildUserInterface(UI* interface) = 0;
116 virtual void init(int samplingRate) = 0;
117 virtual void compute(int len, float** inputs, float** outputs) = 0;
118 };
119
120
121 <<includeclass>>
122
123
124 mydsp DSP;
125
126
127
128 /******************************************************************************
129 *******************************************************************************
130
131 JACK AUDIO INTERFACE
132
133 *******************************************************************************
134 *******************************************************************************/
135
136
137
138 //----------------------------------------------------------------------------
139 // number of input and output channels
140 //----------------------------------------------------------------------------
141
142 int gNumInChans;
143 int gNumOutChans;
144
145
146 //----------------------------------------------------------------------------
147 // Jack ports
148 //----------------------------------------------------------------------------
149
150 jack_port_t *input_ports[256];
151 jack_port_t *output_ports[256];
152
153 //----------------------------------------------------------------------------
154 // tables of noninterleaved input and output channels for FAUST
155 //----------------------------------------------------------------------------
156
157 float* gInChannel[256];
158 float* gOutChannel[256];
159
160
161 //----------------------------------------------------------------------------
162 // Jack Callbacks
163 //----------------------------------------------------------------------------
164
srate(jack_nframes_t nframes,void * arg)165 int srate(jack_nframes_t nframes, void *arg)
166 {
167 printf("the sample rate is now %lu/sec\n", nframes);
168 return 0;
169 }
170
jack_shutdown(void * arg)171 void jack_shutdown(void *arg)
172 {
173 exit(1);
174 }
175
process(jack_nframes_t nframes,void * arg)176 int process (jack_nframes_t nframes, void *arg)
177 {
178 // ATTENTION: en vectoriel il faut s'assurer que gInChannel et gOutChannel soit align�s sur une fronti�re de 128 bits
179
180 for (int i = 0; i < gNumInChans; i++) {
181 gInChannel[i] = (float *)jack_port_get_buffer(input_ports[i], nframes);
182 }
183 for (int i = 0; i < gNumOutChans; i++) {
184 gOutChannel[i] = (float *)jack_port_get_buffer(output_ports[i], nframes);
185 }
186 DSP.compute(nframes, gInChannel, gOutChannel);
187 return 0;
188 }
189
190
191 /******************************************************************************
192 *******************************************************************************
193
194 WXWINDOWS USER INTERFACE
195
196 *******************************************************************************
197 *******************************************************************************/
198
199
200 // les modes d'insertion
201
202 #define kNormalState 0
203 #define kNotebookState 1
204 #define kAutoPageState 2
205
206 #define kProp 0
207 #define kBorder 5
208 #define kFlag wxALL|wxGROW
209
210
211 // faustButton : a wxButton for FAUST.
212 class faustButton : public wxButton
213 {
214 float* fZone;
215 public :
faustButton(wxWindow * parent,const wxString & label,float * zone)216 faustButton(wxWindow* parent, const wxString& label, float* zone)
217 : wxButton(parent, -1, label, wxPoint(-1, -1)), fZone(zone)
218 {
219 *fZone = 0.0;
220 }
221
222 #ifdef MACOSX
clickdown(wxCommandEvent & ev)223 void clickdown (wxCommandEvent& ev) { *fZone = 1.0; /*printf("click down : zone (at %p) = %f\n", fZone, *fZone); ev.Skip();*/}
clickup(wxCommandEvent & ev)224 void clickup (wxCommandEvent& ev) { *fZone = 0.0; /*printf("click up : zone (at %p) = %f\n", fZone, *fZone);ev.Skip();*/ }
225 #else
clickdown(wxCommandEvent & ev)226 void clickdown (wxCommandEvent& ev) { *fZone = 1.0; /*printf("click down : zone (at %p) = %f\n", fZone, *fZone);*/ ev.Skip();}
clickup(wxCommandEvent & ev)227 void clickup (wxCommandEvent& ev) { *fZone = 0.0; /*printf("click up : zone (at %p) = %f\n", fZone, *fZone);*/ ev.Skip(); }
228 #endif
229 private:
230 DECLARE_EVENT_TABLE()
231 };
232
233 BEGIN_EVENT_TABLE(faustButton, wxButton)
234 EVT_LEFT_DOWN(faustButton::clickdown)
235 EVT_LEFT_UP(faustButton::clickup)
236 END_EVENT_TABLE()
237
238
239 class faustCheckBox : public wxCheckBox
240 {
241 float* fZone;
242 public :
faustCheckBox(wxWindow * parent,const wxString & label,float * zone)243 faustCheckBox(wxWindow* parent, const wxString& label, float* zone)
244 : wxCheckBox(parent, -1, label, wxPoint(-1, -1)), fZone(zone)
245 {
246 *fZone = 0.0;
247 }
248
toggle(wxCommandEvent & ev)249 void toggle (wxCommandEvent& ev) {
250 *fZone = (ev.IsChecked()) ? 1.0 : 0.0;
251 //printf("toogle : zone (at %p) = %f\n", fZone, *fZone);
252 }
253
254 private:
255 DECLARE_EVENT_TABLE()
256 };
257
258 BEGIN_EVENT_TABLE(faustCheckBox, wxCheckBox)
259 EVT_CHECKBOX(-1, faustCheckBox::toggle)
260 END_EVENT_TABLE()
261
262
263 class faustHorizontalSlider : public wxSlider
264 {
265 float fStep;
266 float* fZone;
267 public :
faustHorizontalSlider(wxWindow * parent,float * zone,float init,float min,float max,float step)268 faustHorizontalSlider(wxWindow* parent, float* zone, float init , float min, float max, float step)
269 : wxSlider(parent, -1, int(init/step), int(min/step), int(max/step), wxDefaultPosition, wxSize(120,30), wxSL_HORIZONTAL), fStep(step), fZone(zone)
270 {
271 *fZone = init;
272 }
273
update(wxCommandEvent & ev)274 void update (wxCommandEvent& ev) {
275 *fZone = GetValue()*fStep;
276 //printf("horizontal slider update : zone (at %p) = %f\n", fZone, *fZone);
277 }
278
279 private:
280 DECLARE_EVENT_TABLE()
281 };
282
283 BEGIN_EVENT_TABLE(faustHorizontalSlider, wxSlider)
284 EVT_SLIDER (-1, faustHorizontalSlider::update)
285 END_EVENT_TABLE()
286
287
288 class faustVerticalSlider : public wxSlider
289 {
290 float fStep;
291 float* fZone;
292 public :
faustVerticalSlider(wxWindow * parent,float * zone,float init,float min,float max,float step)293 faustVerticalSlider(wxWindow* parent, float* zone, float init , float min, float max, float step)
294 : wxSlider(parent, -1, int((max+min-init)/step), int(min/step), int(max/step), wxDefaultPosition, wxSize(30,120), wxSL_VERTICAL), fStep(step), fZone(zone)
295 {
296 *fZone = init;
297 }
298
update(wxCommandEvent & ev)299 void update (wxCommandEvent& ev) {
300 *fZone = (GetMin()+GetMax()-GetValue())*fStep;
301 //printf("vertical slider update : zone (at %p) = %f\n", fZone, *fZone);
302 }
303
304 private:
305 DECLARE_EVENT_TABLE()
306 };
307
308 BEGIN_EVENT_TABLE(faustVerticalSlider, wxSlider)
309 EVT_SLIDER (-1, faustVerticalSlider::update)
310 END_EVENT_TABLE()
311
312
313 //--------------------------------
314 // faustSpinCtrl* b = new faustSpinCtrl(topPanel(), zone, init, min, max, step);
315 // wxSpinCtrl* b = new wxSpinCtrl( topPanel(), -1, "", wxPoint(200, 160), wxSize(80, -1) );
316 // b->SetRange(int(min),int(max));
317 // b->SetValue(int(init));
318
319
320 class faustSpinCtrl : public wxSpinCtrl
321 {
322 float fStep;
323 float* fZone;
324 public :
faustSpinCtrl(wxWindow * parent,float * zone,float init,float min,float max,float step)325 faustSpinCtrl(wxWindow* parent, float* zone, float init , float min, float max, float step)
326 : wxSpinCtrl(parent), fStep(step), fZone(zone)
327 {
328 SetRange(int(min),int(max));
329 SetValue(int(init));
330 *fZone = init;
331 }
332
update(wxCommandEvent & ev)333 void update (wxCommandEvent& ev) { *fZone = GetValue(); printf("spin ctrl update : zone (at %p) = %f\n", fZone, *fZone); }
334
335 private:
336 DECLARE_EVENT_TABLE()
337 };
338
339 BEGIN_EVENT_TABLE(faustSpinCtrl, wxSpinCtrl)
340 EVT_SPINCTRL (-1, faustSpinCtrl::update)
341 END_EVENT_TABLE()
342
343
344
345 class WXUI : public UI // user interface
346 {
347
348 class State
349 {
350 int const fType;
351 wxWindow* const fPanel;
352 wxSizer* const fSizer;
353
354 public:
State(int t,wxWindow * p,wxSizer * z)355 State (int t, wxWindow* p, wxSizer* z) : fType(t), fPanel(p), fSizer(z) {}
type() const356 int type() const { return fType; }
panel() const357 wxWindow* panel() const { return fPanel; }
sizer() const358 wxSizer* sizer() const { return fSizer; }
359 };
360
361 stack<State> lState;
362 wxFrame* frame;
363 wxSizer* fSizer;
364
365 // gestion de l'etat courant du constructeur
366
push(int t,wxWindow * p,wxSizer * z)367 void push (int t, wxWindow* p, wxSizer* z)
368 {
369 printf("push %d of %d, %p, %p\n", lState.size(), t, p, z);
370 lState.push(State(t,p,z));
371 }
372
topType()373 int topType() { return lState.top().type(); }
topPanel()374 wxWindow* topPanel() { return lState.top().panel(); }
topSizer()375 wxSizer* topSizer() { return lState.top().sizer(); }
376
pop()377 void pop ()
378 {
379 printf("pop %d", lState.size()-1);
380 lState.pop();
381 printf(" ok\n");
382 }
383
openAutoPage(char * label)384 void openAutoPage(char* label)
385 {
386 if (topType() == kNotebookState) {
387
388 if (!label) label = "";
389
390 wxNotebook* nb = (wxNotebook*) topPanel();
391 wxPanel* p = new wxPanel( nb, -1 );
392 wxBoxSizer* z = new wxBoxSizer( wxVERTICAL );
393
394 nb->AddPage(p, label);
395 p->SetAutoLayout(TRUE);
396 p->SetSizer(z);
397
398 push(kAutoPageState, p, z);
399 }
400 }
401
closeAutoPage()402 void closeAutoPage()
403 {
404 if (topType() == kAutoPageState) pop();
405 }
406
openOrientedBox(char * label,int orientation)407 void openOrientedBox(char* label, int orientation)
408 {
409 openAutoPage(label);
410
411 wxSizer* z = (label == 0) ? new wxBoxSizer(orientation)
412 : new wxStaticBoxSizer(new wxStaticBox(topPanel(), -1, label), orientation);
413
414 topSizer()->Add(z, 1, kFlag, kBorder);
415 push(kNormalState, topPanel(), z);
416 }
417
418 public:
419
420
WXUI()421 WXUI(){}
422
~WXUI()423 virtual ~WXUI() {}
424
openFrame(wxFrame * f)425 void openFrame(wxFrame* f)
426 {
427 frame = f;
428 fSizer = new wxBoxSizer(wxVERTICAL);
429 frame->SetSizer(fSizer);
430 push(kNormalState, frame, fSizer);
431 }
432
closeFrame()433 wxFrame* closeFrame()
434 {
435 fSizer->Fit(frame);
436 fSizer->SetSizeHints(frame);
437 return frame;
438 }
439
openHorizontalBox(char * label)440 virtual void openHorizontalBox(char* label) { openOrientedBox(label, wxHORIZONTAL); }
openVerticalBox(char * label)441 virtual void openVerticalBox(char* label) { openOrientedBox(label, wxVERTICAL); }
442
openTabBox(char * label)443 virtual void openTabBox(char* label)
444 {
445 openAutoPage(label);
446
447 wxNotebook* nb = new wxNotebook( topPanel(), -1 );
448 wxNotebookSizer* z = new wxNotebookSizer( nb );
449
450 topSizer()->Add(z, 1, kFlag, kBorder);
451 push(kNotebookState, nb, z);
452 }
453
closeBox()454 virtual void closeBox()
455 {
456 pop();
457 closeAutoPage();
458 }
459
460 //--------------------------------- les elements ------------------------------------------
461
addButton(char * label,float * zone)462 virtual void addButton(char* label, float* zone)
463 {
464 openAutoPage(label);
465 faustButton* b = new faustButton(topPanel(), label, zone);
466 topSizer()->Add(b, kProp, kFlag, kBorder);
467 closeAutoPage();
468 }
469
addCheckButton(char * label,float * zone)470 virtual void addCheckButton(char* label, float* zone)
471 {
472 openAutoPage(label);
473 faustCheckBox* b = new faustCheckBox(topPanel(), label, zone);
474 topSizer()->Add(b, kProp, kFlag, kBorder);
475 closeAutoPage();
476 }
477
addVerticalSlider(char * label,float * zone,float init,float min,float max,float step)478 virtual void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step)
479 {
480 openAutoPage(label);
481 if (label) {
482 wxSizer* z = new wxStaticBoxSizer(new wxStaticBox(topPanel(), -1, label), wxHORIZONTAL);
483 topSizer()->Add(z, 1, kFlag, kBorder);
484 faustVerticalSlider* b = new faustVerticalSlider(topPanel(), zone, init, min, max, step);
485 b->SetToolTip(label);
486 z->Add(b, 1, kFlag|wxALIGN_CENTER_VERTICAL, kBorder);
487 } else {
488 faustVerticalSlider* b = new faustVerticalSlider(topPanel(), zone, init, min, max, step);
489 topSizer()->Add(b, kProp, kFlag, kBorder);
490 }
491 closeAutoPage();
492 }
493
addHorizontalSlider(char * label,float * zone,float init,float min,float max,float step)494 virtual void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step)
495 {
496 openAutoPage(label);
497 if (label) {
498 wxSizer* z = new wxStaticBoxSizer(new wxStaticBox(topPanel(), -1, label), wxVERTICAL);
499 topSizer()->Add(z, 1, kFlag, kBorder);
500 faustHorizontalSlider* b = new faustHorizontalSlider(topPanel(), zone, init, min, max, step);
501 b->SetToolTip(label);
502 z->Add(b, 1, kFlag|wxALIGN_CENTER_HORIZONTAL, kBorder);
503 } else {
504 faustHorizontalSlider* b = new faustHorizontalSlider(topPanel(), zone, init, min, max, step);
505 topSizer()->Add(b, kProp, kFlag, kBorder);
506 }
507 closeAutoPage();
508 }
509
addToggleButton(char * label,float * zone)510 virtual void addToggleButton(char* label, float* zone) {}
addNumEntry(char * label,float * zone,float init,float min,float max,float step)511 virtual void addNumEntry(char* label, float* zone, float init, float min, float max, float step)
512 {
513 openAutoPage(label);
514 if (label) {
515 wxSizer* z = new wxStaticBoxSizer(new wxStaticBox(topPanel(), -1, label), wxVERTICAL);
516 topSizer()->Add(z, 0, kFlag, kBorder);
517 faustSpinCtrl* b = new faustSpinCtrl(topPanel(), zone, init, min, max, step);
518 // wxSpinCtrl* b = new wxSpinCtrl( topPanel(), -1, "", wxPoint(200, 160), wxSize(80, -1) );
519 // b->SetRange(int(min),int(max));
520 // b->SetValue(int(init));
521 b->SetToolTip(label);
522 z->Add(b, 0, kFlag, kBorder);
523 } else {
524 faustSpinCtrl* b = new faustSpinCtrl(topPanel(), zone, init, min, max, step);
525 // wxSpinCtrl* b = new wxSpinCtrl( topPanel(), -1, "", wxPoint(200, 160), wxSize(80, -1) );
526 // b->SetRange(int(min),int(max));
527 // b->SetValue(int(init));
528 topSizer()->Add(b, kProp, kFlag, kBorder);
529 }
530 closeAutoPage();
531 }
openFrameBox(char * label)532 virtual void openFrameBox(char* label) {}
533 };
534
535
536
537 /******************************************************************************
538 *******************************************************************************
539
540 WXWINDOWS TOP FRAME
541
542 *******************************************************************************
543 *******************************************************************************/
544
545
546 enum { ID_QUIT=1, ID_ABOUT };
547
548
549 class MyFrame : public wxFrame
550 {
551 public:
MyFrame(const wxString & title,const wxPoint & pos,const wxSize & size)552 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
553 : wxFrame(0, -1, title, pos, size)
554 {
555 wxMenu* m = new wxMenu;
556 m->Append(ID_ABOUT, "&About...");
557 m->AppendSeparator();
558 m->Append(ID_QUIT, "E&xit");
559
560 wxMenuBar* b = new wxMenuBar;
561 b->Append(m, "&File");
562 SetMenuBar(b);
563 CreateStatusBar();
564 SetStatusText("hello...");
565 }
566
OnQuit(wxCommandEvent & event)567 void OnQuit(wxCommandEvent& event)
568 {
569 Close(TRUE);
570 }
571
OnAbout(wxCommandEvent & event)572 void OnAbout(wxCommandEvent& event)
573 {
574 wxMessageBox("message 1", "message 2", wxOK|wxICON_INFORMATION);
575 }
576
577 private:
578 DECLARE_EVENT_TABLE()
579 };
580
581
582 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
583 EVT_MENU(ID_QUIT, MyFrame::OnQuit)
584 EVT_MENU(ID_ABOUT, MyFrame::OnAbout)
585 END_EVENT_TABLE()
586
587
588
589 /******************************************************************************
590 *******************************************************************************
591
592 WXWINDOWS MAIN APPLICATION
593
594 *******************************************************************************
595 *******************************************************************************/
596
597 // Scan Command Line Arguments
598
599 class MyApp : public wxApp
600 {
601 jack_client_t* client;
602 char jackname[256];
603 char** physicalInPorts;
604 char** physicalOutPorts;
605
OnInit()606 virtual bool OnInit()
607 {
608 MyFrame* frame = new MyFrame(argv[0], wxPoint(50,50), wxSize(-1, -1));
609 /*
610 wxMenu* m = new wxMenu;
611 m->Append(ID_ABOUT, "&About...");
612 m->AppendSeparator();
613 m->Append(ID_QUIT, "E&xit");
614
615 wxMenuBar* b = new wxMenuBar;
616 b->Append(m, "&File");
617
618 frame->SetMenuBar(b);
619 frame->CreateStatusBar();
620 frame->SetStatusText("Faust dsp...");
621 */
622 WXUI* ui = new WXUI();
623 ui->openFrame(frame);
624 DSP.buildUserInterface((UI*)ui);
625 ui->closeFrame();
626
627 frame->Show(TRUE);
628 SetTopWindow(frame);
629
630 snprintf(jackname, 256, "faust_%s", basename(argv[0]));
631
632 if ((client = jack_client_open(jackname, JackNullOption, NULL)) == 0) {
633 fprintf(stderr, "jack server not running?\n");
634 return 1;
635 }
636
637 jack_set_process_callback(client, process, 0);
638 jack_set_sample_rate_callback(client, srate, 0);
639 jack_on_shutdown(client, jack_shutdown, 0);
640
641 gNumInChans = DSP.getNumInputs();
642 gNumOutChans = DSP.getNumOutputs();
643
644 for (int i = 0; i < gNumInChans; i++) {
645 char buf[256];
646 snprintf(buf, 256, "in_%d", i);
647 input_ports[i] = jack_port_register(client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
648 }
649 for (int i = 0; i < gNumOutChans; i++) {
650 char buf[256];
651 snprintf(buf, 256, "out_%d", i);
652 output_ports[i] = jack_port_register(client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
653 }
654
655 DSP.init(jack_get_sample_rate(client));
656
657 physicalInPorts = (char **)jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
658 physicalOutPorts = (char **)jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput);
659
660 if (jack_activate(client)) {
661 fprintf(stderr, "cannot activate client");
662 return 1;
663 }
664
665 if (physicalOutPorts != NULL) {
666 for (int i = 0; i < gNumInChans && physicalOutPorts[i]; i++) {
667 jack_connect(client, physicalOutPorts[i], jack_port_name(input_ports[i]));
668 }
669 free(physicalOutPorts);
670 }
671
672 if (physicalInPorts != NULL) {
673 for (int i = 0; i < gNumOutChans && physicalInPorts[i]; i++) {
674 jack_connect(client, jack_port_name(output_ports[i]), physicalInPorts[i]);
675 }
676 free(physicalInPorts);
677 }
678
679 return TRUE;
680 }
681
OnExit()682 virtual int OnExit()
683 {
684 jack_deactivate(client);
685
686 for (int i = 0; i < gNumInChans; i++) {
687 jack_port_unregister(client, input_ports[i]);
688 }
689 for (int i = 0; i < gNumOutChans; i++) {
690 jack_port_unregister(client, output_ports[i]);
691 }
692
693 jack_client_close(client);
694 return 0;
695 }
696 };
697
698
699 IMPLEMENT_APP(MyApp)
700
701