Commit 31eb243b authored by Jonathan Wilkes's avatar Jonathan Wilkes
Browse files

Merge branch 'port-disis_munger'

parents 02a88eda ecada8c2
#include "ADSR.h"
t_float stk_ADSR_tick(t_stk_ADSR *x)
{
switch (x->state)
{
case ATTACK:
x->value += x->attackRate;
if (x->value >= x->target)
{
x->value = x->target;
x->target = x->sustainLevel;
x->state = DECAY;
}
break;
case DECAY:
if (x->value > x->sustainLevel)
{
x->value -= x->decayRate;
if (x->value <= x->sustainLevel)
{
x->value = x->sustainLevel;
x->state = SUSTAIN;
}
}
else
{
x->value += x->decayRate; // attack target < sustain level
if (x->value >= x->sustainLevel)
{
x->value = x->sustainLevel;
x->state = SUSTAIN;
}
}
break;
case RELEASE:
x->value -= x->releaseRate;
if (x->value <= 0.0)
{
x->value = 0.0;
x->state = IDLE;
}
}
return x->value;
}
void stk_ADSR_init(t_stk_ADSR *x)
{
x->target = 0.0;
x->value = 0.0;
x->attackRate = 0.001;
x->decayRate = 0.001;
x->releaseRate = 0.005;
x->releaseTime = -1.0;
x->sustainLevel = 0.5;
x->state = IDLE;
x->sampleRate = 44100;
}
t_env_state stk_ADSR_getState(t_stk_ADSR *x)
{
return x->state;
}
void stk_ADSR_sampleRateChanged(t_stk_ADSR *x, t_float newRate,
t_float oldRate)
{
x->attackRate = oldRate * x->attackRate / newRate;
x->decayRate = oldRate * x->decayRate / newRate;
x->releaseRate = oldRate * x->releaseRate / newRate;
}
void stk_ADSR_setSampleRate(t_stk_ADSR *x, t_float newRate)
{
x->sampleRate = newRate;
}
void stk_ADSR_keyOn(t_stk_ADSR *x)
{
if (x->target <= 0.0) x->target = 1.0;
x->state = ATTACK;
}
void stk_ADSR_keyOff(t_stk_ADSR *x)
{
x->target = 0.0;
x->state = RELEASE;
// FIXED October 2010 - Nick Donaldson
// Need to make release rate relative to current value!!
// Only update if we have set a TIME rather than a RATE,
// in which case releaseTime will be -1
if (x->releaseTime > 0.0)
x->releaseRate = x->value / (x->releaseTime * x->sampleRate);
}
void stk_ADSR_setAttackRate(t_stk_ADSR *x, t_float rate)
{
if (rate < 0.0)
fprintf(stderr, "stk_ADSR_setAttackRate: argument must be >= 0.0!");
x->attackRate = rate;
}
void stk_ADSR_setAttackTarget(t_stk_ADSR *x, t_float target)
{
if (target < 0.0)
{
fprintf(stderr, "ADSR::setAttackTarget: negative target not allowed!");
}
x->target = target;
}
void stk_ADSR_setDecayRate(t_stk_ADSR *x, t_float rate)
{
if (rate < 0.0)
fprintf(stderr, "ADSR::setDecayRate: negative rates not allowed!");
x->decayRate = rate;
}
void stk_ADSR_setSustainLevel(t_stk_ADSR *x, t_float level)
{
if (level < 0.0)
fprintf(stderr, "ADSR::setSustainLevel: negative level not allowed!");
x->sustainLevel = level;
}
void stk_ADSR_setReleaseRate(t_stk_ADSR *x, t_float rate)
{
if (rate < 0.0)
fprintf(stderr, "ADSR::setReleaseRate: negative rates not allowed!");
x->releaseRate = rate;
// Set to negative value so we don't update the release rate on keyOff()
x->releaseTime = -1.0;
}
void stk_ADSR_setAttackTime(t_stk_ADSR *x, t_float time)
{
if (time <= 0.0)
fprintf(stderr,
"ADSR::setAttackTime: negative or zero times not allowed!");
x->attackRate = 1.0 / (time * x->sampleRate);
}
void stk_ADSR_setDecayTime(t_stk_ADSR *x, t_float time)
{
if (time <= 0.0)
fprintf(stderr,
"ADSR::setDecayTime: negative or zero times not allowed!");
x->decayRate = (1.0 - x->sustainLevel) / (time * x->sampleRate);
}
void stk_ADSR_setReleaseTime(t_stk_ADSR *x, t_float time)
{
if (time <= 0.0)
fprintf(stderr,
"ADSR::setReleaseTime: negative or zero times not allowed!");
x->releaseRate = x->sustainLevel / (time * x->sampleRate);
x->releaseTime = time;
}
void stk_ADSR_setAllTimes(t_stk_ADSR *x, t_float aTime, t_float dTime,
t_float sLevel, t_float rTime)
{
stk_ADSR_setAttackTime(x, aTime);
stk_ADSR_setSustainLevel(x, sLevel);
stk_ADSR_setDecayTime(x, dTime);
stk_ADSR_setReleaseTime(x, rTime);
}
void stk_ADSR_setTarget(t_stk_ADSR *x, t_float target)
{
if (target < 0.0)
fprintf(stderr, "ADSR::setTarget: negative target not allowed!");
x->target = target;
stk_ADSR_setSustainLevel(x, x->target);
if (x->value < x->target) x->state = ATTACK;
if (x->value > x->target) x->state = DECAY;
}
void stk_ADSR_setValue(t_stk_ADSR *x, t_float value)
{
x->state = SUSTAIN;
x->target = value;
x->value = value;
stk_ADSR_setSustainLevel(x, value);
}
#include "m_pd.h"
/* port of stk's ADSR class to C */
/* original class notes */
/***************************************************/
/*! \class ADSR
\brief STK ADSR envelope class.
This class implements a traditional ADSR (Attack, Decay, Sustain,
Release) envelope. It responds to simple keyOn and keyOff
messages, keeping track of its state. The \e state = ADSR::IDLE
before being triggered and after the envelope value reaches 0.0 in
the ADSR::RELEASE state. All rate, target and level settings must
be non-negative. All time settings are in seconds and must be
positive.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
*/
/***************************************************/
/* ADSR envelope states. */
typedef enum {
ATTACK, /* Attack */
DECAY, /* Decay */
SUSTAIN, /* Sustain */
RELEASE, /* Release */
IDLE /* Before attack / after release */
} t_env_state;
typedef struct _stk_ADSR {
t_env_state state;
t_float value;
t_float target;
t_float attackRate;
t_float decayRate;
t_float releaseRate;
t_float releaseTime;
t_float sustainLevel;
// Currently setting this is dsp_add routine...
t_float sampleRate;
} t_stk_ADSR;
/* initialize the struct members to sane values */
void stk_ADSR_init(t_stk_ADSR *x);
/* set the sample rate */
void stk_ADSR_setSampleRate(t_stk_ADSR *x, t_float newRate);
/* Set target = 1, state = ATTACK. */
void stk_ADSR_keyOn(t_stk_ADSR *x);
/* Set target = 0, state = RELEASE. */
void stk_ADSR_keyOff(t_stk_ADSR *x);
/* Set the attack rate (gain / sample). */
void stk_ADSR_setAttackRate(t_stk_ADSR *x, t_float rate);
/* Set the target value for the attack (default = 1.0). */
void stk_ADSR_setAttackTarget(t_stk_ADSR *x, t_float target);
/* Set the decay rate (gain / sample). */
void stk_ADSR_setDecayRate(t_stk_ADSR *x, t_float rate);
/* Set the sustain level. */
void stk_ADSR_setSustainLevel(t_stk_ADSR *x, t_float level);
/* Set the release rate (gain / sample). */
void stk_ADSR_setReleaseRate(t_stk_ADSR *x, t_float rate);
/* Set the attack rate based on a time duration (seconds). */
void stk_ADSR_setAttackTime(t_stk_ADSR *x, t_float time);
/* Set the decay rate based on a time duration (seconds). */
void stk_ADSR_setDecayTime(t_stk_ADSR *x, t_float time);
/* Set the release rate based on a time duration (seconds). */
void stk_ADSR_setReleaseTime(t_stk_ADSR *x, t_float time);
/* Set sustain level and attack, decay, and release time durations (seconds). */
void stk_ADSR_setAllTimes(t_stk_ADSR *x, t_float aTime, t_float dTime,
t_float sLevel, t_float rTime);
/* Set a sustain target value and attack or decay from current value
to target. */
void stk_ADSR_setTarget(t_stk_ADSR *x, t_float target);
/* Return the current envelope state (ATTACK, DECAY, SUSTAIN, RELEASE, IDLE).*/
t_env_state stk_ADSR_getState(t_stk_ADSR *x);
/* Set to state = ADSR::SUSTAIN with current and target values of value. */
void stk_ADSR_setValue(t_stk_ADSR *x, t_float value);
/* Compute and return one output sample. */
t_float stk_ADSR_tick(t_stk_ADSR *x);
/*
disis.munger~ 1.4.3
a realtime multichannel granulator
a flext (cross-platform PD & Max/MSP) port of
the munger~ object from the PeRColate library (0.9 beta6)
http://www.music.columbia.edu/PeRColate/
Original PeRColate library by:
Dan Trueman http://www.music.princeton.edu/~dan/
R. Luke DuBois's http://www.lukedubois.com/
Flext port and additions by:
Ivica Ico Bukvic http://ico.bukvic.net
Ji-Sun Kim hideaway@vt.edu
http://disis.music.vt.edu
Released under GPL license
(whichever is the latest version--as of this release, version 2)
For more info on the GPL license please visit:
http://www.gnu.org/copyleft/gpl.html
For latest changes please see changelog
*/
#include "m_pd.h"
#include "ADSR.h" /* small C library ported from stk */
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
//version
#define MUNGER_MAJOR 1
#define MUNGER_MINOR 4
#define MUNGER_REV 3
/* MSVC doesn't know RANDOM(), while GCC's
(at least on Linux) has rand() limit much higher */
#ifndef __GNUC__
#define RANDOM() (rand())
#else
#define RANDOM() (random()%32768)
#endif
#define ONE_OVER_HALFRAND 0.00006103516 /* constant = 1. / 16384.0 */
#define ONE_OVER_MAXRAND 0.000030517578 /* 1 / 32768 */
#define MINSPEED .001 /* minimum speed through buffer on playback */
#define ENVSIZE 32
#define ONE_OVER_ENVSIZE .0078125
#define MINSIZE 64 /* twice ENVSIZE. minimum grainsize in samples */
#define RAND01 (((long)RANDOM() * ONE_OVER_MAXRAND) /* RANDOM() numbers 0-1 */
/* RANDOM() numbers -1 to 1 */
#define RAND11 (((long)RANDOM() - 16384.) * ONE_OVER_HALFRAND)
#define WINLENGTH 1024
/* max number of transpositions for the "scale" message */
#define PITCHTABLESIZE 1000
#define RECORDRAMP 1000
#define RECORDRAMP_INV 0.001
/* these are arbitrary-- can we trust users not to
do something silly and remove these? */
#define MAXCHANNELS 64
#define MAXVOICES 1000
/* useful define */
#ifndef TWOPI
#define TWOPI 6.28318530717958647692
#endif
static t_class *disis_munger_class;
typedef struct _disis_munger {
t_object x_obj;
t_float x_f;
t_float x_srate;
t_float x_one_over_srate;
t_float x_srate_ms;
t_float x_one_over_srate_ms;
t_float x_initbuflen;
int x_buflen;
t_float x_maxdelay;
int x_num_channels;
int x_numvoices;
t_symbol *x_munger_name;
t_float x_maxsize;
t_float x_minsize;
t_float x_twothirdBufsize;
t_float x_onethirdBufsize;
int x_verbose;
/* Ancillary inlet vars */
t_float x_grate;
t_float x_grate_var;
t_float x_glen;
t_float x_glen_var;
t_float x_gpitch;
t_float x_gpitch_var;
t_float x_gpan_spread;
/* Heap allocated based on number of voices */
t_float *x_recordBuf;
t_float *x_winTime;
t_float *x_winRate;
long *x_gvoiceSize;
double *x_gvoiceSpeed;
double *x_gvoiceCurrent;
int *x_gvoiceDirection;
int *x_gvoiceOn;
long *x_gvoiceDone;
t_float *x_gvoiceLPan;
t_float *x_gvoiceRPan;
t_float *x_gvoiceRamp;
t_float *x_gvoiceOneOverRamp;
t_float *x_gvoiceGain;
t_stk_ADSR *x_gvoiceADSR;
int *x_gvoiceADSRon;
t_float *x_noteTransp;
t_float *x_noteSize;
t_float *x_notePan;
t_float *x_noteGain;
t_float *x_noteAttack;
t_float *x_noteDecay;
t_float *x_noteSustain;
t_float *x_noteRelease;
int *x_noteDirection;
/* nvoices x nchannels */
t_float **x_gvoiceSpat;
t_float **x_notechannelGain;
t_float **x_notechannelGainSpread;
/* Heap allocated for signal vector x nchannels */
t_float **x_out;
/* Heap allocated x nchannels */
t_float *x_outsamp;
t_float *x_channelGain;
t_float *x_channelGainSpread;
/* Oh wow, there are more... */
int x_graincounter;
int x_countsamples;
int x_voices;
t_float x_gain;
t_float x_randgain;
t_float x_twelfth;
t_float x_semitone;
short x_smoothPitch;
int x_scale_len;
t_float x_tempgrate;
long x_time;
t_float x_position;
t_float x_gimme;
int x_power;
short x_ambi;
long x_maxvoices;
short x_oneshot;
int x_newnote;
short x_doHanning;
t_float x_winTable[WINLENGTH];
t_float x_pitchTable[PITCHTABLESIZE];
t_float x_rampLength;
int x_recordOn;
long x_recordCurrent;
int x_recordRampVal; /* ramp for when toggling record on and off */
int x_rec_ramping; /* -1 ramp down, 1 ramp up, 0 not ramping */
t_symbol *x_arrayname;
int x_arraylength;
t_word *x_arrayvec; /* vec to use if we want an external buffer */
long x_l_chan; /* is there any other choice? */
int x_discretepan; /* off by default */
} t_disis_munger;
static void float_2d_alloc(t_float ***fp, int nrow, int ncol)
{
int i;
*fp = t_getbytes(nrow * sizeof(t_float*));
for (i = 0; i < nrow; i++)
(*fp)[i] = t_getbytes(ncol * sizeof(t_float));
}
static void float_2d_free(t_float ***fp, int nrow, int ncol)
{
int i;
for (i = 0; i < nrow; i++)
t_freebytes((*fp)[i], ncol * sizeof(t_float));
t_freebytes(*fp, nrow * sizeof(t_float*));
}
static t_disis_munger *munger_alloc(t_disis_munger *x)
{
/* Heap allocated based on number of voices */
int nv = x->x_numvoices, nchan = x->x_num_channels;
x->x_recordBuf = (t_float *)t_getbytes((x->x_buflen + 1) * sizeof(t_float));
/* If recordBuf didn't get allocated, let's go ahead and bail. Otherwise
we just assume all the ones below will succeed. */
if (!x->x_recordBuf)
{
error("disis_munger~ %s: out of memory", x->x_munger_name->s_name);
return 0;
}
x->x_winTime = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_winRate = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_gvoiceSize = (long *)t_getbytes(nv * sizeof(long));
x->x_gvoiceSpeed = (double *)t_getbytes(nv * sizeof(double));
x->x_gvoiceCurrent = (double *)t_getbytes(nv * sizeof(double));
x->x_gvoiceDirection = (int *)t_getbytes(nv * sizeof(int));
x->x_gvoiceOn = (int *)t_getbytes(nv * sizeof(int));
x->x_gvoiceDone = (long *)t_getbytes(nv * sizeof(long));
x->x_gvoiceLPan = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_gvoiceRPan = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_gvoiceRamp = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_gvoiceOneOverRamp = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_gvoiceGain = (t_float *)t_getbytes(nv * sizeof(t_float));
/* This is its own type */
x->x_gvoiceADSR = (t_stk_ADSR *)t_getbytes(nv * sizeof(t_stk_ADSR));
x->x_gvoiceADSRon = (int *)t_getbytes(nv * sizeof(int));
x->x_noteTransp = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteSize = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_notePan = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteGain = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteAttack = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteDecay = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteSustain = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteRelease = (t_float *)t_getbytes(nv * sizeof(t_float));
x->x_noteDirection = (int *)t_getbytes(nv * sizeof(int));
/* nvoices x nchannels */
float_2d_alloc(&x->x_gvoiceSpat, nv, nchan);
float_2d_alloc(&x->x_notechannelGain, nv, nchan);
float_2d_alloc(&x->x_notechannelGainSpread, nv, nchan);
/* Heap allocated for signal vector x nchannels */
x->x_out = (t_float **)t_getbytes(nchan * sizeof(t_float*));
/* Heap allocated x nchannels */
x->x_outsamp = (t_float *)t_getbytes(nchan * sizeof(t_float));
x->x_channelGain = (t_float *)t_getbytes(nchan * sizeof(t_float));
x->x_channelGainSpread = (t_float *)t_getbytes(nchan * sizeof(t_float));
return x;
}
static void munger_free(t_disis_munger *x)
{
/* Heap allocated based on number of voices */
int nv = x->x_numvoices, nchan = x->x_num_channels;
if (x->x_recordBuf)
t_freebytes(x->x_recordBuf, (x->x_buflen + 1) * sizeof(t_float));
if (x->x_winTime)
t_freebytes(x->x_winTime, nv * sizeof(t_float));
if (x->x_winRate)
t_freebytes(x->x_winRate, nv * sizeof(t_float));
if (x->x_gvoiceSize)
t_freebytes(x->x_gvoiceSize, nv * sizeof(long));
if (x->x_gvoiceSpeed)
t_freebytes(x->x_gvoiceSpeed, nv * sizeof(double));
if (x->x_gvoiceCurrent)
t_freebytes(x->x_gvoiceCurrent, nv * sizeof(double));
if (x->x_gvoiceDirection)
t_freebytes(x->x_gvoiceDirection, nv * sizeof(int));
if (x->x_gvoiceOn)
t_freebytes(x->x_gvoiceOn, nv * sizeof(int));
if (x->x_gvoiceDone)
t_freebytes(x->x_gvoiceDone, nv * sizeof(long));
if (x->x_gvoiceLPan)
t_freebytes(x->x_gvoiceLPan, nv * sizeof(t_float));
if (x->x_gvoiceRPan)
t_freebytes(x->x_gvoiceRPan, nv * sizeof(t_float));
if (x->x_gvoiceRamp)
t_freebytes(x->x_gvoiceRamp, nv * sizeof(t_float));
if (x->x_gvoiceOneOverRamp)
t_freebytes(x->x_gvoiceOneOverRamp, nv * sizeof(t_float));
if (x->x_gvoiceGain)
t_freebytes(x->x_gvoiceGain, nv * sizeof(t_float));
if (x->x_gvoiceADSR)
t_freebytes(x->x_gvoiceADSR, nv * sizeof(t_stk_ADSR));
if (x->x_gvoiceADSRon)
t_freebytes(x->x_gvoiceADSRon, nv * sizeof(int));
if (x->x_noteTransp)
t_freebytes(x->x_noteTransp, nv * sizeof(t_float));
if (x->x_noteSize)
t_freebytes(x->x_noteSize, nv * sizeof(t_float));
if (x->x_notePan)
t_freebytes(x->x_notePan, nv * sizeof(t_float));
if (x->x_noteGain)
t_freebytes(x->x_noteGain, nv * sizeof(t_float));
if (x->x_noteAttack)
t_freebytes(x->x_noteAttack, nv * sizeof(t_float));
if (x->x_noteDecay)
t_freebytes(x->x_noteDecay, nv * sizeof(t_float));
if (x->x_noteSustain)
t_freebytes(x->x_noteSustain, nv * sizeof(t_float));
if (x->x_noteRelease)
t_freebytes(x->x_noteRelease, nv * sizeof(t_float));
if (x->x_noteDirection)
t_freebytes(x->x_noteDirection, nv * sizeof(int));
/* nvoices x nchannels */
float_2d_free(&x->x_gvoiceSpat, nv, nchan);
float_2d_free(&x->x_notechannelGain, nv, nchan);
float_2d_free(&x->x_notechannelGainSpread, nv, nchan);
/* Heap allocated for signal vector x nchannels */
if (x->x_out)