hi all,

i have this external that use libusb. everything is fine if i use alsa, but when using jack every usb poll i get a glitch. why? would it be possible to avoid this glitch? is this a threading issue? why this external is affecting the dsp of pd?

pat

#include "m_pd.h"
#include <usb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ==============================================================================
// Constants
// ------------------------------------------------------------------------------
#define USBDEV_SHARED_VENDOR    	0x16c0  /* VOTI */
#define USBDEV_SHARED_PRODUCT   	0x05dc  /* Obdev's free shared PID */
#define OUTLETS 					17
#define DEFAULT_CLOCK_INTERVAL		10		// Magic number 6 (with alsa, under 6 = glitch)
#define USBREPLYBUFFER 				21

// ==============================================================================
// Our External's Memory structure
// ------------------------------------------------------------------------------
typedef struct _edubeat				// 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 edubeat 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 			values[10];				// stored values from last poll /////////////////////////////////
} t_edubeat;

void *edubeat_class;					// global pointer to the object class - so pd can reference the object 


// ==============================================================================
// Function Prototypes
// ------------------------------------------------------------------------------
void *edubeat_new(t_symbol *s);
void edubeat_assist(t_edubeat *x, void *b, long m, long a, char *s);
void edubeat_bang(t_edubeat *x);				
void edubeat_close(t_edubeat *x);
void edubeat_int(t_edubeat *x, t_floatarg n);
void edubeat_open(t_edubeat *x);
void edubeat_poll(t_edubeat *x, t_floatarg n);
void edubeat_start(t_edubeat *x);
void edubeat_stop(t_edubeat *x);

// functions used to find the USB device
static int  	usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen);
void 			find_device(t_edubeat *x);


//--------------------------------------------------------------------------
// - Message: bang  -> poll edubeat
//--------------------------------------------------------------------------
void edubeat_bang(t_edubeat *x)	// poll edubeat
{
	int                 nBytes,i,n;
	int 				replymask,replyshift,replybyte;
	int					temp;
	unsigned char       buffer[USBREPLYBUFFER];
	
	if (!(x->dev_handle)) find_device(x);
	else {
			// ask edubeat to send us data
			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), 10);
			
			for (i = 0; i < OUTLETS; i++) {
				outlet_float(x->outlets[i], buffer[i]);
			}
	}
}

//--------------------------------------------------------------------------
// - Message: poll 		-> set polling interval
//--------------------------------------------------------------------------
void edubeat_poll(t_edubeat *x, t_floatarg n){
	if (n > 0) { 
		x->m_interval = n;
		x->m_interval_bak = n;
		edubeat_start(x);
	} else {
		edubeat_stop(x);
	}
}

//--------------------------------------------------------------------------
// - Message: open 		-> open connection to edubeat
//--------------------------------------------------------------------------
void edubeat_open(t_edubeat *x)
{
	if (x->dev_handle) {
		post("There is already a connection to Edubeat", 0);
	} else find_device(x);
}

//--------------------------------------------------------------------------
// - Message: close 	-> close connection to edubeat
//--------------------------------------------------------------------------
void edubeat_close(t_edubeat *x)
{
	if (x->dev_handle) {
		usb_close(x->dev_handle);
		x->dev_handle = NULL;
		post("Closed connection to Edubeat",0);
	} else
		post("There was no open connection to Edubeat",0);
}

//--------------------------------------------------------------------------
// - Message: int 		-> zero stops / nonzero starts
//--------------------------------------------------------------------------
void edubeat_int(t_edubeat *x, t_floatarg n) {
	if (n) {
		if (!x->is_running) edubeat_start(x);
	} else {
		if (x->is_running) edubeat_stop(x);
	}
}

//--------------------------------------------------------------------------
// - Message: start 	-> start automatic polling
//--------------------------------------------------------------------------
void edubeat_start (t_edubeat *x) { 
	if (!x->is_running) {
		clock_delay(x->m_clock,0.);
		x->is_running  = 1;
	}
} 

//--------------------------------------------------------------------------
// - Message: stop 		-> stop automatic polling
//--------------------------------------------------------------------------
void edubeat_stop (t_edubeat *x) { 
	if (x->is_running) {
		x->is_running  = 0;
		clock_unset(x->m_clock); 
		edubeat_close(x);
	}
}

//--------------------------------------------------------------------------
// - The clock is ticking, tic, tac...
//--------------------------------------------------------------------------
void edubeat_tick(t_edubeat *x) { 
	clock_delay(x->m_clock, x->m_interval); 	// schedule another tick
	edubeat_bang(x); 								// poll the edubeat
} 

//--------------------------------------------------------------------------
// - Object creation and setup
//--------------------------------------------------------------------------
int edubeat_setup(void)
{
	edubeat_class = class_new ( gensym("edubeat"),(t_newmethod)edubeat_new, 0, sizeof(t_edubeat), 	CLASS_DEFAULT,0);
	
	// Add message handlers
	class_addbang(edubeat_class, (t_method)edubeat_bang);
	class_addfloat(edubeat_class, (t_method)edubeat_int);
	class_addmethod(edubeat_class, (t_method)edubeat_open, gensym("open"), 0);		
	class_addmethod(edubeat_class, (t_method)edubeat_close, gensym("close"), 0);	
	class_addmethod(edubeat_class, (t_method)edubeat_poll, gensym("poll"), A_DEFFLOAT,0);	
	class_addmethod(edubeat_class, (t_method)edubeat_start, gensym("start"), 0);	
	class_addmethod(edubeat_class, (t_method)edubeat_stop, gensym("stop"), 0);	
	post("edubeat version 0.1",0);
	return 1;
}

//--------------------------------------------------------------------------
void *edubeat_new(t_symbol *s)		// s = optional argument typed into object box (A_SYM) -- defaults to 0 if no args are typed
{
	t_edubeat *x;									// local variable (pointer to a t_edubeat data structure)
	x = (t_edubeat *)pd_new(edubeat_class);			 // create a new instance of this object
	x->m_clock = clock_new(x,(t_method)edubeat_tick); 	// make new clock for polling and attach gnsub_tick function to it
	
	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);
	}	

	return x; // return a reference to the object instance 
}

//--------------------------------------------------------------------------
// - Object destruction
//--------------------------------------------------------------------------
void edubeat_free(t_edubeat *x)
{
	if (x->dev_handle) usb_close(x->dev_handle);
	freebytes((t_object *)x->m_clock, sizeof(x->m_clock));
}

//--------------------------------------------------------------------------
// - USB Utility Functions
//--------------------------------------------------------------------------
static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen)
{
char    buffer[256];
int     rval, i;

    if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0)
        return rval;
    if(buffer[1] != USB_DT_STRING)
        return 0;
    if((unsigned char)buffer[0] < rval)
        rval = (unsigned char)buffer[0];
    rval /= 2;
    /* lossy conversion to ISO Latin1 */
    for(i=1;i<rval;i++){
        if(i > buflen)  /* destination buffer overflow */
            break;
        buf[i-1] = buffer[2 * i];
        if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
            buf[i-1] = '?';
    }
    buf[i-1] = 0;
    return i-1;
}

//--------------------------------------------------------------------------
void find_device(t_edubeat *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 edubeat */
                len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
                if(len < 0){
                    post("Edubeat: warning: cannot query manufacturer for device: %s", usb_strerror());
                    goto skipDevice;
                }
                
                if(strcmp(string, "11h11") != 0)
                    goto skipDevice;
                len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
                if(len < 0){
                    post("Edubeat: 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 Edubeat");
		x->dev_handle = NULL;
		if (x->m_interval < 10000) x->m_interval *=2; // throttle polling down to max 20s if we can't find edubeat
	} else {
		x->dev_handle = handle;
		 post("Found USB device Edubeat");
		 x->m_interval = x->m_interval_bak;			// restore original polling interval
		 if (x->is_running) edubeat_tick(x);
		 else edubeat_bang(x);
	}
}
_______________________________________________
[email protected] mailing list
UNSUBSCRIBE and account-management -> 
http://lists.puredata.info/listinfo/pd-list

Reply via email to