X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/1059e1cc0c2ecfa237406949aa26155b6a5b9154..66f23d4fabf89ad09adbd4dfc15ac6b5b2b7da83:/interpreter/preprocessor/faust-0.9.47mr3/benchmark/coreaudio-gtk-bench.cpp diff --git a/interpreter/preprocessor/faust-0.9.47mr3/benchmark/coreaudio-gtk-bench.cpp b/interpreter/preprocessor/faust-0.9.47mr3/benchmark/coreaudio-gtk-bench.cpp new file mode 100644 index 0000000..481df42 --- /dev/null +++ b/interpreter/preprocessor/faust-0.9.47mr3/benchmark/coreaudio-gtk-bench.cpp @@ -0,0 +1,1677 @@ +/* link with : "" */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +using namespace std; + +// handle 32/64 bits int size issues + +#ifdef __x86_64__ + +#define uint32 unsigned int +#define uint64 unsigned long int + +#define int32 int +#define int64 long int + +#else + +#define uint32 unsigned int +#define uint64 unsigned long long int + +#define int32 int +#define int64 long long int +#endif + +// check 32/64 bits issues are correctly handled + +#define CHECKINTSIZE \ + assert(sizeof(int32)==4);\ + assert(sizeof(int64)==8); + + + + +// On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero) +// flags to avoid costly denormals +#ifdef __SSE__ + #include + #ifdef __SSE2__ + #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040) + #else + #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000) + #endif +#else + #define AVOIDDENORMALS +#endif + +//#define BENCHMARKMODE + +// g++ -Wall -O3 -lm -lpthread -lasound `gtk-config --cflags --libs` test.cpp -o test + +#define check_error(err) if (err) { printf("%s:%d, alsa error %d : %s\n", __FILE__, __LINE__, err, snd_strerror(err)); exit(1); } +#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); } +#define display_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); } + +#define max(x,y) (((x)>(y)) ? (x) : (y)) +#define min(x,y) (((x)<(y)) ? (x) : (y)) + +// abs is now predefined +//template T abs (T a) { return (a> n); } + + +inline int int2pow2 (int x) { int r=0; while ((1<> + +#define BENCHMARKMODE + +#ifdef BENCHMARKMODE + +/** + * Returns the number of clock cycles elapsed since the last reset + * of the processor + */ +static __inline__ uint64 rdtsc(void) +{ + union { + uint32 i32[2]; + uint64 i64; + } count; + + __asm__ __volatile__("rdtsc" : "=a" (count.i32[0]), "=d" (count.i32[1])); + + return count.i64; +} + +#define KSKIP 20 +#define KMESURE 600 + +int mesure = 0; + +// these values are used to determine the number of clocks in a second +uint64 firstRDTSC; +uint64 lastRDTSC; + +// these tables contains the last KMESURE in clocks +uint64 starts[KMESURE]; +uint64 stops [KMESURE]; + +#define STARTMESURE starts[mesure%KMESURE] = rdtsc(); +#define STOPMESURE stops[mesure%KMESURE] = rdtsc(); mesure = mesure+1; + +struct timeval tv1; +struct timeval tv2; + +void openMesure() +{ + struct timezone tz; + gettimeofday(&tv1, &tz); + firstRDTSC = rdtsc(); +} + +void closeMesure() +{ + struct timezone tz; + gettimeofday(&tv2, &tz); + lastRDTSC = rdtsc(); +} + +/** + * return the number of RDTSC clocks per seconds + */ +int64 rdtscpersec() +{ + // If the environment variable CLOCKSPERSEC is defined + // we use it instead of our own measurement + char* str = getenv("CLOCKSPERSEC"); + if (str) { + int64 cps = (int64) atoll(str); + if (cps > 1000000000) { + return cps; + } else { + return (lastRDTSC-firstRDTSC) / (tv2.tv_sec - tv1.tv_sec) ; + } + } else { + return (lastRDTSC-firstRDTSC) / (tv2.tv_sec - tv1.tv_sec) ; + } +} + + +/** + * Converts a duration, expressed in RDTSC clocks, into seconds + */ +double rdtsc2sec( uint64 clk) +{ + return double(clk) / double(rdtscpersec()); +} + +double rdtsc2sec( double clk) +{ + return clk / double(rdtscpersec()); +} + + +/** + * Converts RDTSC clocks into Megabytes/seconds according to the + * number of frames processed during the period, the number of channels + * and 4 bytes samples. + */ +double megapersec(int frames, int chans, uint64 clk) +{ + return double(frames*chans*4)/double(1024*1024*rdtsc2sec(clk)); +} + + +/** + * Compute the mean value of a vector of measures + */ +static uint64 meanValue( vector::const_iterator a, vector::const_iterator b) +{ + uint64 r = 0; + unsigned int n = 0; + while (a!=b) { r += *a++; n++; } + return (n>0) ? r/n : 0; +} + +/** + * Print the median value (in Megabytes/second) of KMESURE + * throughputs measurements + */ +void printstats(const char* applname, int bsize, int ichans, int ochans) +{ + assert(mesure > KMESURE); + vector V(KMESURE); + + for (int i = 0; i +#include + +using namespace std; + +struct Meta : map +{ + void declare (const char* key, const char* value) { (*this)[key]=value; } +}; + + +struct uiItem; +typedef void (*uiCallback)(float val, void* data); + +/** + * Graphic User Interface : abstract definition + */ + +class UI +{ + typedef list clist; + typedef map zmap; + + private: + static list fGuiList; + zmap fZoneMap; + bool fStopped; + + public: + + UI() : fStopped(false) { + fGuiList.push_back(this); + } + + virtual ~UI() { + // suppression de this dans fGuiList + } + + // -- zone management + + void registerZone(float* z, uiItem* c) + { + if (fZoneMap.find(z) == fZoneMap.end()) fZoneMap[z] = new clist(); + fZoneMap[z]->push_back(c); + } + + // -- saveState(filename) : save the value of every zone to a file + + void saveState(const char* filename) + { + ofstream f(filename); + + for (zmap::iterator i=fZoneMap.begin(); i!=fZoneMap.end(); i++) { + f << *(i->first) << ' '; + } + + f << endl; + f.close(); + } + + // -- recallState(filename) : load the value of every zone from a file + + void recallState(const char* filename) + { + ifstream f(filename); + if (f.good()) { + for (zmap::iterator i=fZoneMap.begin(); i!=fZoneMap.end(); i++) { + f >> *(i->first); + } + } + f.close(); + } + + void updateAllZones(); + + void updateZone(float* z); + + static void updateAllGuis() + { + list::iterator g; + for (g = fGuiList.begin(); g != fGuiList.end(); g++) { + (*g)->updateAllZones(); + } + } + + // -- active widgets + + virtual void addButton(const char* label, float* zone) = 0; + virtual void addToggleButton(const char* label, float* zone) = 0; + virtual void addCheckButton(const char* label, float* zone) = 0; + virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0; + virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0; + virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0; + + // -- passive widgets + + virtual void addNumDisplay(const char* label, float* zone, int precision) = 0; + virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0; + virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0; + virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0; + + void addCallback(float* zone, uiCallback foo, void* data); + + // -- widget's layouts + + virtual void openFrameBox(const char* label) = 0; + virtual void openTabBox(const char* label) = 0; + virtual void openHorizontalBox(const char* label) = 0; + virtual void openVerticalBox(const char* label) = 0; + virtual void closeBox() = 0; + + virtual void show() = 0; + virtual void run() = 0; + + void stop() { fStopped = true; } + bool stopped() { return fStopped; } + + virtual void declare(float* zone, const char* key, const char* value) {} +}; + + +/** + * User Interface Item: abstract definition + */ + +class uiItem +{ + protected : + + UI* fGUI; + float* fZone; + float fCache; + + uiItem (UI* ui, float* zone) : fGUI(ui), fZone(zone), fCache(-123456.654321) + { + ui->registerZone(zone, this); + } + + + public : + + virtual ~uiItem() {} + + void modifyZone(float v) + { + fCache = v; + if (*fZone != v) { + *fZone = v; + fGUI->updateZone(fZone); + } + } + + float cache() { return fCache; } + virtual void reflectZone() = 0; +}; + + +/** + * Callback Item + */ + +struct uiCallbackItem : public uiItem +{ + uiCallback fCallback; + void* fData; + + uiCallbackItem(UI* ui, float* zone, uiCallback foo, void* data) + : uiItem(ui, zone), fCallback(foo), fData(data) {} + + virtual void reflectZone() { + float v = *fZone; + fCache = v; + fCallback(v, fData); + } +}; + +/** + * Update all user items reflecting zone z + */ + +inline void UI::updateZone(float* z) +{ + float v = *z; + clist* l = fZoneMap[z]; + for (clist::iterator c = l->begin(); c != l->end(); c++) { + if ((*c)->cache() != v) (*c)->reflectZone(); + } +} + + +/** + * Update all user items not up to date + */ + +inline void UI::updateAllZones() +{ + for (zmap::iterator m = fZoneMap.begin(); m != fZoneMap.end(); m++) { + float* z = m->first; + clist* l = m->second; + float v = *z; + for (clist::iterator c = l->begin(); c != l->end(); c++) { + if ((*c)->cache() != v) (*c)->reflectZone(); + } + } +} + +inline void UI::addCallback(float* zone, uiCallback foo, void* data) +{ + new uiCallbackItem(this, zone, foo, data); +}; + + +/****************************************************************************** +******************************************************************************* + + GRAPHIC USER INTERFACE + gtk interface + +******************************************************************************* +*******************************************************************************/ + +#include + +#define stackSize 256 + +// Insertion modes + +#define kSingleMode 0 +#define kBoxMode 1 +#define kTabMode 2 + + +class GTKUI : public UI +{ + private : + static bool fInitialized; + static list fGuiList; + + protected : + GtkWidget* fWindow; + int fTop; + GtkWidget* fBox[stackSize]; + int fMode[stackSize]; + bool fStopped; + + GtkWidget* addWidget(const char* label, GtkWidget* w); + virtual void pushBox(int mode, GtkWidget* w); + + + public : + + static const gboolean expand = TRUE; + static const gboolean fill = TRUE; + static const gboolean homogene = FALSE; + + GTKUI(char * name, int* pargc, char*** pargv); + + // -- layout groups + + virtual void openFrameBox(const char* label); + virtual void openTabBox(const char* label = ""); + virtual void openHorizontalBox(const char* label = ""); + virtual void openVerticalBox(const char* label = ""); + + virtual void closeBox(); + + // -- active widgets + + virtual void addButton(const char* label, float* zone); + virtual void addToggleButton(const char* label, float* zone); + virtual void addCheckButton(const char* label, float* zone); + virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step); + virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step); + virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step); + + // -- passive display widgets + + virtual void addNumDisplay(const char* label, float* zone, int precision); + virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max); + virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max); + virtual void addVerticalBargraph(const char* label, float* zone, float min, float max); + + virtual void show(); + virtual void run(); + +}; + + + +/****************************************************************************** +******************************************************************************* + + GRAPHIC USER INTERFACE (v2) + gtk implementation + +******************************************************************************* +*******************************************************************************/ + +// global static fields + +bool GTKUI::fInitialized = false; +list UI::fGuiList; + + + +static gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ) +{ + return FALSE; +} + +static void destroy_event( GtkWidget *widget, gpointer data ) +{ + gtk_main_quit (); +} + + +GTKUI::GTKUI(char * name, int* pargc, char*** pargv) +{ + if (!fInitialized) { + gtk_init(pargc, pargv); + fInitialized = true; + } + + fWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + //gtk_container_set_border_width (GTK_CONTAINER (fWindow), 10); + gtk_window_set_title (GTK_WINDOW (fWindow), name); + gtk_signal_connect (GTK_OBJECT (fWindow), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL); + gtk_signal_connect (GTK_OBJECT (fWindow), "destroy", GTK_SIGNAL_FUNC (destroy_event), NULL); + + fTop = 0; + fBox[fTop] = gtk_vbox_new (homogene, 4); + fMode[fTop] = kBoxMode; + gtk_container_add (GTK_CONTAINER (fWindow), fBox[fTop]); + fStopped = false; +} + +// empilement des boites + +void GTKUI::pushBox(int mode, GtkWidget* w) +{ + assert(++fTop < stackSize); + fMode[fTop] = mode; + fBox[fTop] = w; +} + +void GTKUI::closeBox() +{ + assert(--fTop >= 0); +} + + +// les differentes boites + +void GTKUI::openFrameBox(const char* label) +{ + GtkWidget * box = gtk_frame_new (label); + //gtk_container_set_border_width (GTK_CONTAINER (box), 10); + + pushBox(kSingleMode, addWidget(label, box)); +} + +void GTKUI::openTabBox(const char* label) +{ + pushBox(kTabMode, addWidget(label, gtk_notebook_new ())); +} + +void GTKUI::openHorizontalBox(const char* label) +{ + GtkWidget * box = gtk_hbox_new (homogene, 4); + gtk_container_set_border_width (GTK_CONTAINER (box), 10); + + if (fMode[fTop] != kTabMode && label[0] != 0) { + GtkWidget * frame = addWidget(label, gtk_frame_new (label)); + gtk_container_add (GTK_CONTAINER(frame), box); + gtk_widget_show(box); + pushBox(kBoxMode, box); + } else { + pushBox(kBoxMode, addWidget(label, box)); + } +} + +void GTKUI::openVerticalBox(const char* label) +{ + GtkWidget * box = gtk_vbox_new (homogene, 4); + gtk_container_set_border_width (GTK_CONTAINER (box), 10); + + if (fMode[fTop] != kTabMode && label[0] != 0) { + GtkWidget * frame = addWidget(label, gtk_frame_new (label)); + gtk_container_add (GTK_CONTAINER(frame), box); + gtk_widget_show(box); + pushBox(kBoxMode, box); + } else { + pushBox(kBoxMode, addWidget(label, box)); + } +} + +GtkWidget* GTKUI::addWidget(const char* label, GtkWidget* w) +{ + switch (fMode[fTop]) { + case kSingleMode : gtk_container_add (GTK_CONTAINER(fBox[fTop]), w); break; + case kBoxMode : gtk_box_pack_start (GTK_BOX(fBox[fTop]), w, expand, fill, 0); break; + case kTabMode : gtk_notebook_append_page (GTK_NOTEBOOK(fBox[fTop]), w, gtk_label_new(label)); break; + } + gtk_widget_show (w); + return w; +} + +// --------------------------- Press button --------------------------- + +struct uiButton : public uiItem +{ + GtkButton* fButton; + + uiButton (UI* ui, float* zone, GtkButton* b) : uiItem(ui, zone), fButton(b) {} + + static void pressed( GtkWidget *widget, gpointer data ) + { + uiItem* c = (uiItem*) data; + c->modifyZone(1.0); + } + + static void released( GtkWidget *widget, gpointer data ) + { + uiItem* c = (uiItem*) data; + c->modifyZone(0.0); + } + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + if (v > 0.0) gtk_button_pressed(fButton); else gtk_button_released(fButton); + } +}; + +void GTKUI::addButton(const char* label, float* zone) +{ + *zone = 0.0; + GtkWidget* button = gtk_button_new_with_label (label); + addWidget(label, button); + + uiButton* c = new uiButton(this, zone, GTK_BUTTON(button)); + + gtk_signal_connect (GTK_OBJECT (button), "pressed", GTK_SIGNAL_FUNC (uiButton::pressed), (gpointer) c); + gtk_signal_connect (GTK_OBJECT (button), "released", GTK_SIGNAL_FUNC (uiButton::released), (gpointer) c); + +} + +// --------------------------- Toggle Buttons --------------------------- + +struct uiToggleButton : public uiItem +{ + GtkToggleButton* fButton; + + uiToggleButton(UI* ui, float* zone, GtkToggleButton* b) : uiItem(ui, zone), fButton(b) {} + + static void toggled (GtkWidget *widget, gpointer data) + { + float v = (GTK_TOGGLE_BUTTON (widget)->active) ? 1.0 : 0.0; + ((uiItem*)data)->modifyZone(v); + } + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + gtk_toggle_button_set_active(fButton, v > 0.0); + } +}; + +void GTKUI::addToggleButton(const char* label, float* zone) +{ + *zone = 0.0; + GtkWidget* button = gtk_toggle_button_new_with_label (label); + addWidget(label, button); + + uiToggleButton* c = new uiToggleButton(this, zone, GTK_TOGGLE_BUTTON(button)); + gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (uiToggleButton::toggled), (gpointer) c); +} + + +// --------------------------- Check Button --------------------------- + +struct uiCheckButton : public uiItem +{ + GtkToggleButton* fButton; + + uiCheckButton(UI* ui, float* zone, GtkToggleButton* b) : uiItem(ui, zone), fButton(b) {} + + static void toggled (GtkWidget *widget, gpointer data) + { + float v = (GTK_TOGGLE_BUTTON (widget)->active) ? 1.0 : 0.0; + ((uiItem*)data)->modifyZone(v); + } + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + gtk_toggle_button_set_active(fButton, v > 0.0); + } +}; + +void GTKUI::addCheckButton(const char* label, float* zone) +{ + *zone = 0.0; + GtkWidget* button = gtk_check_button_new_with_label (label); + addWidget(label, button); + + uiCheckButton* c = new uiCheckButton(this, zone, GTK_TOGGLE_BUTTON(button)); + gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC(uiCheckButton::toggled), (gpointer) c); +} + + +// --------------------------- Adjustmenty based widgets --------------------------- + +struct uiAdjustment : public uiItem +{ + GtkAdjustment* fAdj; + + uiAdjustment(UI* ui, float* zone, GtkAdjustment* adj) : uiItem(ui, zone), fAdj(adj) {} + + static void changed (GtkWidget *widget, gpointer data) + { + float v = GTK_ADJUSTMENT (widget)->value; + ((uiItem*)data)->modifyZone(v); + } + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + gtk_adjustment_set_value(fAdj, v); + } +}; + +static int precision(double n) +{ + if (n < 0.009999) return 3; + else if (n < 0.099999) return 2; + else if (n < 0.999999) return 1; + else return 0; +} + +// -------------------------- Vertical Slider ----------------------------------- + +void GTKUI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) +{ + *zone = init; + GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, 0); + + uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj)); + + gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c); + + GtkWidget* slider = gtk_vscale_new (GTK_ADJUSTMENT(adj)); + gtk_range_set_inverted (GTK_RANGE(slider), TRUE); + gtk_scale_set_digits(GTK_SCALE(slider), precision(step)); + gtk_widget_set_usize(slider, -1, 160); + + openFrameBox(label); + addWidget(label, slider); + closeBox(); +} + +// -------------------------- Horizontal Slider ----------------------------------- + +void GTKUI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) +{ + *zone = init; + GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, 0); + + uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj)); + + gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c); + + GtkWidget* slider = gtk_hscale_new (GTK_ADJUSTMENT(adj)); + gtk_scale_set_digits(GTK_SCALE(slider), precision(step)); + gtk_widget_set_usize(slider, 160, -1); + + openFrameBox(label); + addWidget(label, slider); + closeBox(); +} + + +// ------------------------------ Num Entry ----------------------------------- + +void GTKUI::addNumEntry(const char* label, float* zone, float init, float min, float max, float step) +{ + *zone = init; + GtkObject* adj = gtk_adjustment_new(init, min, max, step, 10*step, step); + + uiAdjustment* c = new uiAdjustment(this, zone, GTK_ADJUSTMENT(adj)); + + gtk_signal_connect (GTK_OBJECT (adj), "value-changed", GTK_SIGNAL_FUNC (uiAdjustment::changed), (gpointer) c); + + GtkWidget* spinner = gtk_spin_button_new (GTK_ADJUSTMENT(adj), 0.005, precision(step)); + + //gtk_widget_set_usize(slider, 160, -1); + openFrameBox(label); + addWidget(label, spinner); + closeBox(); +} + + +// ========================== passive widgets =============================== + + +// ------------------------------ Progress Bar ----------------------------------- + +struct uiBargraph : public uiItem +{ + GtkProgressBar* fProgressBar; + float fMin; + float fMax; + + uiBargraph(UI* ui, float* zone, GtkProgressBar* pbar, float lo, float hi) + : uiItem(ui, zone), fProgressBar(pbar), fMin(lo), fMax(hi) {} + + float scale(float v) { return (v-fMin)/(fMax-fMin); } + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + gtk_progress_bar_set_fraction(fProgressBar, scale(v)); + } +}; + + + +void GTKUI::addVerticalBargraph(const char* label, float* zone, float lo, float hi) +{ + GtkWidget* pb = gtk_progress_bar_new(); + gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb), GTK_PROGRESS_BOTTOM_TO_TOP); + gtk_widget_set_size_request(pb, 8, -1); + new uiBargraph(this, zone, GTK_PROGRESS_BAR(pb), lo, hi); + openFrameBox(label); + addWidget(label, pb); + closeBox(); +} + + +void GTKUI::addHorizontalBargraph(const char* label, float* zone, float lo, float hi) +{ + GtkWidget* pb = gtk_progress_bar_new(); + gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(pb), GTK_PROGRESS_LEFT_TO_RIGHT); + gtk_widget_set_size_request(pb, -1, 8); + new uiBargraph(this, zone, GTK_PROGRESS_BAR(pb), lo, hi); + openFrameBox(label); + addWidget(label, pb); + closeBox(); +} + + +// ------------------------------ Num Display ----------------------------------- + +struct uiNumDisplay : public uiItem +{ + GtkLabel* fLabel; + int fPrecision; + + uiNumDisplay(UI* ui, float* zone, GtkLabel* label, int precision) + : uiItem(ui, zone), fLabel(label), fPrecision(precision) {} + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + char s[64]; + if (fPrecision <= 0) { + snprintf(s, 63, "%d", int(v)); + } else if (fPrecision>3) { + snprintf(s, 63, "%f", v); + } else { + const char* format[] = {"%.1f", "%.2f", "%.3f"}; + snprintf(s, 63, format[fPrecision-1], v); + } + gtk_label_set_text(fLabel, s); + } +}; + + +void GTKUI::addNumDisplay(const char* label, float* zone, int precision ) +{ + GtkWidget* lw = gtk_label_new(""); + new uiNumDisplay(this, zone, GTK_LABEL(lw), precision); + openFrameBox(label); + addWidget(label, lw); + closeBox(); +} + + +// ------------------------------ Text Display ----------------------------------- + +struct uiTextDisplay : public uiItem +{ + GtkLabel* fLabel; + char** fNames; + float fMin; + float fMax; + int fNum; + + + uiTextDisplay (UI* ui, float* zone, GtkLabel* label, char* names[], float lo, float hi) + : uiItem(ui, zone), fLabel(label), fNames(names), fMin(lo), fMax(hi) + { + fNum = 0; + while (fNames[fNum] != 0) fNum++; + } + + virtual void reflectZone() + { + float v = *fZone; + fCache = v; + + int idx = int(fNum*(v-fMin)/(fMax-fMin)); + + if (idx < 0) idx = 0; + else if (idx >= fNum) idx = fNum-1; + + gtk_label_set_text(fLabel, fNames[idx]); + } +}; + + +void GTKUI::addTextDisplay(const char* label, float* zone, char* names[], float lo, float hi ) +{ + GtkWidget* lw = gtk_label_new(""); + new uiTextDisplay (this, zone, GTK_LABEL(lw), names, lo, hi); + openFrameBox(label); + addWidget(label, lw); + closeBox(); +} + + + +void GTKUI::show() +{ + assert(fTop == 0); + gtk_widget_show (fBox[0]); + gtk_widget_show (fWindow); +} + + +/** + * Update all user items reflecting zone z + */ + +static gboolean callUpdateAllGuis(gpointer) +{ + UI::updateAllGuis(); + return TRUE; +} + + +void GTKUI::run() +{ + assert(fTop == 0); + gtk_widget_show (fBox[0]); + gtk_widget_show (fWindow); + gtk_timeout_add(40, callUpdateAllGuis, 0); + gtk_main (); + stop(); +} + + +/****************************************************************************** +******************************************************************************* + + DSP + +******************************************************************************* +*******************************************************************************/ + + +//---------------------------------------------------------------- +// Definition of a Faust Digital Signal Processor +//---------------------------------------------------------------- + +class dsp { + protected: + int fSamplingFreq; + int fThreadNum; + public: + dsp() {} + virtual ~dsp() {} + + virtual int getNumInputs() = 0; + virtual int getNumOutputs() = 0; + virtual void buildUserInterface(UI* interface) = 0; + virtual void init(int samplingRate) = 0; + virtual void compute(int len, float** inputs, float** outputs) = 0; + virtual void conclude() {} +}; + + +<> + + +mydsp DSP; + + + +/****************************************************************************** + ******************************************************************************* + + COREAUDIO INTERFACE + + ******************************************************************************* + *******************************************************************************/ + + +//---------------------------------------------------------------------------- +// number of physical input and output channels of the CA device +//---------------------------------------------------------------------------- + +int gDevNumInChans; +int gDevNumOutChans; + +bool running = true; + +//---------------------------------------------------------------------------- +// tables of noninterleaved input and output channels for FAUST +//---------------------------------------------------------------------------- + +float* gInChannel[256]; +float* gOutChannel[256]; + +#define OPEN_ERR -1 +#define NO_ERR 0 + +class TCoreAudioRenderer +{ + + private: + + AudioBufferList* fInputData; + AudioDeviceID fDeviceID; + AudioUnit fAUHAL; + + OSStatus GetDefaultDevice(int inChan, int outChan, AudioDeviceID* id); + + static OSStatus Render(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData); + + public: + + TCoreAudioRenderer() + {} + virtual ~TCoreAudioRenderer() + {} + + long OpenDefault(long inChan, long outChan, long bufferSize, long sampleRate); + long Close(); + + long Start(); + long Stop(); + +}; + +typedef TCoreAudioRenderer * TCoreAudioRendererPtr; + +static void PrintStreamDesc(AudioStreamBasicDescription *inDesc) +{ + printf("- - - - - - - - - - - - - - - - - - - -\n"); + printf(" Sample Rate:%f\n", inDesc->mSampleRate); + printf(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID); + printf(" Format Flags:%lX\n", inDesc->mFormatFlags); + printf(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket); + printf(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket); + printf(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame); + printf(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame); + printf(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel); + printf("- - - - - - - - - - - - - - - - - - - -\n"); +} + +static void printError(OSStatus err) +{ + switch (err) { + case kAudioHardwareNoError: + printf("error code : kAudioHardwareNoError\n"); + break; + case kAudioConverterErr_FormatNotSupported: + printf("error code : kAudioConverterErr_FormatNotSupported\n"); + break; + case kAudioConverterErr_OperationNotSupported: + printf("error code : kAudioConverterErr_OperationNotSupported\n"); + break; + case kAudioConverterErr_PropertyNotSupported: + printf("error code : kAudioConverterErr_PropertyNotSupported\n"); + break; + case kAudioConverterErr_InvalidInputSize: + printf("error code : kAudioConverterErr_InvalidInputSize\n"); + break; + case kAudioConverterErr_InvalidOutputSize: + printf("error code : kAudioConverterErr_InvalidOutputSize\n"); + break; + case kAudioConverterErr_UnspecifiedError: + printf("error code : kAudioConverterErr_UnspecifiedError\n"); + break; + case kAudioConverterErr_BadPropertySizeError: + printf("error code : kAudioConverterErr_BadPropertySizeError\n"); + break; + case kAudioConverterErr_RequiresPacketDescriptionsError: + printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n"); + break; + case kAudioConverterErr_InputSampleRateOutOfRange: + printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n"); + break; + case kAudioConverterErr_OutputSampleRateOutOfRange: + printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n"); + break; + case kAudioHardwareNotRunningError: + printf("error code : kAudioHardwareNotRunningError\n"); + break; + case kAudioHardwareUnknownPropertyError: + printf("error code : kAudioHardwareUnknownPropertyError\n"); + break; + case kAudioHardwareIllegalOperationError: + printf("error code : kAudioHardwareIllegalOperationError\n"); + break; + case kAudioHardwareBadDeviceError: + printf("error code : kAudioHardwareBadDeviceError\n"); + break; + case kAudioHardwareBadStreamError: + printf("error code : kAudioHardwareBadStreamError\n"); + break; + case kAudioDeviceUnsupportedFormatError: + printf("error code : kAudioDeviceUnsupportedFormatError\n"); + break; + case kAudioDevicePermissionsError: + printf("error code : kAudioDevicePermissionsError\n"); + break; + default: + printf("error code : unknown\n"); + break; + } +} + +OSStatus TCoreAudioRenderer::Render(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + TCoreAudioRendererPtr renderer = (TCoreAudioRendererPtr)inRefCon; + AudioUnitRender(renderer->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, renderer->fInputData); + for (int i = 0; i < gDevNumInChans; i++) { + gInChannel[i] = (float*)renderer->fInputData->mBuffers[i].mData; + } + for (int i = 0; i < gDevNumOutChans; i++) { + gOutChannel[i] = (float*)ioData->mBuffers[i].mData; + } + STARTMESURE + DSP.compute((int)inNumberFrames, gInChannel, gOutChannel); + STOPMESURE + running = mesure <= (KMESURE + KSKIP); + return 0; +} + +OSStatus TCoreAudioRenderer::GetDefaultDevice(int inChan, int outChan, AudioDeviceID* id) +{ + UInt32 theSize = sizeof(UInt32); + AudioDeviceID inDefault; + AudioDeviceID outDefault; + OSStatus res; + + if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, + &theSize, &inDefault)) != noErr) + return res; + + if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, + &theSize, &outDefault)) != noErr) + return res; + + // Duplex mode + if (inChan > 0 && outChan > 0) { + // Get the device only if default input and output are the same + if (inDefault == outDefault) { + *id = inDefault; + return noErr; + } else { + printf("GetDefaultDevice : error input = %ld and output = %ld are not the same\n", inDefault, outDefault); + return kAudioHardwareBadDeviceError; + } + } else if (inChan > 0) { + *id = inDefault; + return noErr; + } else if (outChan > 0) { + *id = outDefault; + return noErr; + } else { + return kAudioHardwareBadDeviceError; + } + + return noErr; +} + +long TCoreAudioRenderer::OpenDefault(long inChan, long outChan, long bufferSize, long samplerate) +{ + OSStatus err = noErr; + ComponentResult err1; + UInt32 outSize; + UInt32 enableIO; + Boolean isWritable; + AudioStreamBasicDescription srcFormat, dstFormat, sampleRate; + long in_nChannels, out_nChannels; + + printf("OpenDefault inChan = %ld outChan = %ld bufferSize = %ld samplerate = %ld\n", inChan, outChan, bufferSize, samplerate); + + if (GetDefaultDevice(inChan, outChan, &fDeviceID) != noErr) { + printf("Cannot open default device\n"); + return OPEN_ERR; + } + + // Setting buffer size + outSize = sizeof(UInt32); + err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &bufferSize); + if (err != noErr) { + printf("Cannot set buffer size %ld\n", bufferSize); + printError(err); + return OPEN_ERR; + } + + // Setting sample rate + outSize = sizeof(AudioStreamBasicDescription); + err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &outSize, &sampleRate); + if (err != noErr) { + printf("Cannot get current sample rate\n"); + printError(err); + return OPEN_ERR; + } + + if (samplerate != long(sampleRate.mSampleRate)) { + sampleRate.mSampleRate = (Float64)(samplerate); + err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyStreamFormat, outSize, &sampleRate); + if (err != noErr) { + printf("Cannot set sample rate = %ld\n", samplerate); + printError(err); + return OPEN_ERR; + } + } + + // AUHAL + ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0}; + Component HALOutput = FindNextComponent(NULL, &cd); + + err1 = OpenAComponent(HALOutput, &fAUHAL); + if (err1 != noErr) { + printf("Error calling OpenAComponent\n"); + printError(err1); + goto error; + } + + err1 = AudioUnitInitialize(fAUHAL); + if (err1 != noErr) { + printf("Cannot initialize AUHAL unit\n"); + printError(err1); + goto error; + } + + enableIO = 1; + err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n"); + printError(err1); + goto error; + } + + enableIO = 1; + err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n"); + printError(err1); + goto error; + } + + err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice\n"); + printError(err1); + goto error; + } + + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n"); + printError(err1); + goto error; + } + + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n"); + printError(err1); + goto error; + } + + err1 = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 1, &outSize, &isWritable); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 1\n"); + printError(err1); + } + + in_nChannels = (err1 == noErr) ? outSize / sizeof(SInt32) : 0; + printf("in_nChannels = %ld\n", in_nChannels); + + err1 = AudioUnitGetPropertyInfo(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, &outSize, &isWritable); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap-INFO 0\n"); + printError(err1); + } + + out_nChannels = (err1 == noErr) ? outSize / sizeof(SInt32) : 0; + printf("out_nChannels = %ld\n", out_nChannels); + + /* + Just ignore this case : seems to work without any further change... + + if (outChan > out_nChannels) { + printf("This device hasn't required output channels\n"); + goto error; + } + if (inChan > in_nChannels) { + printf("This device hasn't required input channels\n"); + goto error; + } + */ + + if (outChan < out_nChannels) { + SInt32 chanArr[out_nChannels]; + for (int i = 0; i < out_nChannels; i++) { + chanArr[i] = -1; + } + for (int i = 0; i < outChan; i++) { + chanArr[i] = i; + } + err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0\n"); + printError(err1); + } + } + + if (inChan < in_nChannels) { + SInt32 chanArr[in_nChannels]; + for (int i = 0; i < in_nChannels; i++) { + chanArr[i] = -1; + } + for (int i = 0; i < inChan; i++) { + chanArr[i] = i; + } + AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1\n"); + printError(err1); + } + } + + if (inChan > 0) { + outSize = sizeof(AudioStreamBasicDescription); + err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize); + if (err1 != noErr) { + printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n"); + printError(err1); + } + PrintStreamDesc(&srcFormat); + + srcFormat.mSampleRate = samplerate; + srcFormat.mFormatID = kAudioFormatLinearPCM; + srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; + srcFormat.mBytesPerPacket = sizeof(float); + srcFormat.mFramesPerPacket = 1; + srcFormat.mBytesPerFrame = sizeof(float); + srcFormat.mChannelsPerFrame = inChan; + srcFormat.mBitsPerChannel = 32; + + PrintStreamDesc(&srcFormat); + + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n"); + printError(err1); + } + } + + if (outChan > 0) { + outSize = sizeof(AudioStreamBasicDescription); + err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize); + if (err1 != noErr) { + printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n"); + printError(err1); + } + PrintStreamDesc(&dstFormat); + + dstFormat.mSampleRate = samplerate; + dstFormat.mFormatID = kAudioFormatLinearPCM; + dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; + dstFormat.mBytesPerPacket = sizeof(float); + dstFormat.mFramesPerPacket = 1; + dstFormat.mBytesPerFrame = sizeof(float); + dstFormat.mChannelsPerFrame = outChan; + dstFormat.mBitsPerChannel = 32; + + PrintStreamDesc(&dstFormat); + + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n"); + printError(err1); + } + } + + if (inChan > 0 && outChan == 0) { + AURenderCallbackStruct output; + output.inputProc = Render; + output.inputProcRefCon = this; + err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n"); + printError(err1); + goto error; + } + } else { + AURenderCallbackStruct output; + output.inputProc = Render; + output.inputProcRefCon = this; + err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output)); + if (err1 != noErr) { + printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n"); + printError(err1); + goto error; + } + } + + fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inChan * sizeof(AudioBuffer)); + if (fInputData == 0) { + printf("Cannot allocate memory for input buffers\n"); + goto error; + } + fInputData->mNumberBuffers = inChan; + + // Prepare buffers + for (int i = 0; i < inChan; i++) { + fInputData->mBuffers[i].mNumberChannels = 1; + fInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(float)); + fInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(float); + } + + return NO_ERR; + +error: + AudioUnitUninitialize(fAUHAL); + CloseComponent(fAUHAL); + return OPEN_ERR; +} + +long TCoreAudioRenderer::Close() +{ + for (int i = 0; i < gDevNumInChans; i++) { + free(fInputData->mBuffers[i].mData); + } + free(fInputData); + AudioUnitUninitialize(fAUHAL); + CloseComponent(fAUHAL); + return NO_ERR; +} + +long TCoreAudioRenderer::Start() +{ + OSStatus err = AudioOutputUnitStart(fAUHAL); + + if (err != noErr) { + printf("Error while opening device : device open error \n"); + return OPEN_ERR; + } else { + return NO_ERR; + } +} + +long TCoreAudioRenderer::Stop() +{ + OSStatus err = AudioOutputUnitStop(fAUHAL); + + if (err != noErr) { + printf("Error while closing device : device close error \n"); + return OPEN_ERR; + } else { + return NO_ERR; + } +} + + +/****************************************************************************** +******************************************************************************* + + MAIN PLAY THREAD + +******************************************************************************* +*******************************************************************************/ + +// lopt : Scan Command Line long int Arguments + +/* +long lopt (int argc, char *argv[], const char* longname, const char* shortname, long def) +{ + for (int i=2; irun(); + pthread_exit(0); + return 0; +} + +int main(int argc, char *argv[] ) +{ + CHECKINTSIZE; + + UI* interface = new GTKUI(argv[0], &argc, &argv); + + // compute rcfilename to (re)store application state + char rcfilename[256]; + char* home = getenv("HOME"); + snprintf(rcfilename, 255, "%s/.%src", home, basename(argv[0])); + + TCoreAudioRenderer audio_device; + + long srate = (long)lopt(argv, "--frequency", 44100); + int fpb = lopt(argv, "--buffer", 512); + + AVOIDDENORMALS; + + DSP.init(srate); + DSP.buildUserInterface(interface); + + gDevNumInChans = DSP.getNumInputs(); + gDevNumOutChans = DSP.getNumOutputs(); + + interface->recallState(rcfilename); + + pthread_create(&guithread, NULL, run_ui, interface); + + openMesure(); + + if (audio_device.OpenDefault(gDevNumInChans, gDevNumOutChans, fpb, srate) < 0) { + printf("Cannot open CoreAudio device\n"); + return 0; + } + + if (audio_device.Start() < 0) { + printf("Cannot start CoreAudio device\n"); + return 0; + } + while(running) { + usleep(100000); + } + closeMesure(); + interface->saveState(rcfilename); + +#ifdef BENCHMARKMODE + printstats(argv[0], fpb, DSP.getNumInputs(), DSP.getNumOutputs()); +#endif + + return 0; +}