Matrices and reallocating memory
I tried to find all my errors, corrected them and now it seemes to work.
(The method init_array is still missing a check if allocations failed.)
Do I really have to free the colums before reallocating the rows? Isn't it the other way around?
#include "m_pd.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
static t_class *average_tilde_class;
typedef struct _average_tilde {
t_object x_obj;
t_int len_avg;
t_int block_size;
t_int pos;
t_sample **sampel_arr;
t_sample *avg;
t_inlet* x_in;
t_outlet* x_out;
} t_average_tilde;
void average_tilde_free (t_average_tilde *x)
{
// Deallocate rows
for (int i = 0; i < x->len_avg; ++i)
free(x->sampel_arr[i]);
// Deallocate columns
free(x->sampel_arr);
// Deallocate avg
free(x->avg);
}
t_int *average_tilde_perform(t_int *w)
{
t_average_tilde *x = (t_average_tilde *)(w[1]);
t_sample *in = (t_sample *)(w[2]);
t_sample *out = (t_sample *)(w[3]);
//int block = (int)(w[4]);
t_sample val;
for (int n = 0; n < x->block_size; n++) {
x->avg[n] -= x->sampel_arr[x->pos][n];
val = in[n] / x->block_size;
x->avg[n] += val;
x->sampel_arr[x->pos][n] = val;
*out++ = x->avg[n];
}
x->pos++;
if (x->pos == x->len_avg) x->pos = 0;
return (w + 5);
}
void resize_avg_array(t_average_tilde *x, int len_avg_new)
{
int i,j;
int success = 1;
t_sample **temp = NULL;
t_sample *temp2 = NULL;
do {
success = 1;
// Allocate the columns
temp = realloc(temp, len_avg_new * sizeof(t_sample*));
if (temp == NULL) {
len_avg_new--;
free(temp);
success = 0;
}
else {
// The new column's pointer must be initialised to NULL
for (i = 0; i < len_avg_new; i++)
temp[i] = NULL;
// Allocate the rows
for (i = 0; i < len_avg_new; i++) {
temp[i] = realloc(temp[i], x->block_size * sizeof(t_sample));
if (temp[i] == NULL) {
len_avg_new--;
success = 0;
break;
}
else {
// Initialize the element(s)
for (j = 0; j < x->block_size; j++)
temp[i][j] = 0.0;
}
}
if (success == 1) {
// Initialize avg-array
temp2 = realloc(temp2, x->block_size * sizeof(t_sample));
if (temp2 == NULL) {
len_avg_new--;
success = 0;
free(temp2);
}
else {
// Initialize the element(s)
for (i = 0; i < x->block_size; i++)
temp2[i] = 0.0;
}
if (success == 1) {
// Deallocate rows
for (i = 0; i < x->len_avg; ++i)
free(x->sampel_arr[i]);
// Deallocate columns
free(x->sampel_arr);
// Copy temps to arrays
x->len_avg = len_avg_new;
x->sampel_arr = temp;
free(x->avg);
x->avg = temp2;
x->pos = 0;
}
}
}
} while (success = 0 && len_avg_new > 0);
if (success = 0) {
post("length of avg-vector stayed at %i samples", x->len_avg);
}
}
void average_tilde_dsp(t_average_tilde *x, t_signal **sp)
{
x->block_size = sp[0]->s_n;
float arr_size = sizeof(x->sampel_arr) / sizeof(x->sampel_arr[0][0]);
if (x->block_size * x->len_avg != arr_size)
resize_avg_array(x, 10);
dsp_add(average_tilde_perform, 4,
x,
sp[0]->s_vec,
sp[1]->s_vec,
sp[0]->s_n);
}
void set_len_avg(t_average_tilde *x, t_floatarg f)
{
if ((int)f > 0)
resize_avg_array(x, f);
}
void init_array(t_average_tilde *x)
{
int i = 0, j = 0;
// Allocate the columns
x->sampel_arr = (t_sample**)calloc(x->len_avg, sizeof(t_sample*));
// Allocate the rows
for (i = 0; i < x->len_avg; i++)
x->sampel_arr[i] = (t_sample*)calloc(x->block_size, sizeof(t_sample));
// Initialize the element(s)
for (i = 0; i < x->len_avg; i++)
for (j = 0; j < x->block_size; j++)
x->sampel_arr[i][j] = 0.0;
// Initialize avg-array
x->avg = realloc(x->avg, x->block_size * sizeof(t_sample));
for (j = 0; j < x->block_size; j++)
x->avg[j] = 0.0;
}
void *average_tilde_new(t_floatarg f)
{
t_average_tilde *x = (t_average_tilde *)pd_new(average_tilde_class);
// initialize values with defaults
x->len_avg = ((int)f > 0) ? (int)f : 10;
x->block_size = 64;
x->pos = 0;
init_array(x);
x->x_out = outlet_new(&x->x_obj, &s_signal);
return (void *)x;
}
void init_average(void) {
average_tilde_class = class_new(gensym("r_avg~"),
(t_newmethod)average_tilde_new,
(t_method)average_tilde_free,
sizeof(t_average_tilde),
CLASS_DEFAULT,
A_DEFFLOAT, 0);
class_addmethod(average_tilde_class,
(t_method)average_tilde_dsp, gensym("dsp"), 0);
CLASS_MAINSIGNALIN(average_tilde_class, t_average_tilde, len_avg);
class_addfloat(average_tilde_class, set_len_avg);
}
void helloworld_setup(void) {
init_average();
}
EDIT: Corrected some logical errors in the code.
The variable success has to be set to 1 in each do while loop
The arrays x->sampel_arr and x->avg have to be freed inside the do while loop
Matrices and reallocating memory
EDIT:
The original thread title was: Interrupt/disable perform method while reallocating memory
I changed it, as it was based on searching for a solution caused by faulty code.
After discarding my code the topic of the thread got a new direction.
Hi,
I try to write an external, which calculates the averages of samples at their positions over time.
For example:
With average time = 3:
3 signals given over 3 blocks: [1, 3, 5 ...], [2, 4, 6...],[1, 3, 5...] should result in [1.33, 3,33, 5,33, ...]
The example code below works, as long as I don't try to resize the average time to a lower value while dsp is running.
On changing the average time while dsp is on, my code reallocates memory for the average vector. The result is an exception in the perform method in line 53 x->avg[n] -= x->sampel_arr[x->pos][n];
The commented lines using x->busy were an attempt to use a switch. But the code of the switch is never used, so it doesn't work.
Does anybody have an idea how to bypass the perform method while memory is reallocated?
#include "m_pd.h"
#include <string.h>
#include <stdlib.h>
static t_class *average_tilde_class;
typedef struct _average_tilde {
t_object x_obj;
t_int len_delay;
t_int block_size;
t_int pos;
t_sample **sampel_arr;
t_float *avg;
t_int busy;
t_inlet* x_in;
t_outlet* x_out;
} t_average_tilde;
void average_tilde_free(t_average_tilde *x)
{
// Deallocate rows
for (int i = 0; i < x->len_delay; ++i)
free(x->sampel_arr[i]);
// Deallocate columns
free(x->sampel_arr);
// Deallocate avg
free(x->avg);
}
t_int *average_tilde_perform(t_int *w)
{
t_average_tilde *x = (t_average_tilde *)(w[1]);
t_sample *in = (t_sample *)(w[2]);
t_sample *out = (t_sample *)(w[3]);
int block = (int)(w[4]);
/*if (x->busy == 1) {
while (block--) {
*out++ = *in++;
}
return (w + 5);
};*/
float val;
for (int n = 0; n < x->block_size; n++) {
x->avg[n] -= x->sampel_arr[x->pos][n];
val = in[n] / x->block_size;
x->avg[n] += val;
x->sampel_arr[x->pos][n] = val;
*out++ = x->avg[n];
}
x->pos++;
if (x->pos == x->len_delay) x->pos = 0;
return (w + 5);
}
void resize_avg_array(t_average_tilde *x)
{
int i,j;
/*post("resize");
x->busy = 1;*/
// Allocate the columns
x->sampel_arr = (int**)realloc(x->sampel_arr, x->len_delay * sizeof(int*));
/*if (x->sampel_arr == NULL)
post("error");*/
// The new column's pointer must be initialised to NULL
for (i = 0; i < x->len_delay; i++)
x->sampel_arr[i] = NULL;
// Allocate the rows
for (i = 0; i < x->len_delay; i++) {
x->sampel_arr[i] = (float*)realloc(x->sampel_arr[i], x->block_size * sizeof(float));
/*if (x->sampel_arr == NULL)
post("error");*/
}
// Initialize the element(s)
for (i = 0; i < x->len_delay; i++)
for (j = 0; j < x->block_size; j++)
x->sampel_arr[i][j] = 0.0;
// Allocate avg-array
x->avg = realloc(x->avg, x->block_size * sizeof(float));
/*if (x->avg == NULL)
post("error");*/
// Initialize avg-array
for (i = 0; i < x->block_size; i++)
x->avg[i] = 0.0;
/*x->busy = 0;
post("resize2");
post(" ");*/
}
void average_tilde_dsp(t_average_tilde *x, t_signal **sp)
{
x->block_size = sp[0]->s_n;
float arr_size = sizeof(x->sampel_arr) / sizeof(x->sampel_arr[0][0]);
if (x->block_size * x->len_delay != arr_size)
resize_avg_array(x);
dsp_add(average_tilde_perform, 4,
x,
sp[0]->s_vec,
sp[1]->s_vec,
sp[0]->s_n);
}
void set_len_delay(t_average_tilde *x, t_floatarg f)
{
if ((int)f > 0) x->len_delay = (int)f;
resize_avg_array(x);
}
void init_array(t_average_tilde *x)
{
int i = 0, j = 0;
// Allocate the columns
x->sampel_arr = (int**)calloc(x->len_delay, sizeof(int*));
// Allocate the rows
for (i = 0; i < x->len_delay; i++)
x->sampel_arr[i] = (float*)calloc(x->block_size, sizeof(float));
// Initialize the element(s)
for (i = 0; i < x->len_delay; i++)
for (j = 0; j < x->block_size; j++)
x->sampel_arr[i][j] = 0.0;
// Initialize avg-array
x->avg = realloc(x->avg, x->block_size * sizeof(float));
for (j = 0; j < x->block_size; j++)
x->avg[j] = 0.0;
}
void *average_tilde_new(t_floatarg f)
{
t_average_tilde *x = (t_average_tilde *)pd_new(average_tilde_class);
// initialize values with defaults
x->len_delay = ((int)f > 0) ? (int)f : 10;
x->block_size = 64;
x->pos = 0;
init_array(x);
x->busy = 0;
x->x_out = outlet_new(&x->x_obj, &s_signal);
return (void *)x;
}
void init_average(void) {
average_tilde_class = class_new(gensym("r_avg~"),
(t_newmethod)average_tilde_new,
(t_method)average_tilde_free,
sizeof(t_average_tilde),
CLASS_DEFAULT,
A_DEFFLOAT, 0);
class_addmethod(average_tilde_class,
(t_method)average_tilde_dsp, gensym("dsp"), 0);
CLASS_MAINSIGNALIN(average_tilde_class, t_average_tilde, len_delay);
class_addfloat(average_tilde_class, set_len_delay);
}
void helloworld_setup(void) {
init_average();
}```
// The code for reallocation is taken from here:
// http://hesham-rafi.blogspot.de/2009/02/resize-2d-matrix-using-realloc.html
send list to outlet in external
Hi,
I try to write an external, which sends a list to an outlet.
The following code is an example of calculating the maximum of a signal and send the maximum and it's index to the outlet.
But line 30 outlet_float(x->f_out, (max[0], max[1]) ); does only send one value to the outlet.
How can I achieve to send lists?
Thanks for help in advance,
Xaver
#include "m_pd.h"
static t_class *maximum_tilde_class;
typedef struct _maximum_tilde {
t_object x_obj;
t_sample d;
t_inlet*x_in1;
t_outlet*f_out;
} t_maximum_tilde;
t_int *maximum_tilde_perform(t_int *w)
{
t_maximum_tilde *x = (t_maximum_tilde *)(w[1]);
t_sample *in1 = (t_sample *)(w[2]);
int n = (int)(w[3]);
float max[] = { 0,-1 };
float abs_val = 0;
for (int i = 0; i < n; i++) {
abs_val = fabs(in1[i]);
if (abs_val > max[0]) {
max[0] = abs_val;
max[1] = i;
}
}
outlet_float(x->f_out, (max[0], max[1]) );
return (w + 4);
}
void maximum_tilde_dsp(t_maximum_tilde *x, t_signal **sp)
{
dsp_add(maximum_tilde_perform, 3,
x,
sp[0]->s_vec, data forum
sp[0]->s_n);
}
void maximum_tilde_free(t_maximum_tilde *x)
{
inlet_free(x->x_in1);
}
void *maximum_tilde_new(t_floatarg f)
{
t_maximum_tilde *x = (t_maximum_tilde *)pd_new(maximum_tilde_class);
x->f_out = outlet_new(&x->x_obj, &s_list);
return (void *)x;
}
void init_maximum(void) {
maximum_tilde_class = class_new(gensym("max~"),
(t_newmethod)maximum_tilde_new,
0,//(t_method)maximum_tilde_free,
sizeof(t_maximum_tilde),
CLASS_DEFAULT,
A_DEFFLOAT, 0);
class_addmethod(maximum_tilde_class,
(t_method)maximum_tilde_dsp, gensym("dsp"), 0);
CLASS_MAINSIGNALIN(maximum_tilde_class, t_maximum_tilde, d);
}
void helloworld_setup(void) {
init_maximum();
}
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
FFT Normalization with different block sizes
FFT normalization factor depends on FFT frame size (which is equal to blocksize for fft~ & Co.), overlap, and window type.
In my experience you can normalize where ever you want: in time domain before FFT, in frequency domain, or in time domain after FFT. It is also possible to normalize in two steps, each of sqrt(normalization-factor), for example when you want the bin content normalized for certain processing or analysis jobs. Then you do one step before processing and the second after processing.
In frequency domain, you can either normalize amplitude of polar coefficients, or real and imaginary part of rectangular coefficients. This has no consequence for normalization factor.
If you would do normalization outside the reblocked subpatch, that is also possible, before or after FFT patch. But you must still consider blocksize and overlap.
You can verify all these possibilities by tweaking mentioned patch. The fact that normalization factor does not depend on the point in the process where you apply it, is convenient. However, for analysis or processing, that point of normalization does matter sometimes.
Consider for example a single-sample click: it's energy is spread over all frequency bins. With no normalization before spectral analysis, magnitude would be 1 for each bin. Next, consider a perfectly white noise, or a complex linear chirp over the full spectrum. With sqrt(normalization-factor) before analysis, the magnitude is 1 for each bin. Next, consider a pure sinusoid. With full normalization before analysis, the magnitude is 1 for a single bin, or the leaked equivalent of that.
You see, it depends on signal type how spectral magnitude can be shown independent of FFT size. Probably, the signals you want to process resemble a white noise rather than single pulses or full-scale pure sinusoids. So my guess is, that you would opt for the two-step normalization if you want to mix spectral data of different FFT sizes.
Good luck,
Katja
Vd~
1. i've never seen vd~ with a 2nd creation argument before. The first creation argument is of course the buffer name, but i think this second creation argument is just gibberish. It's not really an 'error' because it won't hurt your patch, but it does nothing and means nothing. As far as i know, vd~ only takes one creation argument, everything after that will just be ignored.
2. not sure which loadbang you're talking about
3. vd~ stands for "variable delay", so that's all it does. it plays back the buffer specified in [delwrite~] after a period of ~n ms. This delay time is set by the signal coming into [vd~]. So, for example If you just send a normal phasor~ directly into [vd~] then really not much will happen, because you'd just be changing the delay between 0 and 1 ms. This is equivalent to playing back the buffer with the tiniest of tiny vibrato's.
When it gets interesting, is when you use vd~ to change the delay time by much more than 1ms while the patch runs. The end result of this is much like slowing down or speeding up a tape recorder - you get variations in pitch, basically.
What the Karplus-Strong algorithm does, then, is to send FEEDBACK into this process. That's what 'makes the loop go'. If you look at that patch again, follow the signal chain and you will see what is happening. The [noise~] goes into the buffer. Then the buffer is played back (at a variable rate) by vd~. After that, there is some averaging process (not sure about that bit, but it's basically a lowpass filter, i guess) and then the signal is multiplied by about 0.99 and then sent back into the original [delwrite~] object, where it gets read by the vd~ again, etc...that's your feedback loop, and that's what makes the loop go.
incidentally, i think there's another error in that patch as well. The [dac~] should come BEFORE the 'damping factor' calculation, otherwise, with low damping, you also get low volume.
Oh, and just in case the terminology is confusing: "damping" and "feedback amount" are two sides of the one coin in this case. I prefer to use the term 'feedback' because it more clearly expresses what is happening. 90% feedback = 10% damping, etc.
Invert spectra
toxonic:
did you ever connect that FFT shift subpatch that is hidden in your patch? i just tried that and it works really well.
i can see a really neat school of fx coming out of this:
as far as i know, the following can all be pretty easily applied:
inverse
shift
all sort of EQ effects
feedback
then, some that i just brainstormed, but haven't tried yet:
FFT "bitcrush"
reduce the resolution of each value output by the FFT
LFO'd FFT
use lfo's (or envelopes, or whatever) to modulate FFT outputs. i already tried this a little bit with one of my DIY objects, and it works well.
Randomization:
rather than just an inverse, maybe try some random scrambling on a selected range of the FFT to see what happens.
again, might be even more interesting if the range gets modulated with an LFO or something.
however, the bug 'AHA' moment i just had was that it will be a million times more computationally efficient to include ALL of these things within one FFT analysis, and have switches to turn them on and off as desired.
you know, it's going in and out of the FFT domain that uses most of the cpu resources, so while you're in there, you may as well get as much done as possible.
i'll have a go with this in the coming week and see where i can get. any help or more ideas would be totally excellently appreciated!
Invert spectra
toxonic:
did you ever connect that FFT shift subpatch that is hidden in your patch? i just tried that and it works really well.
i can see a really neat school of fx coming out of this:
as far as i know, the following can all be pretty easily applied:
inverse
shift
all sort of EQ effects
feedback
then, some that i just brainstormed, but haven't tried yet:
FFT "bitcrush"
reduce the resolution of each value output by the FFT
LFO'd FFT
use lfo's (or envelopes, or whatever) to modulate FFT outputs. i already tried this a little bit with one of my DIY objects, and it works well.
Randomization:
rather than just an inverse, maybe try some random scrambling on a selected range of the FFT to see what happens.
again, might be even more interesting if the range gets modulated with an LFO or something.
however, the bug 'AHA' moment i just had was that it will be a million times more computationally efficient to include ALL of these things within one FFT analysis, and have switches to turn them on and off as desired.
you know, it's going in and out of the FFT domain that uses most of the cpu resources, so while you're in there, you may as well get as much done as possible.
i'll have a go with this in the coming week and see where i can get. any help would be excellent!
NVidia puredyne vs vista
Hey
Once again I'm back on vista. My brief journey to puredyne goes something like this.
from puredyne
partitioned new hard drive with 4 partitions 1-swap , 2 ext4 200Gib, 1 NTFS 200GB . Copied Vista to NTFS partition with gparted(started to do this with dd but with new Gibabits stuff I was skeered but hey a platter is a platter and a cluster is a cluster right). Actually there was a 5th partition in there which was the vista restoration partition but I eventually deleted it for obvious reasons.
Removed old drive ,
took machine to ethernet connection with internet,
booted to vista ,
installed Norton virus scanner - only 1 virus, 2 tracking cookies, and one gain trickler after over a year with no virus scanner, Thats pretty good and shows you can be selective about what you download and where you visit on the web and not get any viruses.
Was trying to get windows movie maker to work with mov codec which it doesnt.
Installed auto updates for the first and only time. this took about 3 hours and still needed to install service pack 1, 2. Aborted trying to update win movie maker
****Problem 1***** MS movie maker does not work with GEM mov video output codec.
Installed latest Nvidia drivers for vista.
Woohooo OpenGl hardware acceleration GEM works so much better in vista now.
*****Problem 2********ASIO for all does not allow 2 applications to run with audio and midi at the same time. If I wanted to run Widi and play my guitar so puredata can receive midi input from guitar ASIO will not allow it but ASIO for all is the only way I can get latency down so this would be feasible.
Got frustrated.
Installed fresh copy of puredyne onto 2nd ext4 partition.
ran puredata audio latency good with fresh install. gem video bad.
used synaptics to install nvidia drivers. v185 I think.
ran GEm error no opengl config.
downloaded gdeb , flash player, google chrome, nvidia drivers from nvidia site.
installed gdeb from terminal, flash and chrome from gdeb.
rebooted to log in as root and iunstalled nvidia drivers.
woohoo hardware acceleration for opengl
******problem 3************
gem works great but audio glitches with puredata window visible.
when only gem window is visible i can unaudioglitchily move the mouse around to control same parameters that would normaly be controled with sliders in pd window.
Seems like before i upgraded nvidia video drivers hw:do o whatever it is, was listed in JackD as realtek HD Audio, now it is listed as NVIDIA HD Audio.
So Gem works great but not when Pd window is open and I think my audio drivers were replaced with Nvidia.
I would really like to get back to my patch and stop wasting time on these operating systems and hardware configurations I thought in the last 15 years all this hardware acelleration and autodetection would be figured out but no all we got is rc.0, rc.01, rc.02, rc, etc...... instead of just rc.d.
Ok I'm getting an error when I exit puredyne that says pid file not found is jackd running. anyone know what that means?
Also does anyone have a keymap for gem keyboard for linux, windows and mac so I don't have to record them.
Any suggestions about what to do about my ASIO problems in windows?
Any suggestions about my audio driver in Linux?
Any suggestions about my GEM mov video / windows incompatibilities?
I can import the mov video and audio to SF Acid 3.0 and output a 2Gb avi then import it into windows movie maker but this is crazy to do for a 7 minute 12fps 320x240 video.
Ahhhhhhhhh!
Any suggestions are welcome!
PS I believe someone could rewrite puredata's audio and video interface in assembly language to control their hardware before figuring out how to get these operating systems to do it.
Pix\_record
Thanks sonofsol, that was just what I was looking for today.
Great job on your GEM engine. I think it would be awesome to have 3d controllers for the pd stuff. My main synth patch is about 4 screens wide by 2 screens high. Not that there are there that many controls but there are that many things between the controls. It would be nice to just make a slick 3d control interface. I can imagine a block sequencer haha!
Now I have my video and audio recorded. I tried to open the video in microsoft movie maker. Codecs not installed. The video opens in VLC. The video also opens in Sonic Foundry Acid 3.0 but is shorter duration in than the audio. The video barely records at 12 frames per second. While controlling audio. The computer almost hangs up if I select mpg instead of video. VLC reports the fps as 24.788104. I used the default video as the codec at 12fps.
How do I get the video synced with the audio?
Where are the qff codecs for Windows so I can use microsoft movie maker?
What is a better program for editing videos to send to youtube?
I would like to keep my audio in a lossless format at 48k.