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