[PD-cvs] externals/freeverb~ freeverb~-help.pd, NONE, 1.1 freeverb~.c, NONE, 1.1 freeverb~.cpp, 1.1, NONE

Hans-Christoph Steiner eighthave at users.sourceforge.net
Thu Nov 10 17:33:39 CET 2005


Update of /cvsroot/pure-data/externals/freeverb~
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8295

Added Files:
	freeverb~-help.pd freeverb~.c 
Removed Files:
	freeverb~.cpp 
Log Message:
added freeverb~ to the build system and wrote help patch

--- freeverb~.cpp DELETED ---

--- NEW FILE: freeverb~-help.pd ---
#N canvas 92 162 612 570 10;
#X obj 104 540 pddp;
#X obj 8 8 cnv 15 90 553 empty empty empty 20 12 0 14 -233017 -66577
0;
#N canvas 316 127 577 600 More_Info 0;
#X obj 451 407 metro 580;
#X obj 479 429 delay 120;
#X msg 479 450 0;
#X obj 405 471 noise~;
#X obj 435 494 *~;
#X msg 450 450 1;
#X msg 361 450 0;
#X obj 317 494 *~;
#X msg 332 450 1;
#X obj 333 407 metro 700;
#X obj 361 429 delay 200;
#X obj 273 471 osc~ 400;
#X obj 26 536 freeverb~;
#X obj 43 562 dac~;
#X obj 385 364 tgl 30 0 empty empty start 1 15 1 12 -90049 -1 -1 0
1;
#X obj 187 480 readsf~ 2;
#X msg 177 413 open \$1;
#X obj 177 394 openpanel;
#X msg 269 363 \; pd dsp 1;
#X obj 177 361 bng 30 250 50 0 empty empty open 1 15 1 12 -4080 -1
-228;
#X obj 177 432 t b a;
#X msg 164 456 1;
#X msg 25 42 roomsize \$1;
#X msg 25 87 damping \$1;
#X msg 25 131 width \$1;
#X msg 25 175 wet \$1;
#X msg 25 219 dry \$1;
#X msg 59 242 print;
#X msg 78 281 freeze \$1;
#X msg 83 318 bypass \$1;
#X obj 83 299 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
#X obj 78 262 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
#X text 154 274 - start and stop "freeze" mode (off by default). If
on \, reverb tail gets freezed (sample and hold).;
#X obj 37 196 hsl 60 18 0 1 0 1 empty empty dry 2 9 1 12 -225271 -1
-1 2950 0;
#X obj 37 152 hsl 60 18 0 1 0 1 empty empty wet 2 9 1 12 -225271 -1
-1 2950 0;
#X obj 37 108 hsl 60 18 0 1 0 1 empty empty width 2 9 1 12 -262131
-1 -1 2950 0;
#X obj 37 64 hsl 60 18 0 1 0 1 empty empty damping 2 9 1 12 -261689
-1 -1 2950 0;
#X obj 37 19 hsl 60 18 0 2 0 1 empty empty roomsize 2 9 1 12 -261689
-1 -1 0 0;
#X text 117 18 - size of the room to be simulated. Larger values result
in longer reverb. Values above 1 will result in feedback or 'room resonance'
(i.e. reverb getting louder);
#X floatatom 7 20 3 0 0 0 - - -;
#X text 114 65 - amount of damping of the room's surfaces. 1 means
nearly no damping \, resulting in a lot of reflection (long reverb)
\, >1 means high damping of signals (short reverb).;
#X text 116 110 - stereo width of the reverb \, i.e. how much of the
reverb part from the left and right channel mix. Turning this to 1
(nearly gives two separate mono reverbs.;
#X text 115 152 - level of the wet (reverbed) signal \, between 0 and
1;
#X text 113 197 - level of the dry (i.e. unprocessed or original) signal
\, between 0 and 1 Note that wet and dry signals mix and thus can cause
clipping if both are set at high levels.;
#X text 115 242 - print the current values of these parameters.;
#X text 157 305 - bypass reverb processing when set to 1 Can be used
to compare reverbed signal with original signal \, and to save CPU
when reverb is not needed.;
#X connect 0 0 1 0;
#X connect 0 0 5 0;
#X connect 1 0 2 0;
#X connect 2 0 4 1;
#X connect 3 0 4 0;
#X connect 4 0 12 1;
#X connect 5 0 4 1;
#X connect 6 0 7 1;
#X connect 7 0 12 0;
#X connect 8 0 7 1;
#X connect 9 0 8 0;
#X connect 9 0 10 0;
#X connect 10 0 6 0;
#X connect 11 0 7 0;
#X connect 12 0 13 0;
#X connect 12 1 13 1;
#X connect 14 0 9 0;
#X connect 14 0 0 0;
#X connect 15 0 12 0;
#X connect 15 1 12 1;
#X connect 16 0 20 0;
#X connect 17 0 16 0;
#X connect 19 0 17 0;
#X connect 20 0 21 0;
#X connect 20 1 15 0;
#X connect 21 0 15 0;
#X connect 22 0 12 0;
#X connect 23 0 12 0;
#X connect 24 0 12 0;
#X connect 25 0 12 0;
#X connect 26 0 12 0;
#X connect 27 0 12 0;
#X connect 28 0 12 0;
#X connect 29 0 12 0;
#X connect 30 0 29 0;
#X connect 31 0 28 0;
#X connect 33 0 26 0;
#X connect 34 0 25 0;
#X connect 35 0 24 0;
#X connect 36 0 23 0;
#X connect 37 0 22 0;
#X connect 37 0 39 0;
#X restore 104 514 pd More_Info;
#N canvas 85 22 403 252 Related_Objects 0;
#X restore 104 488 pd Related_Objects;
#X text 16 41 ARGUMENTS:;
#X text 32 270 OUTLETS:;
#X text 23 305 EXAMPLES:;
#X text 20 487 SEE ALSO:;
#X obj 19 16 freeverb~;
#X text 39 223 INLETS:;
#X text 108 16 stereo reverb using the Schroeder/Moorer model;
#X text 106 249 Right: audio input for the right channel.;
#X text 106 223 Left: audio input for the left channel and message
input for settings messages.;
#X text 106 270 Signal: the two outlets are the left and right channels
of a stereo output pair.;
#X obj 482 350 metro 580;
#X obj 510 372 delay 120;
#X msg 510 393 0;
#X obj 436 414 noise~;
#X obj 466 437 *~;
#X msg 481 393 1;
#X msg 392 393 0;
#X obj 348 437 *~;
#X msg 363 393 1;
#X obj 364 350 metro 700;
#X obj 392 372 delay 200;
#X obj 304 414 osc~ 400;
#X obj 348 465 freeverb~;
#X obj 365 491 dac~;
#X obj 416 307 tgl 30 0 empty empty start 1 15 1 12 -90049 -1 -1 0
1;
#X obj 180 436 readsf~ 2;
#X msg 170 369 open \$1;
#X obj 170 350 openpanel;
#X msg 263 312 \; pd dsp 1;
#X obj 170 317 bng 30 250 50 0 empty empty open 1 15 1 12 -4080 -1
-228;
#X obj 170 388 t b a;
#X msg 157 412 1;
#X msg 107 44 roomsize \$1;
#X msg 107 66 damping \$1;
#X msg 107 88 width \$1;
#X msg 107 110 wet \$1;
#X msg 107 132 dry \$1;
#X msg 107 154 print;
#X text 198 43 - size of the room to be simulated;
#X msg 107 176 freeze \$1;
#X msg 107 198 bypass \$1;
#X text -179 76 comment;
#X text 195 65 - amount of damping of room's surfaces;
#X text 176 89 - stereo width of reverb;
#X text 168 131 - level of unprocessed signal to include \, between
0 and 1;
#X text 172 110 - level of reverbed signal to include \, between 0
and 1;
#X text 170 153 - print the current values of the above parameters
;
#X text 183 176 - start/stop freeze of reverb tail \, using 1 or 0
;
#X text 187 197 - bypass the reverb processing \, using a 1 or 0;
#X text 152 541 - Hans-Christoph Steiner 2005 \, based on Olaf Matthes'
Max help;
#X connect 14 0 15 0;
#X connect 14 0 19 0;
#X connect 15 0 16 0;
#X connect 16 0 18 1;
#X connect 17 0 18 0;
#X connect 18 0 26 1;
#X connect 19 0 18 1;
#X connect 20 0 21 1;
#X connect 21 0 26 0;
#X connect 22 0 21 1;
#X connect 23 0 22 0;
#X connect 23 0 24 0;
#X connect 24 0 20 0;
#X connect 25 0 21 0;
#X connect 26 0 27 0;
#X connect 26 1 27 1;
#X connect 28 0 23 0;
#X connect 28 0 14 0;
#X connect 29 0 26 0;
#X connect 29 1 26 1;
#X connect 30 0 34 0;
#X connect 31 0 30 0;
#X connect 33 0 31 0;
#X connect 34 0 35 0;
#X connect 34 1 29 0;
#X connect 35 0 29 0;

--- NEW FILE: freeverb~.c ---
/* -------------------------- freeverb~ --------------------------------------- */
/*                                                                              */
/* Tilde object that implements the Schroeder/Moorer reverb model.              */
/* Written by Olaf Matthes <olaf.matthes at gmx.de>.                               */
/* Get source at http://www.akustische-kunst.org/                               */
/*                                                                              */
/* This program is free software; you can redistribute it and/or                */
/* modify it under the terms of the GNU General Public License                  */
/* as published by the Free Software Foundation; either version 2               */
/* of the License, or (at your option) any later version.                       */
/*                                                                              */
/* This program is distributed in the hope that it will be useful,              */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of               */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                */
/* GNU General Public License for more details.                                 */
/*                                                                              */
/* You should have received a copy of the GNU General Public License            */
/* along with this program; if not, write to the Free Software                  */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
/*                                                                              */
/* Based on PureData by Miller Puckette and others.                             */
/* Also compiles for Max/MSP.                                                   */
/*                                                                              */
/* ---------------------------------------------------------------------------- */

#ifdef NT
#pragma warning( disable : 4091 )
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif

#ifdef PD
#include "m_pd.h"
#else	// Max/MSP
#include "ext.h"
#include "z_dsp.h"
#define t_floatarg double
#endif

#include <math.h>
#include <string.h>

#define LOGTEN 2.302585092994

#define	numcombs		8
#define	numallpasses	4
#define	muted			0
#define	fixedgain		0.015
#define scalewet		3.0
#define scaledry		2.0
#define scaledamp		0.4
#define scaleroom		0.28
#define offsetroom		0.7
#define initialroom		0.5
#define initialdamp		0.5
#define initialwet		1.0/scalewet
#define initialdry		0.0
#define initialwidth	1.0
#define initialmode		0
#define initialbypass   0
#define freezemode		0.5
#define	stereospread	23

/* these values assume 44.1KHz sample rate
   they will probably be OK for 48KHz sample rate
   but would need scaling for 96KHz (or other) sample rates.
   the values were obtained by listening tests.                */
static const int combtuningL[numcombs]
                     = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 };
static const int combtuningR[numcombs]
                     = { 1116+stereospread, 1188+stereospread, 1277+stereospread, 1356+stereospread,
					     1422+stereospread, 1491+stereospread, 1557+stereospread, 1617+stereospread };

static const int allpasstuningL[numallpasses]
                     = { 556, 441, 341, 225 };
static const int allpasstuningR[numallpasses]
                     = { 556+stereospread, 441+stereospread, 341+stereospread, 225+stereospread };

static char *version = "freeverb~ v1.2";

#ifdef PD
static t_class *freeverb_class;

typedef struct _freeverb
{
    t_object x_obj;
#else	// Max/MSP
void *freeverb_class;

typedef struct _freeverb
{
	t_pxobject x_obj;
#endif
		/* freeverb stuff */
	t_float	x_gain;
	t_float	x_roomsize,x_roomsize1;
	t_float	x_damp,x_damp1;
	t_float	x_wet,x_wet1,x_wet2;
	t_float	x_dry;
	t_float	x_width;
	t_float	x_mode;
	t_float x_bypass;
	int     x_skip;

	t_float	x_allpassfeedback;			/* feedback of allpass filters */
	t_float	x_combfeedback;				/* feedback of comb filters */
	t_float x_combdamp1;
	t_float x_combdamp2;
	t_float x_filterstoreL[numcombs];	/* stores last sample value */
	t_float x_filterstoreR[numcombs];

		/* buffers for the combs */
	t_float	*x_bufcombL[numcombs];
	t_float	*x_bufcombR[numcombs];
	int x_combidxL[numcombs];
	int x_combidxR[numcombs];

		/* buffers for the allpasses */
	t_float	*x_bufallpassL[numallpasses];
	t_float	*x_bufallpassR[numallpasses];
	int x_allpassidxL[numallpasses];
	int x_allpassidxR[numallpasses];

		/* we'll make local copies adjusted to fit our sample rate */
	int x_combtuningL[numcombs];
	int x_combtuningR[numcombs];

	int x_allpasstuningL[numallpasses];
	int x_allpasstuningR[numallpasses];

#ifdef PD
	t_float x_float;
#endif
} t_freeverb;

#ifndef IRIX
#define IS_DENORM_FLOAT(v)              ((((*(unsigned long*)&(v))&0x7f800000)==0)&&((v)!=0.f))
#define IS_NAN_FLOAT(v)                 (((*(unsigned long*)&(v))&0x7f800000)==0x7f800000)
#define IS_DENORM_NAN_FLOAT(v)          (IS_DENORM_FLOAT(v)||IS_NAN_FLOAT(v))
#define FIX_DENORM_NAN_FLOAT(v)         ((v)=IS_DENORM_NAN_FLOAT(v)?0.f:(v))
#else
#define FIX_DENORM_NAN_FLOAT(v);
#endif

	/* we need prototypes for Mac for everything */
static void comb_setdamp(t_freeverb *x, t_floatarg val);
static void comb_setfeedback(t_freeverb *x, t_floatarg val);
static inline t_float comb_processL(t_freeverb *x, int filteridx, t_float input);
static inline t_float comb_processR(t_freeverb *x, int filteridx, t_float input);
static void allpass_setfeedback(t_freeverb *x, t_floatarg val);
static inline t_float allpass_processL(t_freeverb *x, int filteridx, t_float input);
static inline t_float allpass_processR(t_freeverb *x, int filteridx, t_float input);
t_int *freeverb_perform(t_int *w);
t_int *freeverb_perf8(t_int *w);
static void dsp_add_freeverb(t_freeverb *x, t_sample *in1, t_sample *in2, t_sample *out1, t_sample *out2, int n);
void freeverb_dsp(t_freeverb *x, t_signal **sp);
static void freeverb_update(t_freeverb *x);
static void freeverb_setroomsize(t_freeverb *x, t_floatarg value);
static float freeverb_getroomsize(t_freeverb *x);
static void freeverb_setdamp(t_freeverb *x, t_floatarg value);
static float freeverb_getdamp(t_freeverb *x);
static void freeverb_setwet(t_freeverb *x, t_floatarg value);
static float freeverb_getwet(t_freeverb *x);
static void freeverb_setdry(t_freeverb *x, t_floatarg value);
static float freeverb_getdry(t_freeverb *x);
static void freeverb_setwidth(t_freeverb *x, t_floatarg value);
static float freeverb_getwidth(t_freeverb *x);
static void freeverb_setmode(t_freeverb *x, t_floatarg value);
static float freeverb_getmode(t_freeverb *x);
static void freeverb_setbypass(t_freeverb *x, t_floatarg value);
static void freeverb_mute(t_freeverb *x);
static float freeverb_getdb(float f);
static void freeverb_print(t_freeverb *x);
#ifndef PD
void freeverb_assist(t_freeverb *x, void *b, long m, long a, char *s);
#endif
static void freeverb_free(t_freeverb *x);
void *freeverb_new(t_floatarg val);

/* -------------------- comb filter stuff ----------------------- */
static void comb_setdamp(t_freeverb *x, t_floatarg val) 
{
	x->x_combdamp1 = val; 
	x->x_combdamp2 = 1-val;
}

static void comb_setfeedback(t_freeverb *x, t_floatarg val) 
{
	x->x_combfeedback = val;
}

// Big to inline - but crucial for speed
static inline t_float comb_processL(t_freeverb *x, int filteridx, t_float input)
{
	t_float output;
	int bufidx = x->x_combidxL[filteridx];

	output = x->x_bufcombL[filteridx][bufidx];
	FIX_DENORM_NAN_FLOAT(output);

	x->x_filterstoreL[filteridx] = (output*x->x_combdamp2) + (x->x_filterstoreL[filteridx]*x->x_combdamp1);
	FIX_DENORM_NAN_FLOAT(x->x_filterstoreL[filteridx]);

	x->x_bufcombL[filteridx][bufidx] = input + (x->x_filterstoreL[filteridx]*x->x_combfeedback);

	if(++x->x_combidxL[filteridx] >= x->x_combtuningL[filteridx]) x->x_combidxL[filteridx] = 0;

	return output;
}

static inline t_float comb_processR(t_freeverb *x, int filteridx, t_float input)
{
	t_float output;
	int bufidx = x->x_combidxR[filteridx];

	output = x->x_bufcombR[filteridx][bufidx];
	FIX_DENORM_NAN_FLOAT(output);

	x->x_filterstoreR[filteridx] = (output*x->x_combdamp2) + (x->x_filterstoreR[filteridx]*x->x_combdamp1);
	FIX_DENORM_NAN_FLOAT(x->x_filterstoreR[filteridx]);

	x->x_bufcombR[filteridx][bufidx] = input + (x->x_filterstoreR[filteridx]*x->x_combfeedback);

	if(++x->x_combidxR[filteridx] >= x->x_combtuningR[filteridx]) x->x_combidxR[filteridx] = 0;

	return output;
}

/* -------------------- allpass filter stuff ----------------------- */
static void allpass_setfeedback(t_freeverb *x, t_floatarg val) 
{
	x->x_allpassfeedback = val;
}

// Big to inline - but crucial for speed
static inline t_float allpass_processL(t_freeverb *x, int filteridx, t_float input)
{
	t_float output;
	t_float bufout;
	int bufidx = x->x_allpassidxL[filteridx];
	
	bufout = (t_float)x->x_bufallpassL[filteridx][bufidx];
	FIX_DENORM_NAN_FLOAT(bufout);
	
	output = -input + bufout;
	x->x_bufallpassL[filteridx][bufidx] = input + (bufout*x->x_allpassfeedback);

	if(++x->x_allpassidxL[filteridx] >= x->x_allpasstuningL[filteridx])
		x->x_allpassidxL[filteridx] = 0;

	return output;
}

static inline t_float allpass_processR(t_freeverb *x, int filteridx, t_float input)
{
	t_float output;
	t_float bufout;
	int bufidx = x->x_allpassidxR[filteridx];
	
	bufout = (t_float)x->x_bufallpassR[filteridx][bufidx];
	FIX_DENORM_NAN_FLOAT(bufout);
	
	output = -input + bufout;
	x->x_bufallpassR[filteridx][bufidx] = input + (bufout*x->x_allpassfeedback);

	if(++x->x_allpassidxR[filteridx] >= x->x_allpasstuningR[filteridx])
		x->x_allpassidxR[filteridx] = 0;

	return output;
}

/* -------------------- general DSP stuff ----------------------- */
t_int *freeverb_perform(t_int *w)
{
	// assign from parameters
    t_freeverb *x = (t_freeverb *)(w[1]);
    t_float *in1 = (t_float *)(w[2]);
    t_float *in2 = (t_float *)(w[3]);
    t_float *out1 = (t_float *)(w[4]);
    t_float *out2 = (t_float *)(w[5]);
    int n = (int)(w[6]);
	int i;
	t_float outL, outR, inL, inR, input;
    
#ifndef PD
    if (x->x_obj.z_disabled)
    	goto out;    	 
#endif

	if(x->x_bypass)
	{
		// Bypass, so just copy input to output
		while(n--)
		{
			inL = *in1++;	// We have to copy first before we can write to output
			inR = *in2++;	// since this might be at the same memory position
			*out1++ = inL;
			*out2++ = inR;
		}
	}
	else
	{
    	// DSP loop
		while(n--)
		{
			outL = outR = 0.;
			inL = *in1++;
			inR = *in2++;
			input = (inL + inR) * x->x_gain;

			// Accumulate comb filters in parallel
			for(i=0; i < numcombs; i++)
			{
				outL += comb_processL(x, i, input);
				outR += comb_processR(x, i, input);
			}

			// Feed through allpasses in series
			for(i=0; i < numallpasses; i++)
			{
				outL = allpass_processL(x, i, outL);
				outR = allpass_processR(x, i, outR);
			}

			// Calculate output REPLACING anything already there
			*out1++ = outL*x->x_wet1 + outR*x->x_wet2 + inL*x->x_dry;
			*out2++ = outR*x->x_wet1 + outL*x->x_wet2 + inR*x->x_dry;
		}
	}
#ifndef PD
out:
#endif
	return(w + 7);
}

// This is a hand unrolled version of the perform routine for
// DSP vector sizes that are multiples of 8
t_int *freeverb_perf8(t_int *w)
{
	// assign from parameters
    t_freeverb *x = (t_freeverb *)(w[1]);
    t_float *in1 = (t_float *)(w[2]);
    t_float *in2 = (t_float *)(w[3]);
    t_float *out1 = (t_float *)(w[4]);
    t_float *out2 = (t_float *)(w[5]);
    int n = (int)(w[6]);
	int i;
	t_float outL[8], outR[8], inL[8], inR[8], input[8];
    
#ifndef PD
    if (x->x_obj.z_disabled)
    	goto out;    	 
#endif

	if(x->x_bypass)
	{
		// Bypass, so just copy input to output
		for(; n; n -= 8, out1 += 8, out2 += 8, in1 += 8, in2 += 8)
		{
			inL[0] = in1[0];	// We have to copy first before we can write to output
			inR[0] = in2[0];	// since this might be at the same memory position
			out1[0] = inL[0];
			out2[0] = inR[0];
			inL[1] = in1[1];
			inR[1] = in2[1];
			out1[1] = inL[1];
			out2[1] = inR[1];
			inL[2] = in1[2];
			inR[2] = in2[2];
			out1[2] = inL[2];
			out2[2] = inR[2];
			inL[3] = in1[3];
			inR[3] = in2[3];
			out1[3] = inL[3];
			out2[3] = inR[3];
			inL[4] = in1[4];
			inR[4] = in2[4];
			out1[4] = inL[4];
			out2[4] = inR[4];
			inL[5] = in1[5];
			inR[5] = in2[5];
			out1[5] = inL[5];
			out2[5] = inR[5];
			inL[6] = in1[6];
			inR[6] = in2[6];
			out1[6] = inL[6];
			out2[6] = inR[6];
			inL[7] = in1[7];
			inR[7] = in2[7];
			out1[7] = inL[7];
			out2[7] = inR[7];
		}
	}
	else
	{
    	// DSP loop
		for(; n; n -= 8, out1 += 8, out2 += 8, in1 += 8, in2 += 8)
		{
			outL[0] = outR [0]= 0.;
			inL[0] = in1[0];
			inR[0] = in2[0];
			input[0] = (inL[0] + inR[0]) * x->x_gain;

			outL[1] = outR [1]= 0.;
			inL[1] = in1[1];
			inR[1] = in2[1];
			input[1] = (inL[1] + inR[1]) * x->x_gain;

			outL[2] = outR [2]= 0.;
			inL[2] = in1[2];
			inR[2] = in2[2];
			input[2] = (inL[2] + inR[2]) * x->x_gain;

			outL[3] = outR [3]= 0.;
			inL[3] = in1[3];
			inR[3] = in2[3];
			input[3] = (inL[3] + inR[3]) * x->x_gain;

			outL[4] = outR [4]= 0.;
			inL[4] = in1[4];
			inR[4] = in2[4];
			input[4] = (inL[4] + inR[4]) * x->x_gain;

			outL[5] = outR [5]= 0.;
			inL[5] = in1[5];
			inR[5] = in2[5];
			input[5] = (inL[5] + inR[5]) * x->x_gain;

			outL[6] = outR [6]= 0.;
			inL[6] = in1[6];
			inR[6] = in2[6];
			input[6] = (inL[6] + inR[6]) * x->x_gain;

			outL[7] = outR [7]= 0.;
			inL[7] = in1[7];
			inR[7] = in2[7];
			input[7] = (inL[7] + inR[7]) * x->x_gain;

			// Accumulate comb filters in parallel
			for(i=0; i < numcombs; i++)
			{
				outL[0] += comb_processL(x, i, input[0]);
				outR[0] += comb_processR(x, i, input[0]);
				outL[1] += comb_processL(x, i, input[1]);
				outR[1] += comb_processR(x, i, input[1]);
				outL[2] += comb_processL(x, i, input[2]);
				outR[2] += comb_processR(x, i, input[2]);
				outL[3] += comb_processL(x, i, input[3]);
				outR[3] += comb_processR(x, i, input[3]);
				outL[4] += comb_processL(x, i, input[4]);
				outR[4] += comb_processR(x, i, input[4]);
				outL[5] += comb_processL(x, i, input[5]);
				outR[5] += comb_processR(x, i, input[5]);
				outL[6] += comb_processL(x, i, input[6]);
				outR[6] += comb_processR(x, i, input[6]);
				outL[7] += comb_processL(x, i, input[7]);
				outR[7] += comb_processR(x, i, input[7]);
			}

			// Feed through allpasses in series
			for(i=0; i < numallpasses; i++)
			{
				outL[0] = allpass_processL(x, i, outL[0]);
				outR[0] = allpass_processR(x, i, outR[0]);
				outL[1] = allpass_processL(x, i, outL[1]);
				outR[1] = allpass_processR(x, i, outR[1]);
				outL[2] = allpass_processL(x, i, outL[2]);
				outR[2] = allpass_processR(x, i, outR[2]);
				outL[3] = allpass_processL(x, i, outL[3]);
				outR[3] = allpass_processR(x, i, outR[3]);
				outL[4] = allpass_processL(x, i, outL[4]);
				outR[4] = allpass_processR(x, i, outR[4]);
				outL[5] = allpass_processL(x, i, outL[5]);
				outR[5] = allpass_processR(x, i, outR[5]);
				outL[6] = allpass_processL(x, i, outL[6]);
				outR[6] = allpass_processR(x, i, outR[6]);
				outL[7] = allpass_processL(x, i, outL[7]);
				outR[7] = allpass_processR(x, i, outR[7]);
			}

			// Calculate output REPLACING anything already there
			out1[0] = outL[0]*x->x_wet1 + outR[0]*x->x_wet2 + inL[0]*x->x_dry;
			out2[0] = outR[0]*x->x_wet1 + outL[0]*x->x_wet2 + inR[0]*x->x_dry;

			out1[1] = outL[1]*x->x_wet1 + outR[1]*x->x_wet2 + inL[1]*x->x_dry;
			out2[1] = outR[1]*x->x_wet1 + outL[1]*x->x_wet2 + inR[1]*x->x_dry;
			out1[2] = outL[2]*x->x_wet1 + outR[2]*x->x_wet2 + inL[2]*x->x_dry;
			out2[2] = outR[2]*x->x_wet1 + outL[2]*x->x_wet2 + inR[2]*x->x_dry;
			out1[3] = outL[3]*x->x_wet1 + outR[3]*x->x_wet2 + inL[3]*x->x_dry;
			out2[3] = outR[3]*x->x_wet1 + outL[3]*x->x_wet2 + inR[3]*x->x_dry;
			out1[4] = outL[4]*x->x_wet1 + outR[4]*x->x_wet2 + inL[4]*x->x_dry;
			out2[4] = outR[4]*x->x_wet1 + outL[4]*x->x_wet2 + inR[4]*x->x_dry;
			out1[5] = outL[5]*x->x_wet1 + outR[5]*x->x_wet2 + inL[5]*x->x_dry;
			out2[5] = outR[5]*x->x_wet1 + outL[5]*x->x_wet2 + inR[5]*x->x_dry;
			out1[6] = outL[6]*x->x_wet1 + outR[6]*x->x_wet2 + inL[6]*x->x_dry;
			out2[6] = outR[6]*x->x_wet1 + outL[6]*x->x_wet2 + inR[6]*x->x_dry;
			out1[7] = outL[7]*x->x_wet1 + outR[7]*x->x_wet2 + inL[7]*x->x_dry;
			out2[7] = outR[7]*x->x_wet1 + outL[7]*x->x_wet2 + inR[7]*x->x_dry;
			}
	}
#ifndef PD
out:
#endif
	return(w + 7);
}

static void dsp_add_freeverb(t_freeverb *x, t_sample *in1, t_sample *in2, 
							 t_sample *out1, t_sample *out2, int n)
{
	if(n & 7)	// check whether block size is multiple of 8
		dsp_add(freeverb_perform, 6, x, in1, in2, out1, out2, n);
	else
		dsp_add(freeverb_perf8, 6, x, in1, in2, out1, out2, n);
}

void freeverb_dsp(t_freeverb *x, t_signal **sp)
{
    dsp_add_freeverb(x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n);
}

// ----------- general parameter & calculation stuff -----------

	// recalculate internal values after parameter change
static void freeverb_update(t_freeverb *x)
{

	int i;

	x->x_wet1 = x->x_wet*(x->x_width/2 + 0.5);
	x->x_wet2 = x->x_wet*((1-x->x_width)/2);

	if (x->x_mode >= freezemode)
	{
		x->x_roomsize1 = 1.;
		x->x_damp1 = 0.;
		x->x_gain = muted;
	}
	else
	{
		x->x_roomsize1 = x->x_roomsize;
		x->x_damp1 = x->x_damp;
		x->x_gain = (float)fixedgain;
	}

	comb_setfeedback(x, x->x_roomsize1);
	comb_setdamp(x, x->x_damp1);
}

	// the following functions set / get the parameters
static void freeverb_setroomsize(t_freeverb *x, t_floatarg value)
{
	x->x_roomsize = (value*scaleroom) + offsetroom;
	freeverb_update(x);
}

static float freeverb_getroomsize(t_freeverb *x)
{
	return (x->x_roomsize-offsetroom)/scaleroom;
}

static void freeverb_setdamp(t_freeverb *x, t_floatarg value)
{
	x->x_damp = value*scaledamp;
	freeverb_update(x);
}

static float freeverb_getdamp(t_freeverb *x)
{
	return x->x_damp/scaledamp;
}

static void freeverb_setwet(t_freeverb *x, t_floatarg value)
{
	x->x_wet = value*scalewet;
	freeverb_update(x);
}

static float freeverb_getwet(t_freeverb *x)
{
	return (x->x_wet/scalewet);
}

static void freeverb_setdry(t_freeverb *x, t_floatarg value)
{
	x->x_dry = value*scaledry;
}

static float freeverb_getdry(t_freeverb *x)
{
	return (x->x_dry/scaledry);
}

static void freeverb_setwidth(t_freeverb *x, t_floatarg value)
{
	x->x_width = value;
	freeverb_update(x);
}

static float freeverb_getwidth(t_freeverb *x)
{
	return x->x_width;
}

static void freeverb_setmode(t_freeverb *x, t_floatarg value)
{
	x->x_mode = value;
	freeverb_update(x);
}

static float freeverb_getmode(t_freeverb *x)
{
	if (x->x_mode >= freezemode)
		return 1;
	else
		return 0;
}

static void freeverb_setbypass(t_freeverb *x, t_floatarg value)
{
	x->x_bypass = value;
	if(x->x_bypass)freeverb_mute(x);
}

	// fill delay lines with silence
static void freeverb_mute(t_freeverb *x)
{
	int i;

	if (freeverb_getmode(x) >= freezemode)
		return;

	for (i=0;i<numcombs;i++)
	{
		memset(x->x_bufcombL[i], 0x0, x->x_combtuningL[i]*sizeof(t_float));
		memset(x->x_bufcombR[i], 0x0, x->x_combtuningR[i]*sizeof(t_float));
	}
	for (i=0;i<numallpasses;i++)
	{
		memset(x->x_bufallpassL[i], 0x0, x->x_allpasstuningL[i]*sizeof(t_float));
		memset(x->x_bufallpassR[i], 0x0, x->x_allpasstuningR[i]*sizeof(t_float));
	}
}

	// convert gain factor into dB
static float freeverb_getdb(float f)
{
    if (f <= 0)	// equation does not work for 0...
	{
		return (-96);	// ...so we output max. damping
	}
    else
    {
    	float val = (20./LOGTEN * log(f));
    	return (val);
    }
}

static void freeverb_print(t_freeverb *x)
{
	post("freeverb~:");
	if(x->x_bypass) {
		post("  bypass: on");
	} else post("  bypass: off");
	if(!freeverb_getmode(x)) {
		post("  mode: normal");
	} else post("  mode: freeze");
	post("  roomsize: %g", freeverb_getroomsize(x)*scaleroom+offsetroom);
	post("  damping: %g %%", freeverb_getdamp(x)*100);
	post("  width: %g %%", x->x_width * 100);
	post("  wet level: %g dB", freeverb_getdb(freeverb_getwet(x)*scalewet));
	post("  dry level: %g dB", freeverb_getdb(freeverb_getdry(x)*scaledry));
}

	// clean up
static void freeverb_free(t_freeverb *x)    
{
	int i;
#ifndef PD
	dsp_free((t_pxobject *)x);		// Free the object
#endif
	// free memory used by delay lines
	for(i = 0; i < numcombs; i++)
	{
		t_freebytes(x->x_bufcombL[i], x->x_combtuningL[i]*sizeof(t_float));
		t_freebytes(x->x_bufcombR[i], x->x_combtuningR[i]*sizeof(t_float));
	}

	for(i = 0; i < numallpasses; i++)
	{
		t_freebytes(x->x_bufallpassL[i], x->x_allpasstuningL[i]*sizeof(t_float));
		t_freebytes(x->x_bufallpassR[i], x->x_allpasstuningR[i]*sizeof(t_float));
	}
}

void *freeverb_new(t_floatarg f)
{
	int i;
	int sr = (int)sys_getsr();

#ifdef PD
    t_freeverb *x = (t_freeverb *)pd_new(freeverb_class);

	// add additional signal inlets and signal outlets
	inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);

    outlet_new(&x->x_obj, gensym("signal"));
    outlet_new(&x->x_obj, gensym("signal"));
#else	// Max/MSP
    t_freeverb *x = (t_freeverb *)newobject(freeverb_class);
    
    // zero out the struct, to be careful
    if(x)
    {
    	for(i = sizeof(t_pxobject); i < sizeof(t_freeverb); i++)
    		((char*)x)[i] = 0;
    }
    
    dsp_setup((t_pxobject *)x,2);	// two signal inlets
    
    // two signal outlets
    outlet_new((t_object *)x, "signal");
    outlet_new((t_object *)x, "signal");
#endif	
	// recalculate the reverb parameters in case we don't run at 44.1kHz
	for(i = 0; i < numcombs; i++)
	{
		x->x_combtuningL[i] = (int)(combtuningL[i] * sr / 44100);
		x->x_combtuningR[i] = (int)(combtuningR[i] * sr / 44100);
	}
	for(i = 0; i < numallpasses; i++)
	{
		x->x_allpasstuningL[i] = (int)(allpasstuningL[i] * sr / 44100);
		x->x_allpasstuningR[i] = (int)(allpasstuningL[i] * sr / 44100);
	}

	// get memory for delay lines
	for(i = 0; i < numcombs; i++)
	{
		x->x_bufcombL[i] = (t_float*) t_getbytes(x->x_combtuningL[i]*sizeof(t_float));
		x->x_bufcombR[i] = (t_float*) t_getbytes(x->x_combtuningR[i]*sizeof(t_float));
		x->x_combidxL[i] = 0;
		x->x_combidxR[i] = 0;
	}
	for(i = 0; i < numallpasses; i++)
	{
		x->x_bufallpassL[i] = (t_float*) t_getbytes(x->x_allpasstuningL[i]*sizeof(t_float));
		x->x_bufallpassR[i] = (t_float*) t_getbytes(x->x_allpasstuningR[i]*sizeof(t_float));
		x->x_allpassidxL[i] = 0;
		x->x_allpassidxR[i] = 0;
	}

	// set default values
	x->x_allpassfeedback = 0.5;
	x->x_skip = 1;	// we use every sample
	freeverb_setwet(x, initialwet);
	freeverb_setroomsize(x, initialroom);
	freeverb_setdry(x, initialdry);
	freeverb_setdamp(x, initialdamp);
	freeverb_setwidth(x, initialwidth);
	freeverb_setmode(x, initialmode);
	freeverb_setbypass(x, initialbypass);

	// buffers will be full of rubbish - so we MUST mute them
	freeverb_mute(x);

    return (x);
}

#ifdef PD
void freeverb_tilde_setup(void)
{
    freeverb_class = class_new(gensym("freeverb~"), (t_newmethod)freeverb_new, (t_method)freeverb_free,
    	sizeof(t_freeverb), 0, A_DEFFLOAT, 0);
	CLASS_MAINSIGNALIN(freeverb_class, t_freeverb, x_float);
    class_addmethod(freeverb_class, (t_method)freeverb_dsp, gensym("dsp"), A_NULL);
    class_addmethod(freeverb_class, (t_method)freeverb_setroomsize, gensym("roomsize"), A_FLOAT, A_NULL);
    class_addmethod(freeverb_class, (t_method)freeverb_setdamp, gensym("damping"), A_FLOAT, A_NULL);
    class_addmethod(freeverb_class, (t_method)freeverb_setwidth, gensym("width"), A_FLOAT, A_NULL);
	class_addmethod(freeverb_class, (t_method)freeverb_setwet, gensym("wet"), A_FLOAT, A_NULL);
	class_addmethod(freeverb_class, (t_method)freeverb_setdry, gensym("dry"), A_FLOAT, A_NULL);
	class_addmethod(freeverb_class, (t_method)freeverb_setmode, gensym("freeze"), A_FLOAT, A_NULL);
	class_addmethod(freeverb_class, (t_method)freeverb_setbypass, gensym("bypass"), A_FLOAT, A_NULL);
	class_addmethod(freeverb_class, (t_method)freeverb_mute, gensym("clear"), A_NULL);
    class_addmethod(freeverb_class, (t_method)freeverb_print, gensym("print"), A_NULL);
    class_sethelpsymbol(freeverb_class, gensym("help-freeverb~.pd"));
	post(version);
}

#else
// ----------- Max/MSP -----------
void freeverb_assist(t_freeverb *x, void *b, long m, long a, char *s)
{
	switch(m) {
		case 1: // inlet
			switch(a) {
				case 0:
				sprintf(s, "(signal/message) Left Input & Control Messages");
				break;
				case 1:
				sprintf(s, "(signal) Right Input");
				break;
			}
		break;
		case 2: // outlet
			switch(a) {
				case 0:
				sprintf(s, "(signal) Left Output");
				break;
				case 1:
				sprintf(s, "(signal) Right Output");
				break;
			}
		break;
	}

}

extern "C" void main(void)
{
	setup((t_messlist **)&freeverb_class,(method)freeverb_new, (method)freeverb_free, 
		(short)sizeof(t_freeverb), 0L, A_DEFFLOAT, 0);
	addmess((method)freeverb_dsp, "dsp", A_CANT, 0);
	addmess((method)freeverb_assist, "assist", A_CANT, 0);
	addmess((method)freeverb_setroomsize, "roomsize", A_FLOAT, 0);
	addmess((method)freeverb_setdamp, "damping", A_FLOAT, 0);
	addmess((method)freeverb_setwidth, "width", A_FLOAT, 0);
	addmess((method)freeverb_setwet, "wet", A_FLOAT, 0);
	addmess((method)freeverb_setdry, "dry", A_FLOAT, 0);
	addmess((method)freeverb_setmode, "freeze", A_FLOAT, 0);
	addmess((method)freeverb_setbypass, "bypass", A_FLOAT, 0);
	addmess((method)freeverb_mute, "clear", 0);
	addmess((method)freeverb_print, "print", 0);
	dsp_initclass();
	finder_addclass("MSP Delays","freeverb~");
	post(version);
}
#endif





More information about the Pd-cvs mailing list