Thread: bank of oscillators

  1. #1
    Registered User
    Join Date
    Apr 2006
    Posts
    11

    bank of oscillators

    Hello,

    First off, I'm a little new to C programming. I have recently began writing plugins for an audio program called PureData (like Max/MSP) and so far it has been hard, but doable. I don't have any formal training.

    My question: I would like to write a plugin for this program that receives a list of indeces, frequencies, and amplitudes, and routes these sets to seperate oscillators that will create audio samples from the data. Synthesizing the audio samples is not the hard part, since i have examples for doing this. I need to figure out what the best way is to parse the frequencies and amplitudes according to a unique index, and how to elegantly create a bank of oscillators that can recieve these frequencies and amplitudes indepentant of eachother. Then, I will sum their output into a common audio stream.

    Here is a rough outline minus the actual oscillators. Is there a way I can avoid writing 200 if(j = n) checks and 200 sinewave functions?

    Thanks for any help,

    Richie

    Code:
    /*---------------sinebank.c--------------------*/
    /*list of consecutive ind,freq,amp groups, where ind is unique for each partial*/
    #define OSC_MAX = 200
    t_atom list[OSC_MAX *3]; /*Pd's array type*/
    inlist = inlet (*x_pd, &s_list);  /* matrix from one SDIF frame in the form of a Pd list */
    
    /*distribibute I's , limit partials to max amount */
    for (j = 1; j <= OSC_MAX  &&  j*3 <= size(list); j++)
          {
    		if(j = 1)
    		{
    			ind = inlist(j*3);  /*maybe a check here to make sure the index is an int */
    			freq = inlist(j*3 +1);
    			amp = inlist(j*3 +2);
    			osc1(I, F, A); /*a check will be made to see if I is new,
    						   if it is, no interpolated freq */
    		}
    		
    		else if( j = 2)
    		{
    			ind = inlist(j*3); 
    			freq = inlist(j*3 +1);
    			amp = inlist(j*3 +2);
    			osc2(I, F, A);
    		}
    		. 
    		. /*many many more of these */
    		else ( j = OSC_MAX)
    		{
    			ind = inlist(j*3); 
    			freq = inlist(j*3 +1);
    			amp = inlist(j*3 +2);
    			osc_OSC_MAX(I, F, A);
    		}
    	  }
    /*each osc function will create a seperate partial that is interpolated in a manner that
    will allow for time stretching/shrinking*/
    [somefunction for summing up all partials and sending audiosamples to outlet here];
    
    /* bank of oscillators, maybe a few hundred down here, either table lookup
    or taylor polynomial, with linear or parabolic interpolation from sample to sample
    and frame to frame will be */

  2. #2
    Registered User joed's Avatar
    Join Date
    Mar 2004
    Posts
    59
    Read up on structures and type definitions. You'll most likely end up with an array of 200 instrument structures, an array of output values, and a few simple support functions.

    You can fill arrays of structures with data like this (where INSTRUMENT is your type definition label):

    Code:
    typedef struct {
        int val1;
        int val2;
        int val3;
    } INSTRUMENT;
    
    INSTRUMENT instruments[200];    // array of instruments
    
    instrument[0] = (INSTRUMENT) { 0, 9, 1 };    // fill structure
    Pass the value of J onto the oscillator function, which then uses J to look up the appropriate array index. For example, to read one of the instrument parameters use:

    Code:
    x = instrument[j].val1;
    y = instrument[j].val2;
    z = instrument[j].val3;
    Also, read up on function pointers. They can be used as variables in structures, like this:
    Code:
    typedef struct {
        int val1;
        int val2;
        int val3;
        void (*waveform)();    // helper function
    } INSTRUMENT;
    
    INSTRUMENT instruments[200];    // array of instruments
    
    instrument[0] = (INSTRUMENT) { 0, 9, 1, sine };
    instrument[1] = (INSTRUMENT) { 0, 9, 1, square };
    instrument[2] = (INSTRUMENT) { 0, 9, 1, sawtooth };
    The oscillator function can then call the appropriate function like this:
    Code:
    (*instrument[j].waveform)();
    The functions can accept and return values, of course. This sort of stuff helps you break things down into chewable chunks, instead of cut & paste coding.
    Last edited by joed; 04-16-2006 at 06:51 AM.

  3. #3
    Registered User
    Join Date
    Apr 2006
    Posts
    11
    Hmmm... I don't quite understand how you defined what instrument[] receives, or how to utilize the *waveform function pointer within the instrument structure. The function I need to point to will be the same for all instruments (I call them 'partial's in the code below because it is additive synthesis), but it must performa everything independantly. I gave it a try and I'd like to know what you think. The phase is not taken care of correctly because every sample will return a phase, while there is only one index, frequency, and amplitude for every block of samples (decided by the host application). But, more importantly, will this pass the variables and run the (*osc*)() function for every set of values?

    Here is the struct and (*osc) function:
    Code:
    typedef struct partials
    {
    	int		samplerate;
    	float   phase; /* this needs to start at zero for all partials */
    	int		index;
    	float	freq;
    	float	amp;  /* this needs to start at zero for all partials */
    	float  (*osc)();
    } partial [MAX_PARTIALS];
    
    float (*osc)(int index, float freq, float amp, float phase, int samplerate)
    {
    		float sample = 0;
    		phase = partial [index].phase;  /*recall phase from last cycle*/
    		/* first calculate the phase increment from the frequency
    		 and sample rate - this is the number of cycles per sample
    		 (freq = cyc/sec, sr = samp/sec, phaseinc = cyc/samp = freq/sr)
    		Then,  increment the phase and make sure it doesn't go over 1.0 */
    		phase += *(freq+sample)/x->samplerate;
    		if(phase >= 1.0f)
    			phase -= 1.0f;
    		if(phase < 0.0f)
    			phase += 1.0f;
    		sample = quad_interpolate(phase);  /*wavetable lookup is in here*/
    		partial [index].phase = phase;  /*store the phase */
    		return(sample);
    }
    and here is the perform routine that they are used in:
    Code:
    static t_int *sinetablebank~_perform(t_int *w)
    {
    	t_sinetablebank~ *x = (t_sinetablebank~ *)(w[1]);
        inlist = inlet (*x_pd, &s_list);  /* matrix from one SDIF frame in the form of a Pd list */
        t_float *out = (t_float *)(w[2]);  /*send out audiosamples
        int n = (int)(w[3]);
    
    	/*count from blocksize to zero, it is usually 64 or 256 */
    	int blocksize = n;
    	samplenumber = 0;
    	
        while (n--)
        {
    			for (j = 1; j <= MAX_PARTIALS  &&  j*3 <= size(inlist); j++)
    			{
    				partial[j].index = inlist(j);
    				partial[j].freq = inlist(j+1);
    				partial[j].amp = inlist(j+2);
    				*(out+samplenumber) = (*instrument[j].waveform))(partial[j].index, partial[j].freq, partial[j].amp, 
    										partial[j].phase, x->samplerate);
    			}		
    			samplenumber++;
        }
        return (w+4);
    }
    I know the phase needs to be handled seperately, but I really want to just figure out the basic structure to avoid any unnecessary copying/pasting...although this is all from that method so far.

  4. #4
    Registered User joed's Avatar
    Join Date
    Mar 2004
    Posts
    59
    Skip the function pointers, you don't need them if calling the same function always. I meant only to read up on the subjects, not to use the examples outright.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bank Account Problem
    By JayBlay77 in forum C++ Programming
    Replies: 1
    Last Post: 03-19-2009, 08:41 AM
  2. helppp in bank databse
    By neha007 in forum C++ Programming
    Replies: 1
    Last Post: 06-02-2007, 09:43 AM
  3. Replies: 12
    Last Post: 06-03-2005, 01:13 AM
  4. Bank Account
    By vasanth in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 09-14-2003, 02:27 AM
  5. My graphics library
    By stupid_mutt in forum C Programming
    Replies: 3
    Last Post: 11-26-2001, 06:05 PM