/******************************************************************************** void grainstream_setsnd(t_index *x, t_symbol *s) inputs: x -- pointer to this object s -- name of buffer to link description: links buffer holding the grain sound source returns: nothing ********************************************************************************/ void grainstream_setsnd(t_grainstream *x, t_symbol *s) { t_buffer_ref *b = buffer_ref_new((t_object*)x, s); if (buffer_ref_exists(b)) { t_buffer_obj *b_object = buffer_ref_getobject(b); if (buffer_getchannelcount(b_object) != 1) { error("%s: buffer~ > %s < must be mono", OBJECT_NAME, s->s_name); x->next_snd_buf_ptr = NULL; //added 2002.07.15 } else { if (x->snd_buf_ptr == NULL) { // if first buffer make current buffer x->snd_sym = s; x->snd_buf_ptr = b; //x->snd_last_out = 0.0; //removed 2005.02.03 #ifdef DEBUG post("%s: current sound set to buffer~ > %s <", OBJECT_NAME, s->s_name); #endif /* DEBUG */ } else { // else defer to next buffer x->snd_sym = s; x->next_snd_buf_ptr = b; //x->snd_buf_length = b->b_frames; //removed 2002.07.11 //x->snd_last_out = 0.0; //removed 2002.07.24 #ifdef DEBUG post("%s: next sound set to buffer~ > %s <", OBJECT_NAME, s->s_name); #endif /* DEBUG */ } } } else { error("%s: no buffer~ * %s * found", OBJECT_NAME, s->s_name); x->next_snd_buf_ptr = NULL; } }
void cmgrainlabs_set(t_cmgrainlabs *x, t_symbol *s, long ac, t_atom *av) { if (ac == 2) { x->buffer_modified = 1; x->buffer_name = atom_getsym(av); // write buffer name into object structure x->window_name = atom_getsym(av+1); // write buffer name into object structure buffer_ref_set(x->buffer, x->buffer_name); buffer_ref_set(x->w_buffer, x->window_name); if (buffer_getchannelcount((t_object *)(buffer_ref_getobject(x->buffer))) > 2) { object_error((t_object *)x, "referenced sample buffer has more than 2 channels. using channels 1 and 2."); } if (buffer_getchannelcount((t_object *)(buffer_ref_getobject(x->w_buffer))) > 1) { object_error((t_object *)x, "referenced window buffer has more than 1 channel. expect strange results."); } } else { object_error((t_object *)x, "%d arguments required (sample/window)", 2); } }
void multigrain_setbuf(t_multigrain *x, t_symbol *wavename, t_symbol *windowname) { t_buffer_obj *b; int i; buffer_ref_set(x->wavebuf, wavename); buffer_ref_set(x->windowbuf, windowname); b = buffer_ref_getobject(x->wavebuf); if(b == NULL){ post("invalid sound buffer %s", wavename->s_name); return; } x->b_frames = buffer_getframecount(b); x->hosed = 0; // kill all current grains for(i = 0; i < MAXGRAINS; i++){ x->grains[i].active = 0; } if( buffer_getchannelcount(b) > 2 ){ error("wavetable must be a mono or stereo buffer"); x->hosed = 1; } b = buffer_ref_getobject(x->windowbuf); if(b == NULL){ post("invalid window buffer %s", windowname->s_name); return; } if( buffer_getchannelcount(b) != 1 ){ error("window must be a mono buffer"); x->hosed = 1; } x->wavename = wavename; x->windowname = windowname; x->maxskip = x->b_frames - 1; }
void buff_get_param(t_buff_info *buff) { // If the buffer has no object if (buff->has_obj == false) { buff->has_file = false; return; } // Get the buffer variables buff->fr_cnt = (t_uint32)buffer_getframecount(buff->obj); buff->ch_cnt = (t_uint8)buffer_getchannelcount(buff->obj); buff->msr = buffer_getmillisamplerate(buff->obj); // Test the buffer variables if ((buff->fr_cnt == 0) || (buff->ch_cnt == 0) || (buff->msr == 0)) { buff->has_file = false; } // Otherwise the buffer is linked and a file is loaded. else { buff->has_file = true; } }
void index_perform64(t_index *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { t_double *in = ins[0]; t_double *out = outs[0]; int n = sampleframes; t_float *tab; double temp; double f; long index, chan, frames, nc; t_buffer_obj *buffer = buffer_ref_getobject(x->l_buffer_reference); tab = buffer_locksamples(buffer); if (!tab) goto zero; frames = buffer_getframecount(buffer); nc = buffer_getchannelcount(buffer); chan = MIN(x->l_chan, nc); while (n--) { temp = *in++; f = temp + 0.5; index = f; if (index < 0) index = 0; else if (index >= frames) index = frames - 1; if (nc > 1) index = index * nc + chan; *out++ = tab[index]; } buffer_unlocksamples(buffer); return; zero: while (n--) *out++ = 0.0; }
void multigrain_perform64(t_multigrain *x, t_object *dsp64, double **ins, long numins, double **outs,long numouts, long n, long flags, void *userparam) { t_buffer_obj *wavebuf_b; t_buffer_obj *windowbuf_b; float *wavetable; float *window; t_grain *grains = x->grains; long b_nchans; long b_frames; short interpolate_envelope = x->interpolate_envelope; float sample1; float envelope; float amplitude; float si; float esi; float phase; float ephase; long delay; long eframes; long current_index; float tsmp1, tsmp2; float frac; int i,j,k; long output_channel; // randomly selected channel for output // we really need this clean operation: for(i = 0; i < x->output_channels; i++){ for(j = 0; j < n; j++){ outs[i][j] = 0.0; } } buffer_ref_set(x->wavebuf, x->wavename); buffer_ref_set(x->windowbuf, x->windowname); wavebuf_b = buffer_ref_getobject(x->wavebuf); windowbuf_b = buffer_ref_getobject(x->windowbuf); if(wavebuf_b == NULL || windowbuf_b == NULL){ for(k = 0; k < MAXGRAINS; k++){ grains[k].active = 0; } goto deliverance; } b_nchans = buffer_getchannelcount(wavebuf_b); b_frames= buffer_getframecount(wavebuf_b); eframes = buffer_getframecount(windowbuf_b); if(b_nchans != 1){ goto deliverance; } if(eframes == 0 || b_frames == 0){ for(k = 0; k < MAXGRAINS; k++){ grains[k].active = 0; } goto deliverance; } wavetable = buffer_locksamples(wavebuf_b); window = buffer_locksamples(windowbuf_b); if(!wavetable || !window ){ goto deliverance; } for (j=0; j<MAXGRAINS; j++) { if(!grains[j].active){ goto nextgrain; } amplitude = grains[j].amplitude; si = grains[j].si; esi = grains[j].esi; phase = grains[j].phase; ephase = grains[j].ephase; delay = grains[j].delay; output_channel = grains[j].output_channel; for(i = 0; i < n; i++ ){ if( delay > 0 ){ --delay; } if( delay <= 0 && ephase < eframes){ if(interpolate_envelope){ current_index = floor((double)ephase); frac = ephase - current_index; if(current_index == 0 || current_index == eframes - 1 || frac == 0.0){// boundary conditions envelope = window[current_index]; } else { tsmp1 = window[current_index]; tsmp2 = window[current_index + 1]; envelope = tsmp1 + frac * (tsmp2 - tsmp1); } } else { envelope = window[(int)ephase]; } if(phase < 0 || phase >= b_frames){ error("phase %f is out of bounds",phase); goto nextgrain; } current_index = floor((double)phase); frac = phase - current_index; if(current_index == 0 || current_index == b_frames - 1 || frac == 0.0){// boundary conditions sample1 = wavetable[current_index] * amplitude; // amplitude * is new code } else { tsmp1 = wavetable[current_index]; tsmp2 = wavetable[current_index + 1]; sample1 = tsmp1 + frac * (tsmp2 - tsmp1); } sample1 *= envelope; outs[output_channel][i] += sample1; phase += si; if(phase < 0 || phase >= b_frames){ // error("phase %f out of bounds",phase); grains[j].active = 0; goto nextgrain; } ephase += esi; if( ephase >= eframes ){ grains[j].active = 0; goto nextgrain; // must escape loop now } } } grains[j].phase = phase; grains[j].ephase = ephase; grains[j].delay = delay; nextgrain: ; } deliverance: buffer_unlocksamples(wavebuf_b); buffer_unlocksamples(windowbuf_b); ; }
void buffi_autofunc(t_buffi *x, t_floatarg minval, t_floatarg maxval, t_symbol *buffername) { int minpoints, maxpoints, segpoints, i; int pointcount = 0; double target, lastval; double m1, m2; t_buffer_ref *tablebuf_ref; t_buffer_obj *dbuf; long b_nchans; long b_frames; float *b_samples; ///// tablebuf_ref = buffer_ref_new((t_object*)x, buffername); dbuf = buffer_ref_getobject(tablebuf_ref); if(dbuf == NULL){ object_post((t_object*)x,"%s: nonexistent buffer ( %s )", OBJECT_NAME, buffername->s_name); return; } b_nchans = buffer_getchannelcount(dbuf); b_frames = buffer_getframecount(dbuf); if(b_nchans != 1){ post("%s: table must be mono",OBJECT_NAME); return; } x->warpfunc = (float *)sysmem_newptr(b_frames * sizeof(float)); minpoints = 0.05 * (float) b_frames; maxpoints = 0.25 * (float) b_frames; if( minval > 1000.0 || minval < .001 ){ minval = 0.5; } if( maxval < 0.01 || maxval > 1000.0 ){ minval = 2.0; } lastval = buffi_randf(minval, maxval); // post("automate: min %d max %d",minpoints, maxpoints); while( pointcount < b_frames ){ target = buffi_randf(minval, maxval); segpoints = minpoints + (rand() % (maxpoints-minpoints)); if( pointcount + segpoints > b_frames ){ segpoints = b_frames - pointcount; } for( i = 0; i < segpoints; i++ ){ m2 = (float)i / (float) segpoints ; m1 = 1.0 - m2; x->warpfunc[ pointcount + i ] = m1 * lastval + m2 * target; } lastval = target; pointcount += segpoints; } // buffer stuffer b_samples = buffer_locksamples(dbuf); for(i = 0; i < b_frames; i++){ b_samples[i] = x->warpfunc[i]; } buffer_unlocksamples(dbuf); sysmem_freeptr( (void *) x->warpfunc ); object_method(dbuf, gensym("dirty")); }
void buffi_perform64(t_buffi *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { t_double *in = ins[0]; t_double *out = outs[0]; t_float *src1tab,*src2tab,*desttab; long src1nc, src2nc, destnc; long src1frames, src2frames, destframes; double phase; int i,j; // int k; long dexter; float hybrid; // Max buffers are still 32-bit t_buffer_obj *src1 = buffer_ref_getobject(x->src1_buffer_ref); t_buffer_obj *src2 = buffer_ref_getobject(x->src2_buffer_ref); t_buffer_obj *dest = buffer_ref_getobject(x->dest_buffer_ref); src1tab = buffer_locksamples(src1); src2tab = buffer_locksamples(src2); desttab = buffer_locksamples(dest); if (!src1tab || !src2tab || !desttab){ goto zero; } src1frames = buffer_getframecount(src1); src1nc = buffer_getchannelcount(src1); src2frames = buffer_getframecount(src2); src2nc = buffer_getchannelcount(src2); destframes = buffer_getframecount(dest); destnc = buffer_getchannelcount(dest); // test for lengths match (otherwise jet) if( (src1frames != destframes) || (src2frames != destframes) ){ goto zero; } // test for channels match if( (src1nc != src2nc) || (src2nc != destnc) ){ goto zero; } phase = *in; // only read the first sample of the vector for(i = 0; i < src1frames; i++){ for(j = 0; j < src1nc; j++){ dexter = (i*src1nc) + j; hybrid = (src1tab[dexter] * phase) + (src2tab[dexter] * (1 - phase)); desttab[dexter] = hybrid; } } buffer_unlocksamples(src1); buffer_unlocksamples(src2); buffer_unlocksamples(dest); return; zero: for(i = 0; i < sampleframes; i++){ *out++ = 0.0; } }
void pokef_perform64(t_pokef *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { float *in = (float *)(ins[0]); t_double *index = (t_double *)(ins[1]); t_double *fcoeff = (t_double *)(ins[2]); t_double *out = (t_double *)(outs[0]); int n = sampleframes; double alpha, om_alpha; t_float *tab; t_double temp, input, coeff; t_double chan, frames, nc, length; long pokef, pokef_next, pokef_nextnext, pokef_nextnextnext; t_buffer_obj *buffer = buffer_ref_getobject(x->l_buffer); tab = buffer_locksamples(buffer); if (!tab) goto zero; chan = (t_double)x->l_chan; frames = buffer_getframecount(buffer); nc = buffer_getchannelcount(buffer); length = (t_double)x->length; if (length <= 0.) length = frames; else if (length >= frames) length = frames; while (n--) { input = *in++; temp = *index++; coeff = *fcoeff++; temp += 0.5; if (temp < 0.) temp = 0.; else while (temp >= length) temp -= length; temp = temp * nc + chan; pokef = (long)temp; //bufsample = tab[pokef]; alpha = temp - (double)pokef; om_alpha = 1. - alpha; pokef_next = pokef + nc; while (pokef_next >= length*nc) pokef_next -= length*nc; pokef_nextnext = pokef_next + nc; while (pokef_nextnext >= length*nc) pokef_nextnext -= length*nc; pokef_nextnextnext = pokef_nextnext + nc; while (pokef_nextnextnext >= length*nc) pokef_nextnextnext -= length*nc; //output two ahead of record point...., with interpolation //*out++ = tab[pokef_nextnext]*om_alpha + tab[pokef_nextnextnext]*alpha; //*out++ = tab[pokef_next]*om_alpha + tab[pokef_nextnext]*alpha; *out++ = tab[pokef_next]; //interpolate recording... //tab[pokef] = coeff * tab[pokef] + om_alpha*input; //tab[pokef_next] = coeff * tab[pokef_next] + alpha*input; //or not.... tab[pokef] = coeff * tab[pokef] + input; //*out++ = bufsample; //tab[pokef] = coeff * bufsample + input; } buffer_unlocksamples(buffer); return; zero: while (n--) *out++ = 0.0; }
void munger_perform64(t_munger *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { t_double *in = (t_double *)(ins[0]); t_double grate = x->grate_connected? *(t_double *)(ins[0]) : x->grate; t_double grate_var = x->grate_var_connected? *(t_double *)(ins[1]) : x->grate_var; t_double glen = x->glen_connected? *(t_double *)(ins[2]) : x->glen; t_double glen_var = x->glen_var_connected? *(t_double *)(ins[3]) : x->glen_var; t_double gpitch = x->gpitch_connected? *(t_double *)(ins[4]) : x->gpitch; t_double gpitch_var = x->gpitch_var_connected? *(t_double *)(ins[5]) : x->gpitch_var; t_double gpan_spread= x->gpan_spread_connected? *(t_double *)(ins[6]) : x->gpan_spread; t_double outsamp[MAXCHANNELS], samp; int newvoice, i, j; long n; t_double *out[MAXCHANNELS]; //t_double *outL = (t_double *)(w[10]); //t_double *outR = (t_double *)(w[11]); for (i=0;i<x->num_channels;i++) { out[i] = (t_double *)(outs[i]); } n = sampleframes; //make sure vars are updated if signals are connected; stupid, lazy, boob. x->grate = grate; x->grate_var = grate_var; x->glen = glen; x->glen_var = glen_var; x->gpitch = gpitch; x->gpitch_var = gpitch_var; x->gpan_spread = gpan_spread; //grate = grate + RAND01 * grate_var; //grate = grate + ((t_double)rand() - 16384.) * ONE_OVER_HALFRAND * grate_var; //gimme = x->srate_ms * grate; //grate is actually time-distance between grains if(gpan_spread > 1.) gpan_spread = 1.; if(gpan_spread < 0.) gpan_spread = 0.; if(!x->power) { while(n--) { //copy and zero out when unpowered (this is slightly less efficient than //the z_disabled approach, but some users expect it now for(i=0;i<x->num_channels;i++) { *out[i]++ = 0.; } } } else { t_buffer_obj *buffer = buffer_ref_getobject(x->l_buffer); t_float *tab = buffer_locksamples(buffer); double frames = 0; double nc = 0; if (tab) { frames = buffer_getframecount(buffer); nc = buffer_getchannelcount(buffer); } while(n--) { //outsampL = outsampR = 0.; for(i=0;i<x->num_channels;i++) outsamp[i] = 0.; //record a sample //if(x->recordOn) recordSamp(x, *in++); recordSamp(x, *in++); //grab a note if requested; works in oneshot mode or otherwise while(x->newnote > 0) { newvoice = findVoice(x); if(newvoice >= 0) { x->gvoiceCurrent[newvoice] = newNote(x, newvoice, x->newnote, frames); } x->newnote--; } //find a voice if it's time (high resolution). ignore if in "oneshot" mode if(!x->oneshot) { if(x->time >= (long)x->gimme) { x->time = 0; newvoice = findVoice(x); if(newvoice >= 0) { x->gvoiceCurrent[newvoice] = newSetup(x, newvoice, frames); } grate = grate + ((t_double)rand() - RAND_MAX * 0.5) * ONE_OVER_HALFRAND * grate_var; x->gimme = x->srate_ms * grate; //grate is actually time-distance between grains } } x->time++; //mix 'em, pan 'em for(i=0; i< x->maxvoices; i++) { //for(i=0; i<x->voices; i++) { if(x->gvoiceOn[i]) { //get a sample, envelope it if(x->externalBuffer) samp = getExternalSamp(x, x->gvoiceCurrent[i], tab, frames, nc); else samp = getSamp(x, x->gvoiceCurrent[i]); if (!x->gvoiceADSRon[i]) samp = envelope(x, i, samp) * x->gvoiceGain[i]; else samp = samp * ADSR_ADRtick(&x->gvoiceADSR[i]) * x->gvoiceGain[i]; //pan it if(x->num_channels == 2) { outsamp[0] += samp * x->gvoiceLPan[i]; outsamp[1] += samp * x->gvoiceRPan[i]; } else { //multichannel subroutine for(j=0;j<x->num_channels;j++) { outsamp[j] += samp * x->gvoiceSpat[i][j]; } } //see if grain is done after jumping to next sample point x->gvoiceCurrent[i] += (double)x->gvoiceDirection[i] * (double)x->gvoiceSpeed[i]; if (!x->gvoiceADSRon[i]) { if(++x->gvoiceDone[i] >= x->gvoiceSize[i]) x->gvoiceOn[i] = 0; } else { if(ADSR_getState(&x->gvoiceADSR[i]) == DONE) x->gvoiceOn[i] = 0; } } } for(i=0;i<x->num_channels;i++) { *out[i]++ = outsamp[i]; } } if (tab) buffer_unlocksamples(buffer); } }
void cmgrainlabs_perform64(t_cmgrainlabs *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { // VARIABLE DECLARATIONS short trigger = 0; // trigger occurred yes/no long i, limit; // for loop counterS long n = sampleframes; // number of samples per signal vector double tr_curr; // current trigger value double pan; // temporary random pan information double pitch; // temporary pitch for new grains double distance; // floating point index for reading from buffers long index; // truncated index for reading from buffers double w_read, b_read; // current sample read from the window buffer double outsample_left = 0.0; // temporary left output sample used for adding up all grain samples double outsample_right = 0.0; // temporary right output sample used for adding up all grain samples int slot = 0; // variable for the current slot in the arrays to write grain info to cm_panstruct panstruct; // struct for holding the calculated constant power left and right stereo values // OUTLETS t_double *out_left = (t_double *)outs[0]; // assign pointer to left output t_double *out_right = (t_double *)outs[1]; // assign pointer to right output // BUFFER VARIABLE DECLARATIONS t_buffer_obj *buffer = buffer_ref_getobject(x->buffer); t_buffer_obj *w_buffer = buffer_ref_getobject(x->w_buffer); float *b_sample = buffer_locksamples(buffer); float *w_sample = buffer_locksamples(w_buffer); long b_framecount; // number of frames in the sample buffer long w_framecount; // number of frames in the window buffer t_atom_long b_channelcount; // number of channels in the sample buffer t_atom_long w_channelcount; // number of channels in the window buffer // BUFFER CHECKS if (!b_sample) { // if the sample buffer does not exist goto zero; } if (!w_sample) { // if the window buffer does not exist goto zero; } // GET BUFFER INFORMATION b_framecount = buffer_getframecount(buffer); // get number of frames in the sample buffer w_framecount = buffer_getframecount(w_buffer); // get number of frames in the window buffer b_channelcount = buffer_getchannelcount(buffer); // get number of channels in the sample buffer w_channelcount = buffer_getchannelcount(w_buffer); // get number of channels in the sample buffer // GET INLET VALUES t_double *tr_sigin = (t_double *)ins[0]; // get trigger input signal from 1st inlet t_double startmin = x->connect_status[0]? *ins[1] * x->m_sr : x->startmin_float * x->m_sr; // get start min input signal from 2nd inlet t_double startmax = x->connect_status[1]? *ins[2] * x->m_sr : x->startmax_float * x->m_sr; // get start max input signal from 3rd inlet t_double lengthmin = x->connect_status[2]? *ins[3] * x->m_sr : x->lengthmin_float * x->m_sr; // get grain min length input signal from 4th inlet t_double lengthmax = x->connect_status[3]? *ins[4] * x->m_sr : x->lengthmax_float * x->m_sr; // get grain max length input signal from 5th inlet t_double pitchmin = x->connect_status[4]? *ins[5] : x->pitchmin_float; // get pitch min input signal from 6th inlet t_double pitchmax = x->connect_status[5]? *ins[6] : x->pitchmax_float; // get pitch max input signal from 7th inlet t_double panmin = x->connect_status[6]? *ins[7] : x->panmin_float; // get min pan input signal from 8th inlet t_double panmax = x->connect_status[7]? *ins[8] : x->panmax_float; // get max pan input signal from 9th inlet t_double gainmin = x->connect_status[8]? *ins[9] : x->gainmin_float; // get min gain input signal from 10th inlet t_double gainmax = x->connect_status[9]? *ins[10] : x->gainmax_float; // get max gain input signal from 10th inlet // DSP LOOP while (n--) { tr_curr = *tr_sigin++; // get current trigger value if (x->attr_zero) { if (tr_curr > 0.0 && x->tr_prev < 0.0) { // zero crossing from negative to positive trigger = 1; } } else { if ((x->tr_prev - tr_curr) > 0.9) { trigger = 1; } } if (x->buffer_modified) { // reset all playback information when any of the buffers was modified for (i = 0; i < MAXGRAINS; i++) { x->busy[i] = 0; } x->grains_count = 0; x->buffer_modified = 0; } /************************************************************************************************************************/ // IN CASE OF TRIGGER, LIMIT NOT MODIFIED AND GRAINS COUNT IN THE LEGAL RANGE (AVAILABLE SLOTS) if (trigger && x->grains_count < x->grains_limit && !x->limit_modified) { // based on zero crossing --> when ramp from 0-1 restarts. trigger = 0; // reset trigger x->grains_count++; // increment grains_count // FIND A FREE SLOT FOR THE NEW GRAIN i = 0; while (i < x->grains_limit) { if (!x->busy[i]) { x->busy[i] = 1; slot = i; break; } i++; } /************************************************************************************************************************/ // GET RANDOM START POSITION if (startmin != startmax) { // only call random function when min and max values are not the same! x->start[slot] = (long)cm_random(&startmin, &startmax); } else { x->start[slot] = startmin; } /************************************************************************************************************************/ // GET RANDOM LENGTH if (lengthmin != lengthmax) { // only call random function when min and max values are not the same! x->t_length[slot] = (long)cm_random(&lengthmin, &lengthmax); } else { x->t_length[slot] = lengthmin; } // CHECK IF THE VALUE FOR PERCEPTIBLE GRAIN LENGTH IS LEGAL if (x->t_length[slot] > MAX_GRAINLENGTH * x->m_sr) { // if grain length is larger than the max grain length x->t_length[slot] = MAX_GRAINLENGTH * x->m_sr; // set grain length to max grain length } else if (x->t_length[slot] < MIN_GRAINLENGTH * x->m_sr) { // if grain length is samller than the min grain length x->t_length[slot] = MIN_GRAINLENGTH * x->m_sr; // set grain length to min grain length } /************************************************************************************************************************/ // GET RANDOM PAN if (panmin != panmax) { // only call random function when min and max values are not the same! pan = cm_random(&panmin, &panmax); } else { pan = panmin; } // SOME SANITY TESTING if (pan < -1.0) { pan = -1.0; } if (pan > 1.0) { pan = 1.0; } cm_panning(&panstruct, &pan); // calculate pan values in panstruct x->pan_left[slot] = panstruct.left; x->pan_right[slot] = panstruct.right; /************************************************************************************************************************/ // GET RANDOM PITCH if (pitchmin != pitchmax) { // only call random function when min and max values are not the same! pitch = cm_random(&pitchmin, &pitchmax); } else { pitch = pitchmin; } // CHECK IF THE PITCH VALUE IS LEGAL if (pitch < 0.001) { pitch = 0.001; } if (pitch > MAX_PITCH) { pitch = MAX_PITCH; } /************************************************************************************************************************/ // GET RANDOM GAIN if (gainmin != gainmax) { x->gain[slot] = cm_random(&gainmin, &gainmax); } else { x->gain[slot] = gainmin; } // CHECK IF THE GAIN VALUE IS LEGAL if (x->gain[slot] < 0.0) { x->gain[slot] = 0.0; } if (x->gain[slot] > MAX_GAIN) { x->gain[slot] = MAX_GAIN; } /************************************************************************************************************************/ // CALCULATE THE ACTUAL GRAIN LENGTH (SAMPLES) ACCORDING TO PITCH x->gr_length[slot] = x->t_length[slot] * pitch; // CHECK THAT GRAIN LENGTH IS NOT LARGER THAN SIZE OF BUFFER if (x->gr_length[slot] > b_framecount) { x->gr_length[slot] = b_framecount; } /************************************************************************************************************************/ // CHECK IF START POSITION IS LEGAL ACCORDING TO GRAINzLENGTH (SAMPLES) AND BUFFER SIZE if (x->start[slot] > b_framecount - x->gr_length[slot]) { x->start[slot] = b_framecount - x->gr_length[slot]; } if (x->start[slot] < 0) { x->start[slot] = 0; } } /************************************************************************************************************************/ // CONTINUE WITH THE PLAYBACK ROUTINE if (x->grains_count == 0) { // if grains count is zero, there is no playback to be calculated *out_left++ = 0.0; *out_right++ = 0.0; } else if (!b_sample) { *out_left++ = 0.0; *out_right++ = 0.0; } else if (!w_sample) { *out_left++ = 0.0; *out_right++ = 0.0; } else { if (x->limit_modified) { limit = x->grains_limit_old; } else { limit = x->grains_limit; } for (i = 0; i < limit; i++) { if (x->busy[i]) { // if the current slot contains grain playback information // GET WINDOW SAMPLE FROM WINDOW BUFFER if (x->attr_winterp) { distance = ((double)x->grainpos[i] / (double)x->t_length[i]) * (double)w_framecount; w_read = cm_lininterp(distance, w_sample, w_channelcount, 0); } else { index = (long)(((double)x->grainpos[i] / (double)x->t_length[i]) * (double)w_framecount); w_read = w_sample[index]; } // GET GRAIN SAMPLE FROM SAMPLE BUFFER distance = x->start[i] + (((double)x->grainpos[i]++ / (double)x->t_length[i]) * (double)x->gr_length[i]); if (b_channelcount > 1 && x->attr_stereo) { // if more than one channel if (x->attr_sinterp) { outsample_left += ((cm_lininterp(distance, b_sample, b_channelcount, 0) * w_read) * x->pan_left[i]) * x->gain[i]; // get interpolated sample outsample_right += ((cm_lininterp(distance, b_sample, b_channelcount, 1) * w_read) * x->pan_right[i]) * x->gain[i]; } else { outsample_left += ((b_sample[(long)distance * b_channelcount] * w_read) * x->pan_left[i]) * x->gain[i]; outsample_right += ((b_sample[((long)distance * b_channelcount) + 1] * w_read) * x->pan_right[i]) * x->gain[i]; } } else { if (x->attr_sinterp) { b_read = cm_lininterp(distance, b_sample, b_channelcount, 0) * w_read; // get interpolated sample outsample_left += (b_read * x->pan_left[i]) * x->gain[i]; outsample_right += (b_read * x->pan_right[i]) * x->gain[i]; } else { outsample_left += ((b_sample[(long)distance * b_channelcount] * w_read) * x->pan_left[i]) * x->gain[i]; outsample_right += ((b_sample[(long)distance * b_channelcount] * w_read) * x->pan_right[i]) * x->gain[i]; } } if (x->grainpos[i] == x->t_length[i]) { // if current grain has reached the end position x->grainpos[i] = 0; // reset parameters for overwrite x->busy[i] = 0; x->grains_count--; if (x->grains_count < 0) { x->grains_count = 0; } } } } *out_left++ = outsample_left; // write added sample values to left output vector *out_right++ = outsample_right; // write added sample values to right output vector } // CHECK IF GRAINS COUNT IS ZERO, THEN RESET LIMIT_MODIFIED CHECKFLAG if (x->grains_count == 0) { x->limit_modified = 0; // reset limit modified checkflag } /************************************************************************************************************************/ x->tr_prev = tr_curr; // store current trigger value in object structure outsample_left = 0.0; outsample_right = 0.0; } /************************************************************************************************************************/ // STORE UPDATED RUNNING VALUES INTO THE OBJECT STRUCTURE buffer_unlocksamples(buffer); buffer_unlocksamples(w_buffer); outlet_int(x->grains_count_out, x->grains_count); // send number of currently playing grains to the outlet return; zero: while (n--) { *out_left++ = 0.0; *out_right++ = 0.0; } buffer_unlocksamples(buffer); buffer_unlocksamples(w_buffer); return; // THIS RETURN WAS MISSING FOR A LONG, LONG TIME. MAYBE THIS HELPS WITH STABILITY!? }
void cmbuffercloud_perform64(t_cmbuffercloud *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { // VARIABLE DECLARATIONS short trigger = 0; // trigger occurred yes/no long i, limit; // for loop counterS long n = sampleframes; // number of samples per signal vector double tr_curr; // current trigger value double distance; // floating point index for reading from buffers long index; // truncated index for reading from buffers double w_read, b_read; // current sample read from the window buffer double outsample_left = 0.0; // temporary left output sample used for adding up all grain samples double outsample_right = 0.0; // temporary right output sample used for adding up all grain samples int slot = 0; // variable for the current slot in the arrays to write grain info to cm_panstruct panstruct; // struct for holding the calculated constant power left and right stereo values // OUTLETS t_double *out_left = (t_double *)outs[0]; // assign pointer to left output t_double *out_right = (t_double *)outs[1]; // assign pointer to right output // BUFFER VARIABLE DECLARATIONS t_buffer_obj *buffer = buffer_ref_getobject(x->buffer); t_buffer_obj *w_buffer = buffer_ref_getobject(x->w_buffer); float *b_sample = buffer_locksamples(buffer); float *w_sample = buffer_locksamples(w_buffer); long b_framecount; // number of frames in the sample buffer long w_framecount; // number of frames in the window buffer t_atom_long b_channelcount; // number of channels in the sample buffer t_atom_long w_channelcount; // number of channels in the window buffer // BUFFER CHECKS if (!b_sample || !w_sample) { // if the sample buffer does not exist goto zero; } // GET BUFFER INFORMATION b_framecount = buffer_getframecount(buffer); // get number of frames in the sample buffer w_framecount = buffer_getframecount(w_buffer); // get number of frames in the window buffer b_channelcount = buffer_getchannelcount(buffer); // get number of channels in the sample buffer w_channelcount = buffer_getchannelcount(w_buffer); // get number of channels in the sample buffer // GET INLET VALUES t_double *tr_sigin = (t_double *)ins[0]; // get trigger input signal from 1st inlet x->grain_params[0] = x->connect_status[0] ? *ins[1] * x->m_sr : x->object_inlets[0] * x->m_sr; // start min x->grain_params[1] = x->connect_status[1] ? *ins[2] * x->m_sr : x->object_inlets[1] * x->m_sr; // start max x->grain_params[2] = x->connect_status[2] ? *ins[3] * x->m_sr : x->object_inlets[2] * x->m_sr; // length min x->grain_params[3] = x->connect_status[3] ? *ins[4] * x->m_sr : x->object_inlets[3] * x->m_sr; // length max x->grain_params[4] = x->connect_status[4] ? *ins[5] : x->object_inlets[4]; // pitch min x->grain_params[5] = x->connect_status[5] ? *ins[6] : x->object_inlets[5]; // pitch max x->grain_params[6] = x->connect_status[6] ? *ins[7] : x->object_inlets[6]; // pan min x->grain_params[7] = x->connect_status[7] ? *ins[8] : x->object_inlets[7]; // pan max x->grain_params[8] = x->connect_status[8] ? *ins[9] : x->object_inlets[8]; // gain min x->grain_params[9] = x->connect_status[9] ? *ins[10] : x->object_inlets[9]; // gain max // DSP LOOP while (n--) { tr_curr = *tr_sigin++; // get current trigger value if (x->attr_zero) { if (signbit(tr_curr) != signbit(x->tr_prev)) { // zero crossing from negative to positive trigger = 1; } else if (x->bang_trigger) { trigger = 1; x->bang_trigger = 0; } } else { if (x->tr_prev > tr_curr) { trigger = 1; } else if (x->bang_trigger) { trigger = 1; x->bang_trigger = 0; } } if (x->buffer_modified) { // reset all playback information when any of the buffers was modified for (i = 0; i < MAXGRAINS; i++) { x->busy[i] = 0; } x->grains_count = 0; x->buffer_modified = 0; } /************************************************************************************************************************/ // IN CASE OF TRIGGER, LIMIT NOT MODIFIED AND GRAINS COUNT IN THE LEGAL RANGE (AVAILABLE SLOTS) if (trigger && x->grains_count < x->grains_limit && !x->limit_modified) { // based on zero crossing --> when ramp from 0-1 restarts. trigger = 0; // reset trigger x->grains_count++; // increment grains_count // FIND A FREE SLOT FOR THE NEW GRAIN i = 0; while (i < x->grains_limit) { if (!x->busy[i]) { x->busy[i] = 1; slot = i; break; } i++; } // randomize the grain parameters and write them into the randomized array x->randomized[0] = cm_random(&x->grain_params[0], &x->grain_params[1]); // start x->randomized[1] = cm_random(&x->grain_params[2], &x->grain_params[3]); // length x->randomized[2] = cm_random(&x->grain_params[4], &x->grain_params[5]); // pitch x->randomized[3] = cm_random(&x->grain_params[6], &x->grain_params[7]); // pan x->randomized[4] = cm_random(&x->grain_params[8], &x->grain_params[9]); // gain // check for parameter sanity of the length value if (x->randomized[1] < x->testvalues[2]) { x->randomized[1] = x->testvalues[2]; } else if (x->randomized[1] > x->testvalues[3]) { x->randomized[1] = x->testvalues[3]; } // check for parameter sanity of the pitch value if (x->randomized[2] < x->testvalues[4]) { x->randomized[2] = x->testvalues[4]; } else if (x->randomized[2] > x->testvalues[5]) { x->randomized[2] = x->testvalues[5]; } // check for parameter sanity of the pan value if (x->randomized[3] < x->testvalues[6]) { x->randomized[3] = x->testvalues[6]; } else if (x->randomized[3] > x->testvalues[7]) { x->randomized[3] = x->testvalues[7]; } // check for parameter sanity of the gain value if (x->randomized[4] < x->testvalues[8]) { x->randomized[4] = x->testvalues[8]; } else if (x->randomized[4] > x->testvalues[9]) { x->randomized[4] = x->testvalues[9]; } // write grain lenght slot (non-pitch) x->smp_length[slot] = x->randomized[1]; x->pitch_length[slot] = x->smp_length[slot] * x->randomized[2]; // length * pitch // check that grain length is not larger than size of buffer if (x->pitch_length[slot] > b_framecount) { x->pitch_length[slot] = b_framecount; } // write start position x->start[slot] = x->randomized[0]; // start position sanity testing if (x->start[slot] > b_framecount - x->pitch_length[slot]) { x->start[slot] = b_framecount - x->pitch_length[slot]; } if (x->start[slot] < 0) { x->start[slot] = 0; } // compute pan values cm_panning(&panstruct, &x->randomized[3], x); // calculate pan values in panstruct x->pan_left[slot] = panstruct.left; x->pan_right[slot] = panstruct.right; // write gain value x->gain[slot] = x->randomized[4]; } /************************************************************************************************************************/ // CONTINUE WITH THE PLAYBACK ROUTINE if (x->grains_count == 0 || !b_sample || !w_sample) { // if grains count is zero, there is no playback to be calculated *out_left++ = 0.0; *out_right++ = 0.0; } else { if (x->limit_modified) { limit = x->grains_limit_old; } else { limit = x->grains_limit; } for (i = 0; i < limit; i++) { if (x->busy[i]) { // if the current slot contains grain playback information // GET WINDOW SAMPLE FROM WINDOW BUFFER if (x->attr_winterp) { distance = ((double)x->grainpos[i] / (double)x->smp_length[i]) * (double)w_framecount; w_read = cm_lininterp(distance, w_sample, w_channelcount, 0); } else { index = (long)(((double)x->grainpos[i] / (double)x->smp_length[i]) * (double)w_framecount); w_read = w_sample[index]; } // GET GRAIN SAMPLE FROM SAMPLE BUFFER distance = x->start[i] + (((double)x->grainpos[i]++ / (double)x->smp_length[i]) * (double)x->pitch_length[i]); if (b_channelcount > 1 && x->attr_stereo) { // if more than one channel if (x->attr_sinterp) { outsample_left += ((cm_lininterp(distance, b_sample, b_channelcount, 0) * w_read) * x->pan_left[i]) * x->gain[i]; // get interpolated sample outsample_right += ((cm_lininterp(distance, b_sample, b_channelcount, 1) * w_read) * x->pan_right[i]) * x->gain[i]; } else { outsample_left += ((b_sample[(long)distance * b_channelcount] * w_read) * x->pan_left[i]) * x->gain[i]; outsample_right += ((b_sample[((long)distance * b_channelcount) + 1] * w_read) * x->pan_right[i]) * x->gain[i]; } } else { if (x->attr_sinterp) { b_read = cm_lininterp(distance, b_sample, b_channelcount, 0) * w_read; // get interpolated sample outsample_left += (b_read * x->pan_left[i]) * x->gain[i]; outsample_right += (b_read * x->pan_right[i]) * x->gain[i]; } else { outsample_left += ((b_sample[(long)distance * b_channelcount] * w_read) * x->pan_left[i]) * x->gain[i]; outsample_right += ((b_sample[(long)distance * b_channelcount] * w_read) * x->pan_right[i]) * x->gain[i]; } } if (x->grainpos[i] == x->smp_length[i]) { // if current grain has reached the end position x->grainpos[i] = 0; // reset parameters for overwrite x->busy[i] = 0; x->grains_count--; if (x->grains_count < 0) { x->grains_count = 0; } } } } *out_left++ = outsample_left; // write added sample values to left output vector *out_right++ = outsample_right; // write added sample values to right output vector } // CHECK IF GRAINS COUNT IS ZERO, THEN RESET LIMIT_MODIFIED CHECKFLAG if (x->grains_count == 0) { x->limit_modified = 0; // reset limit modified checkflag } /************************************************************************************************************************/ x->tr_prev = tr_curr; // store current trigger value in object structure outsample_left = 0.0; outsample_right = 0.0; } /************************************************************************************************************************/ // STORE UPDATED RUNNING VALUES INTO THE OBJECT STRUCTURE buffer_unlocksamples(buffer); buffer_unlocksamples(w_buffer); outlet_int(x->grains_count_out, x->grains_count); // send number of currently playing grains to the outlet return; zero: while (n--) { *out_left++ = 0.0; *out_right++ = 0.0; } buffer_unlocksamples(buffer); buffer_unlocksamples(w_buffer); return; // THIS RETURN WAS MISSING FOR A LONG, LONG TIME. MAYBE THIS HELPS WITH STABILITY!? }
void polywave_perform64(t_polywave *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { int i; t_double *out = outs[0]; t_double *in1 = ins[0]; t_double *in2 = ins[1]; int n = sampleframes; if(x->numbufs == 0 || !x->w_connected[0]) { while (n--) *out++ = 0.; return; } int idx_connected = x->w_connected[1]; long numbufs = x->numbufs; long frames[numbufs], nchans[numbufs]; t_buffer_obj *buffer[numbufs]; t_float *tab[numbufs]; int valid[numbufs], modified[numbufs]; for (i=0; i<numbufs; i++) { buffer[i] = buffer_ref_getobject(x->buf_proxy[i]->ref); if(!buffer[i]) valid[i] = 0; else { tab[i] = buffer_locksamples(buffer[i]); if(!tab[i]) valid[i] = 0; else { modified[i] = x->buf_proxy[i]->buffer_modified; if(modified[i]) { frames[i] = buffer_getframecount(buffer[i]); nchans[i] = buffer_getchannelcount(buffer[i]); x->buf_proxy[i]->nframes = frames[i]; x->buf_proxy[i]->nchans = nchans[i]; x->buf_proxy[i]->buffer_modified = false; } else { frames[i] = x->buf_proxy[i]->nframes; nchans[i] = x->buf_proxy[i]->nchans; } valid[i] = (nchans[i] > 0 && frames[i] > 0); } } } t_polywave_interp interp = x->interp_type; double p, pSamp, upperVal, lowerSamp, upperSamp, frac, a, b, c, d; long bindx = 0; switch (interp) { case CUBIC: while(n--) { p = *in1++; p = CLAMP(p, 0, 1); if(idx_connected) { bindx = (long)*in2++; bindx = CLAMP(bindx, 0, numbufs-1); } if(valid[bindx]) { pSamp = frames[bindx] * p; lowerSamp = floor(pSamp); frac = pSamp - lowerSamp; a = (long)lowerSamp - 1 < 0 ? 0 : tab[bindx][ nchans[bindx] * ((long)lowerSamp - 1)]; b = tab[bindx][ nchans[bindx] * (long)lowerSamp]; c = (long)lowerSamp + 1 > frames[bindx] ? 0 : tab[bindx][ nchans[bindx] * ((long)lowerSamp + 1)]; d = (long)lowerSamp + 2 > frames[bindx] ? 0 : tab[bindx][ nchans[bindx] * ((long)lowerSamp + 2)]; *out++ = cubicInterpolate(a,b,c,d,frac); } else *out++ = 0.0; } break; case LINEAR: while(n--) { p = *in1++; p = CLAMP(p, 0, 1); if(idx_connected) { bindx = (long)*in2++; bindx = CLAMP(bindx, 0, numbufs-1); } if(valid[bindx]) { pSamp = frames[bindx] * p; lowerSamp = floor(pSamp); upperSamp = ceil(pSamp); upperVal = (upperSamp < frames[bindx]) ? tab[bindx][ nchans[bindx] * (long)upperSamp ] : 0.0; *out++ = linear_interp(tab[bindx][ nchans[bindx] * (long)lowerSamp ], upperVal, pSamp - lowerSamp); } else *out++ = 0.0; } break; default: case NONE: while(n--) { p = *in1++; p = CLAMP(p, 0, 1); if(idx_connected) { bindx = (long)*in2++; bindx = CLAMP(bindx, 0, numbufs-1); } if(valid[bindx]) { *out++ = tab[bindx][nchans[bindx] * (long)(frames[bindx] * p)]; } else *out++ = 0.0; } break; } for(i=0; i<numbufs; i++) { if(valid[i]) buffer_unlocksamples(buffer[i]); } return; }
void polywave_perform64_two(t_polywave *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) { int i; t_double *out = outs[0]; t_double *x1_in = ins[0]; t_double *x2_in = ins[1]; t_double *interp_in = ins[2]; t_double *idx1_in = ins[3]; t_double *idx2_in = ins[4]; int n = sampleframes; if(x->numbufs == 0 || !x->w_connected[0]) { while (n--) *out++ = 0.; return; } int *connected = x->w_connected; long numbufs = x->numbufs; long frames[numbufs], nchans[numbufs]; t_buffer_obj *buffer[numbufs]; t_float *tab[numbufs]; int valid[numbufs], modified[numbufs]; t_polywave_interp interp_t = x->interp_type; // post("%d %d", x->interp_type, x->backup); for (i=0; i<numbufs; i++) { buffer[i] = buffer_ref_getobject(x->buf_proxy[i]->ref); if(!buffer[i]) valid[i] = 0; else { tab[i] = buffer_locksamples(buffer[i]); if(!tab[i]) valid[i] = 0; else { modified[i] = x->buf_proxy[i]->buffer_modified; if(modified[i]) { frames[i] = buffer_getframecount(buffer[i]); nchans[i] = buffer_getchannelcount(buffer[i]); x->buf_proxy[i]->nframes = frames[i]; x->buf_proxy[i]->nchans = nchans[i]; x->buf_proxy[i]->buffer_modified = false; } else { frames[i] = x->buf_proxy[i]->nframes; nchans[i] = x->buf_proxy[i]->nchans; } valid[i] = (nchans[i] > 0 && frames[i] > 0); } } } double x1_p, x2_p, interp_p = 0, pSamp1, pSamp2, upperVal, lowerSamp, upperSamp, frac, a1, a2, b, c, d; long idx1 = 0, idx2 = 0; switch (interp_t) { case CUBIC: while(n--) { x1_p = *x1_in++; x1_p = CLAMP(x1_p, 0, 1); if(connected[1]) { x2_p = *x2_in++; x2_p = CLAMP(x2_p, 0, 1); } else { x2_p = x1_p; } if (connected[2]) { interp_p = *interp_in++; interp_p = CLAMP(interp_p, 0, 1); } if(connected[3]) { idx1 = (long)*idx1_in++; idx1 = CLAMP(idx1, 0, numbufs-1); } if(connected[4]) { idx2 = (long)*idx2_in++; idx2 = CLAMP(idx2, 0, numbufs-1); } if(valid[idx1] && valid[idx2]) { pSamp1 = frames[idx1] * x1_p; lowerSamp = floor(pSamp1); frac = pSamp1 - lowerSamp; a1 = (long)lowerSamp - 1 < 0 ? 0 : tab[idx1][ nchans[idx1] * ((long)lowerSamp - 1)]; b = tab[idx1][ nchans[idx1] * (long)lowerSamp]; c = (long)lowerSamp + 1 > frames[idx1] ? 0 : tab[idx1][ nchans[idx1] * ((long)lowerSamp + 1)]; d = (long)lowerSamp + 2 > frames[idx1] ? 0 : tab[idx1][ nchans[idx1] * ((long)lowerSamp + 2)]; pSamp1 = cubicInterpolate(a1,b,c,d,frac); pSamp2 = frames[idx2] * x2_p; lowerSamp = floor(pSamp2); frac = pSamp2 - lowerSamp; a2 = (long)lowerSamp - 1 < 0 ? 0 : tab[idx2][ nchans[idx2] * ((long)lowerSamp - 1)]; b = tab[idx2][ nchans[idx2] * (long)lowerSamp]; c = (long)lowerSamp + 1 > frames[idx2] ? 0 : tab[idx2][ nchans[idx2] * ((long)lowerSamp + 1)]; d = (long)lowerSamp + 2 > frames[idx2] ? 0 : tab[idx2][ nchans[idx2] * ((long)lowerSamp + 2)]; pSamp2 = cubicInterpolate(a2,b,c,d,frac); *out++ = cubicInterpolate(a1,pSamp1,pSamp2,d,interp_p); } else *out++ = 0.0; } break; case LINEAR: while(n--) { x1_p = *x1_in++; x1_p = CLAMP(x1_p, 0, 1); if(connected[1]) { x2_p = *x2_in++; x2_p = CLAMP(x2_p, 0, 1); } else { x2_p = x1_p; } if (connected[2]) { interp_p = *interp_in++; interp_p = CLAMP(interp_p, 0, 1); } if(connected[3]) { idx1 = (long)*idx1_in++; idx1 = CLAMP(idx1, 0, numbufs-1); } if(connected[4]) { idx2 = (long)*idx2_in++; idx2 = CLAMP(idx2, 0, numbufs-1); } if(valid[idx1] && valid[idx2]) { pSamp1 = frames[idx1] * x1_p; lowerSamp = floor(pSamp1); upperSamp = ceil(pSamp1); upperVal = (upperSamp < frames[idx1]) ? tab[idx1][ nchans[idx1] * (long)upperSamp ] : 0.0; pSamp1 = linear_interp(tab[idx1][ nchans[idx1] * (long)lowerSamp ], upperVal, pSamp1 - lowerSamp); pSamp2 = frames[idx2] * x2_p; lowerSamp = floor(pSamp2); upperSamp = ceil(pSamp2); upperVal = (upperSamp < frames[idx2]) ? tab[idx2][ nchans[idx2] * (long)upperSamp ] : 0.0; pSamp2 = linear_interp(tab[idx2][ nchans[idx2] * (long)lowerSamp ], upperVal, pSamp2 - lowerSamp); *out++ = linear_interp(pSamp1, pSamp2, interp_p); } else *out++ = 0.0; } break; default: case NONE: while(n--) { x1_p = *x1_in++; x1_p = CLAMP(x1_p, 0, 1); if(connected[2]) { idx1 = (long)*idx1_in++; idx1 = CLAMP(idx1, 0, numbufs-1); } if(valid[idx1]) { *out++ = tab[idx1][nchans[idx1] * (long)(frames[idx1] * x1_p)]; } else *out++ = 0.0; } break; } for(i=0; i<numbufs; i++) { if(valid[i]) buffer_unlocksamples(buffer[i]); } return; }