Ofelia - using addons, GL_TEXTURE_3D and binding openGL functions
i think i learned how to integrate addons (not everything is working yet...).
this is what i added to ofxOfeliaPdBindings.h to integrate ofxVolumetrics:
class pdTexture3d
{
public:
pdTexture3d(){};
void allocate(int w, int h, int d, int internalGlDataType)
{
texture3d.allocate(w, h, d, internalGlDataType);
}
void loadData(unsigned char * data, int w, int h, int d, int xOffset, int yOffset, int zOffset, int glFormat)
{
texture3d.loadData(data, w, h, d, xOffset, yOffset, zOffset, glFormat);
}
void loadData(float* data, int w, int h, int d, int xOffset, int yOffset, int zOffset, int glFormat)
{
texture3d.loadData(data, w, h, d, xOffset, yOffset, zOffset, glFormat);
}
void loadData(unsigned short* data, int w, int h, int d, int xOffset, int yOffset, int zOffset, int glFormat)
{
texture3d.loadData(data, w, h, d, xOffset, yOffset, zOffset, glFormat);
}
void loadData(ofPixels & pix, int d, int xOffset, int yOffset, int zOffset)
{
texture3d.loadData(pix, d, xOffset, yOffset, zOffset);
}
void loadData(ofShortPixels & pix, int d, int xOffset, int yOffset, int zOffset)
{
texture3d.loadData(pix, d, xOffset, yOffset, zOffset);
}
void loadData(ofFloatPixels & pix, int d, int xOffset, int yOffset, int zOffset)
{
texture3d.loadData(pix, d, xOffset, yOffset, zOffset);
}
void bind()
{
texture3d.bind();
}
void unbind()
{
texture3d.unbind();
}
void clear()
{
texture3d.clear();
}
ofxTextureData3d getTextureData()
{
return texture3d.getTextureData();
}
private:
ofxTexture3d texture3d;
};
class pdVolumetrics
{
public:
pdVolumetrics(){};
void setup(int w, int h, int d, ofVec3f voxelSize, bool usePowerOfTwoTexSize=false)
{
volumetrics.setup(w, h, d, voxelSize, usePowerOfTwoTexSize);
}
void destroy()
{
volumetrics.destroy();
}
void updateVolumeData(unsigned char * data, int w, int h, int d, int xOffset, int yOffset, int zOffset)
{
volumetrics.updateVolumeData(data, w, h, d, xOffset, yOffset, zOffset);
}
void drawVolume(float x, float y, float z, float size, int zTexOffset)
{
volumetrics.drawVolume(x, y, z, size, zTexOffset);
}
void drawVolume(float x, float y, float z, float w, float h, float d, int zTexOffset)
{
volumetrics.drawVolume(x, y, z, w, h, d, zTexOffset);
}
bool isInitialized()
{
return volumetrics.isInitialized();
}
int getVolumeWidth()
{
return volumetrics.getVolumeWidth();
}
int getVolumeHeight()
{
return volumetrics.getVolumeHeight();
}
int getVolumeDepth()
{
return volumetrics.getVolumeDepth();
}
ofFbo & getFboReference()
{
return volumetrics.getFboReference();
}
int getRenderWidth()
{
return volumetrics.getRenderWidth();
}
int getRenderHeight()
{
return volumetrics.getRenderHeight();
}
float getXyQuality()
{
return volumetrics.getXyQuality();
}
float getZQuality()
{
return volumetrics.getZQuality();
}
float getThreshold()
{
return volumetrics.getThreshold();
}
float getDensity()
{
return volumetrics.getDensity();
}
void setXyQuality(float q)
{
volumetrics.setXyQuality(q);
}
void setZQuality(float q)
{
volumetrics.setZQuality(q);
}
void setThreshold(float t)
{
volumetrics.setThreshold(t);
}
void setDensity(float d)
{
volumetrics.setDensity(d);
}
void setRenderSettings(float xyQuality, float zQuality, float dens, float thresh)
{
volumetrics.setRenderSettings(xyQuality, zQuality, dens, thresh);
}
void setVolumeTextureFilterMode(GLint filterMode)
{
volumetrics.setVolumeTextureFilterMode(filterMode);
}
private:
ofxVolumetrics volumetrics;
};
class pdImageSequencePlayer
{
public:
pdImageSequencePlayer(){};
void init(std::string prefix, int digits, std::string extension, int start)
{
imageSequencePlayer.init(prefix, digits, extension, start);
}
int getWidth()
{
return imageSequencePlayer.getWidth();
}
int getHeight()
{
return imageSequencePlayer.getHeight();
}
ofPixels_<unsigned char> getPixels()
{
return imageSequencePlayer.getPixels();
}
int getSequenceLength()
{
return imageSequencePlayer.getSequenceLength();
}
bool loadNextFrame()
{
return imageSequencePlayer.loadNextFrame();
}
bool loadPreviousFrame()
{
return imageSequencePlayer.loadPreviousFrame();
}
bool loadFrame(int n)
{
return imageSequencePlayer.loadFrame(n);
}
int getCurrentFrameNumber()
{
return imageSequencePlayer.getCurrentFrameNumber();
}
void setCurrentFrameNumber(int i)
{
imageSequencePlayer.setCurrentFrameNumber(i);
}
bool isInitialized()
{
return imageSequencePlayer.isInitialized();
}
private:
ofxImageSequencePlayer imageSequencePlayer;
};
[small job offer] porting max external to pd
Edit 1: Took a shot porting it in this little textarea. Probably doesn't compile yet...
Edit 2: Ok, this should compile now. I haven't actually tried to instantiate it yet, though. It's possible I set it up with the wrong number of xlets.
Edit 3: Seems to instantiate ok. It appears it doesn't take signal input so the CLASS_MAINSIGNALIN macro is neccessary. Just comment that part out to make it a control signal.
Note-- in my port it's called [vb_fourses~]
for the reason noted below.
I have no idea if the algorithm behaves correctly, but it does output sound.
Btw-- AFAICT you should be able to compile this external for the 64-bit version of Purr Data and it should work properly. It doesn't require a special 64-bit codepath in Pd so I commented that part out.
Btw 2-- there should probably be a "best practices" rule that states you can only name your class something that is a legal C function name. Because this class doesn't follow that practice I made a mistake in the port. Further, the user will make a mistake because I had to change the class name. If I had instead made the setup function a different name than the creator I would create an additional problem that would force users to declare the lib before using it. Bad all around, and not worth whatever benefit there is to naming a class "foo.bar" instead of "foo_bar"
/*
#include "ext.h"
#include "ext_obex.h"
#include "z_dsp.h"
#include "ext_common.h"
*/
#include "m_pd.h"
#include "math.h"
/*
a chaotic oscillator network
based on descriptions of the 'fourses system' by ciat-lonbarde
www.ciat-lonbarde.net
07.april 2013, volker b?hm
*/
#define NUMFOURSES 4
static void *myObj_class;
typedef struct {
// this is a horse... basically a ramp generator
double val;
double inc;
double dec;
double adder;
double incy, incym1; // used for smoothing
double decy, decym1; // used for smoothing
} t_horse;
typedef struct {
t_object x_obj;
double r_sr;
t_horse fourses[NUMFOURSES+2]; // four horses make a fourse...
double smoother;
t_sample x_f;
} t_myObj;
// absolute limits
static void myObj_hilim(t_myObj *x, t_floatarg input);
static void myObj_lolim(t_myObj *x, t_floatarg input);
// up and down freqs for all oscillators
static void myObj_upfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4);
static void myObj_downfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4);
static void myObj_smooth(t_myObj *x, t_floatarg input);
static void myObj_info(t_myObj *x);
// DSP methods
static void myObj_dsp(t_myObj *x, t_signal **sp);
static t_int *myObj_perform(t_int *w);
//void myObj_dsp64(t_myObj *x, t_object *dsp64, short *count, double samplerate,
// long maxvectorsize, long flags);
//void myObj_perform64(t_myObj *x, t_object *dsp64, double **ins, long numins,
// double **outs, long numouts, long sampleframes, long flags, void *userparam);
//
static void *myObj_new( t_symbol *s, int argc, t_atom *argv);
//void myObj_assist(t_myObj *x, void *b, long m, long a, char *s);
void vb_fourses_tilde_setup(void) {
t_class *c;
myObj_class = class_new(gensym("vb_fourses~"), (t_newmethod)myObj_new, 0, sizeof(t_myObj),
0, A_GIMME, NULL);
c = myObj_class;
class_addmethod(c, (t_method)myObj_dsp, gensym("dsp"), A_CANT, 0);
// class_addmethod(c, (t_method)myObj_dsp64, gensym("dsp64"), A_CANT, 0);
class_addmethod(c, (t_method)myObj_smooth, gensym("smooth"), A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_hilim, gensym("hilim"), A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_lolim, gensym("lolim"), A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_upfreq, gensym("upfreq"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_downfreq, gensym("downfreq"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_info, gensym("info"), 0);
//class_addmethod(c, (t_method)myObj_assist, "assist", A_CANT,0);
CLASS_MAINSIGNALIN(myObj_class, t_myObj, x_f);
// class_dspinit(c);
// class_register(CLASS_BOX, c);
post("vb_fourses~ by volker b?hm\n");
// return 0;
}
static void myObj_smooth(t_myObj *x, t_floatarg input) {
// input = CLAMP(input, 0., 1.);
if (input < 0.) input = 0;
if (input > 1.) input = 1;
x->smoother = 0.01 - pow(input,0.2)*0.01;
}
static void myObj_hilim(t_myObj *x, t_floatarg input) {
x->fourses[0].val = input; // store global high limit in fourses[0]
}
static void myObj_lolim(t_myObj *x, t_floatarg input) {
x->fourses[5].val = input; // store global low limit in fourses[5]
}
static void myObj_upfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4) {
x->fourses[1].inc = fabs(freq1)*4*x->r_sr;
x->fourses[2].inc = fabs(freq2)*4*x->r_sr;
x->fourses[3].inc = fabs(freq3)*4*x->r_sr;
x->fourses[4].inc = fabs(freq4)*4*x->r_sr;
}
static void myObj_downfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4) {
x->fourses[1].dec = fabs(freq1)*-4*x->r_sr;
x->fourses[2].dec = fabs(freq2)*-4*x->r_sr;
x->fourses[3].dec = fabs(freq3)*-4*x->r_sr;
x->fourses[4].dec = fabs(freq4)*-4*x->r_sr;
}
//#pragma mark 64bit dsp-loop ------------------
//void myObj_dsp64(t_myObj *x, t_object *dsp64, short *count, double samplerate,
// long maxvectorsize, long flags) {
// object_method(dsp64, gensym("dsp_add64"), x, myObj_perform64, 0, NULL);
//
// if(samplerate<=0) x->r_sr = 1.0/44100.0;
// else x->r_sr = 1.0/samplerate;
//
//
//}
//static void myObj_perform64(t_myObj *x, t_object *dsp64, double **ins, long numins,
// double **outs, long numouts, long sampleframes, long flags, void *userparam){
//
// t_double **output = outs;
// int vs = sampleframes;
// t_horse *fourses = x->fourses;
// double val, c, hilim, lolim;
// int i, n;
//
// if (x->x_obj.z_disabled)
// return;
//
// c = x->smoother;
// hilim = fourses[0].val;
// lolim = fourses[5].val;
//
// for(i=0; i<vs; i++)
// {
// for(n=1; n<=NUMFOURSES; n++) {
// // smoother
// fourses[n].incy = fourses[n].inc*c + fourses[n].incym1*(1-c);
// fourses[n].incym1 = fourses[n].incy;
//
// fourses[n].decy = fourses[n].dec*c + fourses[n].decym1*(1-c);
// fourses[n].decym1 = fourses[n].decy;
//
// val = fourses[n].val;
// val += fourses[n].adder;
//
// if(val <= fourses[n+1].val || val <= lolim ) {
// fourses[n].adder = fourses[n].incy;
// }
// else if( val >= fourses[n-1].val || val >= hilim ) {
// fourses[n].adder = fourses[n].decy;
// }
//
// output[n-1][i] = val;
//
// fourses[n].val = val;
// }
// }
//
// return;
//
//}
//#pragma mark 32bit dsp-loop ------------------
static void myObj_dsp(t_myObj *x, t_signal **sp)
{
dsp_add(myObj_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n);
if(sp[0]->s_sr<=0)
x->r_sr = 1.0/44100.0;
else x->r_sr = 1.0/sp[0]->s_sr;
}
static t_int *myObj_perform(t_int *w)
{
t_myObj *x = (t_myObj*)(w[1]);
t_float *out1 = (float *)(w[2]);
t_float *out2 = (float *)(w[3]);
t_float *out3 = (float *)(w[4]);
t_float *out4 = (float *)(w[5]);
int vs = (int)(w[6]);
// Hm... not sure about this member. I don't think we can disable individual
// objects in Pd...
// if (x->x_obj.z_disabled)
// goto out;
t_horse *fourses = x->fourses;
double val, c, hilim, lolim;
int i, n;
c = x->smoother;
hilim = fourses[0].val;
lolim = fourses[5].val;
for(i=0; i<vs; i++)
{
for(n=1; n<=NUMFOURSES; n++) {
// smoother
fourses[n].incy = fourses[n].inc*c + fourses[n].incym1*(1-c);
fourses[n].incym1 = fourses[n].incy;
fourses[n].decy = fourses[n].dec*c + fourses[n].decym1*(1-c);
fourses[n].decym1 = fourses[n].decy;
val = fourses[n].val;
val += fourses[n].adder;
if(val <= fourses[n+1].val || val <= lolim ) {
fourses[n].adder = fourses[n].incy;
}
else if( val >= fourses[n-1].val || val >= hilim ) {
fourses[n].adder = fourses[n].decy;
}
fourses[n].val = val;
}
out1[i] = fourses[1].val;
out2[i] = fourses[2].val;
out3[i] = fourses[3].val;
out4[i] = fourses[4].val;
}
//out:
return w+7;
}
static void myObj_info(t_myObj *x) {
int i;
// only fourses 1 to 4 are used
post("----- fourses.info -------");
for(i=1; i<=NUMFOURSES; i++) {
post("fourses[%ld].val = %f", i, x->fourses[i].val);
post("fourses[%ld].inc = %f", i, x->fourses[i].inc);
post("fourses[%ld].dec = %f", i, x->fourses[i].dec);
post("fourses[%ld].adder = %f", i, x->fourses[i].adder);
}
post("------ end -------");
}
void *myObj_new(t_symbol *s, int argc, t_atom *argv)
{
t_myObj *x = (t_myObj *)pd_new(myObj_class);
// dsp_setup((t_pxobject*)x, 0);
outlet_new((t_object *)x, &s_signal);
outlet_new((t_object *)x, &s_signal);
outlet_new((t_object *)x, &s_signal);
outlet_new((t_object *)x, &s_signal);
x->r_sr = 1.0/sys_getsr();
if(sys_getsr() <= 0)
x->r_sr = 1.0/44100.f;
int i;
for(i=1; i<=NUMFOURSES; i++) {
x->fourses[i].val = 0.;
x->fourses[i].inc = 0.01;
x->fourses[i].dec = -0.01;
x->fourses[i].adder = x->fourses[i].inc;
}
x->fourses[0].val = 1.; // dummy 'horse' only used as high limit for fourses[1]
x->fourses[5].val = -1.; // dummy 'horse' only used as low limit for fourses[4]
x->smoother = 0.01;
return x;
}
//void myObj_assist(t_myObj *x, void *b, long m, long a, char *s) {
// if (m==1) {
// switch(a) {
// case 0: sprintf (s,"message inlet"); break;
// }
// }
// else {
// switch(a) {
// case 0: sprintf (s,"(signal) signal out osc1"); break;
// case 1: sprintf(s, "(signal) signal out osc2"); break;
// case 2: sprintf(s, "(signal) signal out osc3"); break;
// case 3: sprintf(s, "(signal) signal out osc4"); break;
// }
//
// }
//}
ofelia lua table and a few questions
second try. i commented out the lines where i am not sure if they are a methods (i am quite new to programming except for pure data and a little bit of python). there are only "public:" methods in the list.
class Canvas
// Canvas(t_symbol *s)
// Canvas(t_symbol *s, t_floatarg f)
t_symbol *realizeDollar(t_symbol *s)
t_symbol *getName()
int getIndex()
void getArgs(int *argcp, t_atom **argvp, t_canvas **canvasp)
void setArgs(int argc, t_atom *argv)
void getPosition(int **posp)
void setPosition(int xpos, int ypos)
t_symbol *getDir()
void remove()
class Send
// Send(t_symbol *s)
void sendBang()sendFloat(t_floatarg f)
void sendSymbol(t_symbol *s)
void sendPointer(t_gpointer *p)
void sendList(int argc, t_atom *argv)
void sendAnything(int argc, t_atom *argv)
class Inlet
// Inlet(t_symbol *s)
void setFloatInlet(t_floatarg f)
void setFloatInlets(int n, t_floatarg *f)
void setSignalInlet(t_floatarg f)
class Outlet
// Outlet(t_symbol *s)
void outletBang(int index)
void outletFloat(int index, t_floatarg f)
void outletSymbol(int index, t_symbol *s)
void outletPointer(int index, t_gpointer *p)
void outletList(int index, int argc, t_atom *argv)
void outletAnything(int index, int argc, t_atom *argv)
class Value
// Value(t_symbol *s)
virtual ~Value()
t_float get()
void set(t_floatarg f)
class Array
// Array(t_symbol *s)
bool exists(t_garray **a)
float getAt(int n)
float getAt(int n)
void getTable(t_word **vecp, int *sizep)
void setTable(int n, t_floatarg *f)
int getSize()
void setSize(long n)
class Clock
// Clock(t_symbol *s)
// Clock(t_symbol *s, t_symbol *s2)
virtual ~Clock()
void delay(double delayTime)
void unset()
class Sys
double getRealTime()
void lock()
void unlock()
int tryLock()
void gui(t_symbol *s)
class Signal
int getBlockSize()
t_float getSampleRate()
int getInChannels()
int getOutChannels()
bool getDspState()
class PD
int getMaxString()
int getFloatSize()
t_float getMinFloat()
t_float getMaxFloat()
bool isBadFloat(t_floatarg f)
bool isBigOrSmall(t_floatarg f)
tuple<int, int, int> getVersion()
// int maxString;
// int floatSize;
// t_float minFloat;
// t_float maxFloat;
// tuple<int, int, int> version;
class Log
void post(const char *s)
void post(const char *s, int level)
void startPost(const char *s)
void postString(const char *s)
void postFloat(t_floatarg f)
void postAtom(int argc, t_atom *argv)
void endPost()
void error(const char *s)
ofelia lua table and a few questions
@cuinjune i took a look into ofeliaBindings.h and i tried to make a list of the classes and methods that call internal pd methods.
i am not sure if it is correct / complete but at least it is an orientation for me.
class Canvas
int getIndex()
void getArgs(int *argcp, t_atom **argvp, t_canvas **canvasp)
void setArgs(int argc, t_atom *argv)
void getPosition(int **posp)
void setPosition(int xpos, int ypos)
void remove()
class Send
void sendBang()sendFloat(t_floatarg f)
void sendSymbol(t_symbol *s)
void sendPointer(t_gpointer *p)
void sendList(int argc, t_atom *argv)
void sendAnything(int argc, t_atom *argv)
class Inlet
void setFloatInlet(t_floatarg f)
void setFloatInlets(int n, t_floatarg *f)
void setSignalInlet(t_floatarg f)
class Outlet
void outletBang(int index)
void outletFloat(int index, t_floatarg f)
void outletSymbol(int index, t_symbol *s)
void outletPointer(int index, t_gpointer *p)
void outletList(int index, int argc, t_atom *argv)
void outletAnything(int index, int argc, t_atom *argv)
class Value
void set(t_floatarg f)
class Array
float getAt(int n)
float getAt(int n)
void getTable(t_word **vecp, int *sizep)
void setTable(int n, t_floatarg *f)
int getSize()
void setSize(long n)
class Clock
void delay(double delayTime)
void unset()
class Sys
double getRealTime()
void lock()
void unlock()
int tryLock()
void gui(t_symbol *s)
class PD
int getMaxString()
int getFloatSize()
t_float getMinFloat()
t_float getMaxFloat()
bool isBadFloat(t_floatarg f)
bool isBigOrSmall(t_floatarg f)
tuple<int, int, int> getVersion()
use of threads for i²c I/O external : looking for a good strategy
@nau Hi, same boat (I don't know much about Pd internal functions & pthread), but maybe you can try to see if this external (really similar to my template, but this time to fetch real data for my HiCu project).
Look for m_clock / m_interval and clock_delay.
// ==============================================================================
// gac.c
//
// pd-Interface to [ 11h11 | gac ]
// Adapted by: Patrick Sebastien Coulombe
// Website: http://www.workinprogress.ca/guitare-a-crayon
//
// Original Author: Michael Egger
// Copyright: 2007 [ a n y m a ]
// Website: http://gnusb.sourceforge.net/
//
// License: GNU GPL 2.0 www.gnu.org
// Version: 2009-04-11
// ==============================================================================
// ==============================================================================
#include "m_pd.h"
#include <usb.h> //http://libusb-win32.sourceforge.net
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pthread.h"
#include "../common/gac_cmds.h"
// ==============================================================================
// Constants
// ------------------------------------------------------------------------------
#define USBDEV_SHARED_VENDOR 0x16c0 /* VOTI */
#define USBDEV_SHARED_PRODUCT 0x05dc /* Obdev's free shared PID */
#define DEFAULT_CLOCK_INTERVAL 34 /* ms */
#define OUTLETS 11
#define USBREPLYBUFFER 14
unsigned char buffer[USBREPLYBUFFER]; //accessible everywhere
// ==============================================================================
// Our External's Memory structure
// ------------------------------------------------------------------------------
typedef struct _gac // defines our object's internal variables for each instance in a patch
{
t_object p_ob; // object header - ALL pd external MUST begin with this...
usb_dev_handle *dev_handle; // handle to the gac usb device
void *m_clock; // handle to our clock
double m_interval; // clock interval for polling edubeat
double m_interval_bak; // backup clock interval for polling edubeat
int is_running; // is our clock ticking?
void *outlets[OUTLETS]; // handle to the objects outlets
int x_verbose;
pthread_attr_t gac_thread_attr;
pthread_t x_threadid;
} t_gac;
void *gac_class; // global pointer to the object class - so pd can reference the object
// ==============================================================================
// Function Prototypes
// ------------------------------------------------------------------------------
void *gac_new(t_symbol *s);
void gac_assist(t_gac *x, void *b, long m, long a, char *s);
void gac_bang(t_gac *x);
void gac_bootloader(t_gac *x);
static int usbGetStringAscii(usb_dev_handle *dev, int ndex, int langid, char *buf, int buflen);
void find_device(t_gac *x);
// =============================================================================
// Threading
// ------------------------------------------------------------------------------
static void *usb_thread_read(void *w)
{
t_gac *x = (t_gac*) w;
int nBytes;
while(1) {
pthread_testcancel();
if (!(x->dev_handle)) find_device(x);
else {
nBytes = usb_control_msg(x->dev_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
EDUBEAT_CMD_POLL, 0, 0, (char *)buffer, sizeof(buffer), DEFAULT_CLOCK_INTERVAL);
if(x->x_verbose)post("thread read %i bytes", nBytes);
//post("%i b", nBytes);
}
}
return 0;
}
static void usb_thread_start(t_gac *x) {
// create the worker thread
if(pthread_attr_init(&x->gac_thread_attr) < 0)
{
error("gac: could not launch receive thread");
return;
}
if(pthread_attr_setdetachstate(&x->gac_thread_attr, PTHREAD_CREATE_DETACHED) < 0)
{
error("gac: could not launch receive thread");
return;
}
if(pthread_create(&x->x_threadid, &x->gac_thread_attr, usb_thread_read, x) < 0)
{
error("gac: could not launch receive thread");
return;
}
else
{
if(x->x_verbose)post("gac: thread %d launched", (int)x->x_threadid );
}
}
//--------------------------------------------------------------------------
// - Message: bootloader
//--------------------------------------------------------------------------
void gac_bootloader(t_gac *x)
{
int cmd;
int nBytes;
unsigned char bootloaderbuffer[8];
cmd = 0;
cmd = EDUBEAT_CMD_START_BOOTLOADER;
if (!(x->dev_handle)) find_device(x);
else {
nBytes = usb_control_msg(x->dev_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
cmd, 0, 0, (char *)bootloaderbuffer, sizeof(bootloaderbuffer), DEFAULT_CLOCK_INTERVAL);
}
}
//--------------------------------------------------------------------------
// - Message: bang -> poll gac
//--------------------------------------------------------------------------
void gac_bang(t_gac *x) {
int i,n;
int replymask,replyshift,replybyte;
int temp;
for (i = 0; i < OUTLETS; i++) {
temp = buffer[i];
switch(i) {
case 0:
replybyte = buffer[8];
replyshift = ((0 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 1:
replybyte = buffer[8];
replyshift = ((1 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 2:
replybyte = buffer[8];
replyshift = ((2 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 3:
replybyte = buffer[8];
replyshift = ((3 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 4:
replybyte = buffer[9];
replyshift = ((0 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 5:
replybyte = buffer[9];
replyshift = ((1 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 6:
replybyte = buffer[9];
replyshift = ((2 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 8:
temp = buffer[10];
replybyte = buffer[13];
replyshift = ((0 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 9:
temp = buffer[11];
replybyte = buffer[13];
replyshift = ((1 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 10:
temp = buffer[12];
replybyte = buffer[13];
replyshift = ((2 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
}
outlet_float(x->outlets[i], temp);
}
}
//--------------------------------------------------------------------------
// - The clock is ticking, tic, tac...
//--------------------------------------------------------------------------
void gac_tick(t_gac *x) {
clock_delay(x->m_clock, x->m_interval); // schedule another tick
gac_bang(x); // poll the edubeat
}
//--------------------------------------------------------------------------
// - Object creation and setup
//--------------------------------------------------------------------------
int gac_setup(void)
{
gac_class = class_new ( gensym("gac"),(t_newmethod)gac_new, 0, sizeof(t_gac), CLASS_DEFAULT,0);
// Add message handlers
class_addbang(gac_class, (t_method)gac_bang);
class_addmethod(gac_class, (t_method)gac_bootloader, gensym("bootloader"), A_DEFSYM,0);
post("bald-approved gac version 0.1",0);
return 1;
}
//--------------------------------------------------------------------------
void *gac_new(t_symbol *s) // s = optional argument typed into object box (A_SYM) -- defaults to 0 if no args are typed
{
t_gac *x; // local variable (pointer to a t_gac data structure)
x = (t_gac *)pd_new(gac_class); // create a new instance of this object
x->m_clock = clock_new(x,(t_method)gac_tick);
x->x_verbose = 0;
x->m_interval = DEFAULT_CLOCK_INTERVAL;
x->m_interval_bak = DEFAULT_CLOCK_INTERVAL;
x->dev_handle = NULL;
int i;
// create outlets and assign it to our outlet variable in the instance's data structure
for (i=0; i < OUTLETS; i++) {
x->outlets[i] = outlet_new(&x->p_ob, &s_float);
}
usb_thread_start(x); //start polling the device
clock_delay(x->m_clock,0.); //start reading the buffer
return x; // return a reference to the object instance
}
//--------------------------------------------------------------------------
// - Object destruction
//--------------------------------------------------------------------------
void gac_free(t_gac *x)
{
if (x->dev_handle) usb_close(x->dev_handle);
freebytes((t_object *)x->m_clock, sizeof(x->m_clock));
while(pthread_cancel(x->x_threadid) < 0)
if(x->x_verbose)post("gac: killing thread\n");
if(x->x_verbose)post("gac: thread canceled\n");
}
//--------------------------------------------------------------------------
// - USB Utility Functions
//--------------------------------------------------------------------------
static int usbGetStringAscii(usb_dev_handle *dev, int ndex, int langid, char *buf, int buflen)
{
char asciibuffer[256];
int rval, i;
if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + ndex, langid, asciibuffer, sizeof(asciibuffer), 1000)) < 0)
return rval;
if(asciibuffer[1] != USB_DT_STRING)
return 0;
if((unsigned char)asciibuffer[0] < rval)
rval = (unsigned char)asciibuffer[0];
rval /= 2;
/* lossy conversion to ISO Latin1 */
for(i=1;i<rval;i++){
if(i > buflen) /* destination buffer overflow */
break;
buf[i-1] = asciibuffer[2 * i];
if(asciibuffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
buf[i-1] = '?';
}
buf[i-1] = 0;
return i-1;
}
//--------------------------------------------------------------------------
void find_device(t_gac *x) {
usb_dev_handle *handle = NULL;
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for(bus=usb_busses; bus; bus=bus->next){
for(dev=bus->devices; dev; dev=dev->next){
if(dev->descriptor.idVendor == USBDEV_SHARED_VENDOR && dev->descriptor.idProduct == USBDEV_SHARED_PRODUCT){
char string[256];
int len;
handle = usb_open(dev); /* we need to open the device in order to query strings */
if(!handle){
error ("Warning: cannot open USB device: %s", usb_strerror());
continue;
}
/* now find out whether the device actually is gac */
len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
if(len < 0){
post("gac: warning: cannot query manufacturer for device: %s", usb_strerror());
goto skipDevice;
}
post("::::::%s", string);
if(strcmp(string, "11h11") != 0)
goto skipDevice;
len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
if(len < 0){
post("gac: warning: cannot query product for device: %s", usb_strerror());
goto skipDevice;
}
if(strcmp(string, "Gac") == 0)
break;
skipDevice:
usb_close(handle);
handle = NULL;
}
}
if(handle)
break;
}
if(!handle){
post("Could not find USB device 11h11/gac");
x->dev_handle = NULL;
} else {
x->dev_handle = handle;
post("Found USB device 11h11/gac");
}
}
Cheers
Which fft-code is built into Pd binaries?
Does anyone happen to know which fft-code is built into Pd / Pd-extended binary releases?
The source file d_fft.c states that it interfaces 'to one of the Mayer, Ooura or fftw FFT packages to implement the "fft~", etc, Pd objects. ... The configure script can be used to select which one.'
The configure.in script in SVN says about fftw:
AC_SUBST(fftw, no)
AC_ARG_ENABLE(fftw, [ --enable-fftw use FFTW package],
fftw=$enableval)
dnl Check for fftw package
if test x$fftw = "xyes";
then
AC_CHECK_LIB(fftw, fftw_one,PDLIB="$PDLIB -lfftw",
echo "fftw package not found - using built-in FFT"; fftw=no)
So it depends on the build machines. On the other hand, [partconv~] from Ben Saylor depends on fftw and this object works fine, at least in 0.42.5-extended build for OSX.
From these bits I conclude that fftw is built into Pd binaries and also used for [fft~] & co. Is that correct? fftw claims to be the fastest. Not that it is very important to me, I am just curious.
Katja
Interaction Design Student Patches Available
Greetings all,
I have just posted a collection of student patches for an interaction design course I was teaching at Emily Carr University of Art and Design. I hope that the patches will be useful to people playing around with Pure Data in a learning environment, installation artwork and other uses.
The link is: http://bit.ly/8OtDAq
or: http://www.sfu.ca/~leonardp/VideoGameAudio/main.htm#patches
The patches include multi-area motion detection, colour tracking, live audio looping, live video looping, collision detection, real-time video effects, real-time audio effects, 3D object manipulation and more...
Cheers,
Leonard
Pure Data Interaction Design Patches
These are projects from the Emily Carr University of Art and Design DIVA 202 Interaction Design course for Spring 2010 term. All projects use Pure Data Extended and run on Mac OS X. They could likely be modified with small changes to run on other platforms as well. The focus was on education so the patches are sometimes "works in progress" technically but should be quite useful for others learning about PD and interaction design.
NOTE: This page may move, please link from: http://www.VideoGameAudio.com for correct location.
Instructor: Leonard J. Paul
Students: Ben, Christine, Collin, Euginia, Gabriel K, Gabriel P, Gokce, Huan, Jing, Katy, Nasrin, Quinton, Tony and Sandy
GabrielK-AsteroidTracker - An entire game based on motion tracking. This is a simple arcade-style game in which the user must navigate the spaceship through a field of oncoming asteroids. The user controls the spaceship by moving a specifically coloured object in front of the camera.
Features: Motion tracking, collision detection, texture mapping, real-time music synthesis, game logic
GabrielP-DogHead - Maps your face from the webcam onto different dog's bodies in real-time with an interactive audio loop jammer. Fun!
Features: Colour tracking, audio loop jammer, real-time webcam texture mapping
Euginia-DanceMix - Live audio loop playback of four separate channels. Loop selection is random for first two channels and sequenced for last two channels. Slow volume muting of channels allows for crossfading. Tempo-based video crossfading.
Features: Four channel live loop jammer (extended from Hardoff's ma4u patch), beat-based video cross-cutting
Huan-CarDance - Rotates 3D object based on the audio output level so that it looks like it's dancing to the music.
Features: 3D object display, 3d line synthesis, live audio looper
Ben-VideoGameWiiMix - Randomly remixes classic video game footage and music together. Uses the wiimote to trigger new video by DarwiinRemote and OSC messages.
Features: Wiimote control, OSC, tempo-based video crossmixing, music loop remixing and effects
Christine-eMotionAudio - Mixes together video with recorded sounds and music depending on the amount of motion in the webcam. Intensity level of music increases and speed of video playback increases with more motion.
Features: Adaptive music branching, motion blur, blob size motion detection, video mixing
Collin-LouderCars - Videos of cars respond to audio input level.
Features: Video switching, audio input level detection.
Gokce-AVmixer - Live remixing of video and audio loops.
Features: video remixing, live audio looper
Jing-LadyGaga-ing - Remixes video from Lady Gaga's videos with video effects and music effects.
Features: Video warping, video stuttering, live audio looper, audio effects
KatyC_Bunnies - Triggers video and audio using multi-area motion detection. There are three areas on each side to control the video and audio loop selections. Video and audio loops are loaded from directories.
Features: Multi-area motion detection, audio loop directory loader, video loop directory loader
Nasrin-AnimationMixer - Hand animation videos are superimposed over the webcam image and chosen by multi-area motion sensing. Audio loop playback is randomly chosen with each new video.
Features: Multi-area motion sensing, audio loop directory loader
Quintons-AmericaRedux - Videos are remixed in response to live audio loop playback. Some audio effects are mirrored with corresponding video effects.
Features: Real-time video effects, live audio looper
Tony-MusicGame - A music game where the player needs to find how to piece together the music segments triggered by multi-area motion detection on a webcam.
Features: Multi-area motion detection, audio loop directory loader
Sandy-Exerciser - An exercise game where you move to the motions of the video above the webcam video. Stutter effects on video and live audio looper.
Features: Video stutter effect, real-time webcam video effects
How to Enjoy Your Favorite Videos on Portable Devices at Will For Mac
Are you a Mac user?
Do you still feel frustrated that you can't enjoy your favorite videos on portable devices at will?
Now, a professional software---Aiseesoft Video Converter for Mac(http://www.aiseesoft.com/video-converter-for-mac.html)
can help you to solve all the problems. With it, you can convert between all popular video and audio formats with super fast conversion speed and high output quality, such as AVI, MP4, MOV, MKV, WMV, DivX, XviD, MPEG-1/2, 3GP, 3G2, VOB Video, MP3, AAC, and AC3 Audio etc. In addition, the best video converter for Mac can also extract audio from video file and convert video to MP3, AC3, and AAC...as you want.
OK, let's move to how to use the amazing software.
Step 0: Download and install Aiseesoft Video Converter for Mac.
After a while, you can use the following interface:
http://www.aiseesoft.com/images/guide/dvd-converter-suite-mac/video.jpg
Step 2. Load Video
You can load your video by clicking "Add File" button or clicking "File" button, you can choose "add file" on a drop-down list.
Step 3. Output format and Settings
From the "Profile" drop-down list you can find one format that meets your requirement.
After doing the 3 steps above, you can click "start" button to start conversion.
Wait a minute, the conversion will be soon finished.
Tips:
1. Trim
"Trim" function is for you to select the clips you want to convert.
There are 3 ways that you can trim your video.
a. You can drag the buttons(1) to set the start and end time
b. You can preview the video first and when you want to start trim click the left one of the pair buttons(2) when you want to end click the right one.
c. You can set the exact start and end time on the right side of the pop-up window.
It is for you to select the clips you want to convert.
http://www.aiseesoft.com/images/guide/dvd-ripper-for-mac/trim.jpg
2. Crop
Cut off the black edges of the original movie video and watch in full screen using the "Crop" function.
There are 3 ways that you can crop your video.
a. We provide 7 modes on our "Crop Mode"(1)
b. You can set your own mode on the right side of the pop-up window(2)
c. You can drag frame to set your own crop mode(3)
You can cut off the black edges of the original movie video and watch in full screen using the "Crop" function.
http://www.aiseesoft.com/images/guide/dvd-ripper-for-mac/crop.jpg
3. Snapshot and merge into one file
If you like the current image of the video you can use the "Snapshot" option. Just click the "Snapshot" button the image will be saved and you can click the "Open" button next to "Snapshot" button to open your picture.
If you want to make several files output as one you can choose "Merge into one file".
If you are windows users, you can go to Aiseesoft Total Video Converter(http://www.aiseesoft.com/total-video-converter.html) to get more information.