10 #include <sys/ioctl.h>
14 #include <sys/types.h>
27 #include <AudioToolbox/AudioConverter.h>
28 #include <CoreAudio/CoreAudio.h>
29 #include <AudioUnit/AudioUnit.h>
30 #include <CoreServices/CoreServices.h>
35 // handle 32/64 bits int size issues
39 #define uint32 unsigned int
40 #define uint64 unsigned long int
43 #define int64 long int
47 #define uint32 unsigned int
48 #define uint64 unsigned long long int
51 #define int64 long long int
54 // check 32/64 bits issues are correctly handled
56 #define CHECKINTSIZE \
57 assert(sizeof(int32)==4);\
58 assert(sizeof(int64)==8);
63 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
64 // flags to avoid costly denormals
66 #include <xmmintrin.h>
68 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
70 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
73 #define AVOIDDENORMALS
76 //#define BENCHMARKMODE
78 // g++ -Wall -O3 -lm -lpthread -lasound `gtk-config --cflags --libs` test.cpp -o test
80 #define check_error(err) if (err) { printf("%s:%d, alsa error %d : %s\n", __FILE__, __LINE__, err, snd_strerror(err)); exit(1); }
81 #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); }
82 #define display_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); }
84 #define max(x,y) (((x)>(y)) ? (x) : (y))
85 #define min(x,y) (((x)<(y)) ? (x) : (y))
87 // abs is now predefined
88 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
91 inline int lsr (int x
, int n
) { return int(((unsigned int)x
) >> n
); }
94 inline int int2pow2 (int x
) { int r
=0; while ((1<<r
)<x
) r
++; return r
; }
97 /******************************************************************************
98 *******************************************************************************
102 *******************************************************************************
103 *******************************************************************************/
105 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
106 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
111 #define BENCHMARKMODE
116 * Returns the number of clock cycles elapsed since the last reset
119 static __inline__ uint64
rdtsc(void)
126 __asm__
__volatile__("rdtsc" : "=a" (count
.i32
[0]), "=d" (count
.i32
[1]));
136 // these values are used to determine the number of clocks in a second
140 // these tables contains the last KMESURE in clocks
141 uint64 starts
[KMESURE
];
142 uint64 stops
[KMESURE
];
144 #define STARTMESURE starts[mesure%KMESURE] = rdtsc();
145 #define STOPMESURE stops[mesure%KMESURE] = rdtsc(); mesure = mesure+1;
153 gettimeofday(&tv1
, &tz
);
154 firstRDTSC
= rdtsc();
160 gettimeofday(&tv2
, &tz
);
165 * return the number of RDTSC clocks per seconds
169 // If the environment variable CLOCKSPERSEC is defined
170 // we use it instead of our own measurement
171 char* str
= getenv("CLOCKSPERSEC");
173 int64 cps
= (int64
) atoll(str
);
174 if (cps
> 1000000000) {
177 return (lastRDTSC
-firstRDTSC
) / (tv2
.tv_sec
- tv1
.tv_sec
) ;
180 return (lastRDTSC
-firstRDTSC
) / (tv2
.tv_sec
- tv1
.tv_sec
) ;
186 * Converts a duration, expressed in RDTSC clocks, into seconds
188 double rdtsc2sec( uint64 clk
)
190 return double(clk
) / double(rdtscpersec());
193 double rdtsc2sec( double clk
)
195 return clk
/ double(rdtscpersec());
200 * Converts RDTSC clocks into Megabytes/seconds according to the
201 * number of frames processed during the period, the number of channels
202 * and 4 bytes samples.
204 double megapersec(int frames
, int chans
, uint64 clk
)
206 return double(frames
*chans
*4)/double(1024*1024*rdtsc2sec(clk
));
211 * Compute the mean value of a vector of measures
213 static uint64
meanValue( vector
<uint64
>::const_iterator a
, vector
<uint64
>::const_iterator b
)
217 while (a
!=b
) { r
+= *a
++; n
++; }
218 return (n
>0) ? r
/n
: 0;
222 * Print the median value (in Megabytes/second) of KMESURE
223 * throughputs measurements
225 void printstats(const char* applname
, int bsize
, int ichans
, int ochans
)
227 assert(mesure
> KMESURE
);
228 vector
<uint64
> V(KMESURE
);
230 for (int i
= 0; i
<KMESURE
; i
++) {
231 V
[i
] = stops
[i
] - starts
[i
];
234 sort(V
.begin(), V
.end());
236 // Mean of 10 best values (gives relatively stable results)
237 uint64 meavalx
= meanValue(V
.begin(), V
.begin() + 10);
240 cout
<< megapersec(bsize
, ichans
+ochans
, meavalx
) << "\tMB/s"
242 << '\t' << "(clocks/sec : " << rdtscpersec() << ")"
256 /******************************************************************************
257 *******************************************************************************
259 GRAPHIC USER INTERFACE (v2)
262 *******************************************************************************
263 *******************************************************************************/
270 struct Meta
: map
<const char*, const char*>
272 void declare (const char* key
, const char* value
) { (*this)[key
]=value
; }
277 typedef void (*uiCallback
)(float val
, void* data
);
280 * Graphic User Interface : abstract definition
285 typedef list
<uiItem
*> clist
;
286 typedef map
<float*, clist
*> zmap
;
289 static list
<UI
*> fGuiList
;
295 UI() : fStopped(false) {
296 fGuiList
.push_back(this);
300 // suppression de this dans fGuiList
303 // -- zone management
305 void registerZone(float* z
, uiItem
* c
)
307 if (fZoneMap
.find(z
) == fZoneMap
.end()) fZoneMap
[z
] = new clist();
308 fZoneMap
[z
]->push_back(c
);
311 // -- saveState(filename) : save the value of every zone to a file
313 void saveState(const char* filename
)
315 ofstream
f(filename
);
317 for (zmap::iterator i
=fZoneMap
.begin(); i
!=fZoneMap
.end(); i
++) {
318 f
<< *(i
->first
) << ' ';
325 // -- recallState(filename) : load the value of every zone from a file
327 void recallState(const char* filename
)
329 ifstream
f(filename
);
331 for (zmap::iterator i
=fZoneMap
.begin(); i
!=fZoneMap
.end(); i
++) {
338 void updateAllZones();
340 void updateZone(float* z
);
342 static void updateAllGuis()
344 list
<UI
*>::iterator g
;
345 for (g
= fGuiList
.begin(); g
!= fGuiList
.end(); g
++) {
346 (*g
)->updateAllZones();
352 virtual void addButton(const char* label
, float* zone
) = 0;
353 virtual void addToggleButton(const char* label
, float* zone
) = 0;
354 virtual void addCheckButton(const char* label
, float* zone
) = 0;
355 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
356 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
357 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
359 // -- passive widgets
361 virtual void addNumDisplay(const char* label
, float* zone
, int precision
) = 0;
362 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
) = 0;
363 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
) = 0;
364 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
) = 0;
366 void addCallback(float* zone
, uiCallback foo
, void* data
);
368 // -- widget's layouts
370 virtual void openFrameBox(const char* label
) = 0;
371 virtual void openTabBox(const char* label
) = 0;
372 virtual void openHorizontalBox(const char* label
) = 0;
373 virtual void openVerticalBox(const char* label
) = 0;
374 virtual void closeBox() = 0;
376 virtual void show() = 0;
377 virtual void run() = 0;
379 void stop() { fStopped
= true; }
380 bool stopped() { return fStopped
; }
382 virtual void declare(float* zone
, const char* key
, const char* value
) {}
387 * User Interface Item: abstract definition
398 uiItem (UI
* ui
, float* zone
) : fGUI(ui
), fZone(zone
), fCache(-123456.654321)
400 ui
->registerZone(zone
, this);
408 void modifyZone(float v
)
413 fGUI
->updateZone(fZone
);
417 float cache() { return fCache
; }
418 virtual void reflectZone() = 0;
426 struct uiCallbackItem
: public uiItem
428 uiCallback fCallback
;
431 uiCallbackItem(UI
* ui
, float* zone
, uiCallback foo
, void* data
)
432 : uiItem(ui
, zone
), fCallback(foo
), fData(data
) {}
434 virtual void reflectZone() {
442 * Update all user items reflecting zone z
445 inline void UI::updateZone(float* z
)
448 clist
* l
= fZoneMap
[z
];
449 for (clist::iterator c
= l
->begin(); c
!= l
->end(); c
++) {
450 if ((*c
)->cache() != v
) (*c
)->reflectZone();
456 * Update all user items not up to date
459 inline void UI::updateAllZones()
461 for (zmap::iterator m
= fZoneMap
.begin(); m
!= fZoneMap
.end(); m
++) {
463 clist
* l
= m
->second
;
465 for (clist::iterator c
= l
->begin(); c
!= l
->end(); c
++) {
466 if ((*c
)->cache() != v
) (*c
)->reflectZone();
471 inline void UI::addCallback(float* zone
, uiCallback foo
, void* data
)
473 new uiCallbackItem(this, zone
, foo
, data
);
477 /******************************************************************************
478 *******************************************************************************
480 GRAPHIC USER INTERFACE
483 *******************************************************************************
484 *******************************************************************************/
488 #define stackSize 256
492 #define kSingleMode 0
497 class GTKUI
: public UI
500 static bool fInitialized
;
501 static list
<UI
*> fGuiList
;
506 GtkWidget
* fBox
[stackSize
];
507 int fMode
[stackSize
];
510 GtkWidget
* addWidget(const char* label
, GtkWidget
* w
);
511 virtual void pushBox(int mode
, GtkWidget
* w
);
516 static const gboolean expand
= TRUE
;
517 static const gboolean fill
= TRUE
;
518 static const gboolean homogene
= FALSE
;
520 GTKUI(char * name
, int* pargc
, char*** pargv
);
524 virtual void openFrameBox(const char* label
);
525 virtual void openTabBox(const char* label
= "");
526 virtual void openHorizontalBox(const char* label
= "");
527 virtual void openVerticalBox(const char* label
= "");
529 virtual void closeBox();
533 virtual void addButton(const char* label
, float* zone
);
534 virtual void addToggleButton(const char* label
, float* zone
);
535 virtual void addCheckButton(const char* label
, float* zone
);
536 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
537 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
538 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
540 // -- passive display widgets
542 virtual void addNumDisplay(const char* label
, float* zone
, int precision
);
543 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
);
544 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
);
545 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
);
554 /******************************************************************************
555 *******************************************************************************
557 GRAPHIC USER INTERFACE (v2)
560 *******************************************************************************
561 *******************************************************************************/
563 // global static fields
565 bool GTKUI::fInitialized
= false;
566 list
<UI
*> UI::fGuiList
;
570 static gint
delete_event( GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
575 static void destroy_event( GtkWidget
*widget
, gpointer data
)
581 GTKUI::GTKUI(char * name
, int* pargc
, char*** pargv
)
584 gtk_init(pargc
, pargv
);
588 fWindow
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
589 //gtk_container_set_border_width (GTK_CONTAINER (fWindow), 10);
590 gtk_window_set_title (GTK_WINDOW (fWindow
), name
);
591 gtk_signal_connect (GTK_OBJECT (fWindow
), "delete_event", GTK_SIGNAL_FUNC (delete_event
), NULL
);
592 gtk_signal_connect (GTK_OBJECT (fWindow
), "destroy", GTK_SIGNAL_FUNC (destroy_event
), NULL
);
595 fBox
[fTop
] = gtk_vbox_new (homogene
, 4);
596 fMode
[fTop
] = kBoxMode
;
597 gtk_container_add (GTK_CONTAINER (fWindow
), fBox
[fTop
]);
601 // empilement des boites
603 void GTKUI::pushBox(int mode
, GtkWidget
* w
)
605 assert(++fTop
< stackSize
);
610 void GTKUI::closeBox()
616 // les differentes boites
618 void GTKUI::openFrameBox(const char* label
)
620 GtkWidget
* box
= gtk_frame_new (label
);
621 //gtk_container_set_border_width (GTK_CONTAINER (box), 10);
623 pushBox(kSingleMode
, addWidget(label
, box
));
626 void GTKUI::openTabBox(const char* label
)
628 pushBox(kTabMode
, addWidget(label
, gtk_notebook_new ()));
631 void GTKUI::openHorizontalBox(const char* label
)
633 GtkWidget
* box
= gtk_hbox_new (homogene
, 4);
634 gtk_container_set_border_width (GTK_CONTAINER (box
), 10);
636 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0) {
637 GtkWidget
* frame
= addWidget(label
, gtk_frame_new (label
));
638 gtk_container_add (GTK_CONTAINER(frame
), box
);
639 gtk_widget_show(box
);
640 pushBox(kBoxMode
, box
);
642 pushBox(kBoxMode
, addWidget(label
, box
));
646 void GTKUI::openVerticalBox(const char* label
)
648 GtkWidget
* box
= gtk_vbox_new (homogene
, 4);
649 gtk_container_set_border_width (GTK_CONTAINER (box
), 10);
651 if (fMode
[fTop
] != kTabMode
&& label
[0] != 0) {
652 GtkWidget
* frame
= addWidget(label
, gtk_frame_new (label
));
653 gtk_container_add (GTK_CONTAINER(frame
), box
);
654 gtk_widget_show(box
);
655 pushBox(kBoxMode
, box
);
657 pushBox(kBoxMode
, addWidget(label
, box
));
661 GtkWidget
* GTKUI::addWidget(const char* label
, GtkWidget
* w
)
663 switch (fMode
[fTop
]) {
664 case kSingleMode
: gtk_container_add (GTK_CONTAINER(fBox
[fTop
]), w
); break;
665 case kBoxMode
: gtk_box_pack_start (GTK_BOX(fBox
[fTop
]), w
, expand
, fill
, 0); break;
666 case kTabMode
: gtk_notebook_append_page (GTK_NOTEBOOK(fBox
[fTop
]), w
, gtk_label_new(label
)); break;
672 // --------------------------- Press button ---------------------------
674 struct uiButton
: public uiItem
678 uiButton (UI
* ui
, float* zone
, GtkButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
680 static void pressed( GtkWidget
*widget
, gpointer data
)
682 uiItem
* c
= (uiItem
*) data
;
686 static void released( GtkWidget
*widget
, gpointer data
)
688 uiItem
* c
= (uiItem
*) data
;
692 virtual void reflectZone()
696 if (v
> 0.0) gtk_button_pressed(fButton
); else gtk_button_released(fButton
);
700 void GTKUI::addButton(const char* label
, float* zone
)
703 GtkWidget
* button
= gtk_button_new_with_label (label
);
704 addWidget(label
, button
);
706 uiButton
* c
= new uiButton(this, zone
, GTK_BUTTON(button
));
708 gtk_signal_connect (GTK_OBJECT (button
), "pressed", GTK_SIGNAL_FUNC (uiButton::pressed
), (gpointer
) c
);
709 gtk_signal_connect (GTK_OBJECT (button
), "released", GTK_SIGNAL_FUNC (uiButton::released
), (gpointer
) c
);
713 // --------------------------- Toggle Buttons ---------------------------
715 struct uiToggleButton
: public uiItem
717 GtkToggleButton
* fButton
;
719 uiToggleButton(UI
* ui
, float* zone
, GtkToggleButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
721 static void toggled (GtkWidget
*widget
, gpointer data
)
723 float v
= (GTK_TOGGLE_BUTTON (widget
)->active
) ? 1.0 : 0.0;
724 ((uiItem
*)data
)->modifyZone(v
);
727 virtual void reflectZone()
731 gtk_toggle_button_set_active(fButton
, v
> 0.0);
735 void GTKUI::addToggleButton(const char* label
, float* zone
)
738 GtkWidget
* button
= gtk_toggle_button_new_with_label (label
);
739 addWidget(label
, button
);
741 uiToggleButton
* c
= new uiToggleButton(this, zone
, GTK_TOGGLE_BUTTON(button
));
742 gtk_signal_connect (GTK_OBJECT (button
), "toggled", GTK_SIGNAL_FUNC (uiToggleButton::toggled
), (gpointer
) c
);
746 // --------------------------- Check Button ---------------------------
748 struct uiCheckButton
: public uiItem
750 GtkToggleButton
* fButton
;
752 uiCheckButton(UI
* ui
, float* zone
, GtkToggleButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
754 static void toggled (GtkWidget
*widget
, gpointer data
)
756 float v
= (GTK_TOGGLE_BUTTON (widget
)->active
) ? 1.0 : 0.0;
757 ((uiItem
*)data
)->modifyZone(v
);
760 virtual void reflectZone()
764 gtk_toggle_button_set_active(fButton
, v
> 0.0);
768 void GTKUI::addCheckButton(const char* label
, float* zone
)
771 GtkWidget
* button
= gtk_check_button_new_with_label (label
);
772 addWidget(label
, button
);
774 uiCheckButton
* c
= new uiCheckButton(this, zone
, GTK_TOGGLE_BUTTON(button
));
775 gtk_signal_connect (GTK_OBJECT (button
), "toggled", GTK_SIGNAL_FUNC(uiCheckButton::toggled
), (gpointer
) c
);
779 // --------------------------- Adjustmenty based widgets ---------------------------
781 struct uiAdjustment
: public uiItem
785 uiAdjustment(UI
* ui
, float* zone
, GtkAdjustment
* adj
) : uiItem(ui
, zone
), fAdj(adj
) {}
787 static void changed (GtkWidget
*widget
, gpointer data
)
789 float v
= GTK_ADJUSTMENT (widget
)->value
;
790 ((uiItem
*)data
)->modifyZone(v
);
793 virtual void reflectZone()
797 gtk_adjustment_set_value(fAdj
, v
);
801 static int precision(double n
)
803 if (n
< 0.009999) return 3;
804 else if (n
< 0.099999) return 2;
805 else if (n
< 0.999999) return 1;
809 // -------------------------- Vertical Slider -----------------------------------
811 void GTKUI::addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
814 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, 0);
816 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
818 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
820 GtkWidget
* slider
= gtk_vscale_new (GTK_ADJUSTMENT(adj
));
821 gtk_range_set_inverted (GTK_RANGE(slider
), TRUE
);
822 gtk_scale_set_digits(GTK_SCALE(slider
), precision(step
));
823 gtk_widget_set_usize(slider
, -1, 160);
826 addWidget(label
, slider
);
830 // -------------------------- Horizontal Slider -----------------------------------
832 void GTKUI::addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
835 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, 0);
837 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
839 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
841 GtkWidget
* slider
= gtk_hscale_new (GTK_ADJUSTMENT(adj
));
842 gtk_scale_set_digits(GTK_SCALE(slider
), precision(step
));
843 gtk_widget_set_usize(slider
, 160, -1);
846 addWidget(label
, slider
);
851 // ------------------------------ Num Entry -----------------------------------
853 void GTKUI::addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
856 GtkObject
* adj
= gtk_adjustment_new(init
, min
, max
, step
, 10*step
, step
);
858 uiAdjustment
* c
= new uiAdjustment(this, zone
, GTK_ADJUSTMENT(adj
));
860 gtk_signal_connect (GTK_OBJECT (adj
), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed
), (gpointer
) c
);
862 GtkWidget
* spinner
= gtk_spin_button_new (GTK_ADJUSTMENT(adj
), 0.005, precision(step
));
864 //gtk_widget_set_usize(slider, 160, -1);
866 addWidget(label
, spinner
);
871 // ========================== passive widgets ===============================
874 // ------------------------------ Progress Bar -----------------------------------
876 struct uiBargraph
: public uiItem
878 GtkProgressBar
* fProgressBar
;
882 uiBargraph(UI
* ui
, float* zone
, GtkProgressBar
* pbar
, float lo
, float hi
)
883 : uiItem(ui
, zone
), fProgressBar(pbar
), fMin(lo
), fMax(hi
) {}
885 float scale(float v
) { return (v
-fMin
)/(fMax
-fMin
); }
887 virtual void reflectZone()
891 gtk_progress_bar_set_fraction(fProgressBar
, scale(v
));
897 void GTKUI::addVerticalBargraph(const char* label
, float* zone
, float lo
, float hi
)
899 GtkWidget
* pb
= gtk_progress_bar_new();
900 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb
), GTK_PROGRESS_BOTTOM_TO_TOP
);
901 gtk_widget_set_size_request(pb
, 8, -1);
902 new uiBargraph(this, zone
, GTK_PROGRESS_BAR(pb
), lo
, hi
);
904 addWidget(label
, pb
);
909 void GTKUI::addHorizontalBargraph(const char* label
, float* zone
, float lo
, float hi
)
911 GtkWidget
* pb
= gtk_progress_bar_new();
912 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb
), GTK_PROGRESS_LEFT_TO_RIGHT
);
913 gtk_widget_set_size_request(pb
, -1, 8);
914 new uiBargraph(this, zone
, GTK_PROGRESS_BAR(pb
), lo
, hi
);
916 addWidget(label
, pb
);
921 // ------------------------------ Num Display -----------------------------------
923 struct uiNumDisplay
: public uiItem
928 uiNumDisplay(UI
* ui
, float* zone
, GtkLabel
* label
, int precision
)
929 : uiItem(ui
, zone
), fLabel(label
), fPrecision(precision
) {}
931 virtual void reflectZone()
936 if (fPrecision
<= 0) {
937 snprintf(s
, 63, "%d", int(v
));
938 } else if (fPrecision
>3) {
939 snprintf(s
, 63, "%f", v
);
941 const char* format
[] = {"%.1f", "%.2f", "%.3f"};
942 snprintf(s
, 63, format
[fPrecision
-1], v
);
944 gtk_label_set_text(fLabel
, s
);
949 void GTKUI::addNumDisplay(const char* label
, float* zone
, int precision
)
951 GtkWidget
* lw
= gtk_label_new("");
952 new uiNumDisplay(this, zone
, GTK_LABEL(lw
), precision
);
954 addWidget(label
, lw
);
959 // ------------------------------ Text Display -----------------------------------
961 struct uiTextDisplay
: public uiItem
970 uiTextDisplay (UI
* ui
, float* zone
, GtkLabel
* label
, char* names
[], float lo
, float hi
)
971 : uiItem(ui
, zone
), fLabel(label
), fNames(names
), fMin(lo
), fMax(hi
)
974 while (fNames
[fNum
] != 0) fNum
++;
977 virtual void reflectZone()
982 int idx
= int(fNum
*(v
-fMin
)/(fMax
-fMin
));
984 if (idx
< 0) idx
= 0;
985 else if (idx
>= fNum
) idx
= fNum
-1;
987 gtk_label_set_text(fLabel
, fNames
[idx
]);
992 void GTKUI::addTextDisplay(const char* label
, float* zone
, char* names
[], float lo
, float hi
)
994 GtkWidget
* lw
= gtk_label_new("");
995 new uiTextDisplay (this, zone
, GTK_LABEL(lw
), names
, lo
, hi
);
997 addWidget(label
, lw
);
1006 gtk_widget_show (fBox
[0]);
1007 gtk_widget_show (fWindow
);
1012 * Update all user items reflecting zone z
1015 static gboolean
callUpdateAllGuis(gpointer
)
1017 UI::updateAllGuis();
1025 gtk_widget_show (fBox
[0]);
1026 gtk_widget_show (fWindow
);
1027 gtk_timeout_add(40, callUpdateAllGuis
, 0);
1033 /******************************************************************************
1034 *******************************************************************************
1038 *******************************************************************************
1039 *******************************************************************************/
1042 //----------------------------------------------------------------
1043 // Definition of a Faust Digital Signal Processor
1044 //----------------------------------------------------------------
1054 virtual int getNumInputs() = 0;
1055 virtual int getNumOutputs() = 0;
1056 virtual void buildUserInterface(UI
* interface
) = 0;
1057 virtual void init(int samplingRate
) = 0;
1058 virtual void compute(int len
, float** inputs
, float** outputs
) = 0;
1059 virtual void conclude() {}
1070 /******************************************************************************
1071 *******************************************************************************
1075 *******************************************************************************
1076 *******************************************************************************/
1079 //----------------------------------------------------------------------------
1080 // number of physical input and output channels of the CA device
1081 //----------------------------------------------------------------------------
1084 int gDevNumOutChans
;
1086 bool running
= true;
1088 //----------------------------------------------------------------------------
1089 // tables of noninterleaved input and output channels for FAUST
1090 //----------------------------------------------------------------------------
1092 float* gInChannel
[256];
1093 float* gOutChannel
[256];
1098 class TCoreAudioRenderer
1103 AudioBufferList
* fInputData
;
1104 AudioDeviceID fDeviceID
;
1107 OSStatus
GetDefaultDevice(int inChan
, int outChan
, AudioDeviceID
* id
);
1109 static OSStatus
Render(void *inRefCon
,
1110 AudioUnitRenderActionFlags
*ioActionFlags
,
1111 const AudioTimeStamp
*inTimeStamp
,
1113 UInt32 inNumberFrames
,
1114 AudioBufferList
*ioData
);
1118 TCoreAudioRenderer()
1120 virtual ~TCoreAudioRenderer()
1123 long OpenDefault(long inChan
, long outChan
, long bufferSize
, long sampleRate
);
1131 typedef TCoreAudioRenderer
* TCoreAudioRendererPtr
;
1133 static void PrintStreamDesc(AudioStreamBasicDescription
*inDesc
)
1135 printf("- - - - - - - - - - - - - - - - - - - -\n");
1136 printf(" Sample Rate:%f\n", inDesc
->mSampleRate
);
1137 printf(" Format ID:%.*s\n", (int) sizeof(inDesc
->mFormatID
), (char*)&inDesc
->mFormatID
);
1138 printf(" Format Flags:%lX\n", inDesc
->mFormatFlags
);
1139 printf(" Bytes per Packet:%ld\n", inDesc
->mBytesPerPacket
);
1140 printf(" Frames per Packet:%ld\n", inDesc
->mFramesPerPacket
);
1141 printf(" Bytes per Frame:%ld\n", inDesc
->mBytesPerFrame
);
1142 printf(" Channels per Frame:%ld\n", inDesc
->mChannelsPerFrame
);
1143 printf(" Bits per Channel:%ld\n", inDesc
->mBitsPerChannel
);
1144 printf("- - - - - - - - - - - - - - - - - - - -\n");
1147 static void printError(OSStatus err
)
1150 case kAudioHardwareNoError
:
1151 printf("error code : kAudioHardwareNoError\n");
1153 case kAudioConverterErr_FormatNotSupported
:
1154 printf("error code : kAudioConverterErr_FormatNotSupported\n");
1156 case kAudioConverterErr_OperationNotSupported
:
1157 printf("error code : kAudioConverterErr_OperationNotSupported\n");
1159 case kAudioConverterErr_PropertyNotSupported
:
1160 printf("error code : kAudioConverterErr_PropertyNotSupported\n");
1162 case kAudioConverterErr_InvalidInputSize
:
1163 printf("error code : kAudioConverterErr_InvalidInputSize\n");
1165 case kAudioConverterErr_InvalidOutputSize
:
1166 printf("error code : kAudioConverterErr_InvalidOutputSize\n");
1168 case kAudioConverterErr_UnspecifiedError
:
1169 printf("error code : kAudioConverterErr_UnspecifiedError\n");
1171 case kAudioConverterErr_BadPropertySizeError
:
1172 printf("error code : kAudioConverterErr_BadPropertySizeError\n");
1174 case kAudioConverterErr_RequiresPacketDescriptionsError
:
1175 printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
1177 case kAudioConverterErr_InputSampleRateOutOfRange
:
1178 printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
1180 case kAudioConverterErr_OutputSampleRateOutOfRange
:
1181 printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
1183 case kAudioHardwareNotRunningError
:
1184 printf("error code : kAudioHardwareNotRunningError\n");
1186 case kAudioHardwareUnknownPropertyError
:
1187 printf("error code : kAudioHardwareUnknownPropertyError\n");
1189 case kAudioHardwareIllegalOperationError
:
1190 printf("error code : kAudioHardwareIllegalOperationError\n");
1192 case kAudioHardwareBadDeviceError
:
1193 printf("error code : kAudioHardwareBadDeviceError\n");
1195 case kAudioHardwareBadStreamError
:
1196 printf("error code : kAudioHardwareBadStreamError\n");
1198 case kAudioDeviceUnsupportedFormatError
:
1199 printf("error code : kAudioDeviceUnsupportedFormatError\n");
1201 case kAudioDevicePermissionsError
:
1202 printf("error code : kAudioDevicePermissionsError\n");
1205 printf("error code : unknown\n");
1210 OSStatus
TCoreAudioRenderer::Render(void *inRefCon
,
1211 AudioUnitRenderActionFlags
*ioActionFlags
,
1212 const AudioTimeStamp
*inTimeStamp
,
1214 UInt32 inNumberFrames
,
1215 AudioBufferList
*ioData
)
1217 TCoreAudioRendererPtr renderer
= (TCoreAudioRendererPtr
)inRefCon
;
1218 AudioUnitRender(renderer
->fAUHAL
, ioActionFlags
, inTimeStamp
, 1, inNumberFrames
, renderer
->fInputData
);
1219 for (int i
= 0; i
< gDevNumInChans
; i
++) {
1220 gInChannel
[i
] = (float*)renderer
->fInputData
->mBuffers
[i
].mData
;
1222 for (int i
= 0; i
< gDevNumOutChans
; i
++) {
1223 gOutChannel
[i
] = (float*)ioData
->mBuffers
[i
].mData
;
1226 DSP
.compute((int)inNumberFrames
, gInChannel
, gOutChannel
);
1228 running
= mesure
<= (KMESURE
+ KSKIP
);
1232 OSStatus
TCoreAudioRenderer::GetDefaultDevice(int inChan
, int outChan
, AudioDeviceID
* id
)
1234 UInt32 theSize
= sizeof(UInt32
);
1235 AudioDeviceID inDefault
;
1236 AudioDeviceID outDefault
;
1239 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
,
1240 &theSize
, &inDefault
)) != noErr
)
1243 if ((res
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
,
1244 &theSize
, &outDefault
)) != noErr
)
1248 if (inChan
> 0 && outChan
> 0) {
1249 // Get the device only if default input and output are the same
1250 if (inDefault
== outDefault
) {
1254 printf("GetDefaultDevice : error input = %ld and output = %ld are not the same\n", inDefault
, outDefault
);
1255 return kAudioHardwareBadDeviceError
;
1257 } else if (inChan
> 0) {
1260 } else if (outChan
> 0) {
1264 return kAudioHardwareBadDeviceError
;
1270 long TCoreAudioRenderer::OpenDefault(long inChan
, long outChan
, long bufferSize
, long samplerate
)
1272 OSStatus err
= noErr
;
1273 ComponentResult err1
;
1277 AudioStreamBasicDescription srcFormat
, dstFormat
, sampleRate
;
1278 long in_nChannels
, out_nChannels
;
1280 printf("OpenDefault inChan = %ld outChan = %ld bufferSize = %ld samplerate = %ld\n", inChan
, outChan
, bufferSize
, samplerate
);
1282 if (GetDefaultDevice(inChan
, outChan
, &fDeviceID
) != noErr
) {
1283 printf("Cannot open default device\n");
1287 // Setting buffer size
1288 outSize
= sizeof(UInt32
);
1289 err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, false, kAudioDevicePropertyBufferFrameSize
, outSize
, &bufferSize
);
1291 printf("Cannot set buffer size %ld\n", bufferSize
);
1296 // Setting sample rate
1297 outSize
= sizeof(AudioStreamBasicDescription
);
1298 err
= AudioDeviceGetProperty(fDeviceID
, 0, false, kAudioDevicePropertyStreamFormat
, &outSize
, &sampleRate
);
1300 printf("Cannot get current sample rate\n");
1305 if (samplerate
!= long(sampleRate
.mSampleRate
)) {
1306 sampleRate
.mSampleRate
= (Float64
)(samplerate
);
1307 err
= AudioDeviceSetProperty(fDeviceID
, NULL
, 0, false, kAudioDevicePropertyStreamFormat
, outSize
, &sampleRate
);
1309 printf("Cannot set sample rate = %ld\n", samplerate
);
1316 ComponentDescription cd
= {kAudioUnitType_Output
, kAudioUnitSubType_HALOutput
, kAudioUnitManufacturer_Apple
, 0, 0};
1317 Component HALOutput
= FindNextComponent(NULL
, &cd
);
1319 err1
= OpenAComponent(HALOutput
, &fAUHAL
);
1320 if (err1
!= noErr
) {
1321 printf("Error calling OpenAComponent\n");
1326 err1
= AudioUnitInitialize(fAUHAL
);
1327 if (err1
!= noErr
) {
1328 printf("Cannot initialize AUHAL unit\n");
1334 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, &enableIO
, sizeof(enableIO
));
1335 if (err1
!= noErr
) {
1336 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
1342 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, &enableIO
, sizeof(enableIO
));
1343 if (err1
!= noErr
) {
1344 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
1349 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &fDeviceID
, sizeof(AudioDeviceID
));
1350 if (err1
!= noErr
) {
1351 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice\n");
1356 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 1, (UInt32
*)&bufferSize
, sizeof(UInt32
));
1357 if (err1
!= noErr
) {
1358 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
1363 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_MaximumFramesPerSlice
, kAudioUnitScope_Global
, 0, (UInt32
*)&bufferSize
, sizeof(UInt32
));
1364 if (err1
!= noErr
) {
1365 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
1370 err1
= AudioUnitGetPropertyInfo(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Input
, 1, &outSize
, &isWritable
);
1371 if (err1
!= noErr
) {
1372 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 1\n");
1376 in_nChannels
= (err1
== noErr
) ? outSize
/ sizeof(SInt32
) : 0;
1377 printf("in_nChannels = %ld\n", in_nChannels
);
1379 err1
= AudioUnitGetPropertyInfo(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Output
, 0, &outSize
, &isWritable
);
1380 if (err1
!= noErr
) {
1381 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 0\n");
1385 out_nChannels
= (err1
== noErr
) ? outSize
/ sizeof(SInt32
) : 0;
1386 printf("out_nChannels = %ld\n", out_nChannels
);
1389 Just ignore this case : seems to work without any further change...
1391 if (outChan > out_nChannels) {
1392 printf("This device hasn't required output channels\n");
1395 if (inChan > in_nChannels) {
1396 printf("This device hasn't required input channels\n");
1401 if (outChan
< out_nChannels
) {
1402 SInt32 chanArr
[out_nChannels
];
1403 for (int i
= 0; i
< out_nChannels
; i
++) {
1406 for (int i
= 0; i
< outChan
; i
++) {
1409 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Output
, 0, chanArr
, sizeof(SInt32
) * out_nChannels
);
1410 if (err1
!= noErr
) {
1411 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0\n");
1416 if (inChan
< in_nChannels
) {
1417 SInt32 chanArr
[in_nChannels
];
1418 for (int i
= 0; i
< in_nChannels
; i
++) {
1421 for (int i
= 0; i
< inChan
; i
++) {
1424 AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_ChannelMap
, kAudioUnitScope_Input
, 1, chanArr
, sizeof(SInt32
) * in_nChannels
);
1425 if (err1
!= noErr
) {
1426 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1\n");
1432 outSize
= sizeof(AudioStreamBasicDescription
);
1433 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, &outSize
);
1434 if (err1
!= noErr
) {
1435 printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1438 PrintStreamDesc(&srcFormat
);
1440 srcFormat
.mSampleRate
= samplerate
;
1441 srcFormat
.mFormatID
= kAudioFormatLinearPCM
;
1442 srcFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
1443 srcFormat
.mBytesPerPacket
= sizeof(float);
1444 srcFormat
.mFramesPerPacket
= 1;
1445 srcFormat
.mBytesPerFrame
= sizeof(float);
1446 srcFormat
.mChannelsPerFrame
= inChan
;
1447 srcFormat
.mBitsPerChannel
= 32;
1449 PrintStreamDesc(&srcFormat
);
1451 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &srcFormat
, sizeof(AudioStreamBasicDescription
));
1452 if (err1
!= noErr
) {
1453 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1459 outSize
= sizeof(AudioStreamBasicDescription
);
1460 err1
= AudioUnitGetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, &outSize
);
1461 if (err1
!= noErr
) {
1462 printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1465 PrintStreamDesc(&dstFormat
);
1467 dstFormat
.mSampleRate
= samplerate
;
1468 dstFormat
.mFormatID
= kAudioFormatLinearPCM
;
1469 dstFormat
.mFormatFlags
= kAudioFormatFlagsNativeFloatPacked
| kLinearPCMFormatFlagIsNonInterleaved
;
1470 dstFormat
.mBytesPerPacket
= sizeof(float);
1471 dstFormat
.mFramesPerPacket
= 1;
1472 dstFormat
.mBytesPerFrame
= sizeof(float);
1473 dstFormat
.mChannelsPerFrame
= outChan
;
1474 dstFormat
.mBitsPerChannel
= 32;
1476 PrintStreamDesc(&dstFormat
);
1478 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
, 0, &dstFormat
, sizeof(AudioStreamBasicDescription
));
1479 if (err1
!= noErr
) {
1480 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
1485 if (inChan
> 0 && outChan
== 0) {
1486 AURenderCallbackStruct output
;
1487 output
.inputProc
= Render
;
1488 output
.inputProcRefCon
= this;
1489 err1
= AudioUnitSetProperty(fAUHAL
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &output
, sizeof(output
));
1490 if (err1
!= noErr
) {
1491 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
1496 AURenderCallbackStruct output
;
1497 output
.inputProc
= Render
;
1498 output
.inputProcRefCon
= this;
1499 err1
= AudioUnitSetProperty(fAUHAL
, kAudioUnitProperty_SetRenderCallback
, kAudioUnitScope_Input
, 0, &output
, sizeof(output
));
1500 if (err1
!= noErr
) {
1501 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
1507 fInputData
= (AudioBufferList
*)malloc(sizeof(UInt32
) + inChan
* sizeof(AudioBuffer
));
1508 if (fInputData
== 0) {
1509 printf("Cannot allocate memory for input buffers\n");
1512 fInputData
->mNumberBuffers
= inChan
;
1515 for (int i
= 0; i
< inChan
; i
++) {
1516 fInputData
->mBuffers
[i
].mNumberChannels
= 1;
1517 fInputData
->mBuffers
[i
].mData
= malloc(bufferSize
* sizeof(float));
1518 fInputData
->mBuffers
[i
].mDataByteSize
= bufferSize
* sizeof(float);
1524 AudioUnitUninitialize(fAUHAL
);
1525 CloseComponent(fAUHAL
);
1529 long TCoreAudioRenderer::Close()
1531 for (int i
= 0; i
< gDevNumInChans
; i
++) {
1532 free(fInputData
->mBuffers
[i
].mData
);
1535 AudioUnitUninitialize(fAUHAL
);
1536 CloseComponent(fAUHAL
);
1540 long TCoreAudioRenderer::Start()
1542 OSStatus err
= AudioOutputUnitStart(fAUHAL
);
1545 printf("Error while opening device : device open error \n");
1552 long TCoreAudioRenderer::Stop()
1554 OSStatus err
= AudioOutputUnitStop(fAUHAL
);
1557 printf("Error while closing device : device close error \n");
1565 /******************************************************************************
1566 *******************************************************************************
1570 *******************************************************************************
1571 *******************************************************************************/
1573 // lopt : Scan Command Line long int Arguments
1576 long lopt (int argc, char *argv[], const char* longname, const char* shortname, long def)
1578 for (int i=2; i<argc; i++)
1579 if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
1580 return atoi(argv[i]);
1585 long lopt (char *argv
[], const char *name
, long def
)
1588 for (i
=0; argv
[i
]; i
++) if (!strcmp(argv
[i
], name
)) return atoi(argv
[i
+1]);
1592 // sopt : Scan Command Line string Arguments
1594 const char* sopt (int argc
, char *argv
[], const char* longname
, const char* shortname
, const char* def
)
1596 for (int i
=2; i
<argc
; i
++)
1597 if ( strcmp(argv
[i
-1], shortname
) == 0 || strcmp(argv
[i
-1], longname
) == 0 )
1602 // fopt : Scan Command Line flag option (without argument), return true if the flag
1604 bool fopt (int argc
, char *argv
[], const char* longname
, const char* shortname
)
1606 for (int i
=1; i
<argc
; i
++)
1607 if ( strcmp(argv
[i
], shortname
) == 0 || strcmp(argv
[i
], longname
) == 0 )
1613 //-------------------------------------------------------------------------
1615 //-------------------------------------------------------------------------
1617 pthread_t guithread
;
1619 void* run_ui(void* ptr
)
1621 UI
* interface
= (UI
*) ptr
;
1627 int main(int argc
, char *argv
[] )
1631 UI
* interface
= new GTKUI(argv
[0], &argc
, &argv
);
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]));
1638 TCoreAudioRenderer audio_device
;
1640 long srate
= (long)lopt(argv
, "--frequency", 44100);
1641 int fpb
= lopt(argv
, "--buffer", 512);
1646 DSP
.buildUserInterface(interface
);
1648 gDevNumInChans
= DSP
.getNumInputs();
1649 gDevNumOutChans
= DSP
.getNumOutputs();
1651 interface
->recallState(rcfilename
);
1653 pthread_create(&guithread
, NULL
, run_ui
, interface
);
1657 if (audio_device
.OpenDefault(gDevNumInChans
, gDevNumOutChans
, fpb
, srate
) < 0) {
1658 printf("Cannot open CoreAudio device\n");
1662 if (audio_device
.Start() < 0) {
1663 printf("Cannot start CoreAudio device\n");
1670 interface
->saveState(rcfilename
);
1672 #ifdef BENCHMARKMODE
1673 printstats(argv
[0], fpb
, DSP
.getNumInputs(), DSP
.getNumOutputs());