From 7312e58d17e331d71d4f47e21bf15499609bace8 Mon Sep 17 00:00:00 2001 From: dieter kovacic Date: Tue, 9 Jul 2002 12:41:56 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r33, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/ext13/; revision=34 --- scramble~.c | 637 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 scramble~.c (limited to 'scramble~.c') diff --git a/scramble~.c b/scramble~.c new file mode 100644 index 0000000..dd9414d --- /dev/null +++ b/scramble~.c @@ -0,0 +1,637 @@ +#include "m_pd.h" +#include "ext13.h" +#include +#include +#include +#include +#include +#include + + + +/* ------------------------ scramble_tilde~ ----------------------------- */ + +static t_class *scramble_tilde_class; + +typedef struct _scramble_grain +{ + t_float* L; + t_float* R; + int size; + t_float maximum; + struct _scramble_grain *next; +}t_scramble_grain; + +typedef struct _scramble_tilde +{ + t_object x_obj; + int x_n; + t_int x_channels; + t_float play, analize; + t_float dir, current_dir, pitch, actual_pitch, grain_r, autopitch; + t_float valsum, valavg; + int valsumcount, valsummax; + int autofollow, playmode, semitones; + t_scramble_grain *firstgrain; + t_scramble_grain *workgrain; + t_scramble_grain *ring; + int grains, newgrains, w_grain, r_grain, n_grain, gotagrain, flush; + int r_d, w_d, dist, mindist, lowptr, hiptr, lastlowptr; + t_float lowval, hival, prevval, lowborder, normalize; + int nsamples; + t_outlet *trigger1; + t_outlet *trigger2; +} t_scramble_tilde; + + +/* grain functions*/ +static t_scramble_grain* scramble_tilde_newgrain(){ + t_scramble_grain* thegrain; + thegrain = getbytes( sizeof(t_scramble_grain)); + thegrain->L = NULL; + thegrain->R = NULL; + thegrain->size = 0; + thegrain->next = NULL; + return (thegrain); +} + + +static t_scramble_grain* scramble_tilde_getgrain(t_scramble_grain* firstgrain, int n){ + t_scramble_grain* thegrain = firstgrain; + while (n--){ + if (thegrain->next){ + thegrain = thegrain->next; + }else + return (NULL); + } + return (thegrain); +} + +static int scramble_tilde_getsomegrain(t_scramble_grain* firstgrain,int g){ + t_scramble_grain* thegrain ; + int r; + do{ + r = rand() % g; + thegrain = scramble_tilde_getgrain(firstgrain, r); + }while (thegrain->size == 0); + return (r); +} + +static void scramble_tilde_grainbuf(t_scramble_grain* grain, int c, int n){ + if (!grain->size) + grain->L = getbytes(n * sizeof(t_float)); + else + grain->L = resizebytes(grain->L, grain->size * sizeof(t_float), n * sizeof(t_float)); + + if (c == 2){ + if (!grain->size) + grain->R = getbytes(n * sizeof(t_float)); + else + grain->R = resizebytes(grain->R, grain->size * sizeof(t_float), n * sizeof(t_float)); + } + grain->size = n; +} + +static void scramble_tilde_freegrain(t_scramble_grain* grain, int c){ + if (grain->size){ + freebytes(grain->L, grain->size * sizeof(t_float)); + if (c == 2) freebytes(grain->R, grain->size * sizeof(t_float)); + grain->size = 0; + grain->next = NULL; + } +} + + +t_int *scramble_tilde_perform(t_int *w) +{ + t_scramble_tilde* x = (t_scramble_tilde*)(w[1]); + int i; + int erg=0; + int n; + t_float val, valL, valR, killval; + + t_float* out[x->x_channels]; + t_float* in[x->x_channels]; + + float n_factor, frac, a, b, c, d, cminusb; + int index; + float *fp; + t_atom at[2]; + + /* anything changed?*/ + if (x->flush){ + int i = x->grains; + x->flush = 0; + x->gotagrain = 0; + while (i--) + scramble_tilde_grainbuf(scramble_tilde_getgrain(x->firstgrain,i),x->x_channels,0); + } + + if (x->newgrains){ + int tmp = x->grains; + if (x->newgrains > x->grains){ + x->workgrain = scramble_tilde_getgrain(x->firstgrain,x->grains - 1); /*-1 ???*/ + tmp = x->newgrains; + x->newgrains -= x->grains; + x->grains = tmp; + while (x->newgrains--){ + x->workgrain->next = scramble_tilde_newgrain(); + x->workgrain = x->workgrain->next; + } + // post ("now %d grains",x->grains); + }else{ + if (x->newgrains < x->grains){ + t_scramble_grain* tmpgrain; + + x->grains = x->newgrains; + x->workgrain = scramble_tilde_getgrain(x->firstgrain,x->grains - 1); + + /* delete old grains */ + while (x->workgrain->next){ + tmpgrain = x->workgrain->next; + scramble_tilde_freegrain(x->workgrain,x->x_channels); + x->workgrain = tmpgrain; + } + + /* reset readpointer if needed*/ + if (x->r_grain >= x->grains){ + x->r_grain = 0; + x->grain_r = -1; + } +// post ("now %d grains",x->grains); + } + } + x->newgrains=0; + } + + if ((x->ring->size > x->x_n) || (x->ring->size < x->x_n) ){ +// post ("scramble~: new size for ringbuffer:%d samples, %d channels, oldsize:%d",x->x_n,x->x_channels,x->ring->size); + scramble_tilde_grainbuf(x->ring, x->x_channels ,x->x_n); + x->x_n = x->ring->size; + x->dist = 0; + x->lowptr = x->r_d; + x->lastlowptr = -1; + x->lowval = x->lowborder; + } + + for (i = 0; i < x->x_channels ;i++) + in[i] = (t_float *)(w[2 + i]); + + for (i = 0;i < x->x_channels ;i++) + out[i] = (t_float *)(w[2 + x->x_channels + i]); + + n = (int)(w[2 + x->x_channels * 2]);/*number of samples*/ +// post ("n:%d",n); + + while (n--){ + /*read from input*/ + if (++x->r_d > x->x_n){ + x->r_d = 0; + } + valL = *(t_float*)(x->ring->L + x->r_d) = *in[0]++; + if (valL < 0) valL *= -1; + if (x->x_channels == 2){ + valR = *(t_float*)(x->ring->R + x->r_d) = *in[1]++; + if (valR < 0) valR *= -1; + val = valL + valR / 2.0; + if (valL > x->hival){ + x->hiptr = x->r_d; + x->hival = valL; + } + if (valR > x->hival){ + x->hiptr = x->r_d; + x->hival = valR; + } + }else { + val = valL; + if (valL > x->hival){ + x->hiptr = x->r_d; + x->hival = valL; + } + } + +// if (val < 0) val *= -1; + + x->valsum += val; +// if (x->valsumcount++ > x->mindist * 10){ + if (x->valsumcount++ && (x->r_d == 0)){ + x->valavg = x->valsum / x->valsumcount; + x->valsumcount = 0; + x->valsum = 0; + if (x->autofollow && ( x->valavg > 0.003)) { + x->lowborder = x->valavg; +// post ("lowborder = %f",x->lowborder); + } + } + + if ((val < x->lowborder) && (x->prevval > x->lowborder)){ + /* a new low-period */ + x->dist = -1; + x->lowptr = x->r_d; + x->lowval = val; +// post ("low"); + } + if ((x->r_d + 1) == x->lastlowptr){ + /* one round without a point to cut */ + x->lastlowptr = -1; + x->lowval = x->lowborder; + x->hival = 0; +// post ("lastlowptr: reset"); + } + + if (val < x->lowborder){x->dist++;} + + if (val <= x->lowval) { + x->lowptr = x->r_d; + x->lowval = val; + /*found a point to cut*/ + } + + if ((val > x->lowborder) && (x->prevval < x->lowborder) && ( x->dist < x->mindist)){ + /*too short low-period*/ + x->dist = 0; + x->lowptr = x->r_d; + x->lowval = x->lowborder; +// post ("low too short"); + } + + if ((val > x->lowborder) && (x->prevval < x->lowborder) && ( x->dist > x->mindist)){ + /*found a low-period to cut */ + if ((x->lastlowptr != -1) ){ + int grainlen = 0; + int i = 0; + int wp = 1; /*first and last sample of grain should be 0.0*/ + + x->gotagrain = 1; + /* how long is the new grain */ + if (x->lastlowptr > x->lowptr){ + grainlen = x->x_n - x->lastlowptr + x->lowptr; + }else{ + grainlen = x->lowptr - x->lastlowptr; + } + + if (x->analize){ + /*find and prepare the grain*/ + if (++x->w_grain >= x->grains ) x->w_grain = 0; + x->workgrain = scramble_tilde_getgrain (x->firstgrain, x->w_grain); + scramble_tilde_grainbuf(x->workgrain, x->x_channels, grainlen + 2); + + *(t_float*)(x->workgrain->L) = 0.0; + *(t_float*)(x->workgrain->L + x->workgrain->size -1) = 0.0; + if (x->x_channels == 2){ + *(t_float*)(x->workgrain->R) = 0.0; + *(t_float*)(x->workgrain->R + x->workgrain->size -1) = 0.0; + } + x->workgrain->maximum = x->hival; + + /*notify the world*/ + SETFLOAT(at, grainlen); + SETFLOAT(at+1, x->w_grain + 1); + outlet_list(x->trigger1, 0, 2, at); + + /*copy to the grain*/ + i = x->lastlowptr; + while (grainlen--){ + if (++i >= x->x_n) i = 0; + *(t_float*)(x->workgrain->L + wp ) = *(t_float*)(x->ring->L + i); + if (x->x_channels == 2) + *(t_float*)(x->workgrain->R + wp ) = *(t_float*)(x->ring->R + i); + wp++; + } + }/*end if analize*/ +// post ("copied: w_grain: %d",x->w_grain); + }/* end lastlowptr != -1*/ + x->dist = 0; + x->hival = 0; + x->lastlowptr = x->lowptr; + }/*end found a low-period to cut */ + + x->prevval = val; + }/*end while n-- (read from input)*/ + + +/*--------------------playback--------------*/ + n = (int)(w[2 + x->x_channels * 2]);/*number of samples*/ + + x->workgrain = scramble_tilde_getgrain (x->firstgrain, x->r_grain); + if (x->normalize && x->workgrain) n_factor = x->normalize / x->workgrain->maximum; + else n_factor = 1; + + while (n--){ + int wgs; + if (x->workgrain) wgs = x->workgrain->size - 2; + else wgs = 0; + if (( (x->grain_r >= wgs) || (x->grain_r < 1) || (x->workgrain == NULL) ) && x->play && x->gotagrain){ + if (x->playmode < 2){ + x->r_grain = scramble_tilde_getsomegrain(x->firstgrain, x->grains); + x->workgrain = scramble_tilde_getgrain (x->firstgrain, x->r_grain); + }else{ + if (x->n_grain == -1){ + x->play = 0; + x->r_grain = 0; + x->workgrain = NULL; + }else{ + x->r_grain = x->n_grain; + x->workgrain = scramble_tilde_getgrain (x->firstgrain, x->r_grain); + x->n_grain = -1; + if ((x->r_grain == x->w_grain) || (x->workgrain == NULL)){ + x->play = 0; + x->r_grain = 0; + x->workgrain = NULL; + } else if (!x->workgrain->size){ + x->play = 0; + x->r_grain = 0; + x->workgrain = NULL; + } + } + }/*end if playmode < 2*/ + + if (x->workgrain){ + if (((rand() % 200) / 100.0 - 1.0 ) < x->dir){ + x->current_dir = 1; + x->grain_r = 1; + } + else{ + x->current_dir = -1; + x->grain_r = x->workgrain->size -3; + } + + if ( ( (x->autopitch >= 1.) && (x->semitones) ) || ( (x->autopitch) && (! x->semitones) ) ){ + if (x->semitones){ + int ap = (int)x->autopitch; + int rauf = 0; + int count ; + + if (rand() % 2 == 1){ rauf = 1;} +/* post ("rauf:%d",rauf); */ + + x->actual_pitch = x->pitch; + + for (count = (rand() % ap); count >= 0; count--){ + /*1.05946 = 12te wurzel aus 2 */ + if (rauf){ + x->actual_pitch = x->actual_pitch * 1.05946; + }else{ + x->actual_pitch = x->actual_pitch / 1.05946; + } + } + }else{ + if (((rand() % 200) / 100.0 - 1.0 ) > 0){ + x->actual_pitch = x->pitch + x->pitch * ((rand() % 100 ) / 100.0 * x->autopitch); + }else{ + x->actual_pitch = x->pitch - x->pitch / ((rand() % 100 ) / 100.0 * x->autopitch); + } + }/*end if semitones*/ + } else { + x->actual_pitch = x->pitch; + }/* end if autopitch*/ + +/* post ("x->actual_pitch:%f, x->autopitch:%f",x->actual_pitch,x->autopitch); */ + + if (x->normalize) n_factor = x->normalize / x->workgrain->maximum; + else n_factor = 1; + + SETFLOAT(at, (x->workgrain->size - 2) / x->actual_pitch); + SETFLOAT(at+1, x->r_grain + 1); + outlet_list(x->trigger2, 0, 2, at); + + }/*end if workgrain !=NULL */ + }/* end finding a new grain*/ + + if (x->play && x->gotagrain){ + /*write graincontent to output*/ + /* 4 point interpolation taken from ../src/d_array.c tabread4~ */ + index = x->grain_r; + if (index < 1) + index = 1, frac = 0; + else if (index > x->workgrain->size - 3) + index = x->workgrain->size - 3, frac = 1; + else + frac = x->grain_r - index; + + fp = (t_float*)(x->workgrain->L + index); + a = fp[-1]; + b = fp[0]; + c = fp[1]; + d = fp[2]; + + cminusb = c-b; + *out[0]++ = (b + frac * ( + cminusb - 0.5f * (frac-1.) * ( + (a - d + 3.0f * cminusb) * frac + (b - a - cminusb) + ) + )) * n_factor; + + if (x->x_channels == 2){ + fp = (t_float*)(x->workgrain->R + index); + a = fp[-1]; + b = fp[0]; + c = fp[1]; + d = fp[2]; + cminusb = c-b; + *out[1]++ = (b + frac * ( + cminusb - 0.5f * (frac-1.) * ( + (a - d + 3.0f * cminusb) * frac + (b - a - cminusb) + ) + )) * n_factor; + } + x->grain_r += x->current_dir * x->actual_pitch; + }else/* if play*/{ + *out[0]++ = 0; + if (x->x_channels == 2) + *out[1]++ = 0; + }/*end if play */ + }/*end while n-- */ + return (w + x->x_channels * 2 + 3); +} + +static void scramble_tilde_dsp(t_scramble_tilde *x, t_signal **sp) +{ + switch (x->x_channels) { + case 1: + dsp_add(scramble_tilde_perform, 4, x, sp[0]->s_vec, + sp[1]->s_vec, sp[0]->s_n); +// post ("1 channel"); + break; + case 2: + dsp_add(scramble_tilde_perform, 6, x, sp[0]->s_vec, + sp[1]->s_vec,sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n); +// post ("2 channels"); + break; + } +} + + +static void scramble_tilde_free(t_scramble_tilde *x){ + int n = x->grains - 1; + while (n--){ + scramble_tilde_freegrain (scramble_tilde_getgrain(x->firstgrain,n),x->x_channels); + scramble_tilde_freegrain (x->ring,x->x_channels); + } +} + + +static void *scramble_tilde_new(t_floatarg c,t_floatarg b) +{ + t_scramble_tilde *x = (t_scramble_tilde *)pd_new(scramble_tilde_class); + int i; +// x->bufL = NULL; +// x->bufR = NULL; + x->x_channels = (t_int)c; + if (x->x_channels > 2) { + x->x_channels = 2; + post ("maximum: 2 channels"); + } + if (x->x_channels < 1) x->x_channels = 1; + + outlet_new(&x->x_obj, gensym("signal")); + if (x->x_channels == 2){ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, gensym("signal")); + } + + x->trigger1 = outlet_new(&x->x_obj, &s_float); + x->trigger2 = outlet_new(&x->x_obj, &s_float); + x->dir = 1; + x->pitch = 1; + x->actual_pitch = 1; + x->autopitch = 0; + x->semitones = 1; + x->autofollow = 1; + x->playmode = 1; + x->normalize = 0; + x->analize = 1; + x->flush = 0; + x->x_n = (int)b; + if (x->x_n >882000 ){x->x_n = 882000;} + if (x->x_n < 88200 ){x->x_n = 88200;} +/* x->rR = x->rL = x->wR = x->wL = NULL;*/ + x->lowptr = 0; + x->lastlowptr = x->r_d = x->grain_r = -1; + x->mindist = 1024; + x->lowborder = 0.35; +// scramble_tilde_tempbuf(x,x->x_n); + x->ring = scramble_tilde_newgrain(); + scramble_tilde_grainbuf(x->ring,x->x_channels,x->x_n); + + x->valsum = x->valavg = x->valsumcount = 0; + x->valsummax = 1024; + + /* the grains:*/ + x->grains = 50; + x->r_grain = 0; + x->w_grain = x->n_grain = -1; + x->firstgrain = x->workgrain = scramble_tilde_newgrain(); + for (i = 1;i < x->grains;i++){ + x->workgrain->next = scramble_tilde_newgrain(); + x->workgrain = x->workgrain->next; + } + return (x); +} + +void *scramble_tilde_float(t_scramble_tilde* x, t_float n){ + x->play = n; + if (x->playmode == 2) { + x->n_grain = (int)n - 1; + x->grain_r = -1; + } +} + +void *scramble_tilde_buffer(t_scramble_tilde* x, t_float n){ + if (n > 64) x->x_n = (int)n; +// post ("buffersize now:%d",x->x_n); +} + +void *scramble_tilde_threshold(t_scramble_tilde* x, t_float t){ + if (t >0) { + x->lowborder = t; + x->autofollow = 0; + }else{ + post ("threshold must be a positive value (0.1 - 0.8 makes sense)"); + } + +} + +void *scramble_tilde_grains(t_scramble_tilde* x, t_float g){ + if ((g > 1) && (g < 2048) ) x->newgrains = (int)g; + else post ("scramble~: minimum # of grains must be 2 an maximum # is 2048"); +} + +void scramble_tilde_mindist(t_scramble_tilde* x, t_float t){ + if ((t > 0) && (t < x->x_n)) x->mindist = (int)t; + else post ("scramble~: minimum distance must be positive value lower than buffersize"); +} + +void scramble_tilde_direction(t_scramble_tilde* x, t_float d){ + if (d > 1) d = 1; + if (d < -1) d = -1; + x->dir = d; +} + +void scramble_tilde_autofollow(t_scramble_tilde* x){ + x->autofollow = 1; +} + +void scramble_tilde_pitch(t_scramble_tilde* x, t_float p){ + if (p > 0) x->pitch = p; + else post ("scramble~: pitch must be > 0"); +} + +void scramble_tilde_autopitch(t_scramble_tilde* x, t_float p){ + x->autopitch = p; +} + +void scramble_tilde_semitones(t_scramble_tilde* x, t_float p){ + x->semitones = (int)p; +} + + +void scramble_tilde_normalize(t_scramble_tilde* x, t_float n){ + x->normalize = n; +} + +void scramble_tilde_analize(t_scramble_tilde* x, t_float f){ + x->analize = f; +} + +void scramble_tilde_flush(t_scramble_tilde* x){ + x->flush = 1; +} + +void scramble_tilde_playmode(t_scramble_tilde* x, t_float p){ + x->playmode = (int)p; + if (x->playmode < 0) x->playmode = 0; + if (x->playmode < 1) x->playmode = 2; + switch (x->playmode){ + case 0: post ("scramble~: playmode off"); + break; + case 1: post ("scramble~: active playmode"); + break; + case 2: post ("scramble~: passive playmode"); + break; + default: post ("scramble~: invalid playmode"); + } +} + + +void scramble_tilde_setup(void) +{ + scramble_tilde_class = class_new(gensym("scramble~"), (t_newmethod) scramble_tilde_new, 0, + sizeof(t_scramble_tilde), 0, A_DEFFLOAT,A_DEFFLOAT, 0); + class_addfloat(scramble_tilde_class,scramble_tilde_float); + class_addmethod(scramble_tilde_class, nullfn, gensym("signal"), 0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_dsp, gensym("dsp"), 0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_buffer, gensym("buffer"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_threshold, gensym("threshold"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_grains, gensym("grains"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_mindist, gensym("min_length"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_direction, gensym("direction"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_autofollow, gensym("autofollow"),0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_pitch, gensym("pitch"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_autopitch, gensym("autopitch"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_semitones, gensym("semitones"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_flush, gensym("flush"), 0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_normalize, gensym("normalize"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_analize, gensym("analize"), A_DEFFLOAT,0); + class_addmethod(scramble_tilde_class, (t_method) scramble_tilde_playmode, gensym("playmode"), A_DEFFLOAT,0); +} -- cgit v1.2.1