Bug fixed in the Makefile.
[Faustine.git] / interpretor / faust-0.9.47mr3 / benchmark / alsa-gtk-bench.cpp
1 /* link with : "" */
2 #include <stdlib.h>
3 #include <libgen.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <limits.h>
7 #include <math.h>
8 #include <errno.h>
9 #include <time.h>
10 #include <sys/ioctl.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <alsa/asoundlib.h>
14 #include <pwd.h>
15 #include <sys/types.h>
16 #include <sys/time.h>
17 #include <assert.h>
18 #include <gtk/gtk.h>
19 #include <pthread.h>
20 #include <sys/wait.h>
21 #include <list>
22
23 #include <iostream>
24 #include <fstream>
25 #include <vector>
26 #include <algorithm>
27
28
29 using namespace std;
30
31 // handle 32/64 bits int size issues
32
33 #ifdef __x86_64__
34
35 #define uint32 unsigned int
36 #define uint64 unsigned long int
37
38 #define int32 int
39 #define int64 long int
40
41 #else
42
43 #define uint32 unsigned int
44 #define uint64 unsigned long long int
45
46 #define int32 int
47 #define int64 long long int
48 #endif
49
50 // check 32/64 bits issues are correctly handled
51
52 #define CHECKINTSIZE \
53 assert(sizeof(int32)==4);\
54 assert(sizeof(int64)==8);
55
56
57
58
59 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
60 // flags to avoid costly denormals
61 #ifdef __SSE__
62 #include <xmmintrin.h>
63 #ifdef __SSE2__
64 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
65 #else
66 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
67 #endif
68 #else
69 #define AVOIDDENORMALS
70 #endif
71
72 //#define BENCHMARKMODE
73
74 // g++ -Wall -O3 -lm -lpthread -lasound `gtk-config --cflags --libs` test.cpp -o test
75
76 #define check_error(err) if (err) { printf("%s:%d, alsa error %d : %s\n", __FILE__, __LINE__, err, snd_strerror(err)); exit(1); }
77 #define check_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); exit(1); }
78 #define display_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); }
79
80 #define max(x,y) (((x)>(y)) ? (x) : (y))
81 #define min(x,y) (((x)<(y)) ? (x) : (y))
82
83 // abs is now predefined
84 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
85
86
87 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
88
89
90 inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
91
92
93 /**
94 * Used to set the priority and scheduling of the audio thread
95 */
96 bool setRealtimePriority ()
97 {
98 struct passwd * pw;
99 int err;
100 uid_t uid;
101 struct sched_param param;
102
103 uid = getuid ();
104 pw = getpwnam ("root");
105 setuid (pw->pw_uid);
106 param.sched_priority = 99; /* 0 to 99 */
107 err = sched_setscheduler(0, SCHED_FIFO, &param);
108 setuid (uid);
109 return (err != -1);
110 }
111
112
113 /******************************************************************************
114 *******************************************************************************
115
116 VECTOR INTRINSICS
117
118 *******************************************************************************
119 *******************************************************************************/
120
121 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
122 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
123
124
125 <<includeIntrinsic>>
126
127 #define BENCHMARKMODE
128
129 #ifdef BENCHMARKMODE
130
131 /**
132 * Returns the number of clock cycles elapsed since the last reset
133 * of the processor
134 */
135 static __inline__ uint64 rdtsc(void)
136 {
137 union {
138 uint32 i32[2];
139 uint64 i64;
140 } count;
141
142 __asm__ __volatile__("rdtsc" : "=a" (count.i32[0]), "=d" (count.i32[1]));
143
144 return count.i64;
145 }
146
147 #define KSKIP 20
148 #define KMESURE 600
149
150 int mesure = 0;
151
152 // these values are used to determine the number of clocks in a second
153 uint64 firstRDTSC;
154 uint64 lastRDTSC;
155
156 // these tables contains the last KMESURE in clocks
157 uint64 starts[KMESURE];
158 uint64 stops [KMESURE];
159
160 #define STARTMESURE starts[mesure%KMESURE] = rdtsc();
161 #define STOPMESURE stops[mesure%KMESURE] = rdtsc(); mesure = mesure+1;
162
163 struct timeval tv1;
164 struct timeval tv2;
165
166 void openMesure()
167 {
168 struct timezone tz;
169 gettimeofday(&tv1, &tz);
170 firstRDTSC = rdtsc();
171 }
172
173 void closeMesure()
174 {
175 struct timezone tz;
176 gettimeofday(&tv2, &tz);
177 lastRDTSC = rdtsc();
178 }
179
180 /**
181 * return the number of RDTSC clocks per seconds
182 */
183 int64 rdtscpersec()
184 {
185 // If the environment variable CLOCKSPERSEC is defined
186 // we use it instead of our own measurement
187 char* str = getenv("CLOCKSPERSEC");
188 if (str) {
189 int64 cps = (int64) atoll(str);
190 if (cps > 1000000000) {
191 return cps;
192 } else {
193 return (lastRDTSC-firstRDTSC) / (tv2.tv_sec - tv1.tv_sec) ;
194 }
195 } else {
196 return (lastRDTSC-firstRDTSC) / (tv2.tv_sec - tv1.tv_sec) ;
197 }
198 }
199
200
201 /**
202 * Converts a duration, expressed in RDTSC clocks, into seconds
203 */
204 double rdtsc2sec( uint64 clk)
205 {
206 return double(clk) / double(rdtscpersec());
207 }
208
209 double rdtsc2sec( double clk)
210 {
211 return clk / double(rdtscpersec());
212 }
213
214
215 /**
216 * Converts RDTSC clocks into Megabytes/seconds according to the
217 * number of frames processed during the period, the number of channels
218 * and 4 bytes samples.
219 */
220 double megapersec(int frames, int chans, uint64 clk)
221 {
222 return double(frames*chans*4)/double(1024*1024*rdtsc2sec(clk));
223 }
224
225
226 /**
227 * Compute the mean value of a vector of measures
228 */
229 static uint64 meanValue( vector<uint64>::const_iterator a, vector<uint64>::const_iterator b)
230 {
231 uint64 r = 0;
232 unsigned int n = 0;
233 while (a!=b) { r += *a++; n++; }
234 return (n>0) ? r/n : 0;
235 }
236
237 /**
238 * Print the median value (in Megabytes/second) of KMESURE
239 * throughputs measurements
240 */
241 void printstats(const char* applname, int bsize, int ichans, int ochans)
242 {
243 assert(mesure > KMESURE);
244 vector<uint64> V(KMESURE);
245
246 for (int i = 0; i<KMESURE; i++) {
247 V[i] = stops[i] - starts[i];
248 }
249
250 sort(V.begin(), V.end());
251
252 // Mean of 10 best values (gives relatively stable results)
253 uint64 meaval00 = meanValue(V.begin(), V.begin()+ 5);
254 uint64 meaval25 = meanValue(V.begin()+KMESURE/4 - 2, V.begin()+KMESURE/4 + 3);
255 uint64 meaval50 = meanValue(V.begin()+KMESURE/2 - 2, V.begin()+KMESURE/2 + 3);
256 uint64 meaval75 = meanValue(V.begin()+3*KMESURE/4 - 2, V.begin()+3*KMESURE/4 + 3);
257 uint64 meaval100 = meanValue(V.end() - 5, V.end());
258
259 //printing
260 cout << applname
261 << '\t' << megapersec(bsize, ichans+ochans, meaval00)
262 << '\t' << megapersec(bsize, ichans+ochans, meaval25)
263 << '\t' << megapersec(bsize, ichans+ochans, meaval50)
264 << '\t' << megapersec(bsize, ichans+ochans, meaval75)
265 << '\t' << megapersec(bsize, ichans+ochans, meaval100)
266 << endl;
267
268 }
269
270 #else
271
272 #define STARTMESURE
273 #define STOPMESURE
274
275 #endif
276
277 /******************************************************************************
278 *******************************************************************************
279
280 AUDIO INTERFACE
281
282 *******************************************************************************
283 *******************************************************************************/
284
285 enum { kRead = 1, kWrite = 2, kReadWrite = 3 };
286
287
288 /**
289 * A convenient class to pass parameters to AudioInterface
290 */
291 class AudioParam
292 {
293 public:
294
295 const char* fCardName;
296 unsigned int fFrequency;
297 unsigned int fBuffering;
298 unsigned int fPeriods;
299
300 unsigned int fSoftInputs;
301 unsigned int fSoftOutputs;
302
303 public :
304 AudioParam() :
305 fCardName("hw:0"),
306 fFrequency(44100),
307 fBuffering(512),
308 fPeriods(2),
309 fSoftInputs(2),
310 fSoftOutputs(2)
311 {}
312
313 AudioParam& cardName(const char* n) { fCardName = n; return *this; }
314 AudioParam& frequency(int f) { fFrequency = f; return *this; }
315 AudioParam& buffering(int fpb) { fBuffering = fpb; return *this; }
316 AudioParam& periods(int p) { fPeriods = p; return *this; }
317 AudioParam& inputs(int n) { fSoftInputs = n; return *this; }
318 AudioParam& outputs(int n) { fSoftOutputs = n; return *this; }
319 };
320
321
322
323 /**
324 * An ALSA audio interface
325 */
326 class AudioInterface : public AudioParam
327 {
328 public :
329 snd_pcm_t* fOutputDevice ;
330 snd_pcm_t* fInputDevice ;
331 snd_pcm_hw_params_t* fInputParams;
332 snd_pcm_hw_params_t* fOutputParams;
333
334 snd_pcm_format_t fSampleFormat;
335 snd_pcm_access_t fSampleAccess;
336
337 unsigned int fCardInputs;
338 unsigned int fCardOutputs;
339
340 unsigned int fChanInputs;
341 unsigned int fChanOutputs;
342
343 // interleaved mode audiocard buffers
344 void* fInputCardBuffer;
345 void* fOutputCardBuffer;
346
347 // non interleaved mode audiocard buffers
348 void* fInputCardChannels[256];
349 void* fOutputCardChannels[256];
350
351 // non interleaved mod, floating point software buffers
352 float* fInputSoftChannels[256];
353 float* fOutputSoftChannels[256];
354
355 public :
356
357 const char* cardName() { return fCardName; }
358 int frequency() { return fFrequency; }
359 int buffering() { return fBuffering; }
360 int periods() { return fPeriods; }
361
362 float** inputSoftChannels() { return fInputSoftChannels; }
363 float** outputSoftChannels() { return fOutputSoftChannels; }
364
365
366 AudioInterface(const AudioParam& ap = AudioParam()) : AudioParam(ap)
367 {
368
369 fInputDevice = 0;
370 fOutputDevice = 0;
371 fInputParams = 0;
372 fOutputParams = 0;
373 }
374
375
376 /**
377 * Open the audio interface
378 */
379 void open()
380 {
381 int err;
382
383 // allocation d'un stream d'entree et d'un stream de sortie
384 err = snd_pcm_open( &fInputDevice, fCardName, SND_PCM_STREAM_CAPTURE, 0 ); check_error(err)
385 err = snd_pcm_open( &fOutputDevice, fCardName, SND_PCM_STREAM_PLAYBACK, 0 ); check_error(err)
386
387 // recherche des parametres d'entree
388 err = snd_pcm_hw_params_malloc ( &fInputParams ); check_error(err);
389 setAudioParams(fInputDevice, fInputParams);
390
391 // recherche des parametres de sortie
392 err = snd_pcm_hw_params_malloc ( &fOutputParams ); check_error(err)
393 setAudioParams(fOutputDevice, fOutputParams);
394
395 // set the number of physical input and output channels close to what we need
396 fCardInputs = fSoftInputs;
397 fCardOutputs = fSoftOutputs;
398
399 snd_pcm_hw_params_set_channels_near(fInputDevice, fInputParams, &fCardInputs);
400 snd_pcm_hw_params_set_channels_near(fOutputDevice, fOutputParams, &fCardOutputs);
401
402 printf("inputs : %u, outputs : %u\n", fCardInputs, fCardOutputs);
403
404 // enregistrement des parametres d'entree-sortie
405
406 err = snd_pcm_hw_params (fInputDevice, fInputParams ); check_error (err);
407 err = snd_pcm_hw_params (fOutputDevice, fOutputParams ); check_error (err);
408
409 //assert(snd_pcm_hw_params_get_period_size(fInputParams,NULL) == snd_pcm_hw_params_get_period_size(fOutputParams,NULL));
410
411 // allocation of alsa buffers
412 if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
413 fInputCardBuffer = calloc(interleavedBufferSize(fInputParams), 1);
414 fOutputCardBuffer = calloc(interleavedBufferSize(fOutputParams), 1);
415
416 } else {
417 for (unsigned int i = 0; i < fCardInputs; i++) {
418 fInputCardChannels[i] = calloc(noninterleavedBufferSize(fInputParams), 1);
419 }
420 for (unsigned int i = 0; i < fCardOutputs; i++) {
421 fOutputCardChannels[i] = calloc(noninterleavedBufferSize(fOutputParams), 1);
422 }
423
424 }
425
426 // allocation of floating point buffers needed by the dsp code
427
428 fChanInputs = max(fSoftInputs, fCardInputs); assert (fChanInputs < 256);
429 fChanOutputs = max(fSoftOutputs, fCardOutputs); assert (fChanOutputs < 256);
430
431 for (unsigned int i = 0; i < fChanInputs; i++) {
432 fInputSoftChannels[i] = (float*) calloc (fBuffering, sizeof(float));
433 for (int j = 0; j < fBuffering; j++) {
434 fInputSoftChannels[i][j] = 0.0;
435 }
436 }
437
438 for (unsigned int i = 0; i < fChanOutputs; i++) {
439 fOutputSoftChannels[i] = (float*) calloc (fBuffering, sizeof(float));
440 for (int j = 0; j < fBuffering; j++) {
441 fOutputSoftChannels[i][j] = 0.0;
442 }
443 }
444
445
446 }
447
448
449 void setAudioParams(snd_pcm_t* stream, snd_pcm_hw_params_t* params)
450 {
451 int err;
452
453 // set params record with initial values
454 err = snd_pcm_hw_params_any ( stream, params );
455 check_error_msg(err, "unable to init parameters")
456
457 // set alsa access mode (and fSampleAccess field) either to non interleaved or interleaved
458
459 err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
460 if (err) {
461 err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_INTERLEAVED );
462 check_error_msg(err, "unable to set access mode neither to non-interleaved or to interleaved");
463 }
464 snd_pcm_hw_params_get_access(params, &fSampleAccess);
465
466
467 // search for 32-bits or 16-bits format
468 err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S32);
469 if (err) {
470 err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S16);
471 check_error_msg(err, "unable to set format to either 32-bits or 16-bits");
472 }
473 snd_pcm_hw_params_get_format(params, &fSampleFormat);
474 // set sample frequency
475 snd_pcm_hw_params_set_rate_near (stream, params, &fFrequency, 0);
476
477 // set period and period size (buffering)
478 err = snd_pcm_hw_params_set_period_size (stream, params, fBuffering, 0);
479 check_error_msg(err, "period size not available");
480
481 err = snd_pcm_hw_params_set_periods (stream, params, fPeriods, 0);
482 check_error_msg(err, "number of periods not available");
483
484 }
485
486
487 ssize_t interleavedBufferSize (snd_pcm_hw_params_t* params)
488 {
489 _snd_pcm_format format; snd_pcm_hw_params_get_format(params, &format);
490 snd_pcm_uframes_t psize; snd_pcm_hw_params_get_period_size(params, &psize, NULL);
491 unsigned int channels; snd_pcm_hw_params_get_channels(params, &channels);
492 ssize_t bsize = snd_pcm_format_size (format, psize * channels);
493 return bsize;
494 }
495
496
497 ssize_t noninterleavedBufferSize (snd_pcm_hw_params_t* params)
498 {
499 _snd_pcm_format format; snd_pcm_hw_params_get_format(params, &format);
500 snd_pcm_uframes_t psize; snd_pcm_hw_params_get_period_size(params, &psize, NULL);
501 ssize_t bsize = snd_pcm_format_size (format, psize);
502 return bsize;
503 }
504
505
506 void close()
507 {
508 }
509
510
511
512 /**
513 * Read audio samples from the audio card. Convert samples to floats and take
514 * care of interleaved buffers
515 */
516 void read()
517 {
518
519 if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
520
521 int count = snd_pcm_readi(fInputDevice, fInputCardBuffer, fBuffering);
522 if (count<0) {
523 display_error_msg(count, "reading samples");
524 int err = snd_pcm_prepare(fInputDevice);
525 check_error_msg(err, "preparing input stream");
526 }
527
528 if (fSampleFormat == SND_PCM_FORMAT_S16) {
529
530 short* buffer16b = (short*) fInputCardBuffer;
531 for (int s = 0; s < fBuffering; s++) {
532 for (unsigned int c = 0; c < fCardInputs; c++) {
533 fInputSoftChannels[c][s] = float(buffer16b[c + s*fCardInputs])*(1.0/float(SHRT_MAX));
534 }
535 }
536
537 } else if (fSampleFormat == SND_PCM_FORMAT_S32) {
538
539 int* buffer32b = (int*) fInputCardBuffer;
540 for (int s = 0; s < fBuffering; s++) {
541 for (unsigned int c = 0; c < fCardInputs; c++) {
542 fInputSoftChannels[c][s] = float(buffer32b[c + s*fCardInputs])*(1.0/float(INT_MAX));
543 }
544 }
545 } else {
546
547 printf("unrecognized input sample format : %u\n", fSampleFormat);
548 exit(1);
549 }
550
551 } else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
552
553 int count = snd_pcm_readn(fInputDevice, fInputCardChannels, fBuffering);
554 if (count<0) {
555 display_error_msg(count, "reading samples");
556 int err = snd_pcm_prepare(fInputDevice);
557 check_error_msg(err, "preparing input stream");
558 }
559
560 if (fSampleFormat == SND_PCM_FORMAT_S16) {
561
562 for (unsigned int c = 0; c < fCardInputs; c++) {
563 short* chan16b = (short*) fInputCardChannels[c];
564 for (int s = 0; s < fBuffering; s++) {
565 fInputSoftChannels[c][s] = float(chan16b[s])*(1.0/float(SHRT_MAX));
566 }
567 }
568
569 } else if (fSampleFormat == SND_PCM_FORMAT_S32) {
570
571 for (unsigned int c = 0; c < fCardInputs; c++) {
572 int* chan32b = (int*) fInputCardChannels[c];
573 for (int s = 0; s < fBuffering; s++) {
574 fInputSoftChannels[c][s] = float(chan32b[s])*(1.0/float(INT_MAX));
575 }
576 }
577 } else {
578
579 printf("unrecognized input sample format : %u\n", fSampleFormat);
580 exit(1);
581 }
582
583 } else {
584 check_error_msg(-10000, "unknow access mode");
585 }
586
587
588 }
589
590
591 /**
592 * write the output soft channels to the audio card. Convert sample
593 * format and interleaves buffers when needed
594 */
595 void write()
596 {
597 recovery :
598
599 if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
600
601 if (fSampleFormat == SND_PCM_FORMAT_S16) {
602
603 short* buffer16b = (short*) fOutputCardBuffer;
604 for (int f = 0; f < fBuffering; f++) {
605 for (unsigned int c = 0; c < fCardOutputs; c++) {
606 float x = fOutputSoftChannels[c][f];
607 buffer16b[c + f*fCardOutputs] = short( max(min(x,1.0),-1.0) * float(SHRT_MAX) ) ;
608 }
609 }
610
611 } else if (fSampleFormat == SND_PCM_FORMAT_S32) {
612
613 int* buffer32b = (int*) fOutputCardBuffer;
614 for (int f = 0; f < fBuffering; f++) {
615 for (unsigned int c = 0; c < fCardOutputs; c++) {
616 float x = fOutputSoftChannels[c][f];
617 buffer32b[c + f*fCardOutputs] = int( max(min(x,1.0),-1.0) * float(INT_MAX) ) ;
618 }
619 }
620 } else {
621
622 printf("unrecognized output sample format : %u\n", fSampleFormat);
623 exit(1);
624 }
625
626 int count = snd_pcm_writei(fOutputDevice, fOutputCardBuffer, fBuffering);
627 if (count<0) {
628 display_error_msg(count, "w3");
629 int err = snd_pcm_prepare(fOutputDevice);
630 check_error_msg(err, "preparing output stream");
631 goto recovery;
632 }
633
634
635 } else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
636
637 if (fSampleFormat == SND_PCM_FORMAT_S16) {
638
639 for (unsigned int c = 0; c < fCardOutputs; c++) {
640 short* chan16b = (short*) fOutputCardChannels[c];
641 for (int f = 0; f < fBuffering; f++) {
642 float x = fOutputSoftChannels[c][f];
643 chan16b[f] = short( max(min(x,1.0),-1.0) * float(SHRT_MAX) ) ;
644 }
645 }
646
647 } else if (fSampleFormat == SND_PCM_FORMAT_S32) {
648
649 for (unsigned int c = 0; c < fCardOutputs; c++) {
650 int* chan32b = (int*) fOutputCardChannels[c];
651 for (int f = 0; f < fBuffering; f++) {
652 float x = fOutputSoftChannels[c][f];
653 chan32b[f] = int( max(min(x,1.0),-1.0) * float(INT_MAX) ) ;
654 }
655 }
656
657 } else {
658
659 printf("unrecognized output sample format : %u\n", fSampleFormat);
660 exit(1);
661 }
662
663 int count = snd_pcm_writen(fOutputDevice, fOutputCardChannels, fBuffering);
664 if (count<0) {
665 display_error_msg(count, "w3");
666 int err = snd_pcm_prepare(fOutputDevice);
667 check_error_msg(err, "preparing output stream");
668 goto recovery;
669 }
670
671 } else {
672 check_error_msg(-10000, "unknow access mode");
673 }
674 }
675
676
677
678 /**
679 * print short information on the audio device
680 */
681 void shortinfo()
682 {
683 int err;
684 snd_ctl_card_info_t* card_info;
685 snd_ctl_t* ctl_handle;
686 err = snd_ctl_open (&ctl_handle, fCardName, 0); check_error(err);
687 snd_ctl_card_info_alloca (&card_info);
688 err = snd_ctl_card_info(ctl_handle, card_info); check_error(err);
689 printf("%s|%d|%d|%d|%d|%s\n",
690 snd_ctl_card_info_get_driver(card_info),
691 fCardInputs, fCardOutputs,
692 fFrequency, fBuffering,
693 snd_pcm_format_name((_snd_pcm_format)fSampleFormat));
694 }
695
696 /**
697 * print more detailled information on the audio device
698 */
699 void longinfo()
700 {
701 int err;
702 snd_ctl_card_info_t* card_info;
703 snd_ctl_t* ctl_handle;
704
705 printf("Audio Interface Description :\n");
706 printf("Sampling Frequency : %d, Sample Format : %s, buffering : %d\n",
707 fFrequency, snd_pcm_format_name((_snd_pcm_format)fSampleFormat), fBuffering);
708 printf("Software inputs : %2d, Software outputs : %2d\n", fSoftInputs, fSoftOutputs);
709 printf("Hardware inputs : %2d, Hardware outputs : %2d\n", fCardInputs, fCardOutputs);
710 printf("Channel inputs : %2d, Channel outputs : %2d\n", fChanInputs, fChanOutputs);
711
712 // affichage des infos de la carte
713 err = snd_ctl_open (&ctl_handle, fCardName, 0); check_error(err);
714 snd_ctl_card_info_alloca (&card_info);
715 err = snd_ctl_card_info(ctl_handle, card_info); check_error(err);
716 printCardInfo(card_info);
717
718 // affichage des infos liees aux streams d'entree-sortie
719 if (fSoftInputs > 0) printHWParams(fInputParams);
720 if (fSoftOutputs > 0) printHWParams(fOutputParams);
721 }
722
723 void printCardInfo(snd_ctl_card_info_t* ci)
724 {
725 printf("Card info (address : %p)\n", ci);
726 printf("\tID = %s\n", snd_ctl_card_info_get_id(ci));
727 printf("\tDriver = %s\n", snd_ctl_card_info_get_driver(ci));
728 printf("\tName = %s\n", snd_ctl_card_info_get_name(ci));
729 printf("\tLongName = %s\n", snd_ctl_card_info_get_longname(ci));
730 printf("\tMixerName = %s\n", snd_ctl_card_info_get_mixername(ci));
731 printf("\tComponents = %s\n", snd_ctl_card_info_get_components(ci));
732 printf("--------------\n");
733 }
734
735 void printHWParams( snd_pcm_hw_params_t* params )
736 {
737 printf("HW Params info (address : %p)\n", params);
738 #if 0
739 printf("\tChannels = %d\n", snd_pcm_hw_params_get_channels(params));
740 printf("\tFormat = %s\n", snd_pcm_format_name((_snd_pcm_format)snd_pcm_hw_params_get_format(params)));
741 printf("\tAccess = %s\n", snd_pcm_access_name((_snd_pcm_access)snd_pcm_hw_params_get_access(params)));
742 printf("\tRate = %d\n", snd_pcm_hw_params_get_rate(params, NULL));
743 printf("\tPeriods = %d\n", snd_pcm_hw_params_get_periods(params, NULL));
744 printf("\tPeriod size = %d\n", (int)snd_pcm_hw_params_get_period_size(params, NULL));
745 printf("\tPeriod time = %d\n", snd_pcm_hw_params_get_period_time(params, NULL));
746 printf("\tBuffer size = %d\n", (int)snd_pcm_hw_params_get_buffer_size(params));
747 printf("\tBuffer time = %d\n", snd_pcm_hw_params_get_buffer_time(params, NULL));
748 #endif
749 printf("--------------\n");
750 }
751
752
753 };
754
755
756
757
758
759 /******************************************************************************
760 *******************************************************************************
761
762 GRAPHIC USER INTERFACE (v2)
763 abstract interfaces
764
765 *******************************************************************************
766 *******************************************************************************/
767
768 #include <map>
769 #include <list>
770
771 using namespace std;
772
773 struct Meta : map<const char*, const char*>
774 {
775 void declare (const char* key, const char* value) { (*this)[key]=value; }
776 };
777
778
779 struct uiItem;
780 typedef void (*uiCallback)(float val, void* data);
781
782 /**
783 * Graphic User Interface : abstract definition
784 */
785
786 class UI
787 {
788 typedef list<uiItem*> clist;
789 typedef map<float*, clist*> zmap;
790
791 private:
792 static list<UI*> fGuiList;
793 zmap fZoneMap;
794 bool fStopped;
795
796 public:
797
798 UI() : fStopped(false) {
799 fGuiList.push_back(this);
800 }
801
802 virtual ~UI() {
803 // suppression de this dans fGuiList
804 }
805
806 // -- zone management
807
808 void registerZone(float* z, uiItem* c)
809 {
810 if (fZoneMap.find(z) == fZoneMap.end()) fZoneMap[z] = new clist();
811 fZoneMap[z]->push_back(c);
812 }
813
814 // -- saveState(filename) : save the value of every zone to a file
815
816 void saveState(const char* filename)
817 {
818 ofstream f(filename);
819
820 for (zmap::iterator i=fZoneMap.begin(); i!=fZoneMap.end(); i++) {
821 f << *(i->first) << ' ';
822 }
823
824 f << endl;
825 f.close();
826 }
827
828 // -- recallState(filename) : load the value of every zone from a file
829
830 void recallState(const char* filename)
831 {
832 ifstream f(filename);
833 if (f.good()) {
834 for (zmap::iterator i=fZoneMap.begin(); i!=fZoneMap.end(); i++) {
835 f >> *(i->first);
836 }
837 }
838 f.close();
839 }
840
841 void updateAllZones();
842
843 void updateZone(float* z);
844
845 static void updateAllGuis()
846 {
847 list<UI*>::iterator g;
848 for (g = fGuiList.begin(); g != fGuiList.end(); g++) {
849 (*g)->updateAllZones();
850 }
851 }
852
853 // -- active widgets
854
855 virtual void addButton(const char* label, float* zone) = 0;
856 virtual void addToggleButton(const char* label, float* zone) = 0;
857 virtual void addCheckButton(const char* label, float* zone) = 0;
858 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
859 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
860 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
861
862 // -- passive widgets
863
864 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
865 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
866 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
867 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
868
869 void addCallback(float* zone, uiCallback foo, void* data);
870
871 // -- widget's layouts
872
873 virtual void openFrameBox(const char* label) = 0;
874 virtual void openTabBox(const char* label) = 0;
875 virtual void openHorizontalBox(const char* label) = 0;
876 virtual void openVerticalBox(const char* label) = 0;
877 virtual void closeBox() = 0;
878
879 virtual void show() = 0;
880 virtual void run() = 0;
881
882 void stop() { fStopped = true; }
883 bool stopped() { return fStopped; }
884
885 virtual void declare(float* zone, const char* key, const char* value) {}
886 };
887
888
889 /**
890 * User Interface Item: abstract definition
891 */
892
893 class uiItem
894 {
895 protected :
896
897 UI* fGUI;
898 float* fZone;
899 float fCache;
900
901 uiItem (UI* ui, float* zone) : fGUI(ui), fZone(zone), fCache(-123456.654321)
902 {
903 ui->registerZone(zone, this);
904 }
905
906
907 public :
908
909 virtual ~uiItem() {}
910
911 void modifyZone(float v)
912 {
913 fCache = v;
914 if (*fZone != v) {
915 *fZone = v;
916 fGUI->updateZone(fZone);
917 }
918 }
919
920 float cache() { return fCache; }
921 virtual void reflectZone() = 0;
922 };
923
924
925 /**
926 * Callback Item
927 */
928
929 struct uiCallbackItem : public uiItem
930 {
931 uiCallback fCallback;
932 void* fData;
933
934 uiCallbackItem(UI* ui, float* zone, uiCallback foo, void* data)
935 : uiItem(ui, zone), fCallback(foo), fData(data) {}
936
937 virtual void reflectZone() {
938 float v = *fZone;
939 fCache = v;
940 fCallback(v, fData);
941 }
942 };
943
944 /**
945 * Update all user items reflecting zone z
946 */
947
948 inline void UI::updateZone(float* z)
949 {
950 float v = *z;
951 clist* l = fZoneMap[z];
952 for (clist::iterator c = l->begin(); c != l->end(); c++) {
953 if ((*c)->cache() != v) (*c)->reflectZone();
954 }
955 }
956
957
958 /**
959 * Update all user items not up to date
960 */
961
962 inline void UI::updateAllZones()
963 {
964 for (zmap::iterator m = fZoneMap.begin(); m != fZoneMap.end(); m++) {
965 float* z = m->first;
966 clist* l = m->second;
967 float v = *z;
968 for (clist::iterator c = l->begin(); c != l->end(); c++) {
969 if ((*c)->cache() != v) (*c)->reflectZone();
970 }
971 }
972 }
973
974 inline void UI::addCallback(float* zone, uiCallback foo, void* data)
975 {
976 new uiCallbackItem(this, zone, foo, data);
977 };
978
979
980 /******************************************************************************
981 *******************************************************************************
982
983 GRAPHIC USER INTERFACE
984 gtk interface
985
986 *******************************************************************************
987 *******************************************************************************/
988
989 #include <gtk/gtk.h>
990
991 #define stackSize 256
992
993 // Insertion modes
994
995 #define kSingleMode 0
996 #define kBoxMode 1
997 #define kTabMode 2
998
999
1000 class GTKUI : public UI
1001 {
1002 private :
1003 static bool fInitialized;
1004 static list<UI*> fGuiList;
1005
1006 protected :
1007 GtkWidget* fWindow;
1008 int fTop;
1009 GtkWidget* fBox[stackSize];
1010 int fMode[stackSize];
1011 bool fStopped;
1012
1013 GtkWidget* addWidget(const char* label, GtkWidget* w);
1014 virtual void pushBox(int mode, GtkWidget* w);
1015
1016
1017 public :
1018
1019 static const gboolean expand = TRUE;
1020 static const gboolean fill = TRUE;
1021 static const gboolean homogene = FALSE;
1022
1023 GTKUI(char * name, int* pargc, char*** pargv);
1024
1025 // -- layout groups
1026
1027 virtual void openFrameBox(const char* label);
1028 virtual void openTabBox(const char* label = "");
1029 virtual void openHorizontalBox(const char* label = "");
1030 virtual void openVerticalBox(const char* label = "");
1031
1032 virtual void closeBox();
1033
1034 // -- active widgets
1035
1036 virtual void addButton(const char* label, float* zone);
1037 virtual void addToggleButton(const char* label, float* zone);
1038 virtual void addCheckButton(const char* label, float* zone);
1039 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
1040 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
1041 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
1042
1043 // -- passive display widgets
1044
1045 virtual void addNumDisplay(const char* label, float* zone, int precision);
1046 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max);
1047 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
1048 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
1049
1050 virtual void show();
1051 virtual void run();
1052
1053 };
1054
1055
1056
1057 /******************************************************************************
1058 *******************************************************************************
1059
1060 GRAPHIC USER INTERFACE (v2)
1061 gtk implementation
1062
1063 *******************************************************************************
1064 *******************************************************************************/
1065
1066 // global static fields
1067
1068 bool GTKUI::fInitialized = false;
1069 list<UI*> UI::fGuiList;
1070
1071
1072
1073 static gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
1074 {
1075 return FALSE;
1076 }
1077
1078 static void destroy_event( GtkWidget *widget, gpointer data )
1079 {
1080 gtk_main_quit ();
1081 }
1082
1083
1084 GTKUI::GTKUI(char * name, int* pargc, char*** pargv)
1085 {
1086 if (!fInitialized) {
1087 gtk_init(pargc, pargv);
1088 fInitialized = true;
1089 }
1090
1091 fWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1092 //gtk_container_set_border_width (GTK_CONTAINER (fWindow), 10);
1093 gtk_window_set_title (GTK_WINDOW (fWindow), name);
1094 gtk_signal_connect (GTK_OBJECT (fWindow), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL);
1095 gtk_signal_connect (GTK_OBJECT (fWindow), "destroy", GTK_SIGNAL_FUNC (destroy_event), NULL);
1096
1097 fTop = 0;
1098 fBox[fTop] = gtk_vbox_new (homogene, 4);
1099 fMode[fTop] = kBoxMode;
1100 gtk_container_add (GTK_CONTAINER (fWindow), fBox[fTop]);
1101 fStopped = false;
1102 }
1103
1104 // empilement des boites
1105
1106 void GTKUI::pushBox(int mode, GtkWidget* w)
1107 {
1108 assert(++fTop < stackSize);
1109 fMode[fTop] = mode;
1110 fBox[fTop] = w;
1111 }
1112
1113 void GTKUI::closeBox()
1114 {
1115 assert(--fTop >= 0);
1116 }
1117
1118
1119 // les differentes boites
1120
1121 void GTKUI::openFrameBox(const char* label)
1122 {
1123 GtkWidget * box = gtk_frame_new (label);
1124 //gtk_container_set_border_width (GTK_CONTAINER (box), 10);
1125
1126 pushBox(kSingleMode, addWidget(label, box));
1127 }
1128
1129 void GTKUI::openTabBox(const char* label)
1130 {
1131 pushBox(kTabMode, addWidget(label, gtk_notebook_new ()));
1132 }
1133
1134 void GTKUI::openHorizontalBox(const char* label)
1135 {
1136 GtkWidget * box = gtk_hbox_new (homogene, 4);
1137 gtk_container_set_border_width (GTK_CONTAINER (box), 10);
1138
1139 if (fMode[fTop] != kTabMode && label[0] != 0) {
1140 GtkWidget * frame = addWidget(label, gtk_frame_new (label));
1141 gtk_container_add (GTK_CONTAINER(frame), box);
1142 gtk_widget_show(box);
1143 pushBox(kBoxMode, box);
1144 } else {
1145 pushBox(kBoxMode, addWidget(label, box));
1146 }
1147 }
1148
1149 void GTKUI::openVerticalBox(const char* label)
1150 {
1151 GtkWidget * box = gtk_vbox_new (homogene, 4);
1152 gtk_container_set_border_width (GTK_CONTAINER (box), 10);
1153
1154 if (fMode[fTop] != kTabMode && label[0] != 0) {
1155 GtkWidget * frame = addWidget(label, gtk_frame_new (label));
1156 gtk_container_add (GTK_CONTAINER(frame), box);
1157 gtk_widget_show(box);
1158 pushBox(kBoxMode, box);
1159 } else {
1160 pushBox(kBoxMode, addWidget(label, box));
1161 }
1162 }
1163
1164 GtkWidget* GTKUI::addWidget(const char* label, GtkWidget* w)
1165 {
1166 switch (fMode[fTop]) {
1167 case kSingleMode : gtk_container_add (GTK_CONTAINER(fBox[fTop]), w); break;
1168 case kBoxMode : gtk_box_pack_start (GTK_BOX(fBox[fTop]), w, expand, fill, 0); break;
1169 case kTabMode : gtk_notebook_append_page (GTK_NOTEBOOK(fBox[fTop]), w, gtk_label_new(label)); break;
1170 }
1171 gtk_widget_show (w);
1172 return w;
1173 }
1174
1175 // --------------------------- Press button ---------------------------
1176
1177 struct uiButton : public uiItem
1178 {
1179 GtkButton* fButton;
1180
1181 uiButton (UI* ui, float* zone, GtkButton* b) : uiItem(ui, zone), fButton(b) {}
1182
1183 static void pressed( GtkWidget *widget, gpointer data )
1184 {
1185 uiItem* c = (uiItem*) data;
1186 c->modifyZone(1.0);
1187 }
1188
1189 static void released( GtkWidget *widget, gpointer data )
1190 {
1191 uiItem* c = (uiItem*) data;
1192 c->modifyZone(0.0);
1193 }
1194
1195 virtual void reflectZone()
1196 {
1197 float v = *fZone;
1198 fCache = v;
1199 if (v > 0.0) gtk_button_pressed(fButton); else gtk_button_released(fButton);
1200 }
1201 };
1202
1203 void GTKUI::addButton(const char* label, float* zone)
1204 {
1205 *zone = 0.0;
1206 GtkWidget* button = gtk_button_new_with_label (label);
1207 addWidget(label, button);
1208
1209 uiButton* c = new uiButton(this, zone, GTK_BUTTON(button));
1210
1211 gtk_signal_connect (GTK_OBJECT (button), "pressed", GTK_SIGNAL_FUNC (uiButton::pressed), (gpointer) c);
1212 gtk_signal_connect (GTK_OBJECT (button), "released", GTK_SIGNAL_FUNC (uiButton::released), (gpointer) c);
1213
1214 }
1215
1216 // --------------------------- Toggle Buttons ---------------------------
1217
1218 struct uiToggleButton : public uiItem
1219 {
1220 GtkToggleButton* fButton;
1221
1222 uiToggleButton(UI* ui, float* zone, GtkToggleButton* b) : uiItem(ui, zone), fButton(b) {}
1223
1224 static void toggled (GtkWidget *widget, gpointer data)
1225 {
1226 float v = (GTK_TOGGLE_BUTTON (widget)->active) ? 1.0 : 0.0;
1227 ((uiItem*)data)->modifyZone(v);
1228 }
1229
1230 virtual void reflectZone()
1231 {
1232 float v = *fZone;
1233 fCache = v;
1234 gtk_toggle_button_set_active(fButton, v > 0.0);
1235 }
1236 };
1237
1238 void GTKUI::addToggleButton(const char* label, float* zone)
1239 {
1240 *zone = 0.0;
1241 GtkWidget* button = gtk_toggle_button_new_with_label (label);
1242 addWidget(label, button);
1243
1244 uiToggleButton* c = new uiToggleButton(this, zone, GTK_TOGGLE_BUTTON(button));
1245 gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (uiToggleButton::toggled), (gpointer) c);
1246 }
1247
1248
1249 // --------------------------- Check Button ---------------------------
1250
1251 struct uiCheckButton : public uiItem
1252 {
1253 GtkToggleButton* fButton;
1254
1255 uiCheckButton(UI* ui, float* zone, GtkToggleButton* b) : uiItem(ui, zone), fButton(b) {}
1256
1257 static void toggled (GtkWidget *widget, gpointer data)
1258 {
1259 float v = (GTK_TOGGLE_BUTTON (widget)->active) ? 1.0 : 0.0;
1260 ((uiItem*)data)->modifyZone(v);
1261 }
1262
1263 virtual void reflectZone()
1264 {
1265 float v = *fZone;
1266 fCache = v;
1267 gtk_toggle_button_set_active(fButton, v > 0.0);
1268 }
1269 };
1270
1271 void GTKUI::addCheckButton(const char* label, float* zone)
1272 {
1273 *zone = 0.0;
1274 GtkWidget* button = gtk_check_button_new_with_label (label);
1275 addWidget(label, button);
1276
1277 uiCheckButton* c = new uiCheckButton(this, zone, GTK_TOGGLE_BUTTON(button));
1278 gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC(uiCheckButton::toggled), (gpointer) c);
1279 }
1280
1281
1282 // --------------------------- Adjustmenty based widgets ---------------------------
1283
1284 struct uiAdjustment : public uiItem
1285 {
1286 GtkAdjustment* fAdj;
1287
1288 uiAdjustment(UI* ui, float* zone, GtkAdjustment* adj) : uiItem(ui, zone), fAdj(adj) {}
1289
1290 static void changed (GtkWidget *widget, gpointer data)
1291 {
1292 float v = GTK_ADJUSTMENT (widget)->value;
1293 ((uiItem*)data)->modifyZone(v);
1294 }
1295
1296 virtual void reflectZone()
1297 {
1298 float v = *fZone;
1299 fCache = v;
1300 gtk_adjustment_set_value(fAdj, v);
1301 }
1302 };
1303
1304 static int precision(double n)
1305 {
1306 if (n < 0.009999) return 3;
1307 else if (n < 0.099999) return 2;
1308 else if (n < 0.999999) return 1;
1309 else return 0;
1310 }
1311
1312 // -------------------------- Vertical Slider -----------------------------------
1313
1314 void GTKUI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
1315 {
1316 *zone = init;
1317 GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, 0);
1318
1319 uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj));
1320
1321 gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c);
1322
1323 GtkWidget* slider = gtk_vscale_new (GTK_ADJUSTMENT(adj));
1324 gtk_range_set_inverted (GTK_RANGE(slider), TRUE);
1325 gtk_scale_set_digits(GTK_SCALE(slider), precision(step));
1326 gtk_widget_set_usize(slider, -1, 160);
1327
1328 openFrameBox(label);
1329 addWidget(label, slider);
1330 closeBox();
1331 }
1332
1333 // -------------------------- Horizontal Slider -----------------------------------
1334
1335 void GTKUI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
1336 {
1337 *zone = init;
1338 GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, 0);
1339
1340 uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj));
1341
1342 gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c);
1343
1344 GtkWidget* slider = gtk_hscale_new (GTK_ADJUSTMENT(adj));
1345 gtk_scale_set_digits(GTK_SCALE(slider), precision(step));
1346 gtk_widget_set_usize(slider, 160, -1);
1347
1348 openFrameBox(label);
1349 addWidget(label, slider);
1350 closeBox();
1351 }
1352
1353
1354 // ------------------------------ Num Entry -----------------------------------
1355
1356 void GTKUI::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
1357 {
1358 *zone = init;
1359 GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, step);
1360
1361 uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj));
1362
1363 gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c);
1364
1365 GtkWidget* spinner = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 0.005, precision(step));
1366
1367 //gtk_widget_set_usize(slider, 160, -1);
1368 openFrameBox(label);
1369 addWidget(label, spinner);
1370 closeBox();
1371 }
1372
1373
1374 // ========================== passive widgets ===============================
1375
1376
1377 // ------------------------------ Progress Bar -----------------------------------
1378
1379 struct uiBargraph : public uiItem
1380 {
1381 GtkProgressBar* fProgressBar;
1382 float fMin;
1383 float fMax;
1384
1385 uiBargraph(UI* ui, float* zone, GtkProgressBar* pbar, float lo, float hi)
1386 : uiItem(ui, zone), fProgressBar(pbar), fMin(lo), fMax(hi) {}
1387
1388 float scale(float v) { return (v-fMin)/(fMax-fMin); }
1389
1390 virtual void reflectZone()
1391 {
1392 float v = *fZone;
1393 fCache = v;
1394 gtk_progress_bar_set_fraction(fProgressBar, scale(v));
1395 }
1396 };
1397
1398
1399
1400 void GTKUI::addVerticalBargraph(const char* label, float* zone, float lo, float hi)
1401 {
1402 GtkWidget* pb = gtk_progress_bar_new();
1403 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb), GTK_PROGRESS_BOTTOM_TO_TOP);
1404 gtk_widget_set_size_request(pb, 8, -1);
1405 new uiBargraph(this, zone, GTK_PROGRESS_BAR(pb), lo, hi);
1406 openFrameBox(label);
1407 addWidget(label, pb);
1408 closeBox();
1409 }
1410
1411
1412 void GTKUI::addHorizontalBargraph(const char* label, float* zone, float lo, float hi)
1413 {
1414 GtkWidget* pb = gtk_progress_bar_new();
1415 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb), GTK_PROGRESS_LEFT_TO_RIGHT);
1416 gtk_widget_set_size_request(pb, -1, 8);
1417 new uiBargraph(this, zone, GTK_PROGRESS_BAR(pb), lo, hi);
1418 openFrameBox(label);
1419 addWidget(label, pb);
1420 closeBox();
1421 }
1422
1423
1424 // ------------------------------ Num Display -----------------------------------
1425
1426 struct uiNumDisplay : public uiItem
1427 {
1428 GtkLabel* fLabel;
1429 int fPrecision;
1430
1431 uiNumDisplay(UI* ui, float* zone, GtkLabel* label, int precision)
1432 : uiItem(ui, zone), fLabel(label), fPrecision(precision) {}
1433
1434 virtual void reflectZone()
1435 {
1436 float v = *fZone;
1437 fCache = v;
1438 char s[64];
1439 if (fPrecision <= 0) {
1440 snprintf(s, 63, "%d", int(v));
1441 } else if (fPrecision>3) {
1442 snprintf(s, 63, "%f", v);
1443 } else {
1444 const char* format[] = {"%.1f", "%.2f", "%.3f"};
1445 snprintf(s, 63, format[fPrecision-1], v);
1446 }
1447 gtk_label_set_text(fLabel, s);
1448 }
1449 };
1450
1451
1452 void GTKUI::addNumDisplay(const char* label, float* zone, int precision )
1453 {
1454 GtkWidget* lw = gtk_label_new("");
1455 new uiNumDisplay(this, zone, GTK_LABEL(lw), precision);
1456 openFrameBox(label);
1457 addWidget(label, lw);
1458 closeBox();
1459 }
1460
1461
1462 // ------------------------------ Text Display -----------------------------------
1463
1464 struct uiTextDisplay : public uiItem
1465 {
1466 GtkLabel* fLabel;
1467 char** fNames;
1468 float fMin;
1469 float fMax;
1470 int fNum;
1471
1472
1473 uiTextDisplay (UI* ui, float* zone, GtkLabel* label, char* names[], float lo, float hi)
1474 : uiItem(ui, zone), fLabel(label), fNames(names), fMin(lo), fMax(hi)
1475 {
1476 fNum = 0;
1477 while (fNames[fNum] != 0) fNum++;
1478 }
1479
1480 virtual void reflectZone()
1481 {
1482 float v = *fZone;
1483 fCache = v;
1484
1485 int idx = int(fNum*(v-fMin)/(fMax-fMin));
1486
1487 if (idx < 0) idx = 0;
1488 else if (idx >= fNum) idx = fNum-1;
1489
1490 gtk_label_set_text(fLabel, fNames[idx]);
1491 }
1492 };
1493
1494
1495 void GTKUI::addTextDisplay(const char* label, float* zone, char* names[], float lo, float hi )
1496 {
1497 GtkWidget* lw = gtk_label_new("");
1498 new uiTextDisplay (this, zone, GTK_LABEL(lw), names, lo, hi);
1499 openFrameBox(label);
1500 addWidget(label, lw);
1501 closeBox();
1502 }
1503
1504
1505
1506 void GTKUI::show()
1507 {
1508 assert(fTop == 0);
1509 gtk_widget_show (fBox[0]);
1510 gtk_widget_show (fWindow);
1511 }
1512
1513
1514 /**
1515 * Update all user items reflecting zone z
1516 */
1517
1518 static gboolean callUpdateAllGuis(gpointer)
1519 {
1520 UI::updateAllGuis();
1521 return TRUE;
1522 }
1523
1524
1525 void GTKUI::run()
1526 {
1527 assert(fTop == 0);
1528 gtk_widget_show (fBox[0]);
1529 gtk_widget_show (fWindow);
1530 gtk_timeout_add(40, callUpdateAllGuis, 0);
1531 gtk_main ();
1532 stop();
1533 }
1534
1535
1536 /******************************************************************************
1537 *******************************************************************************
1538
1539 DSP
1540
1541 *******************************************************************************
1542 *******************************************************************************/
1543
1544
1545 //----------------------------------------------------------------
1546 // Definition of a Faust Digital Signal Processor
1547 //----------------------------------------------------------------
1548
1549 class dsp {
1550 protected:
1551 int fSamplingFreq;
1552 int fThreadNum;
1553 public:
1554 dsp() {}
1555 virtual ~dsp() {}
1556
1557 virtual int getNumInputs() = 0;
1558 virtual int getNumOutputs() = 0;
1559 virtual void buildUserInterface(UI* interface) = 0;
1560 virtual void init(int samplingRate) = 0;
1561 virtual void compute(int len, float** inputs, float** outputs) = 0;
1562 virtual void conclude() {}
1563 };
1564
1565
1566 <<includeclass>>
1567
1568
1569 mydsp DSP;
1570
1571
1572
1573
1574 /******************************************************************************
1575 *******************************************************************************
1576
1577 MAIN PLAY THREAD
1578
1579 *******************************************************************************
1580 *******************************************************************************/
1581
1582 // lopt : Scan Command Line long int Arguments
1583
1584 long lopt (int argc, char *argv[], const char* longname, const char* shortname, long def)
1585 {
1586 for (int i=2; i<argc; i++)
1587 if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
1588 return atoi(argv[i]);
1589 return def;
1590 }
1591
1592 // sopt : Scan Command Line string Arguments
1593
1594 const char* sopt (int argc, char *argv[], const char* longname, const char* shortname, const char* def)
1595 {
1596 for (int i=2; i<argc; i++)
1597 if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
1598 return argv[i];
1599 return def;
1600 }
1601
1602 // fopt : Scan Command Line flag option (without argument), return true if the flag
1603
1604 bool fopt (int argc, char *argv[], const char* longname, const char* shortname)
1605 {
1606 for (int i=1; i<argc; i++)
1607 if ( strcmp(argv[i], shortname) == 0 || strcmp(argv[i], longname) == 0 )
1608 return true;
1609 return false;
1610 }
1611
1612
1613 //-------------------------------------------------------------------------
1614 // MAIN
1615 //-------------------------------------------------------------------------
1616
1617 pthread_t guithread;
1618
1619 void* run_ui(void* ptr)
1620 {
1621 UI* interface = (UI*) ptr;
1622 interface->run();
1623 pthread_exit(0);
1624 return 0;
1625 }
1626
1627 int main(int argc, char *argv[] )
1628 {
1629 CHECKINTSIZE;
1630
1631 UI* interface = new GTKUI(argv[0], &argc, &argv);
1632
1633 // compute rcfilename to (re)store application state
1634 char rcfilename[256];
1635 char* home = getenv("HOME");
1636 snprintf(rcfilename, 255, "%s/.%src", home, basename(argv[0]));
1637
1638 AudioInterface audio (
1639 AudioParam().cardName( sopt(argc, argv, "--device", "-d", "hw:0") )
1640 .frequency( lopt(argc, argv, "--frequency", "-f", 44100) )
1641 .buffering( lopt(argc, argv, "--buffer", "-b", 1024) )
1642 .periods( lopt(argc, argv, "--periods", "-p", 2) )
1643 .inputs(DSP.getNumInputs())
1644 .outputs(DSP.getNumOutputs())
1645 );
1646
1647 AVOIDDENORMALS;
1648 audio.open();
1649
1650 DSP.init(audio.frequency());
1651 DSP.buildUserInterface(interface);
1652
1653 interface->recallState(rcfilename);
1654
1655 pthread_create(&guithread, NULL, run_ui, interface);
1656
1657 bool rt = setRealtimePriority();
1658 printf(rt?"RT : ":"NRT: "); audio.shortinfo();
1659 if (fopt(argc, argv, "--verbose", "-v")) audio.longinfo();
1660 bool running = true;
1661 audio.write();
1662 audio.write();
1663 openMesure();
1664 while(running) {
1665 audio.read();
1666 STARTMESURE
1667 DSP.compute(audio.buffering(), audio.inputSoftChannels(), audio.outputSoftChannels());
1668 STOPMESURE
1669 audio.write();
1670 running = mesure <= (KMESURE + KSKIP);
1671 }
1672 closeMesure();
1673 interface->saveState(rcfilename);
1674
1675 #ifdef BENCHMARKMODE
1676 printstats(argv[0], audio.buffering(), DSP.getNumInputs(), DSP.getNumOutputs());
1677 #endif
1678
1679 return 0;
1680 }