mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-28 16:23:49 +01:00
Move library tree where it belongs
This commit is contained in:
256
lib-src/libnyquist/nyquist/tran/pluck.c
Normal file
256
lib-src/libnyquist/nyquist/tran/pluck.c
Normal file
@@ -0,0 +1,256 @@
|
||||
#include "stdio.h"
|
||||
#ifndef mips
|
||||
#include "stdlib.h"
|
||||
#endif
|
||||
#include "xlisp.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include "falloc.h"
|
||||
#include "cext.h"
|
||||
#include "pluck.h"
|
||||
|
||||
void pluck_free();
|
||||
|
||||
|
||||
typedef struct pluck_susp_struct {
|
||||
snd_susp_node susp;
|
||||
long terminate_cnt;
|
||||
|
||||
double stretch;
|
||||
double cons;
|
||||
double loss;
|
||||
long len;
|
||||
double x2;
|
||||
double x3;
|
||||
sample_type *shiftreg;
|
||||
sample_type *i1;
|
||||
sample_type *i2;
|
||||
sample_type *i3;
|
||||
sample_type *i4;
|
||||
sample_type *endptr;
|
||||
} pluck_susp_node, *pluck_susp_type;
|
||||
|
||||
|
||||
#define MAXLENGTH 20000
|
||||
|
||||
long pluck_parameters(double hz, double sr, double final, double dur,
|
||||
double *stretch, double *cons, double *rho)
|
||||
{
|
||||
double t = PI * (hz / sr);
|
||||
double y = fabs(cos(t));
|
||||
/* original m4c code used ratio of initial amp to final amp in dB
|
||||
and then converted to a ratio, e.g. you specify 60 and the
|
||||
parameter Final is 1000.0. This is counterintuitive to me (RBD)
|
||||
because I would expect the value to be -60dB or 0.001. That is
|
||||
what I implemented, so to get this back into correspondence
|
||||
with the m4c algorithm, I take the NEGATIVE log to get lf,
|
||||
whereas m4c takes the positive log:
|
||||
*/
|
||||
double lf = -log(final);
|
||||
double tdecay = -lf / (hz * log(y));
|
||||
double st;
|
||||
long len;
|
||||
double x;
|
||||
|
||||
if (hz <= sr / MAXLENGTH) {
|
||||
xlfail("pluck hz is too low");
|
||||
} else if (hz >= sr / 3) {
|
||||
xlfail("pluck hz is too high");
|
||||
}
|
||||
/*
|
||||
* if desired decay time is shorter than the natural decay time,
|
||||
* then introduce a loss factor. Otherwise, stretch note out.
|
||||
*/
|
||||
st = hz * dur;
|
||||
if (dur < tdecay) {
|
||||
*rho = exp(-lf / st) / y;
|
||||
*stretch = 0.5;
|
||||
} else {
|
||||
*rho = 1;
|
||||
*stretch = 0.5 + sqrt(0.25 -
|
||||
(1 - exp(2 * lf * (hz - sr) / (st * sr))) /
|
||||
(2 - 2 * cos(2 * t)));
|
||||
}
|
||||
|
||||
/* delay line length is */
|
||||
len = (int) ((sr / hz) - *stretch - 0.001);
|
||||
|
||||
/* tuning constant is */
|
||||
x = (sr / hz) - len - *stretch;
|
||||
*cons = (1.0 - x) / (1.0 + x);
|
||||
|
||||
if (len <= 1) {
|
||||
xlfail("internal error: pluck delay line length too short");
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static unsigned int rnext = 1;
|
||||
int krand()
|
||||
{
|
||||
rnext = rnext * 1103515245 + 12345;
|
||||
return (rnext >> 16) & 0x7fff;
|
||||
}
|
||||
|
||||
void pluck_initialize(sample_type *shiftreg, sample_type *array,
|
||||
long len, double cons)
|
||||
{
|
||||
sample_type suma = 0.0F;
|
||||
long k;
|
||||
sample_type avea;
|
||||
array[1] = 0;
|
||||
for (k = len; k > 0; k--, array--) {
|
||||
/* note: the m4c code has a bug. It claims to filter
|
||||
the initial values, but it really just sets the
|
||||
values to +1 or -1. The following does the same
|
||||
thing with much less code:
|
||||
*/
|
||||
*array = (krand() & 2) - 1;
|
||||
suma += *array; /* compute sum for the average */
|
||||
}
|
||||
avea = suma / len;
|
||||
/* zero the average */
|
||||
for (k = 0; k <= len + 1; k++) shiftreg[k] -= avea;
|
||||
shiftreg[len] = 0;
|
||||
shiftreg[len + 1] = 0;
|
||||
}
|
||||
|
||||
void pluck__fetch(register pluck_susp_type susp, snd_list_type snd_list)
|
||||
{
|
||||
int cnt = 0; /* how many samples computed */
|
||||
int togo;
|
||||
int n;
|
||||
sample_block_type out;
|
||||
register sample_block_values_type out_ptr;
|
||||
|
||||
register sample_block_values_type out_ptr_reg;
|
||||
|
||||
register double stretch_reg;
|
||||
register double cons_reg;
|
||||
register double loss_reg;
|
||||
register double x2_reg;
|
||||
register double x3_reg;
|
||||
register sample_type * i1_reg;
|
||||
register sample_type * i2_reg;
|
||||
register sample_type * i3_reg;
|
||||
register sample_type * i4_reg;
|
||||
register sample_type * endptr_reg;
|
||||
falloc_sample_block(out, "pluck__fetch");
|
||||
out_ptr = out->samples;
|
||||
snd_list->block = out;
|
||||
|
||||
while (cnt < max_sample_block_len) { /* outer loop */
|
||||
/* first compute how many samples to generate in inner loop: */
|
||||
/* don't overflow the output sample block: */
|
||||
togo = max_sample_block_len - cnt;
|
||||
|
||||
/* don't run past terminate time */
|
||||
if (susp->terminate_cnt != UNKNOWN &&
|
||||
susp->terminate_cnt <= susp->susp.current + cnt + togo) {
|
||||
togo = susp->terminate_cnt - (susp->susp.current + cnt);
|
||||
if (togo == 0) break;
|
||||
}
|
||||
|
||||
n = togo;
|
||||
stretch_reg = susp->stretch;
|
||||
cons_reg = susp->cons;
|
||||
loss_reg = susp->loss;
|
||||
x2_reg = susp->x2;
|
||||
x3_reg = susp->x3;
|
||||
i1_reg = susp->i1;
|
||||
i2_reg = susp->i2;
|
||||
i3_reg = susp->i3;
|
||||
i4_reg = susp->i4;
|
||||
endptr_reg = susp->endptr;
|
||||
out_ptr_reg = out_ptr;
|
||||
if (n) do { /* the inner sample computation loop */
|
||||
sample_type sum = (sample_type)
|
||||
((*i1_reg++ * x2_reg) + (*i2_reg++ * x3_reg) +
|
||||
(*i3_reg++ * stretch_reg) - (*i4_reg++ * cons_reg));
|
||||
/* wrap pointers around shift register if necessary */
|
||||
if (i1_reg == endptr_reg) i1_reg = susp->shiftreg;
|
||||
if (i2_reg == endptr_reg) i2_reg = susp->shiftreg;
|
||||
if (i3_reg == endptr_reg) i3_reg = susp->shiftreg;
|
||||
if (i4_reg == endptr_reg) i4_reg = susp->shiftreg;
|
||||
|
||||
/* store new value in shift register */
|
||||
*i4_reg = (sample_type) (sum * loss_reg);
|
||||
|
||||
/* deliver sample */
|
||||
*out_ptr_reg++ = sum;
|
||||
;
|
||||
} while (--n); /* inner loop */
|
||||
|
||||
susp->i1 = i1_reg;
|
||||
susp->i2 = i2_reg;
|
||||
susp->i3 = i3_reg;
|
||||
susp->i4 = i4_reg;
|
||||
out_ptr += togo;
|
||||
cnt += togo;
|
||||
} /* outer loop */
|
||||
|
||||
/* test for termination */
|
||||
if (togo == 0 && cnt == 0) {
|
||||
snd_list_terminate(snd_list);
|
||||
} else {
|
||||
snd_list->block_len = cnt;
|
||||
susp->susp.current += cnt;
|
||||
}
|
||||
} /* pluck__fetch */
|
||||
|
||||
|
||||
void pluck_free(pluck_susp_type susp)
|
||||
{
|
||||
free(susp->shiftreg);
|
||||
ffree_generic(susp, sizeof(pluck_susp_node), "pluck_free");
|
||||
}
|
||||
|
||||
|
||||
void pluck_print_tree(pluck_susp_type susp, int n)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
sound_type snd_make_pluck(rate_type sr, double hz, time_type t0, time_type d, double final_amp)
|
||||
{
|
||||
register pluck_susp_type susp;
|
||||
/* sr specified as input parameter */
|
||||
/* t0 specified as input parameter */
|
||||
sample_type scale_factor = 1.0F;
|
||||
falloc_generic(susp, pluck_susp_node, "snd_make_pluck");
|
||||
susp->stretch = 0;
|
||||
susp->cons = 0;
|
||||
susp->loss = 0;
|
||||
susp->len = pluck_parameters(hz, sr, final_amp, d,
|
||||
&susp->stretch, &susp->cons,
|
||||
&susp->loss);
|
||||
susp->x2 = -susp->cons * (susp->stretch - 1);
|
||||
susp->x3 = susp->cons * susp->stretch - susp->stretch + 1;
|
||||
susp->shiftreg = (sample_type *) calloc (susp->len + 4, sizeof(sample_type));
|
||||
susp->i1 = susp->shiftreg + susp->len + 1;
|
||||
susp->i2 = susp->shiftreg + susp->len;
|
||||
susp->i3 = susp->shiftreg + susp->len - 1;
|
||||
susp->i4 = susp->shiftreg + susp->len - 2;
|
||||
susp->endptr = susp->shiftreg + susp->len + 2;
|
||||
pluck_initialize(susp->shiftreg, susp->i3,
|
||||
susp->len, susp->cons);
|
||||
susp->susp.fetch = pluck__fetch;
|
||||
|
||||
susp->terminate_cnt = round((d) * sr);
|
||||
/* initialize susp state */
|
||||
susp->susp.free = pluck_free;
|
||||
susp->susp.sr = sr;
|
||||
susp->susp.t0 = t0;
|
||||
susp->susp.mark = NULL;
|
||||
susp->susp.print_tree = pluck_print_tree;
|
||||
susp->susp.name = "pluck";
|
||||
susp->susp.log_stop_cnt = UNKNOWN;
|
||||
susp->susp.current = 0;
|
||||
return sound_create((snd_susp_type)susp, t0, sr, scale_factor);
|
||||
}
|
||||
|
||||
|
||||
sound_type snd_pluck(rate_type sr, double hz, time_type t0, time_type d, double final_amp)
|
||||
{
|
||||
return snd_make_pluck(sr, hz, t0, d, final_amp);
|
||||
}
|
||||
Reference in New Issue
Block a user