User Manual first draft.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / architecture / oss-gtk.cpp
1 /************************************************************************
2
3 IMPORTANT NOTE : this file contains two clearly delimited sections :
4 the ARCHITECTURE section (in two parts) and the USER section. Each section
5 is governed by its own copyright and license. Please check individually
6 each section for license and copyright information.
7 *************************************************************************/
8
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
10
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
14 ---------------------------------------------------------------------
15 This Architecture section is free software; you can redistribute it
16 and/or modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version 3 of
18 the License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; If not, see <http://www.gnu.org/licenses/>.
27
28 EXCEPTION : As a special exception, you may create a larger work
29 that contains this FAUST architecture section and distribute
30 that work under terms of your choice, so long as this FAUST
31 architecture section is not modified.
32
33
34 ************************************************************************
35 ************************************************************************/
36
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <limits.h>
42 #include <math.h>
43 #include <errno.h>
44 #include <time.h>
45 #include <sys/ioctl.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <sys/soundcard.h>
49 #include <pwd.h>
50 #include <sys/types.h>
51 #include <assert.h>
52 #include <gtk/gtk.h>
53 #include <pthread.h>
54 #include <sys/wait.h>
55
56 #include <map>
57 #include <list>
58 #include <vector>
59
60 #include <iostream>
61 #include <fstream>
62
63
64 using namespace std;
65
66 struct Meta : map<const char*, const char*>
67 {
68 void declare (const char* key, const char* value) { (*this)[key]=value; }
69 };
70
71
72 // g++ -O3 -lm -lpthread `gtk-config --cflags --libs` ex2.cpp
73
74
75 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
76 // flags to avoid costly denormals
77 #ifdef __SSE__
78 #include <xmmintrin.h>
79 #ifdef __SSE2__
80 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
81 #else
82 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
83 #endif
84 #else
85 #define AVOIDDENORMALS
86 #endif
87
88 //#define BENCHMARKMODE
89
90 //-------------------------------------------------------------------
91 // Generic min and max using c++ inline
92 //-------------------------------------------------------------------
93
94 inline int max (unsigned int a, unsigned int b) { return (a>b) ? a : b; }
95 inline int max (int a, int b) { return (a>b) ? a : b; }
96
97 inline long max (long a, long b) { return (a>b) ? a : b; }
98 inline long max (int a, long b) { return (a>b) ? a : b; }
99 inline long max (long a, int b) { return (a>b) ? a : b; }
100
101 inline float max (float a, float b) { return (a>b) ? a : b; }
102 inline float max (int a, float b) { return (a>b) ? a : b; }
103 inline float max (float a, int b) { return (a>b) ? a : b; }
104 inline float max (long a, float b) { return (a>b) ? a : b; }
105 inline float max (float a, long b) { return (a>b) ? a : b; }
106
107 inline double max (double a, double b) { return (a>b) ? a : b; }
108 inline double max (int a, double b) { return (a>b) ? a : b; }
109 inline double max (double a, int b) { return (a>b) ? a : b; }
110 inline double max (long a, double b) { return (a>b) ? a : b; }
111 inline double max (double a, long b) { return (a>b) ? a : b; }
112 inline double max (float a, double b) { return (a>b) ? a : b; }
113 inline double max (double a, float b) { return (a>b) ? a : b; }
114
115
116 inline int min (int a, int b) { return (a<b) ? a : b; }
117
118 inline long min (long a, long b) { return (a<b) ? a : b; }
119 inline long min (int a, long b) { return (a<b) ? a : b; }
120 inline long min (long a, int b) { return (a<b) ? a : b; }
121
122 inline float min (float a, float b) { return (a<b) ? a : b; }
123 inline float min (int a, float b) { return (a<b) ? a : b; }
124 inline float min (float a, int b) { return (a<b) ? a : b; }
125 inline float min (long a, float b) { return (a<b) ? a : b; }
126 inline float min (float a, long b) { return (a<b) ? a : b; }
127
128 inline double min (double a, double b) { return (a<b) ? a : b; }
129 inline double min (int a, double b) { return (a<b) ? a : b; }
130 inline double min (double a, int b) { return (a<b) ? a : b; }
131 inline double min (long a, double b) { return (a<b) ? a : b; }
132 inline double min (double a, long b) { return (a<b) ? a : b; }
133 inline double min (float a, double b) { return (a<b) ? a : b; }
134 inline double min (double a, float b) { return (a<b) ? a : b; }
135
136
137 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
138
139 inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
140
141
142 void setRealtimePriority ()
143 {
144 struct passwd * pw;
145 int err;
146 uid_t uid;
147 struct sched_param param;
148
149 uid = getuid ();
150 pw = getpwnam ("root");
151 setuid (pw->pw_uid);
152 param.sched_priority = 50; /* 0 to 99 */
153 err = sched_setscheduler(0, SCHED_RR, &param);
154 setuid (uid);
155 if (err != -1) {
156 printf("OK : Running with realtime priority\n");
157 } else {
158 printf("Warning : running with non-realtime priority\n");
159 }
160
161 }
162
163
164
165 /******************************************************************************
166 *******************************************************************************
167
168 VECTOR INTRINSICS
169
170 *******************************************************************************
171 *******************************************************************************/
172
173 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
174 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
175
176
177 <<includeIntrinsic>>
178
179 #ifdef BENCHMARKMODE
180 // mesuring jack performances
181 static __inline__ unsigned long long int rdtsc(void)
182 {
183 unsigned long long int x;
184 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
185 return x;
186 }
187
188 #define KSKIP 10
189 #define KMESURE 1024
190 int mesure = 0;
191 unsigned long long int starts[KMESURE];
192 unsigned long long int stops [KMESURE];
193
194 #define STARTMESURE starts[mesure%KMESURE] = rdtsc();
195 #define STOPMESURE stops[mesure%KMESURE] = rdtsc(); mesure = mesure+1;
196
197 void printstats()
198 {
199 unsigned long long int low, hi, tot;
200 low = hi = tot = (stops[KSKIP] - starts[KSKIP]);
201
202 if (mesure < KMESURE) {
203
204 for (int i = KSKIP+1; i<mesure; i++) {
205 unsigned long long int m = stops[i] - starts[i];
206 if (m<low) low = m;
207 if (m>hi) hi = m;
208 tot += m;
209 }
210 cout << low << ' ' << tot/(mesure-KSKIP) << ' ' << hi << endl;
211
212 } else {
213
214 for (int i = KSKIP+1; i<KMESURE; i++) {
215 unsigned long long int m = stops[i] - starts[i];
216 if (m<low) low = m;
217 if (m>hi) hi = m;
218 tot += m;
219 }
220 cout << low << ' ' << tot/(KMESURE-KSKIP) << ' ' << hi << endl;
221
222 }
223 }
224 #else
225
226 #define STARTMESURE
227 #define STOPMESURE
228
229 #endif
230
231
232 /******************************************************************************
233 *******************************************************************************
234
235 AUDIO INTERFACE
236
237 *******************************************************************************
238 *******************************************************************************/
239
240 enum { kRead = 1, kWrite = 2, kReadWrite = 3 };
241
242 // AudioParam : a convenient class to pass parameters to the AudioInterface
243 struct AudioParam
244 {
245 const char* fDeviceName;
246 int fSamplingFrequency;
247 int fRWMode;
248 int fSampleFormat;
249 int fFramesPerBuffer;
250
251 AudioParam() :
252 fDeviceName("/dev/dsp"),
253 fSamplingFrequency(44100),
254 fRWMode(kReadWrite),
255 fSampleFormat(AFMT_S16_LE),
256 fFramesPerBuffer(512)
257 {}
258
259 AudioParam& device(const char * n) { fDeviceName = n; return *this; }
260 AudioParam& frequency(int f) { fSamplingFrequency = f; return *this; }
261 AudioParam& mode(int m) { fRWMode = m; return *this; }
262 AudioParam& format(int f) { fSampleFormat = f; return *this; }
263 AudioParam& buffering(int fpb) { fFramesPerBuffer = fpb; return *this; }
264 };
265
266 class AudioInterface
267 {
268 private :
269 AudioParam fParam;
270 int fOutputDevice ;
271 int fInputDevice ;
272 int fNumOfOutputChannels;
273 int fNumOfInputChannels;
274 int fInputBufferSize;
275 short* fInputBuffer;
276 int fOutputBufferSize;
277 short* fOutputBuffer;
278
279
280 public :
281
282 const char* getDeviceName() { return fParam.fDeviceName; }
283 int getSamplingFrequency() { return fParam.fSamplingFrequency; }
284 int getRWMode() { return fParam.fRWMode; }
285 int getSampleFormat() { return fParam.fSampleFormat; }
286 int getFramesPerBuffer() { return fParam.fFramesPerBuffer; }
287
288 int getNumOutputs() { return fNumOfOutputChannels; }
289 int getNumInputs() { return fNumOfInputChannels; }
290 int getInputBufferSize() { return fInputBufferSize; }
291 int getOutputBufferSize() { return fOutputBufferSize; }
292
293
294 AudioInterface(const AudioParam& ap = AudioParam()) : fParam(ap)
295 {
296 fOutputDevice = -1;
297 fInputDevice = -1;
298 fNumOfOutputChannels = 0;
299 fNumOfInputChannels = 0;
300 fInputBufferSize = 0;
301 fInputBuffer = 0;
302 fOutputBufferSize = 0;
303 fOutputBuffer = 0;
304 }
305
306
307 void openInputAudioDev ()
308 {
309 assert( (fInputDevice = ::open(fParam.fDeviceName, O_RDONLY, 0)) > 0);
310 assert( ioctl(fInputDevice, SNDCTL_DSP_SETFMT, &fParam.fSampleFormat) != -1);
311 assert( ioctl(fInputDevice, SNDCTL_DSP_CHANNELS, &fNumOfInputChannels) != -1);
312 assert( ioctl(fInputDevice, SNDCTL_DSP_SPEED, &fParam.fSamplingFrequency) != -1);
313
314 int gFragFormat = (1 << 16) + int2pow2(fParam.fFramesPerBuffer * 2 * fNumOfInputChannels);
315 assert( ioctl(fInputDevice, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) != -1);
316
317 fInputBufferSize = 0;
318 assert( ioctl(fInputDevice, SNDCTL_DSP_GETBLKSIZE, &fInputBufferSize) != -1);
319 assert( fInputBufferSize == fParam.fFramesPerBuffer * 2 * fNumOfInputChannels );
320
321 fInputBuffer = (short*) calloc(fInputBufferSize, 1);
322 }
323
324
325 void openOutputAudioDev ()
326 {
327 assert( (fOutputDevice = ::open(fParam.fDeviceName, O_WRONLY, 0)) > 0);
328 assert( ioctl(fOutputDevice, SNDCTL_DSP_SETFMT, &fParam.fSampleFormat) != -1);
329 assert( ioctl(fOutputDevice, SNDCTL_DSP_CHANNELS,&fNumOfOutputChannels)!= -1);
330 assert( ioctl(fOutputDevice, SNDCTL_DSP_SPEED, &fParam.fSamplingFrequency) != -1);
331
332 int gFragFormat = (1 << 16) + int2pow2(fParam.fFramesPerBuffer * 2 * fNumOfOutputChannels);
333 assert( ioctl(fOutputDevice, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) != -1);
334
335 fOutputBufferSize = 0;
336 assert( ioctl(fOutputDevice, SNDCTL_DSP_GETBLKSIZE, &fOutputBufferSize) != -1);
337 assert( fOutputBufferSize == fParam.fFramesPerBuffer * 2 * fNumOfOutputChannels );
338
339 fOutputBuffer = (short*)calloc(fOutputBufferSize, 1);
340 }
341
342
343 void open()
344 {
345 if (fParam.fRWMode & kRead) openInputAudioDev();
346 if (fParam.fRWMode & kWrite) openOutputAudioDev();
347 }
348
349
350 void close()
351 {
352 if (fParam.fRWMode & kRead) ::close(fOutputDevice);
353 if (fParam.fRWMode & kWrite) ::close(fInputDevice);
354 }
355
356
357
358 //----------------------------------------------------------------
359 // allocChanGroup() : allocate a group of audio buffers
360 // chan[] : is an array of buffer pointers
361 // n : is the number of buffers to allocate
362 // len : is the length of each buffer
363 //----------------------------------------------------------------
364
365 void allocChanGroup(float* chan[], int n, int len)
366 {
367 for (int c = 0; c < n; c++) {
368 chan[c] = (float*) calloc (len, sizeof(float));
369 }
370 }
371
372
373 //----------------------------------------------------------------
374 // info() : print information on the audio device
375 //----------------------------------------------------------------
376
377 void info()
378 {
379 audio_buf_info info;
380 int cap;
381 printf("Audio Interface Description :\n");
382 printf("Sampling Frequency : %d, Sample Format : %d, Mode : %d\n", getSamplingFrequency(), getSampleFormat(), getRWMode());
383
384 if (getRWMode() & kWrite) {
385 assert( ioctl(fOutputDevice, SNDCTL_DSP_GETOSPACE, &info) != -1);
386 printf("output space info: fragments=%d, fragstotal=%d, fragsize=%d, bytes=%d\n", info.fragments, info.fragstotal,
387 info.fragsize, info.bytes);
388
389 assert( ioctl(fOutputDevice,SNDCTL_DSP_GETCAPS, &cap) != -1);
390 printf("Output capabilities - %d channels : ", fNumOfOutputChannels);
391
392 if (cap & DSP_CAP_DUPLEX) printf(" DSP_CAP_DUPLEX");
393 if (cap & DSP_CAP_REALTIME) printf(" DSP_CAP_REALTIME");
394 if (cap & DSP_CAP_DUPLEX) printf(" DSP_CAP_DUPLEX");
395 if (cap & DSP_CAP_BATCH) printf(" DSP_CAP_BATCH");
396 if (cap & DSP_CAP_COPROC) printf(" DSP_CAP_COPROC");
397 if (cap & DSP_CAP_TRIGGER) printf(" DSP_CAP_TRIGGER");
398 if (cap & DSP_CAP_MMAP) printf(" DSP_CAP_MMAP");
399 if (cap & DSP_CAP_MULTI) printf(" DSP_CAP_MULTI");
400 if (cap & DSP_CAP_BIND) printf(" DSP_CAP_BIND");
401 printf("\n");
402 printf("Output block size = %d\n", fOutputBufferSize);
403 }
404
405
406 if (getRWMode() & kRead) {
407 assert( ioctl(fInputDevice, SNDCTL_DSP_GETISPACE, &info) != -1);
408 printf("input space info: fragments=%d, fragstotal=%d, fragsize=%d, bytes=%d\n", info.fragments, info.fragstotal,
409 info.fragsize, info.bytes);
410
411
412 assert( ioctl(fInputDevice,SNDCTL_DSP_GETCAPS, &cap) != -1);
413 printf("Input capabilities - %d channels : ", fNumOfInputChannels);
414 if (cap & DSP_CAP_DUPLEX) printf(" DSP_CAP_DUPLEX");
415 if (cap & DSP_CAP_REALTIME) printf(" DSP_CAP_REALTIME");
416 if (cap & DSP_CAP_DUPLEX) printf(" DSP_CAP_DUPLEX");
417 if (cap & DSP_CAP_BATCH) printf(" DSP_CAP_BATCH");
418 if (cap & DSP_CAP_COPROC) printf(" DSP_CAP_COPROC");
419 if (cap & DSP_CAP_TRIGGER) printf(" DSP_CAP_TRIGGER");
420 if (cap & DSP_CAP_MMAP) printf(" DSP_CAP_MMAP");
421 if (cap & DSP_CAP_MULTI) printf(" DSP_CAP_MULTI");
422 if (cap & DSP_CAP_BIND) printf(" DSP_CAP_BIND");
423 printf("\n");
424 printf("Input block size = %d\n", fInputBufferSize);
425 }
426 }
427
428
429 //----------------------------------------------------------------
430 // read() : read
431 //----------------------------------------------------------------
432
433 bool read(int frames, float* channel[])
434 {
435 int bytes = frames * 2 * fNumOfInputChannels; assert(bytes <= fInputBufferSize);
436 int count = ::read(fInputDevice, fInputBuffer, bytes);
437 //assert (bytes == count);
438
439 for (int s = 0; s < frames; s++) {
440 for (int c = 0; c < fNumOfInputChannels; c++) {
441 channel[c][s] = float(fInputBuffer[c + s*fNumOfInputChannels])*(1.0/float(SHRT_MAX));
442 }
443 }
444 return bytes == count;
445 }
446
447
448 bool write(int frames, float* channel[])
449 {
450 int bytes = frames * 2 * fNumOfOutputChannels; assert(bytes <= fOutputBufferSize);
451
452 for (int f = 0; f < frames; f++) {
453 for (int c = 0; c < fNumOfOutputChannels; c++) {
454 float x = channel[c][f];
455 fOutputBuffer[c + f*fNumOfOutputChannels] = short( max(min(x,1.0),-1.0) * float(SHRT_MAX) ) ;
456 }
457 }
458
459 int count = ::write(fOutputDevice, fOutputBuffer, bytes);
460 assert (bytes == count);
461
462 return bytes == count;
463 }
464
465
466
467 };
468
469
470
471 /******************************************************************************
472 *******************************************************************************
473
474 GRAPHIC USER INTERFACE (v2)
475 abstract interfaces
476
477 *******************************************************************************
478 *******************************************************************************/
479
480 #include <map>
481 #include <list>
482
483 using namespace std;
484
485
486 struct uiItem;
487 typedef void (*uiCallback)(float val, void* data);
488
489 /**
490 * Graphic User Interface : abstract definition
491 */
492
493 class UI
494 {
495 typedef list<uiItem*> clist;
496 typedef map<float*, clist*> zmap;
497
498 private:
499 static list<UI*> fGuiList;
500 zmap fZoneMap;
501 bool fStopped;
502
503 public:
504
505 UI() : fStopped(false) {
506 fGuiList.push_back(this);
507 }
508
509 virtual ~UI() {
510 // suppression de this dans fGuiList
511 }
512
513 // -- registerZone(z,c) : zone management
514
515 void registerZone(float* z, uiItem* c)
516 {
517 if (fZoneMap.find(z) == fZoneMap.end()) fZoneMap[z] = new clist();
518 fZoneMap[z]->push_back(c);
519 }
520
521 // -- saveState(filename) : save the value of every zone to a file
522
523 void saveState(char* filename)
524 {
525 ofstream f(filename);
526
527 for (zmap::iterator i=fZoneMap.begin(); i!=fZoneMap.end(); i++) {
528 f << *(i->first) << ' ';
529 }
530
531 f << endl;
532 f.close();
533 }
534
535 // -- recallState(filename) : load the value of every zone from a file
536
537 void recallState(char* filename)
538 {
539 ifstream f(filename);
540 if (f.good()) {
541 for (zmap::iterator i=fZoneMap.begin(); i!=fZoneMap.end(); i++) {
542 f >> *(i->first);
543 }
544 }
545 f.close();
546 }
547
548 void updateAllZones();
549
550 void updateZone(float* z);
551
552 static void updateAllGuis()
553 {
554 list<UI*>::iterator g;
555 for (g = fGuiList.begin(); g != fGuiList.end(); g++) {
556 (*g)->updateAllZones();
557 }
558 }
559
560 // -- active widgets
561
562 virtual void addButton(const char* label, float* zone) = 0;
563 virtual void addToggleButton(const char* label, float* zone) = 0;
564 virtual void addCheckButton(const char* label, float* zone) = 0;
565 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
566 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
567 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
568
569 // -- passive widgets
570
571 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
572 virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) = 0;
573 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
574 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
575
576 void addCallback(float* zone, uiCallback foo, void* data);
577
578 // -- widget's layouts
579
580 virtual void openFrameBox(const char* label) = 0;
581 virtual void openTabBox(const char* label) = 0;
582 virtual void openHorizontalBox(const char* label) = 0;
583 virtual void openVerticalBox(const char* label) = 0;
584 virtual void closeBox() = 0;
585
586 virtual void show() = 0;
587 virtual void run() = 0;
588
589 void stop() { fStopped = true; }
590 bool stopped() { return fStopped; }
591
592 virtual void declare(float* zone, const char* key, const char* value) {}
593 };
594
595
596 /**
597 * User Interface Item: abstract definition
598 */
599
600 class uiItem
601 {
602 protected :
603
604 UI* fGUI;
605 float* fZone;
606 float fCache;
607
608 uiItem (UI* ui, float* zone) : fGUI(ui), fZone(zone), fCache(-123456.654321)
609 {
610 ui->registerZone(zone, this);
611 }
612
613
614 public :
615 virtual ~uiItem() {}
616
617 void modifyZone(float v)
618 {
619 fCache = v;
620 if (*fZone != v) {
621 *fZone = v;
622 fGUI->updateZone(fZone);
623 }
624 }
625
626 float cache() { return fCache; }
627 virtual void reflectZone() = 0;
628 };
629
630
631 /**
632 * Callback Item
633 */
634
635 struct uiCallbackItem : public uiItem
636 {
637 uiCallback fCallback;
638 void* fData;
639
640 uiCallbackItem(UI* ui, float* zone, uiCallback foo, void* data)
641 : uiItem(ui, zone), fCallback(foo), fData(data) {}
642
643 virtual void reflectZone() {
644 float v = *fZone;
645 fCache = v;
646 fCallback(v, fData);
647 }
648 };
649
650 // en cours d'installation de call back. a finir!!!!!
651
652 /**
653 * Update all user items reflecting zone z
654 */
655
656 inline void UI::updateZone(float* z)
657 {
658 float v = *z;
659 clist* l = fZoneMap[z];
660 for (clist::iterator c = l->begin(); c != l->end(); c++) {
661 if ((*c)->cache() != v) (*c)->reflectZone();
662 }
663 }
664
665
666 /**
667 * Update all user items not up to date
668 */
669
670 inline void UI::updateAllZones()
671 {
672 for (zmap::iterator m = fZoneMap.begin(); m != fZoneMap.end(); m++) {
673 float* z = m->first;
674 clist* l = m->second;
675 float v = *z;
676 for (clist::iterator c = l->begin(); c != l->end(); c++) {
677 if ((*c)->cache() != v) (*c)->reflectZone();
678 }
679 }
680 }
681
682 inline void UI::addCallback(float* zone, uiCallback foo, void* data)
683 {
684 new uiCallbackItem(this, zone, foo, data);
685 };
686
687 /******************************************************************************
688 *******************************************************************************
689
690 GRAPHIC USER INTERFACE
691 gtk interface
692
693 *******************************************************************************
694 *******************************************************************************/
695
696 #include <gtk/gtk.h>
697
698 #define stackSize 256
699
700 // Insertion modes
701
702 #define kSingleMode 0
703 #define kBoxMode 1
704 #define kTabMode 2
705
706
707 /**
708 * rmWhiteSpaces(): Remove the leading and trailing white spaces of a string
709 * (but not those in the middle of the string)
710 */
711 static string rmWhiteSpaces(const string& s)
712 {
713 size_t i = s.find_first_not_of(" \t");
714 size_t j = s.find_last_not_of(" \t");
715
716 if (i != string::npos & j != string::npos) {
717 return s.substr(i, 1+j-i);
718 } else {
719 return "";
720 }
721 }
722
723
724 /**
725 * Extracts metdata from a label : 'vol [unit: dB]' -> 'vol' + metadata
726 */
727 static void extractMetadata(const string& fulllabel, string& label, map<string, string>& metadata)
728 {
729 enum {kLabel, kEscape1, kEscape2, kEscape3, kKey, kValue};
730 int state = kLabel; int deep = 0;
731 string key, value;
732
733 for (unsigned int i=0; i < fulllabel.size(); i++) {
734 char c = fulllabel[i];
735 switch (state) {
736 case kLabel :
737 assert (deep == 0);
738 switch (c) {
739 case '\\' : state = kEscape1; break;
740 case '[' : state = kKey; deep++; break;
741 default : label += c;
742 }
743 break;
744
745 case kEscape1 :
746 label += c;
747 state = kLabel;
748 break;
749
750 case kEscape2 :
751 key += c;
752 state = kKey;
753 break;
754
755 case kEscape3 :
756 value += c;
757 state = kValue;
758 break;
759
760 case kKey :
761 assert (deep > 0);
762 switch (c) {
763 case '\\' : state = kEscape2;
764 break;
765
766 case '[' : deep++;
767 key += c;
768 break;
769
770 case ':' : if (deep == 1) {
771 state = kValue;
772 } else {
773 key += c;
774 }
775 break;
776 case ']' : deep--;
777 if (deep < 1) {
778 metadata[rmWhiteSpaces(key)] = "";
779 state = kLabel;
780 key="";
781 value="";
782 } else {
783 key += c;
784 }
785 break;
786 default : key += c;
787 }
788 break;
789
790 case kValue :
791 assert (deep > 0);
792 switch (c) {
793 case '\\' : state = kEscape3;
794 break;
795
796 case '[' : deep++;
797 value += c;
798 break;
799
800 case ']' : deep--;
801 if (deep < 1) {
802 metadata[rmWhiteSpaces(key)]=rmWhiteSpaces(value);
803 state = kLabel;
804 key="";
805 value="";
806 } else {
807 value += c;
808 }
809 break;
810 default : value += c;
811 }
812 break;
813
814 default :
815 cerr << "ERROR unrecognized state " << state << endl;
816 }
817 }
818 label = rmWhiteSpaces(label);
819 }
820
821
822 class GTKUI : public UI
823 {
824 private :
825 static bool fInitialized;
826 static list<UI*> fGuiList;
827 static map<float*, float> fGuiSize; // map widget zone with widget size coef
828 static map<float*, string> fTooltip; // map widget zone with tooltip strings
829
830 protected :
831 GtkWidget* fWindow;
832 int fTop;
833 GtkWidget* fBox[stackSize];
834 int fMode[stackSize];
835 bool fStopped;
836
837 GtkWidget* addWidget(const char* label, GtkWidget* w);
838 virtual void pushBox(int mode, GtkWidget* w);
839
840
841 public :
842
843 static const gboolean expand = TRUE;
844 static const gboolean fill = TRUE;
845 static const gboolean homogene = FALSE;
846
847 GTKUI(char * name, int* pargc, char*** pargv);
848
849 // -- Labels and metadata
850
851 virtual void declare (float* zone, const char* key, const char* value);
852 virtual int checkLabelOptions (GtkWidget* widget, const string& fullLabel, string& simplifiedLabel);
853 virtual void checkForTooltip (float* zone, GtkWidget* widget);
854
855 // -- layout groups
856
857 virtual void openFrameBox(const char* label);
858 virtual void openTabBox(const char* label = "");
859 virtual void openHorizontalBox(const char* label = "");
860 virtual void openVerticalBox(const char* label = "");
861
862 // -- extra widget's layouts
863
864 virtual void openDialogBox(const char* label, float* zone);
865 virtual void openEventBox(const char* label = "");
866 virtual void openHandleBox(const char* label = "");
867 virtual void openExpanderBox(const char* label, float* zone);
868
869 virtual void closeBox();
870 virtual void adjustStack(int n);
871
872 // -- active widgets
873
874 virtual void addButton(const char* label, float* zone);
875 virtual void addToggleButton(const char* label, float* zone);
876 virtual void addCheckButton(const char* label, float* zone);
877 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
878 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
879 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
880
881 // -- passive display widgets
882
883 virtual void addNumDisplay(const char* label, float* zone, int precision);
884 virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max);
885 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
886 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
887
888 virtual void show();
889 virtual void run();
890
891 };
892
893
894
895 /******************************************************************************
896 *******************************************************************************
897
898 GRAPHIC USER INTERFACE (v2)
899 gtk implementation
900
901 *******************************************************************************
902 *******************************************************************************/
903
904 // global static fields
905
906 list<UI*> UI::fGuiList;
907
908 bool GTKUI::fInitialized = false;
909 map<float*, float> GTKUI::fGuiSize;
910 map<float*, string> GTKUI::fTooltip;
911
912
913
914 static gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
915 {
916 return FALSE;
917 }
918
919 static void destroy_event( GtkWidget *widget, gpointer data )
920 {
921 gtk_main_quit ();
922 }
923
924
925 GTKUI::GTKUI(char * name, int* pargc, char*** pargv)
926 {
927 if (!fInitialized) {
928 gtk_init(pargc, pargv);
929 fInitialized = true;
930 }
931
932 fWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
933 //gtk_container_set_border_width (GTK_CONTAINER (fWindow), 10);
934 gtk_window_set_title (GTK_WINDOW (fWindow), name);
935 gtk_signal_connect (GTK_OBJECT (fWindow), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL);
936 gtk_signal_connect (GTK_OBJECT (fWindow), "destroy", GTK_SIGNAL_FUNC (destroy_event), NULL);
937
938 fTop = 0;
939 fBox[fTop] = gtk_vbox_new (homogene, 4);
940 fMode[fTop] = kBoxMode;
941 gtk_container_add (GTK_CONTAINER (fWindow), fBox[fTop]);
942 fStopped = false;
943 }
944
945 // empilement des boites
946
947 void GTKUI::pushBox(int mode, GtkWidget* w)
948 {
949 ++fTop;
950 assert(fTop < stackSize);
951 fMode[fTop] = mode;
952 fBox[fTop] = w;
953 }
954
955
956 /**
957 * Remove n levels from the stack S before the top level
958 * adjustStack(n): S -> S' with S' = S(0),S(n+1),S(n+2),...
959 */
960 void GTKUI::adjustStack(int n)
961 {
962 if (n > 0) {
963 assert(fTop >= n);
964
965 fTop -= n;
966 fMode[fTop] = fMode[fTop+n];
967 fBox[fTop] = fBox[fTop+n];
968 }
969 }
970
971 void GTKUI::closeBox()
972 {
973 --fTop;
974 assert(fTop >= 0);
975 }
976
977
978 /**
979 * Analyses the widget zone metadata declarations and takes
980 * appropriate actions
981 */
982 void GTKUI::declare(float* zone, const char* key, const char* value)
983 {
984 if (strcmp(key,"size")==0) {
985 fGuiSize[zone]=atof(value);
986 }
987 else if (strcmp(key,"tooltip")==0) {
988 fTooltip[zone] = value ;
989 }
990 }
991
992
993
994 /**
995 * Analyses a full label and activates the relevant options. returns a simplified
996 * label (without options) and an amount of stack adjustement (in case additional
997 * containers were pushed on the stack).
998 */
999
1000 int GTKUI::checkLabelOptions(GtkWidget* widget, const string& fullLabel, string& simplifiedLabel)
1001 {
1002 map<string, string> metadata;
1003 extractMetadata(fullLabel, simplifiedLabel, metadata);
1004
1005 if (metadata.count("tooltip")) {
1006 gtk_tooltips_set_tip (gtk_tooltips_new (), widget, metadata["tooltip"].c_str(), NULL);
1007 }
1008 if (metadata["option"] == "detachable") {
1009 openHandleBox(simplifiedLabel.c_str());
1010 return 1;
1011 }
1012
1013 // no adjustement of the stack needed
1014 return 0;
1015 }
1016
1017 /**
1018 * Check if a tooltip is associated to a zone and add it to the corresponding widget
1019 */
1020 void GTKUI::checkForTooltip(float* zone, GtkWidget* widget)
1021 {
1022 if (fTooltip.count(zone)) {
1023 gtk_tooltips_set_tip (gtk_tooltips_new (), widget, fTooltip[zone].c_str(), NULL);
1024 }
1025 }
1026
1027
1028 // les differentes boites
1029
1030 void GTKUI::openFrameBox(const char* label)
1031 {
1032 GtkWidget * box = gtk_frame_new (label);
1033 //gtk_container_set_border_width (GTK_CONTAINER (box), 10);
1034
1035 pushBox(kSingleMode, addWidget(label, box));
1036 }
1037
1038
1039 void GTKUI::openTabBox(const char* fullLabel)
1040 {
1041 string label;
1042 GtkWidget* widget = gtk_notebook_new();
1043
1044 int adjust = checkLabelOptions(widget, fullLabel, label);
1045
1046 pushBox(kTabMode, addWidget(label.c_str(), widget));
1047
1048 // adjust stack because otherwise Handlebox will remain open
1049 adjustStack(adjust);
1050 }
1051
1052
1053 void GTKUI::openHorizontalBox(const char* fullLabel)
1054 {
1055 string label;
1056 GtkWidget* box = gtk_hbox_new (homogene, 4);
1057 int adjust = checkLabelOptions(box, fullLabel, label);
1058
1059 gtk_container_set_border_width (GTK_CONTAINER (box), 10);
1060
1061 if (fMode[fTop] != kTabMode && label[0] != 0) {
1062 GtkWidget * frame = addWidget(label.c_str(), gtk_frame_new (label.c_str()));
1063 gtk_container_add (GTK_CONTAINER(frame), box);
1064 gtk_widget_show(box);
1065 pushBox(kBoxMode, box);
1066 } else {
1067 pushBox(kBoxMode, addWidget(label.c_str(), box));
1068 }
1069
1070 // adjust stack because otherwise Handlebox will remain open
1071 adjustStack(adjust);
1072 }
1073
1074
1075 void GTKUI::openVerticalBox(const char* fullLabel)
1076 {
1077 string label;
1078 GtkWidget * box = gtk_vbox_new (homogene, 4);
1079 int adjust = checkLabelOptions(box, fullLabel, label);
1080
1081 gtk_container_set_border_width (GTK_CONTAINER (box), 10);
1082
1083 if (fMode[fTop] != kTabMode && label[0] != 0) {
1084 GtkWidget * frame = addWidget(label.c_str(), gtk_frame_new (label.c_str()));
1085 gtk_container_add (GTK_CONTAINER(frame), box);
1086 gtk_widget_show(box);
1087 pushBox(kBoxMode, box);
1088 } else {
1089 pushBox(kBoxMode, addWidget(label.c_str(), box));
1090 }
1091
1092 // adjust stack because otherwise Handlebox will remain open
1093 adjustStack(adjust);
1094 }
1095
1096
1097 void GTKUI::openHandleBox(const char* label)
1098 {
1099 GtkWidget * box = gtk_hbox_new (homogene, 4);
1100 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
1101 if (fMode[fTop] != kTabMode && label[0] != 0)
1102 {
1103 GtkWidget * frame = addWidget(label, gtk_handle_box_new ());
1104 gtk_container_add (GTK_CONTAINER(frame), box);
1105 gtk_widget_show(box);
1106 pushBox(kBoxMode, box);
1107 }
1108 else
1109 {
1110 pushBox(kBoxMode, addWidget(label, box));
1111 }
1112 }
1113
1114
1115 void GTKUI::openEventBox(const char* label)
1116 {
1117 GtkWidget * box = gtk_hbox_new (homogene, 4);
1118 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
1119 if (fMode[fTop] != kTabMode && label[0] != 0)
1120 {
1121 GtkWidget * frame = addWidget(label, gtk_event_box_new ());
1122 gtk_container_add (GTK_CONTAINER(frame), box);
1123 gtk_widget_show(box);
1124 pushBox(kBoxMode, box);
1125 }
1126 else
1127 {
1128 pushBox(kBoxMode, addWidget(label, box));
1129 }
1130 }
1131
1132
1133 struct uiExpanderBox : public uiItem
1134 {
1135 GtkExpander* fButton;
1136 uiExpanderBox(UI* ui, float* zone, GtkExpander* b) : uiItem(ui, zone), fButton(b) {}
1137 static void expanded (GtkWidget *widget, gpointer data)
1138 {
1139 float v = gtk_expander_get_expanded (GTK_EXPANDER(widget));
1140 if (v == 1.000000)
1141 {
1142 v = 0;
1143 }
1144 else v = 1;
1145 ((uiItem*)data)->modifyZone(v);
1146 }
1147
1148 virtual void reflectZone()
1149 {
1150 float v = *fZone;
1151 fCache = v;
1152 gtk_expander_set_expanded(GTK_EXPANDER(fButton), v);
1153 }
1154 };
1155
1156 void GTKUI::openExpanderBox(const char* label, float* zone)
1157 {
1158 *zone = 0.0;
1159 GtkWidget * box = gtk_hbox_new (homogene, 4);
1160 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
1161 if (fMode[fTop] != kTabMode && label[0] != 0)
1162 {
1163 GtkWidget * frame = addWidget(label, gtk_expander_new (label));
1164 gtk_container_add (GTK_CONTAINER(frame), box);
1165 uiExpanderBox* c = new uiExpanderBox(this, zone, GTK_EXPANDER(frame));
1166 gtk_signal_connect (GTK_OBJECT (frame), "activate", GTK_SIGNAL_FUNC (uiExpanderBox::expanded), (gpointer)c);
1167 gtk_widget_show(box);
1168 pushBox(kBoxMode, box);
1169 }
1170 else
1171 {
1172 pushBox(kBoxMode, addWidget(label, box));
1173 }
1174 }
1175
1176
1177
1178 GtkWidget* GTKUI::addWidget(const char* label, GtkWidget* w)
1179 {
1180 switch (fMode[fTop]) {
1181 case kSingleMode : gtk_container_add (GTK_CONTAINER(fBox[fTop]), w); break;
1182 case kBoxMode : gtk_box_pack_start (GTK_BOX(fBox[fTop]), w, expand, fill, 0); break;
1183 case kTabMode : gtk_notebook_append_page (GTK_NOTEBOOK(fBox[fTop]), w, gtk_label_new(label)); break;
1184 }
1185 gtk_widget_show (w);
1186 return w;
1187 }
1188
1189 // --------------------------- Press button ---------------------------
1190
1191 struct uiButton : public uiItem
1192 {
1193 GtkButton* fButton;
1194
1195 uiButton (UI* ui, float* zone, GtkButton* b) : uiItem(ui, zone), fButton(b) {}
1196
1197 static void pressed( GtkWidget *widget, gpointer data )
1198 {
1199 uiItem* c = (uiItem*) data;
1200 c->modifyZone(1.0);
1201 }
1202
1203 static void released( GtkWidget *widget, gpointer data )
1204 {
1205 uiItem* c = (uiItem*) data;
1206 c->modifyZone(0.0);
1207 }
1208
1209 virtual void reflectZone()
1210 {
1211 float v = *fZone;
1212 fCache = v;
1213 if (v > 0.0) gtk_button_pressed(fButton); else gtk_button_released(fButton);
1214 }
1215 };
1216
1217 void GTKUI::addButton(const char* label, float* zone)
1218 {
1219 *zone = 0.0;
1220 GtkWidget* button = gtk_button_new_with_label (label);
1221 addWidget(label, button);
1222
1223 uiButton* c = new uiButton(this, zone, GTK_BUTTON(button));
1224
1225 gtk_signal_connect (GTK_OBJECT (button), "pressed", GTK_SIGNAL_FUNC (uiButton::pressed), (gpointer) c);
1226 gtk_signal_connect (GTK_OBJECT (button), "released", GTK_SIGNAL_FUNC (uiButton::released), (gpointer) c);
1227
1228 checkForTooltip(zone, button);
1229 }
1230
1231 // --------------------------- Toggle Buttons ---------------------------
1232
1233 struct uiToggleButton : public uiItem
1234 {
1235 GtkToggleButton* fButton;
1236
1237 uiToggleButton(UI* ui, float* zone, GtkToggleButton* b) : uiItem(ui, zone), fButton(b) {}
1238
1239 static void toggled (GtkWidget *widget, gpointer data)
1240 {
1241 float v = (GTK_TOGGLE_BUTTON (widget)->active) ? 1.0 : 0.0;
1242 ((uiItem*)data)->modifyZone(v);
1243 }
1244
1245 virtual void reflectZone()
1246 {
1247 float v = *fZone;
1248 fCache = v;
1249 gtk_toggle_button_set_active(fButton, v > 0.0);
1250 }
1251 };
1252
1253 void GTKUI::addToggleButton(const char* label, float* zone)
1254 {
1255 *zone = 0.0;
1256 GtkWidget* button = gtk_toggle_button_new_with_label (label);
1257 addWidget(label, button);
1258
1259 uiToggleButton* c = new uiToggleButton(this, zone, GTK_TOGGLE_BUTTON(button));
1260 gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (uiToggleButton::toggled), (gpointer) c);
1261
1262 checkForTooltip(zone, button);
1263 }
1264
1265
1266
1267 void show_dialog(GtkWidget *widget, gpointer data)
1268 {
1269 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == TRUE)
1270 {
1271 gtk_widget_show(GTK_WIDGET(data));
1272 gint root_x, root_y;
1273 gtk_window_get_position (GTK_WINDOW(data), &root_x, &root_y);
1274 root_y -= 120;
1275 gtk_window_move(GTK_WINDOW(data), root_x, root_y);
1276 }
1277 else gtk_widget_hide(GTK_WIDGET(data));
1278 }
1279
1280 static gboolean deleteevent( GtkWidget *widget, gpointer data )
1281 {
1282 return TRUE;
1283 }
1284
1285 void GTKUI::openDialogBox(const char* label, float* zone)
1286 {
1287 // create toplevel window and set properties
1288 GtkWidget * dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1289 gtk_window_set_decorated(GTK_WINDOW(dialog), TRUE);
1290 gtk_window_set_deletable(GTK_WINDOW(dialog), FALSE);
1291 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1292 gtk_window_set_gravity(GTK_WINDOW(dialog), GDK_GRAVITY_SOUTH);
1293 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(fWindow));
1294 gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
1295 gtk_window_set_keep_below (GTK_WINDOW(dialog), FALSE);
1296 gtk_window_set_title (GTK_WINDOW (dialog), label);
1297 g_signal_connect (G_OBJECT (dialog), "delete_event", G_CALLBACK (deleteevent), NULL);
1298 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
1299
1300 GtkWidget * box = gtk_hbox_new (homogene, 4);
1301
1302 *zone = 0.0;
1303 GtkWidget* button = gtk_toggle_button_new ();
1304 gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (show_dialog), (gpointer) dialog);
1305
1306 gtk_container_add (GTK_CONTAINER(fBox[fTop]), button);
1307 gtk_container_add (GTK_CONTAINER(dialog), box);
1308 gtk_widget_show (button);
1309 gtk_widget_show(box);
1310 pushBox(kBoxMode, box);
1311 }
1312
1313
1314
1315
1316 // --------------------------- Check Button ---------------------------
1317
1318 struct uiCheckButton : public uiItem
1319 {
1320 GtkToggleButton* fButton;
1321
1322 uiCheckButton(UI* ui, float* zone, GtkToggleButton* b) : uiItem(ui, zone), fButton(b) {}
1323
1324 static void toggled (GtkWidget *widget, gpointer data)
1325 {
1326 float v = (GTK_TOGGLE_BUTTON (widget)->active) ? 1.0 : 0.0;
1327 ((uiItem*)data)->modifyZone(v);
1328 }
1329
1330 virtual void reflectZone()
1331 {
1332 float v = *fZone;
1333 fCache = v;
1334 gtk_toggle_button_set_active(fButton, v > 0.0);
1335 }
1336 };
1337
1338 void GTKUI::addCheckButton(const char* label, float* zone)
1339 {
1340 *zone = 0.0;
1341 GtkWidget* button = gtk_check_button_new_with_label (label);
1342 addWidget(label, button);
1343
1344 uiCheckButton* c = new uiCheckButton(this, zone, GTK_TOGGLE_BUTTON(button));
1345 gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC(uiCheckButton::toggled), (gpointer) c);
1346
1347 checkForTooltip(zone, button);
1348 }
1349
1350
1351 // --------------------------- Adjustmenty based widgets ---------------------------
1352
1353 struct uiAdjustment : public uiItem
1354 {
1355 GtkAdjustment* fAdj;
1356
1357 uiAdjustment(UI* ui, float* zone, GtkAdjustment* adj) : uiItem(ui, zone), fAdj(adj) {}
1358
1359 static void changed (GtkWidget *widget, gpointer data)
1360 {
1361 float v = GTK_ADJUSTMENT (widget)->value;
1362 ((uiItem*)data)->modifyZone(v);
1363 }
1364
1365 virtual void reflectZone()
1366 {
1367 float v = *fZone;
1368 fCache = v;
1369 gtk_adjustment_set_value(fAdj, v);
1370 }
1371 };
1372
1373 static int precision(double n)
1374 {
1375 if (n < 0.009999) return 3;
1376 else if (n < 0.099999) return 2;
1377 else if (n < 0.999999) return 1;
1378 else return 0;
1379 }
1380
1381 // -------------------------- Vertical Slider -----------------------------------
1382
1383 void GTKUI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
1384 {
1385 *zone = init;
1386 GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, 0);
1387
1388 uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj));
1389
1390 gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c);
1391
1392 GtkWidget* slider = gtk_vscale_new (GTK_ADJUSTMENT(adj));
1393 gtk_range_set_inverted (GTK_RANGE(slider), TRUE);
1394 gtk_scale_set_digits(GTK_SCALE(slider), precision(step));
1395 float size = 160 * pow(2, fGuiSize[zone]);
1396 gtk_widget_set_usize(slider, -1, size);
1397
1398 if (label && label[0]!=0) {
1399 openFrameBox(label);
1400 addWidget(label, slider);
1401 closeBox();
1402 } else {
1403 addWidget(label, slider);
1404 }
1405
1406 checkForTooltip(zone, slider);
1407 }
1408
1409 // -------------------------- Horizontal Slider -----------------------------------
1410
1411 void GTKUI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
1412 {
1413 *zone = init;
1414 GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, 0);
1415
1416 uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj));
1417
1418 gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c);
1419
1420 GtkWidget* slider = gtk_hscale_new (GTK_ADJUSTMENT(adj));
1421 gtk_scale_set_digits(GTK_SCALE(slider), precision(step));
1422 float size = 160 * pow(2, fGuiSize[zone]);
1423 gtk_widget_set_usize(slider, size, -1);
1424
1425 if (label && label[0]!=0) {
1426 openFrameBox(label);
1427 addWidget(label, slider);
1428 closeBox();
1429 } else {
1430 addWidget(label, slider);
1431 }
1432
1433 checkForTooltip(zone, slider);
1434 }
1435
1436
1437 // ------------------------------ Num Entry -----------------------------------
1438
1439 void GTKUI::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
1440 {
1441 *zone = init;
1442 GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, step);
1443
1444 uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj));
1445
1446 gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c);
1447
1448 GtkWidget* spinner = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 0.005, precision(step));
1449
1450 //gtk_widget_set_usize(slider, 160, -1);
1451 openFrameBox(label);
1452 addWidget(label, spinner);
1453 closeBox();
1454
1455 checkForTooltip(zone, spinner);
1456 }
1457
1458
1459 // ========================== passive widgets ===============================
1460
1461
1462 // ------------------------------ Progress Bar -----------------------------------
1463
1464 struct uiBargraph : public uiItem
1465 {
1466 GtkProgressBar* fProgressBar;
1467 float fMin;
1468 float fMax;
1469
1470 uiBargraph(UI* ui, float* zone, GtkProgressBar* pbar, float lo, float hi)
1471 : uiItem(ui, zone), fProgressBar(pbar), fMin(lo), fMax(hi) {}
1472
1473 float scale(float v) { return (v-fMin)/(fMax-fMin); }
1474
1475 virtual void reflectZone()
1476 {
1477 float v = *fZone;
1478 fCache = v;
1479 gtk_progress_bar_set_fraction(fProgressBar, scale(v));
1480 }
1481 };
1482
1483
1484
1485 void GTKUI::addVerticalBargraph(const char* label, float* zone, float lo, float hi)
1486 {
1487 GtkWidget* pb = gtk_progress_bar_new();
1488 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb), GTK_PROGRESS_BOTTOM_TO_TOP);
1489 gtk_widget_set_size_request(pb, 8, -1);
1490 new uiBargraph(this, zone, GTK_PROGRESS_BAR(pb), lo, hi);
1491 openFrameBox(label);
1492 addWidget(label, pb);
1493 closeBox();
1494
1495 checkForTooltip(zone, pb);
1496 }
1497
1498
1499 void GTKUI::addHorizontalBargraph(const char* label, float* zone, float lo, float hi)
1500 {
1501 GtkWidget* pb = gtk_progress_bar_new();
1502 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb), GTK_PROGRESS_LEFT_TO_RIGHT);
1503 gtk_widget_set_size_request(pb, -1, 8);
1504 new uiBargraph(this, zone, GTK_PROGRESS_BAR(pb), lo, hi);
1505 openFrameBox(label);
1506 addWidget(label, pb);
1507 closeBox();
1508
1509 checkForTooltip(zone, pb);
1510 }
1511
1512
1513 // ------------------------------ Num Display -----------------------------------
1514
1515 struct uiNumDisplay : public uiItem
1516 {
1517 GtkLabel* fLabel;
1518 int fPrecision;
1519
1520 uiNumDisplay(UI* ui, float* zone, GtkLabel* label, int precision)
1521 : uiItem(ui, zone), fLabel(label), fPrecision(precision) {}
1522
1523 virtual void reflectZone()
1524 {
1525 float v = *fZone;
1526 fCache = v;
1527 char s[64];
1528 if (fPrecision <= 0) {
1529 snprintf(s, 63, "%d", int(v));
1530 } else if (fPrecision>3) {
1531 snprintf(s, 63, "%f", v);
1532 } else {
1533 const char* format[] = {"%.1f", "%.2f", "%.3f"};
1534 snprintf(s, 63, format[fPrecision-1], v);
1535 }
1536 gtk_label_set_text(fLabel, s);
1537 }
1538 };
1539
1540
1541 void GTKUI::addNumDisplay(const char* label, float* zone, int precision )
1542 {
1543 GtkWidget* lw = gtk_label_new("");
1544 new uiNumDisplay(this, zone, GTK_LABEL(lw), precision);
1545 openFrameBox(label);
1546 addWidget(label, lw);
1547 closeBox();
1548
1549 checkForTooltip(zone, lw);
1550 }
1551
1552
1553 // ------------------------------ Text Display -----------------------------------
1554
1555 struct uiTextDisplay : public uiItem
1556 {
1557 GtkLabel* fLabel;
1558 const char** fNames;
1559 float fMin;
1560 float fMax;
1561 int fNum;
1562
1563
1564 uiTextDisplay (UI* ui, float* zone, GtkLabel* label, const char* names[], float lo, float hi)
1565 : uiItem(ui, zone), fLabel(label), fNames(names), fMin(lo), fMax(hi)
1566 {
1567 fNum = 0;
1568 while (fNames[fNum] != 0) fNum++;
1569 }
1570
1571 virtual void reflectZone()
1572 {
1573 float v = *fZone;
1574 fCache = v;
1575
1576 int idx = int(fNum*(v-fMin)/(fMax-fMin));
1577
1578 if (idx < 0) idx = 0;
1579 else if (idx >= fNum) idx = fNum-1;
1580
1581 gtk_label_set_text(fLabel, fNames[idx]);
1582 }
1583 };
1584
1585
1586 void GTKUI::addTextDisplay(const char* label, float* zone, const char* names[], float lo, float hi )
1587 {
1588 GtkWidget* lw = gtk_label_new("");
1589 new uiTextDisplay (this, zone, GTK_LABEL(lw), names, lo, hi);
1590 openFrameBox(label);
1591 addWidget(label, lw);
1592 closeBox();
1593
1594 checkForTooltip(zone, lw);
1595 }
1596
1597
1598
1599 void GTKUI::show()
1600 {
1601 assert(fTop == 0);
1602 gtk_widget_show (fBox[0]);
1603 gtk_widget_show (fWindow);
1604 }
1605
1606
1607 /**
1608 * Update all user items reflecting zone z
1609 */
1610
1611 static gboolean callUpdateAllGuis(gpointer)
1612 {
1613 UI::updateAllGuis();
1614 return TRUE;
1615 }
1616
1617
1618 void GTKUI::run()
1619 {
1620 assert(fTop == 0);
1621 gtk_widget_show (fBox[0]);
1622 gtk_widget_show (fWindow);
1623 gtk_timeout_add(40, callUpdateAllGuis, 0);
1624 gtk_main ();
1625 stop();
1626 }
1627
1628
1629
1630
1631 /******************************************************************************
1632 *******************************************************************************
1633
1634 DSP
1635
1636 *******************************************************************************
1637 *******************************************************************************/
1638
1639
1640 //---------------------------------------------------
1641 // tableaux de buffers initialis� par allocChannels
1642 //---------------------------------------------------
1643
1644 float* gInChannel[256];
1645 float* gOutChannel[256];
1646
1647 void allocChannels (int size, int numInChan, int numOutChan)
1648 {
1649
1650 assert (numInChan < 256);
1651 assert (numOutChan < 256);
1652
1653
1654 for (int i = 0; i < numInChan; i++) {
1655 gInChannel[i] = (float*) calloc (size, sizeof(float));
1656 for (int j = 0; j < size; j++) {
1657 gInChannel[i][j] = 0.0;
1658 }
1659 }
1660
1661 for (int i = 0; i < numOutChan; i++) {
1662 gOutChannel[i] = (float*) calloc (size, sizeof(float));
1663 for (int j = 0; j < size; j++) {
1664 gOutChannel[i][j] = 0.0;
1665 }
1666 }
1667 }
1668
1669
1670
1671 //----------------------------------------------------------------
1672 // d�inition du processeur de signal
1673 //----------------------------------------------------------------
1674
1675 class dsp {
1676 protected:
1677 int fSamplingFreq;
1678 public:
1679 dsp() {}
1680 virtual ~dsp() {}
1681
1682 virtual int getNumInputs() = 0;
1683 virtual int getNumOutputs() = 0;
1684 virtual void buildUserInterface(UI* interface) = 0;
1685 virtual void init(int samplingRate) = 0;
1686 virtual void compute(int len, float** inputs, float** outputs) = 0;
1687 };
1688
1689
1690
1691 /********************END ARCHITECTURE SECTION (part 1/2)****************/
1692
1693 /**************************BEGIN USER SECTION **************************/
1694
1695 <<includeclass>>
1696
1697 /***************************END USER SECTION ***************************/
1698
1699 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
1700
1701
1702 mydsp DSP;
1703
1704
1705
1706
1707 /******************************************************************************
1708 *******************************************************************************
1709
1710 MAIN PLAY THREAD
1711
1712 *******************************************************************************
1713 *******************************************************************************/
1714
1715 // Scan Command Line Arguments
1716
1717 long lopt (char *argv[], const char *name, long def)
1718 {
1719 int i;
1720 for (i=0; argv[i]; i++) if (!strcmp(argv[i], name)) return atoi(argv[i+1]);
1721 return def;
1722 }
1723
1724
1725 //-------------------------------------------------------------------------
1726 // MAIN
1727 //-------------------------------------------------------------------------
1728 pthread_t guithread;
1729
1730 void* run_ui(void* ptr)
1731 {
1732 UI* interface = (UI*) ptr;
1733 interface->run();
1734 pthread_exit(0);
1735 return 0;
1736 }
1737
1738 int main(int argc, char *argv[] )
1739 {
1740 UI* interface = new GTKUI(argv[0], &argc, &argv);
1741 // compute rcfilename to (re)store application state
1742 char rcfilename[256];
1743 char* home = getenv("HOME");
1744 snprintf(rcfilename, 255, "%s/.%src", home, basename(argv[0]));
1745
1746 AudioInterface audio (
1747 AudioParam().frequency(lopt(argv, "--frequency", 44100))
1748 .buffering(lopt(argv, "--buffer", 128))
1749 //.mode( ((DSP.getNumInputs()>0)?kRead:0) | ((DSP.getNumOutputs()>0)?kWrite:0) )
1750 );
1751 audio.open();
1752 audio.info();
1753
1754 DSP.init(audio.getSamplingFrequency());
1755 DSP.buildUserInterface(interface);
1756
1757 interface->recallState(rcfilename);
1758
1759 pthread_create(&guithread, NULL, run_ui, interface);
1760
1761 float* inChannel[256];
1762 float* outChannel[256];
1763 int fpb = audio.getFramesPerBuffer();
1764
1765 audio.allocChanGroup(inChannel, max(audio.getNumInputs(), DSP.getNumInputs()), fpb);
1766 audio.allocChanGroup(outChannel, max(audio.getNumOutputs(), DSP.getNumOutputs()), fpb);
1767 setRealtimePriority();
1768 AVOIDDENORMALS;
1769 // Sound processing loop
1770 audio.write(fpb, outChannel);
1771 audio.write(fpb, outChannel);
1772 while(!interface->stopped()) {
1773 if ( !audio.write(fpb, outChannel)) printf("w");
1774 if ( !audio.read (fpb, inChannel)) printf("r");;
1775 STARTMESURE
1776 DSP.compute(fpb, inChannel, outChannel);
1777 STOPMESURE
1778 }
1779
1780 audio.close();
1781 interface->saveState(rcfilename);
1782
1783 #ifdef BENCHMARKMODE
1784 printstats();
1785 #endif
1786 //wait(0);
1787 return 0;
1788 }
1789
1790 /********************END ARCHITECTURE SECTION (part 2/2)****************/
1791
1792