--- /dev/null
+/* link with : "" */
+#include <stdlib.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <gtk/gtk.h>
+#include <pthread.h>
+#include <sys/wait.h>
+#include <list>
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <algorithm>
+
+#include <AudioToolbox/AudioConverter.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreServices/CoreServices.h>
+
+
+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 <xmmintrin.h>
+ #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<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
+
+
+inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
+
+
+inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
+
+
+/******************************************************************************
+*******************************************************************************
+
+ VECTOR INTRINSICS
+
+*******************************************************************************
+*******************************************************************************/
+
+//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
+//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
+
+
+<<includeIntrinsic>>
+
+#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<uint64>::const_iterator a, vector<uint64>::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<uint64> V(KMESURE);
+
+ for (int i = 0; i<KMESURE; i++) {
+ V[i] = stops[i] - starts[i];
+ }
+
+ sort(V.begin(), V.end());
+
+ // Mean of 10 best values (gives relatively stable results)
+ uint64 meavalx = meanValue(V.begin(), V.begin() + 10);
+
+ //printing
+ cout << megapersec(bsize, ichans+ochans, meavalx) << "\tMB/s"
+ << '\t' << applname
+ << '\t' << "(clocks/sec : " << rdtscpersec() << ")"
+ << endl;
+
+}
+
+#else
+
+#define STARTMESURE
+#define STOPMESURE
+
+#endif
+
+
+
+/******************************************************************************
+*******************************************************************************
+
+ GRAPHIC USER INTERFACE (v2)
+ abstract interfaces
+
+*******************************************************************************
+*******************************************************************************/
+
+#include <map>
+#include <list>
+
+using namespace std;
+
+struct Meta : map<const char*, const char*>
+{
+ 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<uiItem*> clist;
+ typedef map<float*, clist*> zmap;
+
+ private:
+ static list<UI*> 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<UI*>::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 <gtk/gtk.h>
+
+#define stackSize 256
+
+// Insertion modes
+
+#define kSingleMode 0
+#define kBoxMode 1
+#define kTabMode 2
+
+
+class GTKUI : public UI
+{
+ private :
+ static bool fInitialized;
+ static list<UI*> 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*> 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() {}
+};
+
+
+<<includeclass>>
+
+
+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; i<argc; i++)
+ if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
+ return atoi(argv[i]);
+ return def;
+}
+*/
+
+long lopt (char *argv[], const char *name, long def)
+{
+ int i;
+ for (i=0; argv[i]; i++) if (!strcmp(argv[i], name)) return atoi(argv[i+1]);
+ return def;
+}
+
+// sopt : Scan Command Line string Arguments
+
+const char* sopt (int argc, char *argv[], const char* longname, const char* shortname, const char* def)
+{
+ for (int i=2; i<argc; i++)
+ if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
+ return argv[i];
+ return def;
+}
+
+// fopt : Scan Command Line flag option (without argument), return true if the flag
+
+bool fopt (int argc, char *argv[], const char* longname, const char* shortname)
+{
+ for (int i=1; i<argc; i++)
+ if ( strcmp(argv[i], shortname) == 0 || strcmp(argv[i], longname) == 0 )
+ return true;
+ return false;
+}
+
+
+//-------------------------------------------------------------------------
+// MAIN
+//-------------------------------------------------------------------------
+
+pthread_t guithread;
+
+void* run_ui(void* ptr)
+{
+ UI* interface = (UI*) ptr;
+ interface->run();
+ 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;
+}