|
- /* CLM (Music V) implementation */
-
- #include "mus-config.h"
-
- #if USE_SND
- #include "snd.h"
- #endif
-
- #include <stddef.h>
- #include <math.h>
- #include <stdio.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
-
- #ifndef _MSC_VER
- #include <unistd.h>
- #else
- #include <io.h>
- #pragma warning(disable: 4244)
- #endif
-
- #include "_sndlib.h"
- #include "clm.h"
- #include "clm-strings.h"
-
- #if HAVE_GSL
- #include <gsl/gsl_complex.h>
- #include <gsl/gsl_complex_math.h>
- #endif
-
- #if HAVE_FFTW3
- #include <fftw3.h>
- #endif
-
- #if HAVE_COMPLEX_TRIG
- #include <complex.h>
- #endif
-
- #if (!DISABLE_SINCOS) && defined(__GNUC__) && defined(__linux__)
- #define HAVE_SINCOS 1
- void sincos(double x, double *sin, double *cos);
- #else
- #define HAVE_SINCOS 0
- #endif
-
- #ifndef TWO_PI
- #define TWO_PI (2.0 * M_PI)
- #endif
-
- struct mus_any_class {
- int type;
- char *name;
- void (*release)(mus_any *ptr);
- char *(*describe)(mus_any *ptr); /* caller should free the string */
- bool (*equalp)(mus_any *gen1, mus_any *gen2);
- mus_float_t *(*data)(mus_any *ptr);
- mus_float_t *(*set_data)(mus_any *ptr, mus_float_t *new_data);
- mus_long_t (*length)(mus_any *ptr);
- mus_long_t (*set_length)(mus_any *ptr, mus_long_t new_length);
- mus_float_t (*frequency)(mus_any *ptr);
- mus_float_t (*set_frequency)(mus_any *ptr, mus_float_t new_freq);
- mus_float_t (*phase)(mus_any *ptr);
- mus_float_t (*set_phase)(mus_any *ptr, mus_float_t new_phase);
- mus_float_t (*scaler)(mus_any *ptr);
- mus_float_t (*set_scaler)(mus_any *ptr, mus_float_t val);
- mus_float_t (*increment)(mus_any *ptr);
- mus_float_t (*set_increment)(mus_any *ptr, mus_float_t val);
- mus_float_t (*run)(mus_any *gen, mus_float_t arg1, mus_float_t arg2);
- mus_clm_extended_t extended_type;
- void *(*closure)(mus_any *gen);
- int (*channels)(mus_any *ptr);
- mus_float_t (*offset)(mus_any *ptr);
- mus_float_t (*set_offset)(mus_any *ptr, mus_float_t val);
- mus_float_t (*width)(mus_any *ptr);
- mus_float_t (*set_width)(mus_any *ptr, mus_float_t val);
- mus_float_t (*xcoeff)(mus_any *ptr, int index);
- mus_float_t (*set_xcoeff)(mus_any *ptr, int index, mus_float_t val);
- mus_long_t (*hop)(mus_any *ptr);
- mus_long_t (*set_hop)(mus_any *ptr, mus_long_t new_length);
- mus_long_t (*ramp)(mus_any *ptr);
- mus_long_t (*set_ramp)(mus_any *ptr, mus_long_t new_length);
- mus_float_t (*read_sample)(mus_any *ptr, mus_long_t samp, int chan);
- mus_float_t (*write_sample)(mus_any *ptr, mus_long_t samp, int chan, mus_float_t data);
- char *(*file_name)(mus_any *ptr);
- int (*end)(mus_any *ptr);
- mus_long_t (*location)(mus_any *ptr);
- mus_long_t (*set_location)(mus_any *ptr, mus_long_t loc);
- int (*channel)(mus_any *ptr);
- mus_float_t (*ycoeff)(mus_any *ptr, int index);
- mus_float_t (*set_ycoeff)(mus_any *ptr, int index, mus_float_t val);
- mus_float_t *(*xcoeffs)(mus_any *ptr);
- mus_float_t *(*ycoeffs)(mus_any *ptr);
- void (*reset)(mus_any *ptr);
- void *(*set_closure)(mus_any *gen, void *e);
- mus_any *(*copy)(mus_any *ptr);
- };
-
-
- enum {MUS_OSCIL, MUS_NCOS, MUS_DELAY, MUS_COMB, MUS_NOTCH, MUS_ALL_PASS,
- MUS_TABLE_LOOKUP, MUS_SQUARE_WAVE, MUS_SAWTOOTH_WAVE, MUS_TRIANGLE_WAVE, MUS_PULSE_TRAIN,
- MUS_RAND, MUS_RAND_INTERP, MUS_ASYMMETRIC_FM, MUS_ONE_ZERO, MUS_ONE_POLE, MUS_TWO_ZERO, MUS_TWO_POLE, MUS_FORMANT,
- MUS_SRC, MUS_GRANULATE, MUS_WAVE_TRAIN,
- MUS_FILTER, MUS_FIR_FILTER, MUS_IIR_FILTER, MUS_CONVOLVE, MUS_ENV, MUS_LOCSIG,
- MUS_READIN, MUS_FILE_TO_SAMPLE, MUS_FILE_TO_FRAMPLE,
- MUS_SAMPLE_TO_FILE, MUS_FRAMPLE_TO_FILE, MUS_PHASE_VOCODER,
- MUS_MOVING_AVERAGE, MUS_MOVING_MAX, MUS_MOVING_NORM, MUS_NSIN, MUS_SSB_AM, MUS_POLYSHAPE, MUS_FILTERED_COMB,
- MUS_MOVE_SOUND, MUS_NRXYSIN, MUS_NRXYCOS, MUS_POLYWAVE, MUS_FIRMANT, MUS_FORMANT_BANK,
- MUS_ONE_POLE_ALL_PASS, MUS_COMB_BANK, MUS_ALL_PASS_BANK, MUS_FILTERED_COMB_BANK, MUS_OSCIL_BANK,
- MUS_PULSED_ENV, MUS_RXYKSIN, MUS_RXYKCOS,
- MUS_INITIAL_GEN_TAG};
-
- mus_any_class *mus_generator_class(mus_any *ptr) {return(ptr->core);}
-
- void mus_generator_set_extended_type(mus_any_class *p, mus_clm_extended_t extended_type) {p->extended_type = extended_type;}
- void mus_generator_set_length(mus_any_class *p, mus_long_t (*length)(mus_any *ptr)) {p->length = length;}
- void mus_generator_set_scaler(mus_any_class *p, mus_float_t (*scaler)(mus_any *ptr)) {p->scaler = scaler;}
- void mus_generator_set_channels(mus_any_class *p, int (*channels)(mus_any *ptr)) {p->channels = channels;}
- void mus_generator_set_location(mus_any_class *p, mus_long_t (*location)(mus_any *ptr)) {p->location = location;}
- void mus_generator_set_set_location(mus_any_class *p, mus_long_t (*set_location)(mus_any *ptr, mus_long_t loc)) {p->set_location = set_location;}
- void mus_generator_set_read_sample(mus_any_class *p, mus_float_t (*read_sample)(mus_any *ptr, mus_long_t samp, int chan)) {p->read_sample = read_sample;}
- void mus_generator_set_channel(mus_any_class *p, int (*channel)(mus_any *ptr)) {p->channel = channel;}
- void mus_generator_set_file_name(mus_any_class *p, char *(*file_name)(mus_any *ptr)) {p->file_name = file_name;}
-
- mus_any_class *mus_make_generator(int type, char *name,
- void (*release)(mus_any *ptr),
- char *(*describe)(mus_any *ptr),
- bool (*equalp)(mus_any *gen1, mus_any *gen2))
- {
- mus_any_class *p;
- p = (mus_any_class *)calloc(1, sizeof(mus_any_class));
- p->type = type;
- p->name = name;
- p->release = release;
- p->describe = describe;
- p->equalp = equalp;
- return(p);
- }
-
-
- static int mus_generator_type = MUS_INITIAL_GEN_TAG;
-
- int mus_make_generator_type(void) {return(mus_generator_type++);}
-
-
- static const char *interp_name[] = {"step", "linear", "sinusoidal", "all-pass", "lagrange", "bezier", "hermite"};
-
- static const char *interp_type_to_string(int type)
- {
- if (mus_is_interp_type(type))
- return(interp_name[type]);
- return("unknown");
- }
-
-
- static mus_float_t sampling_rate = MUS_DEFAULT_SAMPLING_RATE;
-
- static mus_float_t w_rate = (TWO_PI / MUS_DEFAULT_SAMPLING_RATE);
-
-
- static mus_float_t float_equal_fudge_factor = 0.0000001;
-
- mus_float_t mus_float_equal_fudge_factor(void) {return(float_equal_fudge_factor);}
-
- mus_float_t mus_set_float_equal_fudge_factor(mus_float_t val)
- {
- mus_float_t prev;
- prev = float_equal_fudge_factor;
- float_equal_fudge_factor = val;
- return(prev);
- }
-
-
- static int array_print_length = MUS_DEFAULT_ARRAY_PRINT_LENGTH;
-
- int mus_array_print_length(void) {return(array_print_length);}
-
- int mus_set_array_print_length(int val)
- {
- int prev;
- prev = array_print_length;
- if (val >= 0) array_print_length = val;
- return(prev);
- }
-
-
- static mus_long_t clm_file_buffer_size = MUS_DEFAULT_FILE_BUFFER_SIZE;
-
- mus_long_t mus_file_buffer_size(void) {return(clm_file_buffer_size);}
-
- mus_long_t mus_set_file_buffer_size(mus_long_t size)
- {
- /* this is set in with-sound, among other places */
- mus_long_t prev;
- prev = clm_file_buffer_size;
- clm_file_buffer_size = size;
- return(prev);
- }
-
-
- mus_float_t mus_radians_to_hz(mus_float_t rads) {return(rads / w_rate);}
- mus_float_t mus_hz_to_radians(mus_float_t hz) {return(hz * w_rate);}
-
-
- mus_float_t mus_degrees_to_radians(mus_float_t degree) {return(degree * TWO_PI / 360.0);}
- mus_float_t mus_radians_to_degrees(mus_float_t rads) {return(rads * 360.0 / TWO_PI);}
-
-
- mus_float_t mus_db_to_linear(mus_float_t x) {return(pow(10.0, x / 20.0));}
- mus_float_t mus_linear_to_db(mus_float_t x) {if (x > 0.0) return(20.0 * log10(x)); return(-100.0);}
-
-
- mus_float_t mus_odd_multiple(mus_float_t x, mus_float_t y) {mus_long_t f; f = (mus_long_t)floor(x); return(y * ((f & 1) ? f : (f + 1)));}
- mus_float_t mus_even_multiple(mus_float_t x, mus_float_t y) {mus_long_t f; f = (mus_long_t)floor(x); return(y * ((f & 1) ? (f + 1) : f));}
- mus_float_t mus_odd_weight(mus_float_t x) {mus_long_t f; f = (mus_long_t)floor(x); return(1.0 - fabs(x - ((f & 1) ? f : (f + 1))));}
- mus_float_t mus_even_weight(mus_float_t x) {mus_long_t f; f = (mus_long_t)floor(x); return(1.0 - fabs(x - ((f & 1) ? (f + 1) : f)));}
-
- mus_float_t mus_srate(void) {return(sampling_rate);}
-
- mus_float_t mus_set_srate(mus_float_t val)
- {
- mus_float_t prev;
- prev = sampling_rate;
- if (val > 0.0)
- {
- sampling_rate = val;
- w_rate = (TWO_PI / sampling_rate);
- }
- return(prev);
- }
-
-
- mus_long_t mus_seconds_to_samples(mus_float_t secs) {return((mus_long_t)(secs * sampling_rate));}
- mus_float_t mus_samples_to_seconds(mus_long_t samps) {return((mus_float_t)((mus_float_t)samps / (mus_float_t)sampling_rate));}
-
-
- #define DESCRIBE_BUFFER_SIZE 2048
- #define STR_SIZE 128
-
-
- static char *float_array_to_string(mus_float_t *arr, int len, int loc)
- {
- /* %g is needed here rather than %f -- otherwise the number strings can be any size */
- #define MAX_NUM_SIZE 64
- char *base, *str;
- int i, lim, size = 512;
- if (arr == NULL)
- {
- str = (char *)malloc(4 * sizeof(char));
- snprintf(str, 4, "nil");
- return(str);
- }
- lim = (array_print_length + 4) * MAX_NUM_SIZE; /* 4 for possible bounds below */
- if (lim > size) size = lim;
- if (loc < 0) loc = 0;
-
- base = (char *)calloc(size, sizeof(char));
- str = (char *)malloc(STR_SIZE * sizeof(char));
-
- if (len > 0)
- {
- int k;
- snprintf(base, size, "[");
- lim = len;
- if (lim > array_print_length) lim = array_print_length;
- k = loc;
- if (k >= len) k = 0;
- for (i = 0; i < lim - 1; i++)
- {
- snprintf(str, STR_SIZE, "%.3g ", arr[k]);
- strcat(base, str);
- if ((int)(strlen(base) + MAX_NUM_SIZE) > size)
- {
- base = (char *)realloc(base, size * 2 * sizeof(char));
- base[size] = 0;
- size *= 2;
- }
- k++;
- if (k >= len) k = 0;
- }
- snprintf(str, STR_SIZE, "%.3g%s", arr[k], (len > lim) ? "..." : "]");
- strcat(base, str);
- }
- else snprintf(base, size, "[]");
- if (len > lim)
- {
- /* print ranges */
- int min_loc = 0, max_loc = 0;
- mus_float_t min_val, max_val;
- min_val = arr[0];
- max_val = arr[0];
- for (i = 1; i < len; i++)
- {
- if (arr[i] < min_val) {min_val = arr[i]; min_loc = i;}
- if (arr[i] > max_val) {max_val = arr[i]; max_loc = i;}
- }
- snprintf(str, STR_SIZE, "(%d: %.3g, %d: %.3g)]", min_loc, min_val, max_loc, max_val);
- strcat(base, str);
- }
- free(str);
- return(base);
- }
-
-
- static char *clm_array_to_string(mus_any **gens, int num_gens, const char *name, const char *indent)
- {
- char *descr = NULL;
- if ((gens) && (num_gens > 0))
- {
- int i, len = 0;
- char **descrs;
- descrs = (char **)calloc(num_gens, sizeof(char *));
- for (i = 0; i < num_gens; i++)
- {
- if (gens[i])
- {
- char *str = NULL;
- descrs[i] = mus_format("\n%s[%d]: %s", indent, i, str = mus_describe(gens[i]));
- if (str) free(str);
- }
- else descrs[i] = mus_format("\n%s[%d]: nil", indent, i);
- len += strlen(descrs[i]);
- }
- len += (64 + strlen(name));
- descr = (char *)malloc(len * sizeof(char));
- snprintf(descr, len, "%s[%d]:", name, num_gens);
- for (i = 0; i < num_gens; i++)
- {
- strcat(descr, descrs[i]);
- free(descrs[i]);
- }
- free(descrs);
- }
- else
- {
- descr = (char *)malloc(128 * sizeof(char));
- snprintf(descr, 128, "%s: nil", name);
- }
- return(descr);
- }
-
-
- static char *int_array_to_string(int *arr, int num_ints, const char *name)
- {
- #define MAX_INT_SIZE 32
- char *descr = NULL;
- if ((arr) && (num_ints > 0))
- {
- int i, len;
- char *intstr;
- len = num_ints * MAX_INT_SIZE + 64;
- descr = (char *)calloc(len, sizeof(char));
- intstr = (char *)malloc(MAX_INT_SIZE * sizeof(char));
- snprintf(descr, len, "%s[%d]: (", name, num_ints);
- for (i = 0; i < num_ints - 1; i++)
- {
- snprintf(intstr, MAX_INT_SIZE, "%d ", arr[i]);
- strcat(descr, intstr);
- }
- snprintf(intstr, MAX_INT_SIZE, "%d)", arr[num_ints - 1]);
- strcat(descr, intstr);
- free(intstr);
- }
- else
- {
- descr = (char *)malloc(128 * sizeof(char));
- snprintf(descr, 128, "%s: nil", name);
- }
- return(descr);
- }
-
-
- /* ---------------- generic functions ---------------- */
-
- #define check_gen(Ptr, Name) ((Ptr) ? true : (!mus_error(MUS_NO_GEN, "null generator passed to %s", Name)))
-
- int mus_type(mus_any *ptr)
- {
- return(((check_gen(ptr, S_mus_type)) && (ptr->core)) ? ptr->core->type : -1);
- }
-
-
- const char *mus_name(mus_any *ptr)
- {
- return((ptr == NULL) ? "null" : ptr->core->name);
- }
-
-
- void mus_free(mus_any *gen)
- {
- if (gen)
- (*(gen->core->release))(gen);
- }
-
-
- char *mus_describe(mus_any *gen)
- {
- if (gen == NULL)
- return(mus_strdup((char *)"null"));
- if ((gen->core) && (gen->core->describe))
- return((*(gen->core->describe))(gen));
- else mus_error(MUS_NO_DESCRIBE, "can't describe %s", mus_name(gen));
- return(NULL);
- }
-
-
- bool mus_equalp(mus_any *p1, mus_any *p2)
- {
- if ((p1) && (p2))
- {
- if ((p1->core)->equalp)
- return((*((p1->core)->equalp))(p1, p2));
- else return(p1 == p2);
- }
- return(true); /* (eq nil nil) */
- }
-
-
- void mus_reset(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_reset)) &&
- (gen->core->reset))
- (*(gen->core->reset))(gen);
- else mus_error(MUS_NO_RESET, "can't reset %s", mus_name(gen));
- }
-
-
- mus_any *mus_copy(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_copy)) &&
- (gen->core->copy))
- return((*(gen->core->copy))(gen));
- else mus_error(MUS_NO_COPY, "can't copy %s", mus_name(gen));
- return(NULL);
- }
-
-
- mus_float_t mus_frequency(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_frequency)) &&
- (gen->core->frequency))
- return((*(gen->core->frequency))(gen));
- return((mus_float_t)mus_error(MUS_NO_FREQUENCY, "can't get %s's frequency", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_frequency(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_frequency)) &&
- (gen->core->set_frequency))
- return((*(gen->core->set_frequency))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_FREQUENCY, "can't set %s's frequency", mus_name(gen)));
- }
-
-
- mus_float_t mus_phase(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_phase)) &&
- (gen->core->phase))
- return((*(gen->core->phase))(gen));
- return((mus_float_t)mus_error(MUS_NO_PHASE, "can't get %s's phase", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_phase(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_phase)) &&
- (gen->core->set_phase))
- return((*(gen->core->set_phase))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_PHASE, "can't set %s's phase", mus_name(gen)));
- }
-
-
-
- mus_float_t mus_scaler(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_scaler)) &&
- (gen->core->scaler))
- return((*(gen->core->scaler))(gen));
- return((mus_float_t)mus_error(MUS_NO_SCALER, "can't get %s's scaler", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_scaler(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_scaler)) &&
- (gen->core->set_scaler))
- return((*(gen->core->set_scaler))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_SCALER, "can't set %s's scaler", mus_name(gen)));
- }
-
-
- mus_float_t mus_feedforward(mus_any *gen) /* shares "scaler" */
- {
- if ((check_gen(gen, S_mus_feedforward)) &&
- (gen->core->scaler))
- return((*(gen->core->scaler))(gen));
- return((mus_float_t)mus_error(MUS_NO_FEEDFORWARD, "can't get %s's feedforward", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_feedforward(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_feedforward)) &&
- (gen->core->set_scaler))
- return((*(gen->core->set_scaler))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_FEEDFORWARD, "can't set %s's feedforward", mus_name(gen)));
- }
-
-
- mus_float_t mus_offset(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_offset)) &&
- (gen->core->offset))
- return((*(gen->core->offset))(gen));
- return((mus_float_t)mus_error(MUS_NO_OFFSET, "can't get %s's offset", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_offset(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_offset)) &&
- (gen->core->set_offset))
- return((*(gen->core->set_offset))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_OFFSET, "can't set %s's offset", mus_name(gen)));
- }
-
-
- mus_float_t mus_width(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_width)) &&
- (gen->core->width))
- return((*(gen->core->width))(gen));
- return((mus_float_t)mus_error(MUS_NO_WIDTH, "can't get %s's width", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_width(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_width)) &&
- (gen->core->set_width))
- return((*(gen->core->set_width))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_WIDTH, "can't set %s's width", mus_name(gen)));
- }
-
-
- mus_float_t mus_increment(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_increment)) &&
- (gen->core->increment))
- return((*(gen->core->increment))(gen));
- return((mus_float_t)mus_error(MUS_NO_INCREMENT, "can't get %s's increment", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_increment(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_increment)) &&
- (gen->core->set_increment))
- return((*(gen->core->set_increment))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_INCREMENT, "can't set %s's increment", mus_name(gen)));
- }
-
-
- mus_float_t mus_feedback(mus_any *gen) /* shares "increment" */
- {
- if ((check_gen(gen, S_mus_feedback)) &&
- (gen->core->increment))
- return((*(gen->core->increment))(gen));
- return((mus_float_t)mus_error(MUS_NO_FEEDBACK, "can't get %s's feedback", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_feedback(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_feedback)) &&
- (gen->core->set_increment))
- return((*(gen->core->set_increment))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_FEEDBACK, "can't set %s's feedback", mus_name(gen)));
- }
-
-
- void *mus_environ(mus_any *gen)
- {
- if (check_gen(gen, "mus-environ"))
- return((*(gen->core->closure))(gen));
- return(NULL);
- }
-
-
- void *mus_set_environ(mus_any *gen, void *e)
- {
- if (check_gen(gen, S_set "mus-environ"))
- return((*(gen->core->set_closure))(gen, e));
- return(NULL);
- }
-
-
- mus_float_t mus_run(mus_any *gen, mus_float_t arg1, mus_float_t arg2)
- {
- if ((check_gen(gen, "mus-run")) &&
- (gen->core->run))
- return((*(gen->core->run))(gen, arg1, arg2));
- return((mus_float_t)mus_error(MUS_NO_RUN, "can't run %s", mus_name(gen)));
- }
-
-
- mus_long_t mus_length(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_length)) &&
- (gen->core->length))
- return((*(gen->core->length))(gen));
- return(mus_error(MUS_NO_LENGTH, "can't get %s's length", mus_name(gen)));
- }
-
-
- mus_long_t mus_set_length(mus_any *gen, mus_long_t len)
- {
- if ((check_gen(gen, S_set S_mus_length)) &&
- (gen->core->set_length))
- return((*(gen->core->set_length))(gen, len));
- return(mus_error(MUS_NO_LENGTH, "can't set %s's length", mus_name(gen)));
- }
-
-
- mus_long_t mus_order(mus_any *gen) /* shares "length", no set */
- {
- if ((check_gen(gen, S_mus_order)) &&
- (gen->core->length))
- return((*(gen->core->length))(gen));
- return(mus_error(MUS_NO_ORDER, "can't get %s's order", mus_name(gen)));
- }
-
-
- int mus_channels(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_channels)) &&
- (gen->core->channels))
- return((*(gen->core->channels))(gen));
- return(mus_error(MUS_NO_CHANNELS, "can't get %s's channels", mus_name(gen)));
- }
-
-
- int mus_interp_type(mus_any *gen) /* shares "channels", no set */
- {
- if ((check_gen(gen, S_mus_interp_type)) &&
- (gen->core->channels))
- return((*(gen->core->channels))(gen));
- return(mus_error(MUS_NO_INTERP_TYPE, "can't get %s's interp type", mus_name(gen)));
- }
-
-
- int mus_position(mus_any *gen) /* shares "channels", no set, only used in C (snd-env.c) */
- {
- if ((check_gen(gen, "mus-position")) &&
- (gen->core->channels))
- return((*(gen->core->channels))(gen));
- return(mus_error(MUS_NO_POSITION, "can't get %s's position", mus_name(gen)));
- }
-
-
- int mus_channel(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_channel)) &&
- (gen->core->channel))
- return(((*gen->core->channel))(gen));
- return(mus_error(MUS_NO_CHANNEL, "can't get %s's channel", mus_name(gen)));
- }
-
-
- mus_long_t mus_hop(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_hop)) &&
- (gen->core->hop))
- return((*(gen->core->hop))(gen));
- return(mus_error(MUS_NO_HOP, "can't get %s's hop value", mus_name(gen)));
- }
-
-
- mus_long_t mus_set_hop(mus_any *gen, mus_long_t len)
- {
- if ((check_gen(gen, S_set S_mus_hop)) &&
- (gen->core->set_hop))
- return((*(gen->core->set_hop))(gen, len));
- return(mus_error(MUS_NO_HOP, "can't set %s's hop value", mus_name(gen)));
- }
-
-
- mus_long_t mus_ramp(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_ramp)) &&
- (gen->core->ramp))
- return((*(gen->core->ramp))(gen));
- return(mus_error(MUS_NO_RAMP, "can't get %s's ramp value", mus_name(gen)));
- }
-
-
- mus_long_t mus_set_ramp(mus_any *gen, mus_long_t len)
- {
- if ((check_gen(gen, S_set S_mus_ramp)) &&
- (gen->core->set_ramp))
- return((*(gen->core->set_ramp))(gen, len));
- return(mus_error(MUS_NO_RAMP, "can't set %s's ramp value", mus_name(gen)));
- }
-
-
- mus_float_t *mus_data(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_data)) &&
- (gen->core->data))
- return((*(gen->core->data))(gen));
- mus_error(MUS_NO_DATA, "can't get %s's data", mus_name(gen));
- return(NULL);
- }
-
-
- /* every case that implements the data or set data functions needs to include
- * a var-allocated flag, since all such memory has to be handled via vcts
- */
-
- mus_float_t *mus_set_data(mus_any *gen, mus_float_t *new_data)
- {
- if (check_gen(gen, S_set S_mus_data))
- {
- if (gen->core->set_data)
- {
- (*(gen->core->set_data))(gen, new_data);
- return(new_data);
- }
- else mus_error(MUS_NO_DATA, "can't set %s's data", mus_name(gen));
- }
- return(new_data);
- }
-
-
- mus_float_t *mus_xcoeffs(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_xcoeffs)) &&
- (gen->core->xcoeffs))
- return((*(gen->core->xcoeffs))(gen));
- mus_error(MUS_NO_XCOEFFS, "can't get %s's xcoeffs", mus_name(gen));
- return(NULL);
- }
-
-
- mus_float_t *mus_ycoeffs(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_ycoeffs)) &&
- (gen->core->ycoeffs))
- return((*(gen->core->ycoeffs))(gen));
- mus_error(MUS_NO_YCOEFFS, "can't get %s's ycoeffs", mus_name(gen));
- return(NULL);
- }
-
-
- mus_float_t mus_xcoeff(mus_any *gen, int index)
- {
- if ((check_gen(gen, S_mus_xcoeff)) &&
- (gen->core->xcoeff))
- return((*(gen->core->xcoeff))(gen, index));
- return(mus_error(MUS_NO_XCOEFF, "can't get %s's xcoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_float_t mus_set_xcoeff(mus_any *gen, int index, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_xcoeff)) &&
- (gen->core->set_xcoeff))
- return((*(gen->core->set_xcoeff))(gen, index, val));
- return(mus_error(MUS_NO_XCOEFF, "can't set %s's xcoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_float_t mus_ycoeff(mus_any *gen, int index)
- {
- if ((check_gen(gen, S_mus_ycoeff)) &&
- (gen->core->ycoeff))
- return((*(gen->core->ycoeff))(gen, index));
- return(mus_error(MUS_NO_YCOEFF, "can't get %s's ycoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_float_t mus_set_ycoeff(mus_any *gen, int index, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_ycoeff)) &&
- (gen->core->set_ycoeff))
- return((*(gen->core->set_ycoeff))(gen, index, val));
- return(mus_error(MUS_NO_YCOEFF, "can't set %s's ycoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_long_t mus_location(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_location)) &&
- (gen->core->location))
- return(((*gen->core->location))(gen));
- return((mus_long_t)mus_error(MUS_NO_LOCATION, "can't get %s's location", mus_name(gen)));
- }
-
-
- /* ---------------- AM etc ---------------- */
-
- mus_float_t mus_ring_modulate(mus_float_t sig1, mus_float_t sig2)
- {
- return(sig1 * sig2);
- }
-
-
- mus_float_t mus_amplitude_modulate(mus_float_t carrier, mus_float_t sig1, mus_float_t sig2)
- {
- return(sig1 * (carrier + sig2));
- }
-
-
- mus_float_t mus_contrast_enhancement(mus_float_t sig, mus_float_t index)
- {
- return(sin((sig * M_PI_2) + (index * sin(sig * TWO_PI))));
- }
-
-
- bool mus_arrays_are_equal(mus_float_t *arr1, mus_float_t *arr2, mus_float_t fudge, mus_long_t len)
- {
- mus_long_t i;
- if (fudge == 0.0)
- {
- for (i = 0; i < len; i++)
- if (arr1[i] != arr2[i])
- return(false);
- }
- else
- {
- mus_long_t len4;
- len4 = len - 4;
- i = 0;
- while (i <= len4)
- {
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- }
- for (; i < len; i++)
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- }
- return(true);
- }
-
-
- static bool clm_arrays_are_equal(mus_float_t *arr1, mus_float_t *arr2, mus_long_t len)
- {
- return(mus_arrays_are_equal(arr1, arr2, float_equal_fudge_factor, len));
- }
-
-
- mus_float_t mus_dot_product(mus_float_t *data1, mus_float_t *data2, mus_long_t size)
- {
- mus_long_t i, size4;
- mus_float_t sum = 0.0;
- size4 = size - 4;
- i = 0;
- while (i <= size4)
- {
- sum += (data1[i] * data2[i]);
- i++;
- sum += (data1[i] * data2[i]);
- i++;
- sum += (data1[i] * data2[i]);
- i++;
- sum += (data1[i] * data2[i]);
- i++;
- }
- for (; i < size; i++)
- sum += (data1[i] * data2[i]);
- return(sum);
- }
-
-
- #if HAVE_COMPLEX_TRIG
- #if HAVE_FORTH
- #include "xen.h"
- #endif
-
- complex double mus_edot_product(complex double freq, complex double *data, mus_long_t size)
- {
- int i;
- complex double sum = 0.0;
- for (i = 0; i < size; i++)
- sum += (cexp(i * freq) * data[i]);
- return(sum);
- }
- #endif
-
-
- mus_float_t mus_polynomial(mus_float_t *coeffs, mus_float_t x, int ncoeffs)
- {
- mus_float_t sum;
- int i;
- if (ncoeffs <= 0) return(0.0);
- if (ncoeffs == 1) return(coeffs[0]); /* just a constant term */
- sum = coeffs[ncoeffs - 1];
- /* unrolled is slower */
- for (i = ncoeffs - 2; i >= 0; i--)
- sum = (sum * x) + coeffs[i];
- return((mus_float_t)sum);
- }
-
- void mus_rectangular_to_polar(mus_float_t *rl, mus_float_t *im, mus_long_t size)
- {
- mus_long_t i;
- for (i = 0; i < size; i++)
- {
- mus_float_t temp; /* apparently floating underflows (denormals?) in sqrt are bringing us to a halt */
- temp = rl[i] * rl[i] + im[i] * im[i];
- if (temp < .00000001)
- {
- rl[i] = 0.0;
- im[i] = 0.0;
- }
- else
- {
- im[i] = -atan2(im[i], rl[i]); /* "-" here so that clockwise is positive? is this backwards? */
- rl[i] = sqrt(temp);
- }
- }
- }
-
-
- void mus_rectangular_to_magnitudes(mus_float_t *rl, mus_float_t *im, mus_long_t size)
- {
- mus_long_t i;
- for (i = 0; i < size; i++)
- {
- mus_float_t temp; /* apparently floating underflows in sqrt are bringing us to a halt */
- temp = rl[i] * rl[i] + im[i] * im[i];
- if (temp < .00000001)
- rl[i] = 0.0;
- else rl[i] = sqrt(temp);
- }
- }
-
-
- void mus_polar_to_rectangular(mus_float_t *rl, mus_float_t *im, mus_long_t size)
- {
- mus_long_t i;
- for (i = 0; i < size; i++)
- {
- #if HAVE_SINCOS
- double sx, cx;
- sincos(-im[i], &sx, &cx);
- im[i] = sx * rl[i];
- rl[i] *= cx;
- #else
- mus_float_t temp;
- temp = rl[i] * sin(-im[i]); /* minus to match sense of rectangular->polar above */
- rl[i] *= cos(-im[i]);
- im[i] = temp;
- #endif
- }
- }
-
-
- static mus_float_t *array_normalize(mus_float_t *table, mus_long_t table_size)
- {
- mus_float_t amp = 0.0;
- mus_long_t i;
-
- for (i = 0; i < table_size; i++)
- if (amp < (fabs(table[i])))
- amp = fabs(table[i]);
-
- if ((amp > 0.0) &&
- (amp != 1.0))
- for (i = 0; i < table_size; i++)
- table[i] /= amp;
-
- return(table);
- }
-
-
- /* ---------------- interpolation ---------------- */
-
- mus_float_t mus_array_interp(mus_float_t *wave, mus_float_t phase, mus_long_t size)
- {
- /* changed 26-Sep-00 to be closer to mus.lisp */
- mus_long_t int_part;
- mus_float_t frac_part;
- if ((phase < 0.0) || (phase > size))
- {
- /* 28-Mar-01 changed to fmod; I was hoping to avoid this... */
- phase = fmod((mus_float_t)phase, (mus_float_t)size);
- if (phase < 0.0) phase += size;
- }
-
- int_part = (mus_long_t)phase; /* (mus_long_t)floor(phase); */
- frac_part = phase - int_part;
- if (int_part == size) int_part = 0;
-
- if (frac_part == 0.0)
- return(wave[int_part]);
- else
- {
- mus_long_t inx;
- inx = int_part + 1;
- if (inx >= size) inx = 0;
- return(wave[int_part] + (frac_part * (wave[inx] - wave[int_part])));
- }
- }
-
-
- static mus_float_t mus_array_all_pass_interp(mus_float_t *wave, mus_float_t phase, mus_long_t size, mus_float_t yn1)
- {
- /* this is intended for delay lines where you have a stream of values; in table-lookup it can be a mess */
- mus_long_t int_part, inx;
- mus_float_t frac_part;
- if ((phase < 0.0) || (phase > size))
- {
- phase = fmod((mus_float_t)phase, (mus_float_t)size);
- if (phase < 0.0) phase += size;
- }
- int_part = (mus_long_t)floor(phase);
- frac_part = phase - int_part;
- if (int_part == size) int_part = 0;
- inx = int_part + 1;
- if (inx >= size) inx -= size;
- #if 1
- /* from DAFX */
- if (frac_part == 0.0)
- return(wave[inx] - yn1);
- return(wave[int_part] * frac_part + (1.0 - frac_part) * (wave[inx] - yn1));
- #else
- /* from Perry Cook */
- if (frac_part == 0.0)
- return(wave[int_part] + wave[inx] - yn1);
- else return(wave[int_part] + ((1.0 - frac_part) / (1 + frac_part)) * (wave[inx] - yn1));
- #endif
- }
-
-
- static mus_float_t mus_array_lagrange_interp(mus_float_t *wave, mus_float_t x, mus_long_t size)
- {
- /* Abramovitz and Stegun 25.2.11 -- everyone badmouths this poor formula */
- /* x assumed to be in the middle, between second and third vals */
- mus_long_t x0, xp1, xm1;
- mus_float_t p, pp;
- if ((x < 0.0) || (x > size))
- {
- x = fmod((mus_float_t)x, (mus_float_t)size);
- if (x < 0.0) x += size;
- }
- x0 = (mus_long_t)floor(x);
- p = x - x0;
- if (x0 >= size) x0 -= size;
- if (p == 0.0) return(wave[x0]);
- xp1 = x0 + 1;
- if (xp1 >= size) xp1 -= size;
- xm1 = x0 - 1;
- if (xm1 < 0) xm1 += size;
- pp = p * p;
- return((wave[xm1] * 0.5 * (pp - p)) +
- (wave[x0] * (1.0 - pp)) +
- (wave[xp1] * 0.5 * (p + pp)));
- }
-
-
- static mus_float_t mus_array_hermite_interp(mus_float_t *wave, mus_float_t x, mus_long_t size)
- {
- /* from James McCartney */
- mus_long_t x0, x1, x2, x3;
- mus_float_t p, c0, c1, c2, c3, y0, y1, y2, y3;
- if ((x < 0.0) || (x > size))
- {
- x = fmod((mus_float_t)x, (mus_float_t)size);
- if (x < 0.0) x += size;
- }
- x1 = (mus_long_t)floor(x);
- p = x - x1;
- if (x1 == size) x1 = 0;
- if (p == 0.0) return(wave[x1]);
- x2 = x1 + 1;
- if (x2 == size) x2 = 0;
- x3 = x2 + 1;
- if (x3 == size) x3 = 0;
- x0 = x1 - 1;
- if (x0 < 0) x0 = size - 1;
- y0 = wave[x0];
- y1 = wave[x1];
- y2 = wave[x2];
- y3 = wave[x3];
- c0 = y1;
- c1 = 0.5 * (y2 - y0);
- c3 = 1.5 * (y1 - y2) + 0.5 * (y3 - y0);
- c2 = y0 - y1 + c1 - c3;
- return(((c3 * p + c2) * p + c1) * p + c0);
- }
-
-
- static mus_float_t mus_array_bezier_interp(mus_float_t *wave, mus_float_t x, mus_long_t size)
- {
- mus_long_t x0, x1, x2, x3;
- mus_float_t p, y0, y1, y2, y3, ay, by, cy;
- if ((x < 0.0) || (x > size))
- {
- x = fmod((mus_float_t)x, (mus_float_t)size);
- if (x < 0.0) x += size;
- }
- x1 = (mus_long_t)floor(x);
- p = ((x - x1) + 1.0) / 3.0;
- if (x1 == size) x1 = 0;
- x2 = x1 + 1;
- if (x2 == size) x2 = 0;
- x3 = x2 + 1;
- if (x3 == size) x3 = 0;
- x0 = x1 - 1;
- if (x0 < 0) x0 = size - 1;
- y0 = wave[x0];
- y1 = wave[x1];
- y2 = wave[x2];
- y3 = wave[x3];
- cy = 3 * (y1 - y0);
- by = 3 * (y2 - y1) - cy;
- ay = y3 - y0 - cy - by;
- return(y0 + p * (cy + (p * (by + (p * ay)))));
- }
-
-
- bool mus_is_interp_type(int val)
- {
- /* this is C++'s fault. */
- switch (val)
- {
- case MUS_INTERP_NONE:
- case MUS_INTERP_LINEAR:
- case MUS_INTERP_SINUSOIDAL:
- case MUS_INTERP_LAGRANGE:
- case MUS_INTERP_HERMITE:
- case MUS_INTERP_ALL_PASS:
- case MUS_INTERP_BEZIER:
- return(true);
- break;
- }
- return(false);
- }
-
-
- mus_float_t mus_interpolate(mus_interp_t type, mus_float_t x, mus_float_t *table, mus_long_t table_size, mus_float_t y)
- {
- switch (type)
- {
- case MUS_INTERP_NONE:
- {
- mus_long_t x0;
- x0 = ((mus_long_t)x) % table_size;
- if (x0 < 0) x0 += table_size;
- return(table[x0]);
- }
- break;
-
- case MUS_INTERP_LAGRANGE:
- return(mus_array_lagrange_interp(table, x, table_size));
- break;
-
- case MUS_INTERP_HERMITE:
- return(mus_array_hermite_interp(table, x, table_size));
- break;
-
- case MUS_INTERP_LINEAR:
- return(mus_array_interp(table, x, table_size));
- break;
-
- case MUS_INTERP_ALL_PASS:
- return(mus_array_all_pass_interp(table, x, table_size, y));
- break;
-
- case MUS_INTERP_BEZIER:
- return(mus_array_bezier_interp(table, x, table_size));
- break;
-
- default:
- mus_error(MUS_ARG_OUT_OF_RANGE, "unknown interpolation type: %d", type);
- break;
- }
- return(0.0);
- }
-
-
-
- /* ---------------- oscil ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t phase, freq;
- } osc;
-
-
- mus_float_t mus_oscil(mus_any *ptr, mus_float_t fm, mus_float_t pm)
- {
- osc *gen = (osc *)ptr;
- mus_float_t result;
- result = gen->phase + pm;
- gen->phase += (gen->freq + fm);
- return(sin(result));
- }
-
-
- mus_float_t mus_oscil_unmodulated(mus_any *ptr)
- {
- osc *gen = (osc *)ptr;
- mus_float_t result;
- result = gen->phase;
- gen->phase += gen->freq;
- return(sin(result));
- }
-
-
- mus_float_t mus_oscil_fm(mus_any *ptr, mus_float_t fm)
- {
- osc *gen = (osc *)ptr;
- mus_float_t result;
- result = gen->phase;
- gen->phase += (gen->freq + fm);
- return(sin(result));
- }
-
-
- mus_float_t mus_oscil_pm(mus_any *ptr, mus_float_t pm)
- {
- mus_float_t result;
- osc *gen = (osc *)ptr;
- result = gen->phase + pm;
- gen->phase += gen->freq;
- return(sin(result));
- }
-
-
- bool mus_is_oscil(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_OSCIL));
- }
- /* this could be: bool mus_is_oscil(mus_any *ptr) {return((ptr) && (ptr->core == &OSCIL_CLASS));}
- */
-
-
- static void free_oscil(mus_any *ptr) {free(ptr);}
-
- static mus_float_t oscil_freq(mus_any *ptr) {return(mus_radians_to_hz(((osc *)ptr)->freq));}
- static mus_float_t oscil_set_freq(mus_any *ptr, mus_float_t val) {((osc *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t oscil_increment(mus_any *ptr) {return(((osc *)ptr)->freq);}
- static mus_float_t oscil_set_increment(mus_any *ptr, mus_float_t val) {((osc *)ptr)->freq = val; return(val);}
-
- static mus_float_t oscil_phase(mus_any *ptr) {return(fmod(((osc *)ptr)->phase, TWO_PI));}
- static mus_float_t oscil_set_phase(mus_any *ptr, mus_float_t val) {((osc *)ptr)->phase = val; return(val);}
-
- static mus_long_t oscil_cosines(mus_any *ptr) {return(1);}
- static void oscil_reset(mus_any *ptr) {((osc *)ptr)->phase = 0.0;}
-
- static mus_any *oscil_copy(mus_any *ptr)
- {
- osc *g;
- g = (osc *)malloc(sizeof(osc));
- memcpy((void *)g, (void *)ptr, sizeof(osc));
- return((mus_any *)g);
- }
-
- static mus_float_t fallback_scaler(mus_any *ptr) {return(1.0);}
-
-
- static bool oscil_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_oscil((mus_any *)p1)) &&
- (mus_is_oscil((mus_any *)p2)) &&
- ((((osc *)p1)->freq) == (((osc *)p2)->freq)) &&
- ((((osc *)p1)->phase) == (((osc *)p2)->phase))));
- }
-
-
- static char *describe_oscil(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr));
- return(describe_buffer);
- }
-
-
- static mus_any_class OSCIL_CLASS = {
- MUS_OSCIL,
- (char *)S_oscil, /* the "(char *)" business is for g++'s benefit */
- &free_oscil,
- &describe_oscil,
- &oscil_equalp,
- 0, 0,
- &oscil_cosines, 0,
- &oscil_freq,
- &oscil_set_freq,
- &oscil_phase,
- &oscil_set_phase,
- &fallback_scaler, 0,
- &oscil_increment,
- &oscil_set_increment,
- &mus_oscil,
- MUS_NOT_SPECIAL,
- NULL,
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &oscil_reset,
- 0,
- &oscil_copy
- };
-
-
-
- mus_any *mus_make_oscil(mus_float_t freq, mus_float_t phase)
- {
- osc *gen;
- gen = (osc *)malloc(sizeof(osc));
- gen->core = &OSCIL_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- return((mus_any *)gen);
- }
-
- /* decided against feedback-oscil (as in cellon) because it's not clear how to handle the index,
- * and there are many options for the filtering -- since this part of the signal path
- * is not hidden, there's no reason to bring it out explicitly (as in filtered-comb)
- */
-
-
- /* ---------------- oscil-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size, orig_size;
- mus_float_t *amps, *phases, *freqs; /* these can change, so sincos is not always safe */
- bool free_phases;
- mus_float_t (*ob_func)(mus_any *ptr);
- #if HAVE_SINCOS
- double *sn1, *cs1, *sn2, *cs2, *phs;
- bool use_sc;
- #endif
- } ob;
-
-
- static void free_oscil_bank(mus_any *ptr)
- {
- ob *g = (ob *)ptr;
- #if HAVE_SINCOS
- if (g->sn1) {free(g->sn1); g->sn1 = NULL;}
- if (g->sn2) {free(g->sn2); g->sn2 = NULL;}
- if (g->cs1) {free(g->cs1); g->cs1 = NULL;}
- if (g->cs2) {free(g->cs2); g->cs2 = NULL;}
- if (g->phs) {free(g->phs); g->phs = NULL;}
- #endif
- if ((g->phases) && (g->free_phases)) {free(g->phases); g->phases = NULL;}
- free(ptr);
- }
-
- static mus_any *ob_copy(mus_any *ptr)
- {
- ob *g, *p;
- int bytes;
-
- p = (ob *)ptr;
- g = (ob *)malloc(sizeof(ob));
- memcpy((void *)g, (void *)ptr, sizeof(ob));
-
- g->ob_func = p->ob_func;
-
- #if HAVE_SINCOS
- if (g->sn1)
- {
- bytes = g->size * sizeof(double);
- g->sn1 = (double *)malloc(bytes);
- memcpy((void *)(g->sn1), (void *)(p->sn1), bytes);
- g->sn2 = (double *)malloc(bytes);
- memcpy((void *)(g->sn2), (void *)(p->sn2), bytes);
- g->cs1 = (double *)malloc(bytes);
- memcpy((void *)(g->cs1), (void *)(p->cs1), bytes);
- g->cs2 = (double *)malloc(bytes);
- memcpy((void *)(g->cs2), (void *)(p->cs2), bytes);
- g->phs = (double *)malloc(bytes);
- memcpy((void *)(g->phs), (void *)(p->phs), bytes);
- g->use_sc = p->use_sc;
- }
- #endif
-
- bytes = g->size * sizeof(mus_float_t);
- /* we have to make a new phases array -- otherwise the original and copy step on each other */
- g->free_phases = true;
- g->phases = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->phases), (void *)(p->phases), bytes);
- return((mus_any *)g);
- }
-
- static mus_float_t *ob_data(mus_any *ptr) {return(((ob *)ptr)->phases);}
-
- static mus_float_t run_oscil_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_oscil_bank(ptr));
- }
-
-
- static mus_long_t oscil_bank_length(mus_any *ptr)
- {
- return(((ob *)ptr)->size);
- }
-
-
- static mus_long_t oscil_bank_set_length(mus_any *ptr, mus_long_t len)
- {
- ob *g = (ob *)ptr;
- if (len < 0)
- g->size = 0;
- else
- {
- if (len > g->orig_size)
- g->size = g->orig_size;
- else g->size = len;
- }
- return(len);
- }
-
-
- static void oscil_bank_reset(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- p->size = p->orig_size;
- memset((void *)(p->phases), 0, p->orig_size * sizeof(mus_float_t));
- }
-
-
- static bool oscil_bank_equalp(mus_any *p1, mus_any *p2)
- {
- ob *o1 = (ob *)p1;
- ob *o2 = (ob *)p2;
- if (p1 == p2) return(true);
- return((o1->size == o2->size) &&
- (o1->orig_size == o2->orig_size) &&
- (o1->amps == o2->amps) &&
- (o1->freqs == o2->freqs) &&
- ((o1->phases == o2->phases) ||
- (clm_arrays_are_equal(o1->phases, o2->phases, o2->size))));
- }
-
-
- static char *describe_oscil_bank(mus_any *ptr)
- {
- ob *gen = (ob *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class OSCIL_BANK_CLASS = {
- MUS_OSCIL_BANK,
- (char *)S_oscil_bank,
- &free_oscil_bank,
- &describe_oscil_bank,
- &oscil_bank_equalp,
- &ob_data, 0,
- &oscil_bank_length, &oscil_bank_set_length,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_oscil_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &oscil_bank_reset,
- 0, &ob_copy
- };
-
-
- bool mus_is_oscil_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_OSCIL_BANK));
- }
-
-
- static mus_float_t oscil_bank(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- int i;
- mus_float_t sum = 0.0;
- if (!p->amps)
- {
- for (i = 0; i < p->size; i++)
- {
- sum += sin(p->phases[i]);
- p->phases[i] += p->freqs[i];
- }
- }
- else
- {
- for (i = 0; i < p->size; i++)
- {
- sum += (p->amps[i] * sin(p->phases[i]));
- p->phases[i] += p->freqs[i];
- }
- }
- return(sum);
- }
-
-
- #if HAVE_SINCOS
- static mus_float_t stable_oscil_bank(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- int i;
- mus_float_t sum = 0.0;
- if (p->use_sc)
- {
- for (i = 0; i < p->size; i++)
- sum += (p->sn1[i] * p->cs2[i] + p->cs1[i] * p->sn2[i]);
- p->use_sc = false;
- }
- else
- {
- double s, c;
- if (!p->amps)
- {
- for (i = 0; i < p->size; i++)
- {
- sincos(p->phases[i], &s, &c);
- p->sn2[i] = s;
- p->cs2[i] = c;
- sum += s;
- p->phases[i] += p->phs[i];
- }
- }
- else
- {
- for (i = 0; i < p->size; i++)
- {
- sincos(p->phases[i], &s, &c);
- p->sn2[i] = s;
- p->cs2[i] = c;
- sum += p->amps[i] * s;
- p->phases[i] += p->phs[i];
- }
- }
- p->use_sc = true;
- }
- return(sum);
- }
- #endif
-
-
- mus_float_t mus_oscil_bank(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- return(p->ob_func(ptr));
- }
-
-
- mus_any *mus_make_oscil_bank(int size, mus_float_t *freqs, mus_float_t *phases, mus_float_t *amps, bool stable)
- {
- ob *gen;
-
- gen = (ob *)malloc(sizeof(ob));
- gen->core = &OSCIL_BANK_CLASS;
- gen->orig_size = size;
- gen->size = size;
- gen->amps = amps;
- gen->freqs = freqs;
- gen->phases = phases;
- gen->free_phases = false;
- gen->ob_func = oscil_bank;
-
- #if HAVE_SINCOS
- if (stable)
- {
- int i;
- double s, c;
-
- gen->ob_func = stable_oscil_bank;
- gen->use_sc = false;
- gen->sn1 = (double *)malloc(size * sizeof(double));
- gen->sn2 = (double *)malloc(size * sizeof(double));
- gen->cs1 = (double *)malloc(size * sizeof(double));
- gen->cs2 = (double *)malloc(size * sizeof(double));
- gen->phs = (double *)malloc(size * sizeof(double));
-
- for (i = 0; i < size; i++)
- {
- sincos(freqs[i], &s, &c);
- if (amps)
- {
- s *= amps[i];
- c *= amps[i];
- }
- gen->sn1[i] = s;
- gen->cs1[i] = c;
- gen->phs[i] = freqs[i] * 2.0;
- }
- }
- else
- {
- gen->sn1 = NULL;
- gen->sn2 = NULL;
- gen->cs1 = NULL;
- gen->cs2 = NULL;
- gen->phs = NULL;
- }
- #endif
-
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- ncos ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int n;
- mus_float_t scaler, cos5, phase, freq;
- } cosp;
-
- #define DIVISOR_NEAR_ZERO(Den) (fabs(Den) < 1.0e-14)
-
- mus_float_t mus_ncos(mus_any *ptr, mus_float_t fm)
- {
- /* changed 25-Apr-04: use less stupid formula */
- /* (/ (- (/ (sin (* (+ n 0.5) angle)) (* 2 (sin (* 0.5 angle)))) 0.5) n) */
- mus_float_t val, den;
- cosp *gen = (cosp *)ptr;
- den = sin(gen->phase * 0.5);
- if (DIVISOR_NEAR_ZERO(den)) /* see note -- this was den == 0.0 1-Aug-07 */
- /* perhaps use DBL_EPSILON (1.0e-9 I think) */
- val = 1.0;
- else
- {
- val = (gen->scaler * (((sin(gen->phase * gen->cos5)) / (2.0 * den)) - 0.5));
- if (val > 1.0) val = 1.0;
- /* I think this can't happen now that we check den above, but just in case... */
- /* this check is actually incomplete, since we can be much below the correct value also, but the den check should fix those cases too */
- }
- gen->phase += (gen->freq + fm);
- return((mus_float_t)val);
- }
-
-
- /* I think we could add ncos_pm via:
- *
- * mus_float_t mus_ncos_pm(mus_any *ptr, mus_float_t fm, mus_float_t pm)
- * {
- * cosp *gen = (cosp *)ptr;
- * mus_float_t result;
- * gen->phase += pm;
- * result = mus_ncos(ptr, fm);
- * gen->phase -= pm;
- * return(result);
- * }
- *
- * and the same trick could add pm to anything:
- *
- * mus_float_t mus_run_with_pm(mus_any *ptr, mus_float_t fm, mus_float_t pm)
- * {
- * mus_float_t result;
- * mus_set_phase(ptr, mus_phase(ptr) + pm);
- * result = mus_run(ptr, fm, 0.0);
- * mus_set_phase (ptr, mus_phase(ptr) - pm);
- * return(result);
- * }
- *
- * fm could also be handled here so the 4 cases become gen, mus_run_with_fm|pm|fm_and_pm(gen)
- * but... this could just as well happen at the extension language level, except that run doesn't expand macros?
- * The problem with differentiating the pm and using the fm arg is that we'd need a closure.
- */
-
- #if 0
- /* if the current phase is close to 0.0, there were numerical troubles here:
- :(/ (cos (* 1.5 pi 1.0000000000000007)) (cos (* 0.5 pi 1.0000000000000007)))
- -3.21167411694788
- :(/ (cos (* 1.5 pi 1.0000000000000004)) (cos (* 0.5 pi 1.0000000000000004)))
- -2.63292557243357
- :(/ (cos (* 1.5 pi 1.0000000000000002)) (cos (* 0.5 pi 1.0000000000000002)))
- -1.84007079646018
- :(/ (cos (* 1.5 pi 1.0000000000000001)) (cos (* 0.5 pi 1.0000000000000001)))
- -3.0
- :(/ (cos (* 1.5 pi 1.0000000000000008)) (cos (* 0.5 pi 1.0000000000000008)))
- -3.34939116712516
- ;; 16 bits in is probably too much for mus_float_ts
- ;; these numbers can be hit in normal cases:
-
- (define (ncos-with-inversions n x)
- ;; Andrews Askey Roy 261
- (let* ((num (cos (* x (+ 0.5 n))))
- (den (cos (* x 0.5)))
- (val (/ num den))) ; Chebyshev polynomial of the third kind! (4th uses sin = our current formula)
- (/ (- (if (even? n) val (- val))
- 0.5)
- (+ 1 (* n 2)))))
-
- (with-sound (:scaled-to 1.0)
- (do ((i 0 (+ i 1))
- (x 0.0 (+ x .01)))
- ((= i 200)) ; glitch at 100 (= 1)
- (outa i (ncos-with-inversions 1 (* pi x)) *output*)))
- */
- #endif
-
-
- bool mus_is_ncos(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NCOS));
- }
-
-
- static void free_ncos(mus_any *ptr) {free(ptr);}
- static void ncos_reset(mus_any *ptr) {((cosp *)ptr)->phase = 0.0;}
-
- static mus_float_t ncos_freq(mus_any *ptr) {return(mus_radians_to_hz(((cosp *)ptr)->freq));}
- static mus_float_t ncos_set_freq(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t ncos_increment(mus_any *ptr) {return(((cosp *)ptr)->freq);}
- static mus_float_t ncos_set_increment(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->freq = val; return(val);}
-
- static mus_float_t ncos_phase(mus_any *ptr) {return(fmod(((cosp *)ptr)->phase, TWO_PI));}
- static mus_float_t ncos_set_phase(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->phase = val; return(val);}
-
- static mus_float_t ncos_scaler(mus_any *ptr) {return(((cosp *)ptr)->scaler);}
- static mus_float_t ncos_set_scaler(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->scaler = val; return(val);}
-
- static mus_long_t ncos_n(mus_any *ptr) {return(((cosp *)ptr)->n);}
-
- static mus_any *cosp_copy(mus_any *ptr)
- {
- cosp *g;
- g = (cosp *)malloc(sizeof(cosp));
- memcpy((void *)g, (void *)ptr, sizeof(cosp));
- return((mus_any *)g);
- }
-
- static mus_long_t ncos_set_n(mus_any *ptr, mus_long_t val)
- {
- cosp *gen = (cosp *)ptr;
- if (val > 0)
- {
- gen->n = (int)val;
- gen->cos5 = val + 0.5;
- gen->scaler = 1.0 / (mus_float_t)val;
- }
- return(val);
- }
-
- static mus_float_t run_ncos(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_ncos(ptr, fm));}
-
-
- static bool ncos_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_ncos((mus_any *)p1)) && (mus_is_ncos((mus_any *)p2)) &&
- ((((cosp *)p1)->freq) == (((cosp *)p2)->freq)) &&
- ((((cosp *)p1)->phase) == (((cosp *)p2)->phase)) &&
- ((((cosp *)p1)->n) == (((cosp *)p2)->n)) &&
- ((((cosp *)p1)->scaler) == (((cosp *)p2)->scaler))));
- }
-
-
- static char *describe_ncos(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, n: %d",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_order(ptr));
- return(describe_buffer);
- }
-
-
- static mus_any_class NCOS_CLASS = {
- MUS_NCOS,
- (char *)S_ncos,
- &free_ncos,
- &describe_ncos,
- &ncos_equalp,
- 0, 0, /* data */
- &ncos_n,
- &ncos_set_n,
- &ncos_freq,
- &ncos_set_freq,
- &ncos_phase,
- &ncos_set_phase,
- &ncos_scaler,
- &ncos_set_scaler,
- &ncos_increment,
- &ncos_set_increment,
- &run_ncos,
- MUS_NOT_SPECIAL,
- NULL,
- 0,
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &ncos_reset,
- 0,
- &cosp_copy
- };
-
-
- mus_any *mus_make_ncos(mus_float_t freq, int n)
- {
- cosp *gen;
- gen = (cosp *)malloc(sizeof(cosp));
- gen->core = &NCOS_CLASS;
- if (n == 0) n = 1;
- gen->scaler = 1.0 / (mus_float_t)n;
- gen->n = n;
- gen->cos5 = n + 0.5;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = 0.0;
- return((mus_any *)gen);
- }
-
-
- /* ---------------- nsin ---------------- */
-
- static bool nsin_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_nsin((mus_any *)p1)) && (mus_is_nsin((mus_any *)p2)) &&
- ((((cosp *)p1)->freq) == (((cosp *)p2)->freq)) &&
- ((((cosp *)p1)->phase) == (((cosp *)p2)->phase)) &&
- ((((cosp *)p1)->n) == (((cosp *)p2)->n)) &&
- ((((cosp *)p1)->scaler) == (((cosp *)p2)->scaler))));
- }
-
-
- static char *describe_nsin(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, n: %d",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_order(ptr));
- return(describe_buffer);
- }
-
-
- bool mus_is_nsin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NSIN));
- }
-
-
- #if 0
- /* its simplest to get the maxes by running an example and recording the maxamp, but it also
- * works for small "n" to use the derivative of the sum-of-sines as a Chebyshev polynomial in cos x,
- * find its roots, and plug acos(root) into the original, recording the max:
- *
- (define (smax coeffs)
- (let* ((n (vct-length coeffs))
- (dcos (make-vct n 1.0)))
- (do ((i 0 (+ i 1)))
- ((= i n))
- (vct-set! dcos i (* (+ i 1) (vct-ref coeffs i))))
- (let ((partials ()))
- (do ((i 0 (+ i 1)))
- ((= i n))
- (set! partials (append (list (vct-ref dcos i) (+ i 1)) partials)))
- (let ((Tn (partials->polynomial (reverse partials))))
- (let ((roots (poly-roots Tn)))
- (let ((mx (* -2 n)))
- (for-each
- (lambda (root)
- (let ((acr (acos root))
- (sum 0.0))
- (do ((i 0 (+ i 1)))
- ((= i n))
- (set! sum (+ sum (* (vct-ref coeffs i) (sin (* (+ i 1) acr))))))
- (if (> (abs sum) mx)
- (set! mx (abs sum)))))
- roots)
- mx))))))
-
- (smax (make-vct n 1.0))
-
- * but that's too much effort for an initialization function.
- * much faster is this search (it usually hits an answer in 2 or 3 tries):
- *
- (define (find-nsin-max n)
-
- (define (ns x n)
- (let* ((a2 (/ x 2))
- (den (sin a2)))
- (if (= den 0.0)
- 0.0
- (/ (* (sin (* n a2)) (sin (* (+ n 1) a2))) den))))
-
- (define (find-mid-max n lo hi)
- (let ((mid (/ (+ lo hi) 2)))
- (let ((ylo (ns lo n))
- (yhi (ns hi n)))
- (if (< (abs (- ylo yhi)) 1e-100)
- (list (ns mid n)
- (rationalize (/ mid pi) 0.0))
- (if (> ylo yhi)
- (find-mid-max n lo mid)
- (find-mid-max n mid hi))))))
-
- (find-mid-max n 0.0 (/ pi (+ n .5))))
- *
- * the 'mid' point has a surprisingly simple relation to pi:
- *
- * (find-max 100000000000000)
- * 7.24518620297426541161857919764185053934850053037407235e13
- *
- * (find-max 1000000000000000000000000)
- * 7.24518620297422918568756794921595308358209723004380140e23 1/1333333333333333333333334 = .75e-24 -> (3*pi)/(4*n)
- *
- * (find-max 10000000000000000000000000000000000)
- * 7.24518620297422918568756432662285195872681453497436666955413707681801083640192066844820049586929551886747925783e33
- *
- * which is approximately (/ (* 8 (expt (sin (* pi 3/8)) 2)) (* 3 pi)):
- * 7.245186202974229185687564326622851596467504
- *
- * (to get that expression, plug in 3pi/4n, treat (n+1)/n as essentially 1 as n gets very large,
- * treat (sin x) as about x when x is very small, and simplify)
- * so if n>10, we could use (ns (/ (* 3 pi) (* 4 n)) n) without major error
- * It's possible to differentiate the nsin formula:
- *
- * -(cos(x/2)sin(nx/2)sin((n+1)x/2))/(2sin^2(x/2)) + ncos(nx/2)sin((n+1)x/2)/(2sin(x/2)) + (n+1)sin(nx/2)cos((n+1)x/2)/(2sin(x/2))
- *
- * and find the first 0 when n is very large -- it is very close to 3pi/(4*n)
- */
- #endif
-
-
- static mus_float_t nsin_ns(mus_float_t x, int n)
- {
- mus_float_t a2, den;
- a2 = x / 2;
- den = sin(a2);
- if (den == 0.0)
- return(0.0);
- return(sin(n * a2) * sin((n + 1) * a2) / den);
- }
-
-
- static mus_float_t find_nsin_scaler(int n, mus_float_t lo, mus_float_t hi)
- {
- mus_float_t mid, ylo, yhi;
- mid = (lo + hi) / 2;
- ylo = nsin_ns(lo, n);
- yhi = nsin_ns(hi, n);
- if (fabs(ylo - yhi) < 1e-12)
- return(nsin_ns(mid, n));
- if (ylo > yhi)
- return(find_nsin_scaler(n, lo, mid));
- return(find_nsin_scaler(n, mid, hi));
- }
-
-
- static mus_float_t nsin_scaler(int n)
- {
- return(1.0 / find_nsin_scaler(n, 0.0, M_PI / (n + 0.5)));
- }
-
-
- static mus_long_t nsin_set_n(mus_any *ptr, mus_long_t val)
- {
- cosp *gen = (cosp *)ptr;
- gen->n = (int)val;
- gen->cos5 = val + 1.0;
- gen->scaler = nsin_scaler((int)val);
- return(val);
- }
-
-
- mus_float_t mus_nsin(mus_any *ptr, mus_float_t fm)
- {
- /* (let* ((a2 (* angle 0.5))
- (den (sin a2)))
- (if (= den 0.0)
- 0.0
- (/ (* (sin (* n a2)) (sin (* (+ n 1) a2))) den)))
- */
- #if HAVE_SINCOS
- double val, a2, ns, nc, s, c;
- cosp *gen = (cosp *)ptr;
- a2 = gen->phase * 0.5;
- sincos(a2, &s, &c);
- if (DIVISOR_NEAR_ZERO(s)) /* see note under ncos */
- val = 0.0;
- else
- {
- sincos(gen->n * a2, &ns, &nc);
- val = gen->scaler * ns * (ns * c + nc * s) / s;
- }
- #else
- mus_float_t val, den, a2;
- cosp *gen = (cosp *)ptr;
- a2 = gen->phase * 0.5;
- den = sin(a2);
- if (DIVISOR_NEAR_ZERO(den)) /* see note under ncos */
- val = 0.0;
- else val = gen->scaler * sin(gen->n * a2) * sin(a2 * gen->cos5) / den;
- #endif
- gen->phase += (gen->freq + fm);
- return((mus_float_t)val);
- }
-
-
- static mus_float_t run_nsin(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_nsin(ptr, fm));}
-
- static mus_any_class NSIN_CLASS = {
- MUS_NSIN,
- (char *)S_nsin,
- &free_ncos,
- &describe_nsin,
- &nsin_equalp,
- 0, 0, /* data */
- &ncos_n,
- &nsin_set_n,
- &ncos_freq,
- &ncos_set_freq,
- &ncos_phase,
- &ncos_set_phase,
- &ncos_scaler,
- &ncos_set_scaler,
- &ncos_increment,
- &ncos_set_increment,
- &run_nsin,
- MUS_NOT_SPECIAL,
- NULL,
- 0,
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &ncos_reset,
- 0,
- &cosp_copy
- };
-
-
- mus_any *mus_make_nsin(mus_float_t freq, int n)
- {
- cosp *gen;
- gen = (cosp *)mus_make_ncos(freq, n);
- gen->core = &NSIN_CLASS;
- gen->scaler = nsin_scaler(n);
- gen->cos5 = gen->n + 1.0;
- return((mus_any *)gen);
- }
-
-
- /* ---------------- asymmetric-fm ---------------- */
-
- /* changed from sin(sin) to cos(sin) and added amplitude normalization 6-Sep-07 */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t r;
- mus_float_t freq, phase;
- mus_float_t ratio;
- mus_float_t cosr, sinr;
- mus_float_t one;
- } asyfm;
-
-
- static void free_asymmetric_fm(mus_any *ptr) {free(ptr);}
- static void asyfm_reset(mus_any *ptr) {((asyfm *)ptr)->phase = 0.0;}
-
- static mus_any *asyfm_copy(mus_any *ptr)
- {
- asyfm *g;
- g = (asyfm *)malloc(sizeof(asyfm));
- memcpy((void *)g, (void *)ptr, sizeof(asyfm));
- return((mus_any *)g);
- }
-
- static mus_float_t asyfm_freq(mus_any *ptr) {return(mus_radians_to_hz(((asyfm *)ptr)->freq));}
- static mus_float_t asyfm_set_freq(mus_any *ptr, mus_float_t val) {((asyfm *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t asyfm_increment(mus_any *ptr) {return(((asyfm *)ptr)->freq);}
- static mus_float_t asyfm_set_increment(mus_any *ptr, mus_float_t val) {((asyfm *)ptr)->freq = val; return(val);}
-
- static mus_float_t asyfm_phase(mus_any *ptr) {return(fmod(((asyfm *)ptr)->phase, TWO_PI));}
- static mus_float_t asyfm_set_phase(mus_any *ptr, mus_float_t val) {((asyfm *)ptr)->phase = val; return(val);}
-
- static mus_float_t asyfm_ratio(mus_any *ptr) {return(((asyfm *)ptr)->ratio);}
-
- static mus_float_t asyfm_r(mus_any *ptr) {return(((asyfm *)ptr)->r);}
-
- static mus_float_t asyfm_set_r(mus_any *ptr, mus_float_t val)
- {
- asyfm *gen = (asyfm *)ptr;
- if (val != 0.0)
- {
- gen->r = val;
- gen->cosr = 0.5 * (val - (1.0 / val));
- gen->sinr = 0.5 * (val + (1.0 / val));
- if ((val > 1.0) ||
- ((val < 0.0) && (val > -1.0)))
- gen->one = -1.0;
- else gen->one = 1.0;
- }
- return(val);
- }
-
-
- static bool asyfm_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- (((p1->core)->type == (p2->core)->type) &&
- ((((asyfm *)p1)->freq) == (((asyfm *)p2)->freq)) &&
- ((((asyfm *)p1)->phase) == (((asyfm *)p2)->phase)) &&
- ((((asyfm *)p1)->ratio) == (((asyfm *)p2)->ratio)) &&
- ((((asyfm *)p1)->r) == (((asyfm *)p2)->r))));
- }
-
-
- static char *describe_asyfm(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, ratio: %.3f, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- ((asyfm *)ptr)->ratio,
- asyfm_r(ptr));
- return(describe_buffer);
- }
-
-
- bool mus_is_asymmetric_fm(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ASYMMETRIC_FM));
- }
-
-
- mus_float_t mus_asymmetric_fm(mus_any *ptr, mus_float_t index, mus_float_t fm)
- {
- asyfm *gen = (asyfm *)ptr;
- mus_float_t result;
- mus_float_t mth;
- mth = gen->ratio * gen->phase;
- result = exp(index * gen->cosr * (gen->one + cos(mth))) * cos(gen->phase + index * gen->sinr * sin(mth));
- /* second index factor added 4-Mar-02 and (+/-)1.0 + cos to normalize amps 6-Sep-07 */
- gen->phase += (gen->freq + fm);
- return(result);
- }
-
-
- mus_float_t mus_asymmetric_fm_unmodulated(mus_any *ptr, mus_float_t index)
- {
- asyfm *gen = (asyfm *)ptr;
- mus_float_t result, mth;
- mth = gen->ratio * gen->phase;
- result = exp(index * gen->cosr * (gen->one + cos(mth))) * cos(gen->phase + index * gen->sinr * sin(mth));
- /* second index factor added 4-Mar-02 */
- gen->phase += gen->freq;
- return(result);
- }
-
- static mus_any_class ASYMMETRIC_FM_CLASS = {
- MUS_ASYMMETRIC_FM,
- (char *)S_asymmetric_fm,
- &free_asymmetric_fm,
- &describe_asyfm,
- &asyfm_equalp,
- 0, 0, 0, 0,
- &asyfm_freq,
- &asyfm_set_freq,
- &asyfm_phase,
- &asyfm_set_phase,
- &asyfm_r,
- &asyfm_set_r,
- &asyfm_increment,
- &asyfm_set_increment,
- &mus_asymmetric_fm,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &asyfm_ratio,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &asyfm_reset,
- 0,
- &asyfm_copy
- };
-
-
- mus_any *mus_make_asymmetric_fm(mus_float_t freq, mus_float_t phase, mus_float_t r, mus_float_t ratio) /* r default 1.0, ratio 1.0 */
- {
- asyfm *gen = NULL;
- if (r == 0.0)
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_asymmetric_fm ": r can't be 0.0");
- else
- {
- gen = (asyfm *)malloc(sizeof(asyfm));
- gen->core = &ASYMMETRIC_FM_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- gen->r = r;
- gen->ratio = ratio;
- gen->cosr = 0.5 * (r - (1.0 / r)); /* 0.5 factor for I/2 */
- gen->sinr = 0.5 * (r + (1.0 / r));
- if ((r > 1.0) ||
- ((r < 0.0) && (r > -1.0)))
- gen->one = -1.0;
- else gen->one = 1.0;
- }
- return((mus_any *)gen);
- }
-
-
-
-
- /*---------------- nrxysin (sine-summation) and nrxycos ---------------- */
-
- /* the generator uses x and y (frequencies), but it's very common to start up with 0 freqs
- * and let the fm arg set the frequency, so it seems like we want to give the ratio between
- * the frequencies at make time, rather than two (possibly dummy) frequencies).
- * xy-ratio negative to build (via r) backwards.
- */
-
- #define MAX_R 0.999999
- #define MIN_R -0.999999
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, phase;
- int n;
- mus_float_t norm, r, r_to_n_plus_1, r_squared_plus_1, y_over_x;
- } nrxy;
-
-
- static void free_nrxy(mus_any *ptr) {free(ptr);}
- static void nrxy_reset(mus_any *ptr) {((nrxy *)ptr)->phase = 0.0;}
-
- static mus_any *nrxy_copy(mus_any *ptr)
- {
- nrxy *g;
- g = (nrxy *)malloc(sizeof(nrxy));
- memcpy((void *)g, (void *)ptr, sizeof(nrxy));
- return((mus_any *)g);
- }
-
- static mus_float_t nrxy_freq(mus_any *ptr) {return(mus_radians_to_hz(((nrxy *)ptr)->freq));}
- static mus_float_t nrxy_set_freq(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t nrxy_increment(mus_any *ptr) {return(((nrxy *)ptr)->freq);}
- static mus_float_t nrxy_set_increment(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->freq = val; return(val);}
-
- static mus_float_t nrxy_phase(mus_any *ptr) {return(fmod(((nrxy *)ptr)->phase, TWO_PI));}
- static mus_float_t nrxy_set_phase(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->phase = val; return(val);}
-
- static mus_long_t nrxy_n(mus_any *ptr) {return((mus_long_t)(((nrxy *)ptr)->n));}
-
- static mus_float_t nrxy_y_over_x(mus_any *ptr) {return(((nrxy *)ptr)->y_over_x);}
- static mus_float_t nrxy_set_y_over_x(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->y_over_x = val; return(val);}
-
- static mus_float_t nrxy_r(mus_any *ptr) {return(((nrxy *)ptr)->r);}
-
- static mus_float_t nrxy_set_r(mus_any *ptr, mus_float_t r)
- {
- nrxy *gen = (nrxy *)ptr;
- int n;
- n = gen->n;
- if (r > MAX_R) r = MAX_R;
- if (r < MIN_R) r = MIN_R;
- gen->r = r;
- gen->r_to_n_plus_1 = pow(r, n + 1);
- gen->r_squared_plus_1 = 1.0 + r * r;
- if (n == 0)
- gen->norm = 1.0;
- else gen->norm = (pow(fabs(r), n + 1) - 1.0) / (fabs(r) - 1.0);
- /* fabs here because if r<0.0, we line up at (2k-1)*pi rather than 2k*pi, but
- * otherwise the waveform is identical
- */
- return(r);
- }
-
- static bool nrxy_equalp(mus_any *p1, mus_any *p2)
- {
- nrxy *g1 = (nrxy *)p1;
- nrxy *g2 = (nrxy *)p2;
- return((p1 == p2) ||
- (((g1->core)->type == (g2->core)->type) &&
- (g1->freq == g2->freq) &&
- (g1->phase == g2->phase) &&
- (g1->n == g2->n) &&
- (g1->r == g2->r) &&
- (g1->y_over_x == g2->y_over_x)));
- }
-
-
- bool mus_is_nrxysin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NRXYSIN));
- }
-
-
- static char *describe_nrxysin(mus_any *ptr)
- {
- nrxy *gen = (nrxy *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, ratio: %.3f, phase: %.3f, n: %d, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- gen->y_over_x,
- mus_phase(ptr),
- gen->n,
- nrxy_r(ptr));
- return(describe_buffer);
- }
-
-
- mus_float_t mus_nrxysin(mus_any *ptr, mus_float_t fm)
- {
- /* Jolley 475 but 0..n rather than 0..n-1 */
- /* see also Durell and Robson "Advanced Trigonometry" p 175 */
-
- nrxy *gen = (nrxy *)ptr;
- mus_float_t x, y, r, divisor;
- int n;
-
- x = gen->phase;
- n = gen->n;
- r = gen->r;
- gen->phase += (gen->freq + fm);
-
-
- if (gen->y_over_x == 1.0)
- {
- #if (!HAVE_SINCOS)
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cos(x)));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
- return((sin(x) - gen->r_to_n_plus_1 * (sin(x * (n + 2)) - r * sin(x * (n + 1)))) / divisor);
- #else
- double sx, cx, snx, cnx;
- sincos(x, &sx, &cx);
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cx));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
- sincos((n + 1) * x, &snx, &cnx);
- return((sx - gen->r_to_n_plus_1 * (sx * cnx + (cx - r) * snx)) / divisor);
- #endif
- }
-
- #if HAVE_SINCOS
- {
- double xs, xc, ys, yc, nys, nyc, sin_x_y, sin_x_ny, sin_x_n1y, cos_x_ny;
-
- y = x * gen->y_over_x;
- sincos(y, &ys, &yc);
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * yc));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
-
- sincos(x, &xs, &xc);
- sincos(n * y, &nys, &nyc);
- sin_x_y = (xs * yc - ys * xc);
- sin_x_ny = (xs * nyc + nys * xc);
- cos_x_ny = (xc * nyc - xs * nys);
- sin_x_n1y = (sin_x_ny * yc + cos_x_ny * ys);
-
- return((xs -
- r * sin_x_y -
- gen->r_to_n_plus_1 * (sin_x_n1y - r * sin_x_ny)) / divisor);
- }
- #else
- y = x * gen->y_over_x;
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cos(y)));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
-
- return((sin(x) -
- r * sin(x - y) -
- gen->r_to_n_plus_1 * (sin(x + (n + 1) * y) -
- r * sin(x + n * y))) /
- divisor);
- #endif
- }
-
-
- static mus_float_t run_nrxysin(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_nrxysin(ptr, fm));}
-
-
- static mus_any_class NRXYSIN_CLASS = {
- MUS_NRXYSIN,
- (char *)S_nrxysin,
- &free_nrxy,
- &describe_nrxysin,
- &nrxy_equalp,
- 0, 0,
- &nrxy_n, 0,
- &nrxy_freq,
- &nrxy_set_freq,
- &nrxy_phase,
- &nrxy_set_phase,
- &nrxy_r,
- &nrxy_set_r,
- &nrxy_increment,
- &nrxy_set_increment,
- &run_nrxysin,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &nrxy_y_over_x,
- &nrxy_set_y_over_x,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &nrxy_reset,
- 0,
- &nrxy_copy
- };
-
-
- mus_any *mus_make_nrxysin(mus_float_t frequency, mus_float_t y_over_x, int n, mus_float_t r)
- {
- nrxy *gen;
- gen = (nrxy *)malloc(sizeof(nrxy));
- gen->core = &NRXYSIN_CLASS;
- gen->freq = mus_hz_to_radians(frequency);
- gen->y_over_x = y_over_x;
- gen->phase = 0.0;
- gen->n = n;
- nrxy_set_r((mus_any *)gen, r);
- return((mus_any *)gen);
- }
-
-
- bool mus_is_nrxycos(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NRXYCOS));
- }
-
-
- static char *describe_nrxycos(mus_any *ptr)
- {
- nrxy *gen = (nrxy *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, ratio: %.3f, phase: %.3f, n: %d, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- gen->y_over_x,
- mus_phase(ptr),
- gen->n,
- nrxy_r(ptr));
- return(describe_buffer);
- }
-
-
- mus_float_t mus_nrxycos(mus_any *ptr, mus_float_t fm)
- {
- nrxy *gen = (nrxy *)ptr;
- mus_float_t x, y, r, divisor;
- int n;
-
- x = gen->phase;
- y = x * gen->y_over_x;
- n = gen->n;
- r = gen->r;
-
- gen->phase += (gen->freq + fm);
-
- #if HAVE_SINCOS
- {
- double xs, xc, ys, yc, nys, nyc, cos_x_y, cos_x_ny, cos_x_n1y, sin_x_ny;
-
- sincos(y, &ys, &yc);
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * yc));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(1.0);
-
- sincos(x, &xs, &xc);
- sincos(n * y, &nys, &nyc);
- cos_x_y = (xc * yc + ys * xs);
- sin_x_ny = (xs * nyc + nys * xc);
- cos_x_ny = (xc * nyc - xs * nys);
- cos_x_n1y = (cos_x_ny * yc - sin_x_ny * ys);
- return((xc -
- r * cos_x_y -
- gen->r_to_n_plus_1 * (cos_x_n1y - r * cos_x_ny)) / divisor);
- }
- #else
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cos(y)));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(1.0);
- /* this can happen if r>0.9999999 or thereabouts;
- */
-
- return((cos(x) -
- r * cos(x - y) -
- gen->r_to_n_plus_1 * (cos(x + (n + 1) * y) -
- r * cos(x + n * y))) /
- divisor);
- #endif
- }
-
-
- static mus_float_t run_nrxycos(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_nrxycos(ptr, fm));}
-
-
- static mus_any_class NRXYCOS_CLASS = {
- MUS_NRXYCOS,
- (char *)S_nrxycos,
- &free_nrxy,
- &describe_nrxycos,
- &nrxy_equalp,
- 0, 0,
- &nrxy_n, 0,
- &nrxy_freq,
- &nrxy_set_freq,
- &nrxy_phase,
- &nrxy_set_phase,
- &nrxy_r,
- &nrxy_set_r,
- &nrxy_increment,
- &nrxy_set_increment,
- &run_nrxycos,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &nrxy_y_over_x,
- &nrxy_set_y_over_x,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &nrxy_reset,
- 0,
- &nrxy_copy
- };
-
-
- mus_any *mus_make_nrxycos(mus_float_t frequency, mus_float_t y_over_x, int n, mus_float_t r)
- {
- nrxy *gen;
- gen = (nrxy *)mus_make_nrxysin(frequency, y_over_x, n, r);
- gen->core = &NRXYCOS_CLASS;
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- rxykcos/sin ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t r, ar;
- mus_float_t freq, phase;
- mus_float_t ratio;
- } rxyk;
-
-
- static void free_rxykcos(mus_any *ptr) {free(ptr);}
- static void rxyk_reset(mus_any *ptr) {((rxyk *)ptr)->phase = 0.0;}
-
- static mus_any *rxyk_copy(mus_any *ptr)
- {
- rxyk *g;
- g = (rxyk *)malloc(sizeof(rxyk));
- memcpy((void *)g, (void *)ptr, sizeof(rxyk));
- return((mus_any *)g);
- }
-
- static mus_float_t rxyk_freq(mus_any *ptr) {return(mus_radians_to_hz(((rxyk *)ptr)->freq));}
- static mus_float_t rxyk_set_freq(mus_any *ptr, mus_float_t val) {((rxyk *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t rxyk_increment(mus_any *ptr) {return(((rxyk *)ptr)->freq);}
- static mus_float_t rxyk_set_increment(mus_any *ptr, mus_float_t val) {((rxyk *)ptr)->freq = val; return(val);}
-
- static mus_float_t rxyk_phase(mus_any *ptr) {return(fmod(((rxyk *)ptr)->phase, TWO_PI));}
- static mus_float_t rxyk_set_phase(mus_any *ptr, mus_float_t val) {((rxyk *)ptr)->phase = val; return(val);}
-
- static mus_float_t rxyk_ratio(mus_any *ptr) {return(((rxyk *)ptr)->ratio);}
-
- static mus_float_t rxyk_r(mus_any *ptr) {return(((rxyk *)ptr)->r);}
-
- static mus_float_t rxyk_set_r(mus_any *ptr, mus_float_t val)
- {
- rxyk *gen = (rxyk *)ptr;
- gen->r = val;
- gen->ar = 1.0 / exp(fabs(val));
- return(val);
- }
-
- static mus_float_t run_rxykcos(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rxykcos(ptr, fm));}
- static mus_float_t run_rxyksin(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rxyksin(ptr, fm));}
-
- static bool rxyk_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- (((p1->core)->type == (p2->core)->type) &&
- ((((rxyk *)p1)->freq) == (((rxyk *)p2)->freq)) &&
- ((((rxyk *)p1)->phase) == (((rxyk *)p2)->phase)) &&
- ((((rxyk *)p1)->ratio) == (((rxyk *)p2)->ratio)) &&
- ((((rxyk *)p1)->r) == (((rxyk *)p2)->r))));
- }
-
-
- static char *describe_rxyk(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, ratio: %.3f, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- ((rxyk *)ptr)->ratio,
- rxyk_r(ptr));
- return(describe_buffer);
- }
-
-
- bool mus_is_rxykcos(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RXYKCOS));
- }
-
-
- mus_float_t mus_rxykcos(mus_any *ptr, mus_float_t fm)
- {
- rxyk *gen = (rxyk *)ptr;
- mus_float_t result, rx;
-
- rx = gen->ratio * gen->phase;
- result = gen->ar * exp(gen->r * cos(rx)) * cos(gen->phase + (gen->r * sin(rx)));
- gen->phase += (fm + gen->freq);
-
- return(result);
- }
-
-
- static mus_any_class RXYKCOS_CLASS = {
- MUS_RXYKCOS,
- (char *)S_rxykcos,
- &free_rxykcos,
- &describe_rxyk,
- &rxyk_equalp,
- 0, 0, 0, 0,
- &rxyk_freq,
- &rxyk_set_freq,
- &rxyk_phase,
- &rxyk_set_phase,
- &rxyk_r,
- &rxyk_set_r,
- &rxyk_increment,
- &rxyk_set_increment,
- &run_rxykcos,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &rxyk_ratio,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &rxyk_reset,
- 0,
- &rxyk_copy
- };
-
-
- mus_any *mus_make_rxykcos(mus_float_t freq, mus_float_t phase, mus_float_t r, mus_float_t ratio) /* r default 0.5, ratio 1.0 */
- {
- rxyk *gen = NULL;
- gen = (rxyk *)malloc(sizeof(rxyk));
- gen->core = &RXYKCOS_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- gen->r = r;
- gen->ar = 1.0 / exp(fabs(r));
- gen->ratio = ratio;
- return((mus_any *)gen);
- }
-
-
-
- bool mus_is_rxyksin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RXYKSIN));
- }
-
-
- mus_float_t mus_rxyksin(mus_any *ptr, mus_float_t fm)
- {
- rxyk *gen = (rxyk *)ptr;
- mus_float_t result, rx;
-
- rx = gen->ratio * gen->phase;
- result = gen->ar * exp(gen->r * cos(rx)) * sin(gen->phase + (gen->r * sin(rx)));
- gen->phase += (fm + gen->freq);
-
- return(result);
- }
-
-
- static mus_any_class RXYKSIN_CLASS = {
- MUS_RXYKSIN,
- (char *)S_rxyksin,
- &free_rxykcos,
- &describe_rxyk,
- &rxyk_equalp,
- 0, 0, 0, 0,
- &rxyk_freq,
- &rxyk_set_freq,
- &rxyk_phase,
- &rxyk_set_phase,
- &rxyk_r,
- &rxyk_set_r,
- &rxyk_increment,
- &rxyk_set_increment,
- &run_rxyksin,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &rxyk_ratio,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &rxyk_reset,
- 0,
- &rxyk_copy
- };
-
-
- mus_any *mus_make_rxyksin(mus_float_t freq, mus_float_t phase, mus_float_t r, mus_float_t ratio) /* r default 0.5, ratio 1.0 */
- {
- rxyk *gen = NULL;
- gen = (rxyk *)malloc(sizeof(rxyk));
- gen->core = &RXYKSIN_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- gen->r = r;
- gen->ar = 1.0 / exp(fabs(r));
- gen->ratio = ratio;
- return((mus_any *)gen);
- }
-
-
-
-
- /* ---------------- table lookup ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, internal_mag, phase;
- mus_float_t *table;
- mus_long_t table_size;
- mus_interp_t type;
- bool table_allocated;
- mus_float_t yn1;
- mus_float_t (*tbl_look)(mus_any *ptr, mus_float_t fm);
- mus_float_t (*tbl_look_unmod)(mus_any *ptr);
- } tbl;
-
-
- mus_float_t *mus_partials_to_wave(mus_float_t *partial_data, int partials, mus_float_t *table, mus_long_t table_size, bool normalize)
- {
- int partial, k;
- if (!table) return(NULL);
- memset((void *)table, 0, table_size * sizeof(mus_float_t));
- for (partial = 0, k = 1; partial < partials; partial++, k += 2)
- {
- mus_float_t amp;
- amp = partial_data[k];
- if (amp != 0.0)
- {
- mus_long_t i;
- mus_float_t freq, angle;
- freq = (partial_data[partial * 2] * TWO_PI) / (mus_float_t)table_size;
- for (i = 0, angle = 0.0; i < table_size; i++, angle += freq)
- table[i] += amp * sin(angle);
- }
- }
- if (normalize)
- return(array_normalize(table, table_size));
- return(table);
- }
-
-
- mus_float_t *mus_phase_partials_to_wave(mus_float_t *partial_data, int partials, mus_float_t *table, mus_long_t table_size, bool normalize)
- {
- int partial, k, n;
- if (!table) return(NULL);
- memset((void *)table, 0, table_size * sizeof(mus_float_t));
- for (partial = 0, k = 1, n = 2; partial < partials; partial++, k += 3, n += 3)
- {
- mus_float_t amp;
- amp = partial_data[k];
- if (amp != 0.0)
- {
- mus_long_t i;
- mus_float_t freq, angle;
- freq = (partial_data[partial * 3] * TWO_PI) / (mus_float_t)table_size;
- for (i = 0, angle = partial_data[n]; i < table_size; i++, angle += freq)
- table[i] += amp * sin(angle);
- }
- }
- if (normalize)
- return(array_normalize(table, table_size));
- return(table);
- }
-
-
- mus_float_t mus_table_lookup(mus_any *ptr, mus_float_t fm)
- {
- return(((tbl *)ptr)->tbl_look(ptr, fm));
- }
-
- static mus_float_t table_look_linear(mus_any *ptr, mus_float_t fm)
- {
- tbl *gen = (tbl *)ptr;
-
- /* we're checking already for out-of-range indices, so mus_array_interp is more than we need */
- mus_long_t int_part;
- mus_float_t frac_part, f1;
-
- int_part = (mus_long_t)(gen->phase); /* floor(gen->phase) -- slow! modf is even worse */
- frac_part = gen->phase - int_part;
- f1 = gen->table[int_part];
- int_part++;
-
- if (int_part == gen->table_size)
- gen->yn1 = f1 + frac_part * (gen->table[0] - f1);
- else gen->yn1 = f1 + frac_part * (gen->table[int_part] - f1);
-
- gen->phase += (gen->freq + (fm * gen->internal_mag));
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(gen->yn1);
- }
-
-
- static mus_float_t table_look_any(mus_any *ptr, mus_float_t fm)
- {
- tbl *gen = (tbl *)ptr;
-
- gen->yn1 = mus_interpolate(gen->type, gen->phase, gen->table, gen->table_size, gen->yn1);
- gen->phase += (gen->freq + (fm * gen->internal_mag));
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(gen->yn1);
- }
-
-
- mus_float_t mus_table_lookup_unmodulated(mus_any *ptr)
- {
- return(((tbl *)ptr)->tbl_look_unmod(ptr));
- }
-
- static mus_float_t table_look_unmodulated_linear(mus_any *ptr)
- {
- tbl *gen = (tbl *)ptr;
- mus_long_t int_part;
- mus_float_t frac_part, f1;
-
- int_part = (mus_long_t)(gen->phase);
- frac_part = gen->phase - int_part;
- f1 = gen->table[int_part];
- int_part++;
-
- if (int_part == gen->table_size)
- f1 += frac_part * (gen->table[0] - f1);
- else f1 += frac_part * (gen->table[int_part] - f1);
-
- gen->phase += gen->freq;
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(f1);
- }
-
-
- static mus_float_t table_look_unmodulated_any(mus_any *ptr)
- {
- tbl *gen = (tbl *)ptr;
-
- gen->yn1 = mus_interpolate(gen->type, gen->phase, gen->table, gen->table_size, gen->yn1);
- gen->phase += gen->freq;
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(gen->yn1);
- }
-
-
- static mus_float_t run_table_lookup(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(((tbl *)ptr)->tbl_look(ptr, fm)); }
-
- bool mus_is_table_lookup(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TABLE_LOOKUP));
- }
-
- static mus_long_t table_lookup_length(mus_any *ptr) {return(((tbl *)ptr)->table_size);}
- static mus_float_t *table_lookup_data(mus_any *ptr) {return(((tbl *)ptr)->table);}
-
- static mus_float_t table_lookup_freq(mus_any *ptr) {return((((tbl *)ptr)->freq * sampling_rate) / (((tbl *)ptr)->table_size));}
- static mus_float_t table_lookup_set_freq(mus_any *ptr, mus_float_t val) {((tbl *)ptr)->freq = (val * ((tbl *)ptr)->table_size) / sampling_rate; return(val);}
-
- static mus_float_t table_lookup_increment(mus_any *ptr) {return(((tbl *)ptr)->freq);}
- static mus_float_t table_lookup_set_increment(mus_any *ptr, mus_float_t val) {((tbl *)ptr)->freq = val; return(val);}
-
- static mus_float_t table_lookup_phase(mus_any *ptr) {return(fmod(((TWO_PI * ((tbl *)ptr)->phase) / ((tbl *)ptr)->table_size), TWO_PI));}
- static mus_float_t table_lookup_set_phase(mus_any *ptr, mus_float_t val) {((tbl *)ptr)->phase = (val * ((tbl *)ptr)->table_size) / TWO_PI; return(val);}
-
- static int table_lookup_interp_type(mus_any *ptr) {return((int)(((tbl *)ptr)->type));} /* ints here and elsewhere to fit mus_channels method = interp-type */
-
- static void table_lookup_reset(mus_any *ptr) {((tbl *)ptr)->phase = 0.0;}
-
-
- static char *describe_table_lookup(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, length: %d, interp: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_length(ptr),
- interp_type_to_string(table_lookup_interp_type(ptr)));
- return(describe_buffer);
- }
-
-
- static bool table_lookup_equalp(mus_any *p1, mus_any *p2)
- {
- tbl *t1 = (tbl *)p1;
- tbl *t2 = (tbl *)p2;
- if (p1 == p2) return(true);
- return((t1) && (t2) &&
- (t1->core->type == t2->core->type) &&
- (t1->table_size == t2->table_size) &&
- (t1->freq == t2->freq) &&
- (t1->phase == t2->phase) &&
- (t1->type == t2->type) &&
- (t1->internal_mag == t2->internal_mag) &&
- (clm_arrays_are_equal(t1->table, t2->table, t1->table_size)));
- }
-
-
- static void free_table_lookup(mus_any *ptr)
- {
- tbl *gen = (tbl *)ptr;
- if ((gen->table) && (gen->table_allocated)) free(gen->table);
- free(gen);
- }
-
- static mus_any *tbl_copy(mus_any *ptr)
- {
- mus_long_t bytes;
- tbl *g, *p;
-
- p = (tbl *)ptr;
- g = (tbl *)malloc(sizeof(tbl));
- memcpy((void *)g, (void *)ptr, sizeof(tbl));
-
- bytes = g->table_size * sizeof(mus_float_t);
- g->table = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->table), (void *)(p->table), bytes);
- g->table_allocated = true;
-
- return((mus_any *)g);
- }
-
- static mus_float_t *table_set_data(mus_any *ptr, mus_float_t *val)
- {
- tbl *gen = (tbl *)ptr;
- if (gen->table_allocated) {free(gen->table); gen->table_allocated = false;}
- gen->table = val;
- return(val);
- }
-
-
- static mus_any_class TABLE_LOOKUP_CLASS = {
- MUS_TABLE_LOOKUP,
- (char *)S_table_lookup,
- &free_table_lookup,
- &describe_table_lookup,
- &table_lookup_equalp,
- &table_lookup_data,
- &table_set_data,
- &table_lookup_length,
- 0,
- &table_lookup_freq,
- &table_lookup_set_freq,
- &table_lookup_phase,
- &table_lookup_set_phase,
- &fallback_scaler, 0,
- &table_lookup_increment,
- &table_lookup_set_increment,
- &run_table_lookup,
- MUS_NOT_SPECIAL,
- NULL,
- &table_lookup_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &table_lookup_reset,
- 0, &tbl_copy
- };
-
-
- mus_any *mus_make_table_lookup(mus_float_t freq, mus_float_t phase, mus_float_t *table, mus_long_t table_size, mus_interp_t type)
- {
- tbl *gen;
- gen = (tbl *)malloc(sizeof(tbl));
- gen->core = &TABLE_LOOKUP_CLASS;
- gen->table_size = table_size;
- gen->internal_mag = table_size / TWO_PI;
- gen->freq = (freq * table_size) / sampling_rate;
- gen->phase = (fmod(phase, TWO_PI) * table_size) / TWO_PI;
- gen->type = type;
- if (type == MUS_INTERP_LINEAR)
- {
- gen->tbl_look = table_look_linear;
- gen->tbl_look_unmod = table_look_unmodulated_linear;
- }
- else
- {
- gen->tbl_look = table_look_any;
- gen->tbl_look_unmod = table_look_unmodulated_any;
- }
- gen->yn1 = 0.0;
- if (table)
- {
- gen->table = table;
- gen->table_allocated = false;
- }
- else
- {
- gen->table = (mus_float_t *)calloc(table_size, sizeof(mus_float_t));
- gen->table_allocated = true;
- }
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- polywave ---------------- */
-
- mus_float_t *mus_partials_to_polynomial(int npartials, mus_float_t *partials, mus_polynomial_t kind)
- {
- /* coeffs returned in partials */
- int i;
- mus_long_t *T0, *T1, *Tn;
- mus_float_t *Cc1;
-
- T0 = (mus_long_t *)calloc(npartials + 1, sizeof(mus_long_t));
- T1 = (mus_long_t *)calloc(npartials + 1, sizeof(mus_long_t));
- Tn = (mus_long_t *)calloc(npartials + 1, sizeof(mus_long_t));
- Cc1 = (mus_float_t *)calloc(npartials + 1, sizeof(mus_float_t));
-
- if (kind == MUS_CHEBYSHEV_FIRST_KIND)
- T0[0] = 1;
- else T0[0] = 0;
- T1[1] = 1;
-
- Cc1[0] = partials[0]; /* DC requested? */
-
- for (i = 1; i < npartials; i++)
- {
- int k;
- mus_float_t amp;
- amp = partials[i];
- if (amp != 0.0)
- {
- if (kind == MUS_CHEBYSHEV_FIRST_KIND)
- for (k = 0; k <= i; k++)
- Cc1[k] += (amp * T1[k]);
- else
- for (k = 1; k <= i; k++)
- Cc1[k - 1] += (amp * T1[k]);
- }
- for (k = i + 1; k > 0; k--)
- Tn[k] = (2 * T1[k - 1]) - T0[k];
- Tn[0] = -T0[0];
- for (k = i + 1; k >= 0; k--)
- {
- T0[k] = T1[k];
- T1[k] = Tn[k];
- }
- }
-
- for (i = 0; i < npartials; i++)
- partials[i] = Cc1[i];
-
- free(T0);
- free(T1);
- free(Tn);
- free(Cc1);
- return(partials);
- }
-
-
- mus_float_t *mus_normalize_partials(int num_partials, mus_float_t *partials)
- {
- int i;
- mus_float_t sum = 0.0;
- for (i = 0; i < num_partials; i++)
- sum += fabs(partials[2 * i + 1]);
- if ((sum != 0.0) &&
- (sum != 1.0))
- {
- sum = 1.0 / sum;
- for (i = 0; i < num_partials; i++)
- partials[2 * i + 1] *= sum;
- }
- return(partials);
- }
-
-
- typedef struct {
- mus_any_class *core;
- mus_float_t phase, freq;
- mus_float_t *coeffs, *ucoeffs;
- int n, cheby_choice;
- mus_float_t index;
- mus_float_t (*polyw)(mus_any *ptr, mus_float_t fm);
- } pw;
-
-
- mus_float_t (*mus_polywave_function(mus_any *g))(mus_any *gen, mus_float_t fm)
- {
- if (mus_is_polywave(g))
- return(((pw *)g)->polyw);
- return(NULL);
- }
-
- static void free_pw(mus_any *pt) {free(pt);}
-
- static mus_any *pw_copy(mus_any *ptr)
- {
- pw *g;
- g = (pw *)malloc(sizeof(pw));
- memcpy((void *)g, (void *)ptr, sizeof(pw));
- return((mus_any *)g);
- }
-
- static void pw_reset(mus_any *ptr)
- {
- pw *gen = (pw *)ptr;
- gen->phase = 0.0;
- }
-
-
- static bool pw_equalp(mus_any *p1, mus_any *p2)
- {
- pw *w1 = (pw *)p1;
- pw *w2 = (pw *)p2;
- if (p1 == p2) return(true);
- return((w1) && (w2) &&
- (w1->core->type == w2->core->type) &&
- (w1->freq == w2->freq) &&
- (w1->phase == w2->phase) &&
- (w1->n == w2->n) &&
- (w1->index == w2->index) &&
- (w1->cheby_choice == w2->cheby_choice) &&
- (clm_arrays_are_equal(w1->coeffs, w2->coeffs, w1->n)));
- }
-
-
- static mus_float_t pw_freq(mus_any *ptr) {return(mus_radians_to_hz(((pw *)ptr)->freq));}
- static mus_float_t pw_set_freq(mus_any *ptr, mus_float_t val) {((pw *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t pw_increment(mus_any *ptr) {return(((pw *)ptr)->freq);}
- static mus_float_t pw_set_increment(mus_any *ptr, mus_float_t val) {((pw *)ptr)->freq = val; return(val);}
-
- static mus_float_t pw_phase(mus_any *ptr) {return(fmod(((pw *)ptr)->phase, TWO_PI));}
- static mus_float_t pw_set_phase(mus_any *ptr, mus_float_t val) {((pw *)ptr)->phase = val; return(val);}
-
- static mus_long_t pw_n(mus_any *ptr) {return(((pw *)ptr)->n);}
- static mus_long_t pw_set_n(mus_any *ptr, mus_long_t val) {((pw *)ptr)->n = (int)val; return(val);}
-
- static mus_float_t *pw_data(mus_any *ptr) {return(((pw *)ptr)->coeffs);}
- static mus_float_t *pw_udata(mus_any *ptr) {return(((pw *)ptr)->ucoeffs);}
- static mus_float_t *pw_set_data(mus_any *ptr, mus_float_t *val) {((pw *)ptr)->coeffs = val; return(val);}
-
- static mus_float_t pw_xcoeff(mus_any *ptr, int index) {return(((pw *)ptr)->coeffs[index]);}
- static mus_float_t pw_set_xcoeff(mus_any *ptr, int index, mus_float_t val) {((pw *)ptr)->coeffs[index] = val; return(val);}
-
- static mus_float_t pw_ycoeff(mus_any *ptr, int index) {if (((pw *)ptr)->ucoeffs) return(((pw *)ptr)->ucoeffs[index]); return(0.0);}
- static mus_float_t pw_set_ycoeff(mus_any *ptr, int index, mus_float_t val) {if (((pw *)ptr)->ucoeffs) ((pw *)ptr)->ucoeffs[index] = val; return(val);}
-
- static mus_float_t pw_index(mus_any *ptr) {return(((pw *)ptr)->index);}
- static mus_float_t pw_set_index(mus_any *ptr, mus_float_t val) {((pw *)ptr)->index = val; return(val);}
-
- static int pw_choice(mus_any *ptr) {return(((pw *)ptr)->cheby_choice);}
-
-
- mus_float_t mus_chebyshev_tu_sum(mus_float_t x, int n, mus_float_t *tn, mus_float_t *un)
- {
- /* the Clenshaw algorithm -- beware of -cos(nx) where you'd expect cos(nx) */
- mus_float_t x2, tb, tb1 = 0.0, tb2, cx, ub, ub1 = 0.0;
- mus_float_t *tp, *up;
-
- cx = cos(x);
- x2 = 2.0 * cx;
-
- tp = (mus_float_t *)(tn + n - 1);
- up = (mus_float_t *)(un + n - 1);
- tb = (*tp--);
- ub = (*up--);
-
- while (up != un)
- {
- mus_float_t ub2;
- tb2 = tb1;
- tb1 = tb;
- tb = x2 * tb1 - tb2 + (*tp--);
-
- ub2 = ub1;
- ub1 = ub;
- ub = x2 * ub1 - ub2 + (*up--);
- }
-
- tb2 = tb1;
- tb1 = tb;
- tb = x2 * tb1 - tb2 + tn[0];
-
- return((mus_float_t)((tb - tb1 * cx) + (sin(x) * ub)));
- }
-
-
- mus_float_t mus_chebyshev_t_sum(mus_float_t x, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i >= 0; i--)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
- #if 0
- /* here is the trick to do odd Tn without doing the intervening evens: */
- (define (mus-chebyshev-odd-t-sum x n t2n)
- (let* ((b1 0.0)
- (b2 0.0)
- (cx1 (cos x))
- (cx (- (* 2 cx1 cx1) 1))
- (x2 (* 2.0 cx))
- (b (vct-ref t2n (- n 1))))
- (do ((i (- n 2) (1- i)))
- ((< i 0))
- (set! b2 b1)
- (set! b1 b)
- (set! b (- (+ (* b1 x2) (vct-ref t2n i)) b2)))
- (* cx1 (- b b1))))
-
- (with-sound ()
- (let ((t2n (vct 0.5 0.25 0.25))
- (x 0.0)
- (dx (hz->radians 10.0)))
- (do ((i 0 (+ i 1)))
- ((= i 22050))
- (outa i (mus-chebyshev-odd-t-sum x 3 t2n))
- (set! x (+ x dx)))))
- #endif
-
-
- mus_float_t mus_chebyshev_u_sum(mus_float_t x, int n, mus_float_t *un)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = cos(x);
- x2 = 2.0 * cx;
-
- /* Un calc */
- b = un[n - 1];
- for (i = n - 2; i > 0; i--)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + un[i];
- }
-
- return((mus_float_t)(sin(x) * b));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, b2, cx;
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- i = n - 2;
- while (i >= 4)
- {
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- for (; i >= 0; i--)
- {
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index_2(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i > 0;)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index_3(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i > 0;)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index_5(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i > 0;) /* this was >= ?? (also cases above) -- presumably a copy-and-paste typo? */
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_u_sum_with_index(mus_float_t x, mus_float_t index, int n, mus_float_t *un)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Un calc */
- b = un[n - 1];
- for (i = n - 2; i > 0; i--)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + un[i];
- }
-
- return((mus_float_t)(sin(x) * b + un[0])); /* don't drop the constant, 16-Jan-14 */
- }
-
- /* (with-sound () (let ((p (make-polywave 100 (list 0 0.5 1 -.2) mus-chebyshev-second-kind))) (do ((i 0 (+ i 1))) ((= i 1000)) (outa i (polywave p)))))
- */
-
- static mus_float_t polyw_second_2(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
-
- x = gen->phase; /* this order (as opposed to saving the full expr below) is much faster?! */
- gen->phase += (gen->freq + fm);
- return(gen->coeffs[1] * sin(x) + gen->coeffs[0]);
- }
-
-
- static mus_float_t polyw_first_1(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
-
- x = gen->phase;
- gen->phase += (gen->freq + fm);
- return(gen->index * cos(x));
- }
-
-
- static mus_float_t polyw_first_3(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x, cx;
- mus_float_t *tn;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- return((2.0 * cx * tn[2] + tn[1]) * cx - tn[2]);
-
- /* b = x2 * b1 - b2;, then return(b - b1 * cx)
- * but x2 = 2 * cx, so b1*(x2 - cx) -> b1 * cx
- * and the final recursion unrolls. The old code
- * (which thought tn[0] might not be 0.0) was:
- * cx = cos(x);
- * x2 = 2.0 * cx;
- * b = tn[2];
- * b2 = b1; -- but b1 is 0
- * b1 = b; -- b not used so this is tn[2]
- * b = x2 * b1 - b2 + tn[1]; -- b2 is 0.0
- * b2 = b1;
- * b1 = b;
- * b = x2 * b1 - b2 + tn[0];
- * return(b - b1 * cx);
- */
- }
-
- /* (with-sound () (let ((p (make-polywave 100 (list 1 .5 2 .25)))) (do ((i 0 (+ i 1))) ((= i 30000)) (outa i (polywave p))))) */
-
-
- static mus_float_t polyw_first_4(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x, x2, b, cx;
- mus_float_t *tn;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b = x2 * tn[3] + tn[2]; /* was -tn[2]! 19-Feb-14 */
- return((x2 * b - tn[3] + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_5(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[4];
- b = x2 * b1 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_6(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[5];
- b = x2 * b1 + tn[4];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_8(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[7];
- b = x2 * b1 + tn[6];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[5];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[4];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_11(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[10];
- b = x2 * b1 + tn[9];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[8];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[7];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[6];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[5];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[4];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_f1(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t cx;
- cx = gen->index * cos(gen->phase);
- gen->phase += (gen->freq + fm);
- return(cx * gen->coeffs[1] + gen->coeffs[0]);
- }
-
-
- static mus_float_t polyw_f2(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index_2(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_f3(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index_3(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_f5(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index_5(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_second(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_u_sum_with_index(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_second_5(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t *un;
- mus_float_t x, b, b1, cx;
-
- x = gen->phase;
- gen->phase += (gen->freq + fm);
- /* gen->n is 5 */
- un = gen->coeffs;
-
- /* this is a candidate for sincos, but gcc is already using it here! */
- cx = 2.0 * cos(x);
- b1 = cx * un[4] + un[3];
- b = cx * b1 + gen->index;
-
- return(sin(x) * (cx * b - b1 + un[1]));
- }
-
-
- static mus_float_t polyw_third(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_tu_sum(ph, gen->n, gen->coeffs, gen->ucoeffs));
- }
-
-
- mus_float_t mus_polywave(mus_any *ptr, mus_float_t fm)
- {
- /* changed to use recursion, rather than polynomial in x, 25-May-08
- * this algorithm taken from Mason and Handscomb, "Chebyshev Polynomials" p27
- */
- return((((pw *)ptr)->polyw)(ptr, fm));
- }
-
-
- mus_float_t mus_polywave_unmodulated(mus_any *ptr)
- {
- return(mus_polywave(ptr, 0.0));
- }
-
-
- static mus_float_t run_polywave(mus_any *ptr, mus_float_t fm, mus_float_t ignored) {return(mus_polywave(ptr, fm));}
-
-
- static char *describe_polywave(mus_any *ptr)
- {
- pw *gen = (pw *)ptr;
- char *str;
- char *describe_buffer;
- str = float_array_to_string(gen->coeffs, gen->n, 0);
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, coeffs[%d]: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- gen->n,
- str);
- free(str);
- return(describe_buffer);
- }
-
-
- static mus_float_t pw_set_index_and_func(mus_any *ptr, mus_float_t val)
- {
- pw *gen = (pw *)ptr;
- gen->index = val;
- if (gen->cheby_choice == MUS_CHEBYSHEV_FIRST_KIND)
- gen->polyw = polyw_first;
- else gen->polyw = polyw_second;
- return(val);
- }
-
-
- static mus_any_class POLYWAVE_CLASS = {
- MUS_POLYWAVE,
- (char *)S_polywave,
- &free_pw,
- &describe_polywave,
- &pw_equalp,
- &pw_data,
- &pw_set_data,
- &pw_n,
- &pw_set_n,
- &pw_freq,
- &pw_set_freq,
- &pw_phase,
- &pw_set_phase,
- &pw_index,
- &pw_set_index_and_func,
- &pw_increment,
- &pw_set_increment,
- &run_polywave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- &pw_xcoeff, &pw_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
- &pw_choice,
- &pw_ycoeff, &pw_set_ycoeff,
- &pw_data, &pw_udata,
- &pw_reset,
- 0, &pw_copy
- };
-
-
- mus_any *mus_make_polywave(mus_float_t frequency, mus_float_t *coeffs, int n, int cheby_choice)
- {
- pw *gen;
- gen = (pw *)malloc(sizeof(pw));
- gen->core = &POLYWAVE_CLASS;
- gen->phase = 0.0; /* cos used in cheby funcs above */
- gen->freq = mus_hz_to_radians(frequency);
- gen->coeffs = coeffs;
- gen->ucoeffs = NULL;
- gen->n = n;
- gen->index = 1.0;
- gen->cheby_choice = cheby_choice;
- if (cheby_choice != MUS_CHEBYSHEV_SECOND_KIND)
- {
- if (coeffs[0] == 0.0)
- {
- /* these also ignore gen->index (assumed to be 1.0) (leaving aside the first_1 case)
- * pw_set_index_and_func protects against that case
- */
- if (n == 2)
- {
- gen->polyw = polyw_first_1;
- gen->index = coeffs[1];
- }
- else
- {
- if (n == 3)
- gen->polyw = polyw_first_3;
- else
- {
- if (n == 4)
- gen->polyw = polyw_first_4;
- else
- {
- if (n == 5)
- gen->polyw = polyw_first_5;
- else
- {
- if (n == 6)
- gen->polyw = polyw_first_6;
- else
- {
- if (n == 8)
- gen->polyw = polyw_first_8;
- else
- {
- if (n == 11) /* a common case oddly enough */
- gen->polyw = polyw_first_11;
- else
- {
- if (((n - 1) % 5) == 0)
- gen->polyw = polyw_f5;
- else
- {
- if (((n - 1) % 3) == 0)
- gen->polyw = polyw_f3;
- else
- {
- if (((n - 1) % 2) == 0)
- gen->polyw = polyw_f2;
- else
- {
- /* lots of n=8 here */
- gen->polyw = polyw_first;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- else
- {
- if (n == 2)
- gen->polyw = polyw_f1;
- else
- {
- if (((n - 1) % 3) == 0)
- gen->polyw = polyw_f3;
- else
- {
- if (((n - 1) % 2) == 0)
- gen->polyw = polyw_f2;
- else gen->polyw = polyw_first;
- }
- }
- }
- }
- else
- {
- if ((n == 5) &&
- (coeffs[0] == 0.0))
- {
- gen->polyw = polyw_second_5;
- gen->index = coeffs[2] - coeffs[4];
- }
- else
- {
- if (n == 2)
- gen->polyw = polyw_second_2;
- else gen->polyw = polyw_second;
- }
- }
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_polywave_tu(mus_float_t frequency, mus_float_t *tcoeffs, mus_float_t *ucoeffs, int n)
- {
- pw *gen;
- gen = (pw *)malloc(sizeof(pw));
- gen->core = &POLYWAVE_CLASS;
- gen->phase = 0.0; /* cos used in cheby funcs above */
- gen->freq = mus_hz_to_radians(frequency);
- gen->coeffs = tcoeffs;
- gen->ucoeffs = ucoeffs;
- gen->n = n;
- gen->index = 1.0;
- gen->cheby_choice = MUS_CHEBYSHEV_BOTH_KINDS;
- gen->polyw = polyw_third;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_polywave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_POLYWAVE));
- }
-
-
-
- /* ---------------- polyshape ---------------- */
-
- static char *describe_polyshape(mus_any *ptr)
- {
- pw *gen = (pw *)ptr;
- char *str;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- str = float_array_to_string(gen->coeffs, gen->n, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, coeffs[%d]: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- gen->n,
- str);
- free(str);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_polyshape(mus_any *ptr, mus_float_t index, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t result;
- gen->index = index;
- result = mus_polynomial(gen->coeffs,
- index * cos(gen->phase),
- gen->n);
-
- if (gen->cheby_choice == MUS_CHEBYSHEV_SECOND_KIND)
- result *= sin(gen->phase);
-
- gen->phase += (gen->freq + fm);
- return(result);
- }
-
-
- mus_float_t mus_polyshape_unmodulated(mus_any *ptr, mus_float_t index)
- {
- pw *gen = (pw *)ptr;
- mus_float_t result;
- gen->index = index;
- result = mus_polynomial(gen->coeffs,
- index * cos(gen->phase),
- gen->n);
-
- if (gen->cheby_choice == MUS_CHEBYSHEV_SECOND_KIND)
- result *= sin(gen->phase);
-
- gen->phase += gen->freq;
- return(result);
- }
-
-
- static mus_any_class POLYSHAPE_CLASS = {
- MUS_POLYSHAPE,
- (char *)S_polyshape,
- &free_pw,
- &describe_polyshape,
- &pw_equalp,
- &pw_data,
- &pw_set_data,
- &pw_n,
- &pw_set_n,
- &pw_freq,
- &pw_set_freq,
- &pw_phase,
- &pw_set_phase,
- &pw_index, &pw_set_index,
- &pw_increment,
- &pw_set_increment,
- &mus_polyshape,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &pw_reset,
- 0, &pw_copy
- };
-
-
- mus_any *mus_make_polyshape(mus_float_t frequency, mus_float_t phase, mus_float_t *coeffs, int size, int cheby_choice)
- {
- mus_any *gen;
- gen = mus_make_polywave(frequency, coeffs, size, cheby_choice);
- gen->core = &POLYSHAPE_CLASS;
- pw_set_phase(gen, phase);
- return(gen);
- }
-
-
- bool mus_is_polyshape(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_POLYSHAPE));
- }
-
-
-
-
-
- /* ---------------- wave-train ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, phase;
- mus_float_t *wave; /* passed in from caller */
- mus_long_t wave_size;
- mus_float_t *out_data;
- mus_long_t out_data_size;
- mus_interp_t interp_type; /* "type" field exists in core -- avoid confusion */
- mus_float_t next_wave_time;
- mus_long_t out_pos;
- bool first_time;
- mus_float_t yn1;
- } wt;
-
-
- static mus_float_t wt_freq(mus_any *ptr) {return(((wt *)ptr)->freq);}
- static mus_float_t wt_set_freq(mus_any *ptr, mus_float_t val) {((wt *)ptr)->freq = val; return(val);}
-
- static mus_float_t wt_phase(mus_any *ptr) {return(fmod(((TWO_PI * ((wt *)ptr)->phase) / ((mus_float_t)((wt *)ptr)->wave_size)), TWO_PI));}
- static mus_float_t wt_set_phase(mus_any *ptr, mus_float_t val) {((wt *)ptr)->phase = (fmod(val, TWO_PI) * ((wt *)ptr)->wave_size) / TWO_PI; return(val);}
-
- static mus_long_t wt_length(mus_any *ptr) {return(((wt *)ptr)->wave_size);}
- static mus_long_t wt_set_length(mus_any *ptr, mus_long_t val) {if (val > 0) ((wt *)ptr)->wave_size = val; return(((wt *)ptr)->wave_size);}
-
- static int wt_interp_type(mus_any *ptr) {return((int)(((wt *)ptr)->interp_type));}
-
- static mus_float_t *wt_data(mus_any *ptr) {return(((wt *)ptr)->wave);}
- static mus_float_t *wt_set_data(mus_any *ptr, mus_float_t *data) {((wt *)ptr)->wave = data; return(data);}
-
- static mus_any *wt_copy(mus_any *ptr)
- {
- wt *g, *p;
- int bytes;
- p = (wt *)ptr;
- g = (wt *)malloc(sizeof(wt));
- memcpy((void *)g, (void *)ptr, sizeof(wt));
- bytes = g->out_data_size * sizeof(mus_float_t);
- g->out_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->out_data), (void *)(p->out_data), bytes);
- /* g->wave is caller's data */
- return((mus_any *)g);
- }
-
- static bool wt_equalp(mus_any *p1, mus_any *p2)
- {
- wt *w1 = (wt *)p1;
- wt *w2 = (wt *)p2;
- if (p1 == p2) return(true);
- return((w1) && (w2) &&
- (w1->core->type == w2->core->type) &&
- (w1->freq == w2->freq) &&
- (w1->phase == w2->phase) &&
- (w1->interp_type == w2->interp_type) &&
- (w1->wave_size == w2->wave_size) &&
- (w1->out_data_size == w2->out_data_size) &&
- (w1->out_pos == w2->out_pos) &&
- (clm_arrays_are_equal(w1->wave, w2->wave, w1->wave_size)) &&
- (clm_arrays_are_equal(w1->out_data, w2->out_data, w1->out_data_size)));
- }
-
- static char *describe_wt(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, size: %lld, interp: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_length(ptr),
- interp_type_to_string(wt_interp_type(ptr)));
- return(describe_buffer);
- }
-
-
- static mus_float_t mus_wave_train_any(mus_any *ptr, mus_float_t fm)
- {
- wt *gen = (wt *)ptr;
- mus_float_t result = 0.0;
-
- if (gen->out_pos < gen->out_data_size)
- result = gen->out_data[gen->out_pos];
- gen->out_pos++;
- if (gen->out_pos >= gen->next_wave_time)
- {
- mus_long_t i;
- mus_float_t *wave, *out_data;
- mus_long_t wave_size;
-
- wave = gen->wave;
- wave_size = gen->wave_size;
- out_data = gen->out_data;
-
- if (gen->out_pos < gen->out_data_size)
- {
- mus_long_t good_samps;
- good_samps = gen->out_data_size - gen->out_pos;
- memmove((void *)out_data, (void *)(out_data + gen->out_pos), good_samps * sizeof(mus_float_t));
- memset((void *)(out_data + good_samps), 0, gen->out_pos * sizeof(mus_float_t));
- }
- else memset((void *)out_data, 0, gen->out_data_size * sizeof(mus_float_t));
- if (gen->interp_type == MUS_INTERP_LINEAR)
- {
- /* gen->phase doesn't change, and i is an int, so we can precalculate the fractional part, etc
- */
- mus_float_t phase, frac_part;
- mus_long_t int_part;
-
- phase = gen->phase;
- if ((phase < 0.0) || (phase > wave_size))
- {
- phase = fmod((mus_float_t)phase, (mus_float_t)wave_size);
- if (phase < 0.0) phase += wave_size;
- }
-
- int_part = (mus_long_t)floor(phase);
- frac_part = phase - int_part;
- if (int_part == wave_size) int_part = 0;
-
- if (frac_part == 0.0)
- {
- mus_long_t p;
- for (i = 0, p = int_part; i < wave_size; i++, p++)
- {
- if (p == wave_size) p = 0;
- out_data[i] += wave[p];
- }
- }
- else
- {
- mus_long_t p, p1;
- for (i = 0, p = int_part, p1 = int_part + 1; i < wave_size; i++, p1++)
- {
- if (p1 == wave_size) p1 = 0;
- out_data[i] += (wave[p] + frac_part * (wave[p1] - wave[p]));
- p = p1;
- }
- }
- }
- else
- {
- for (i = 0; i < wave_size; i++)
- {
- gen->yn1 = mus_interpolate(gen->interp_type, gen->phase + i, wave, wave_size, gen->yn1);
- out_data[i] += gen->yn1;
- }
- }
- if (gen->first_time)
- {
- gen->first_time = false;
- gen->out_pos = (mus_long_t)(gen->phase); /* initial phase, but as an integer in terms of wave table size (gad...) */
- if (gen->out_pos >= wave_size)
- gen->out_pos = gen->out_pos % wave_size;
- result = out_data[gen->out_pos++];
- gen->next_wave_time = ((mus_float_t)sampling_rate / (gen->freq + fm));
- }
- else
- {
- gen->next_wave_time += (((mus_float_t)sampling_rate / (gen->freq + fm)) - gen->out_pos);
- gen->out_pos = 0;
- }
- }
- return(result);
- }
-
-
- mus_float_t mus_wave_train(mus_any *ptr, mus_float_t fm) {return(mus_wave_train_any(ptr, fm / w_rate));}
-
- mus_float_t mus_wave_train_unmodulated(mus_any *ptr) {return(mus_wave_train(ptr, 0.0));}
-
- static mus_float_t run_wave_train(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_wave_train_any(ptr, fm / w_rate));}
-
- static void free_wt(mus_any *p)
- {
- wt *ptr = (wt *)p;
- if (ptr->out_data)
- {
- free(ptr->out_data);
- ptr->out_data = NULL;
- }
- free(ptr);
- }
-
-
- static void wt_reset(mus_any *ptr)
- {
- wt *gen = (wt *)ptr;
- gen->phase = 0.0;
- memset((void *)(gen->out_data), 0, gen->out_data_size * sizeof(mus_float_t));
- gen->out_pos = gen->out_data_size;
- gen->next_wave_time = 0.0;
- gen->first_time = true;
- }
-
-
- static mus_any_class WAVE_TRAIN_CLASS = {
- MUS_WAVE_TRAIN,
- (char *)S_wave_train,
- &free_wt,
- &describe_wt,
- &wt_equalp,
- &wt_data,
- &wt_set_data,
- &wt_length,
- &wt_set_length,
- &wt_freq,
- &wt_set_freq,
- &wt_phase,
- &wt_set_phase,
- &fallback_scaler, 0,
- 0, 0,
- &run_wave_train,
- MUS_NOT_SPECIAL,
- NULL,
- &wt_interp_type,
- 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &wt_reset,
- 0, &wt_copy
- };
-
-
- mus_any *mus_make_wave_train(mus_float_t freq, mus_float_t phase, mus_float_t *wave, mus_long_t wave_size, mus_interp_t type)
- {
- wt *gen;
- gen = (wt *)malloc(sizeof(wt));
- gen->core = &WAVE_TRAIN_CLASS;
- gen->freq = freq;
- gen->phase = (wave_size * fmod(phase, TWO_PI)) / TWO_PI;
- gen->wave = wave;
- gen->wave_size = wave_size;
- gen->interp_type = type;
- gen->out_data_size = wave_size + 2;
- gen->out_data = (mus_float_t *)calloc(gen->out_data_size, sizeof(mus_float_t));
- gen->out_pos = gen->out_data_size;
- gen->next_wave_time = 0.0;
- gen->first_time = true;
- gen->yn1 = 0.0;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_wave_train(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_WAVE_TRAIN));
- }
-
-
-
-
- /* ---------------- delay, comb, notch, all-pass, moving-average, filtered-comb ---------------- */
-
- typedef struct dly {
- mus_any_class *core;
- unsigned int loc, size;
- bool zdly, line_allocated, filt_allocated;
- mus_float_t *line;
- unsigned int zloc, zsize;
- mus_float_t xscl, yscl, yn1, y1, norm;
- mus_interp_t type;
- mus_any *filt;
- struct dly *next;
- mus_float_t (*runf)(mus_any *gen, mus_float_t arg1, mus_float_t arg2);
- mus_float_t (*del)(mus_any *ptr, mus_float_t input); /* zdelay or normal tap */
- mus_float_t (*delt)(mus_any *ptr, mus_float_t input); /* just tick */
- mus_float_t (*delu)(mus_any *ptr, mus_float_t input); /* unmodulated */
- } dly;
-
-
-
- mus_float_t mus_delay_tick(mus_any *ptr, mus_float_t input)
- {
- return(((dly *)ptr)->delt(ptr, input));
- }
-
-
- mus_float_t mus_tap(mus_any *ptr, mus_float_t loc)
- {
- return(((dly *)ptr)->del(ptr, loc));
- }
-
-
- mus_float_t mus_delay_unmodulated(mus_any *ptr, mus_float_t input)
- {
- return(((dly *)ptr)->delu(ptr, input));
- }
-
-
- static mus_float_t ztap(mus_any *ptr, mus_float_t loc)
- {
- dly *gen = (dly *)ptr;
- /* this is almost always linear */
- if (gen->type == MUS_INTERP_LINEAR)
- return(mus_array_interp(gen->line, gen->zloc - loc, gen->zsize));
- gen->yn1 = mus_interpolate(gen->type, gen->zloc - loc, gen->line, gen->zsize, gen->yn1);
- return(gen->yn1);
- }
-
-
- static mus_float_t dtap(mus_any *ptr, mus_float_t loc)
- {
- dly *gen = (dly *)ptr;
- int taploc;
- if (gen->size == 0) return(gen->line[0]);
- if ((int)loc == 0) return(gen->line[gen->loc]);
- taploc = (int)(gen->loc - (int)loc) % gen->size;
- if (taploc < 0) taploc += gen->size;
- return(gen->line[taploc]);
- }
-
-
- mus_float_t mus_tap_unmodulated(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- return(gen->line[gen->loc]);
- }
-
-
- static mus_float_t zdelt(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->zsize) gen->loc = 0;
- gen->zloc++;
- if (gen->zloc >= gen->zsize) gen->zloc = 0;
- return(input);
- }
-
-
- static mus_float_t delt(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->size) gen->loc = 0;
- return(input);
- }
-
-
- mus_float_t mus_delay(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- mus_float_t result;
- dly *gen = (dly *)ptr;
- if ((gen->size == 0) && (pm < 1.0))
- result = pm * gen->line[0] + (1.0 - pm) * input;
- else result = mus_tap(ptr, pm);
- mus_delay_tick(ptr, input);
- return(result);
- }
-
-
- static mus_float_t zdelay_unmodulated(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->zloc];
- mus_delay_tick(ptr, input);
- return(result);
- }
-
-
- static mus_float_t delay_unmodulated_zero(mus_any *ptr, mus_float_t input)
- {
- return(input);
- }
-
-
- mus_float_t mus_delay_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->loc];
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
-
- static dly *dly_free_list = NULL;
-
- static void free_delay(mus_any *gen)
- {
- dly *ptr = (dly *)gen;
- if ((ptr->line) && (ptr->line_allocated)) free(ptr->line);
- if ((ptr->filt) && (ptr->filt_allocated)) mus_free(ptr->filt);
- /* free(ptr); */
- ptr->next = dly_free_list;
- dly_free_list = ptr;
- }
-
-
- static mus_any *dly_copy(mus_any *ptr)
- {
- dly *g, *p;
- mus_long_t bytes;
- p = (dly *)ptr;
- if (dly_free_list)
- {
- g = dly_free_list;
- dly_free_list = g->next;
- }
- else g = (dly *)malloc(sizeof(dly));
- memcpy((void *)g, (void *)ptr, sizeof(dly));
-
- bytes = g->size * sizeof(mus_float_t);
- g->line = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->line), (void *)(p->line), bytes);
- g->line_allocated = true;
-
- if (p->filt)
- {
- g->filt = mus_copy(p->filt);
- g->filt_allocated = true;
- }
- return((mus_any *)g);
- }
-
-
- static char *describe_delay(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s line[%u,%u, %s]: %s",
- mus_name(ptr),
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s line[%u, %s]: %s",
- mus_name(ptr),
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static bool delay_equalp(mus_any *p1, mus_any *p2)
- {
- dly *d1 = (dly *)p1;
- dly *d2 = (dly *)p2;
- if (p1 == p2) return(true);
- return((d1) && (d2) &&
- (d1->core->type == d2->core->type) &&
- (d1->size == d2->size) &&
- (d1->loc == d2->loc) &&
- (d1->zdly == d2->zdly) &&
- (d1->zloc == d2->zloc) &&
- (d1->zsize == d2->zsize) &&
- (d1->xscl == d2->xscl) &&
- (d1->yscl == d2->yscl) &&
- (d1->yn1 == d2->yn1) &&
- (d1->type == d2->type) &&
- (clm_arrays_are_equal(d1->line, d2->line, d1->size)));
- }
-
-
- static mus_long_t delay_length(mus_any *ptr)
- {
- dly *d = (dly *)ptr;
- if (d->size > 0) /* this is possible (not sure it's a good idea...) */
- return(d->size);
- return(d->zsize); /* maybe always use this? */
- }
-
-
- static mus_float_t delay_scaler(mus_any *ptr) {return(((dly *)ptr)->xscl);}
- static mus_float_t delay_set_scaler(mus_any *ptr, mus_float_t val) {((dly *)ptr)->xscl = val; return(val);}
-
- static mus_float_t delay_fb(mus_any *ptr) {return(((dly *)ptr)->yscl);}
- static mus_float_t delay_set_fb(mus_any *ptr, mus_float_t val) {((dly *)ptr)->yscl = val; return(val);}
-
- static int delay_interp_type(mus_any *ptr) {return((int)(((dly *)ptr)->type));}
- static mus_long_t delay_loc(mus_any *ptr){return((mus_long_t)(((dly *)ptr)->loc));}
- static mus_float_t *delay_data(mus_any *ptr) {return(((dly *)ptr)->line);}
- static mus_float_t *delay_set_data(mus_any *ptr, mus_float_t *val)
- {
- dly *gen = (dly *)ptr;
- if (gen->line_allocated) {free(gen->line); gen->line_allocated = false;}
- gen->line = val;
- return(val);
- }
-
-
- static mus_long_t delay_set_length(mus_any *ptr, mus_long_t val)
- {
- dly *gen = (dly *)ptr;
- if (val > 0)
- {
- unsigned int old_size;
- old_size = gen->size;
- gen->size = (unsigned int)val;
- if (gen->size < old_size)
- {
- if (gen->loc > gen->size) gen->loc = 0;
- gen->zdly = false; /* otherwise too many ways to screw up */
- }
- }
- return((mus_long_t)(gen->size));
- }
-
-
- bool mus_is_tap(mus_any *gen)
- {
- return((gen) &&
- (gen->core->extended_type == MUS_DELAY_LINE));
- }
-
-
- static void delay_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- gen->loc = 0;
- gen->zloc = 0;
- gen->yn1 = 0.0;
- memset((void *)(gen->line), 0, gen->zsize * sizeof(mus_float_t));
- }
-
-
- static mus_any_class DELAY_CLASS = {
- MUS_DELAY,
- (char *)S_delay,
- &free_delay,
- &describe_delay,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_delay,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_delay(int size, mus_float_t *preloaded_line, int line_size, mus_interp_t type)
- {
- /* if preloaded_line null, allocated locally.
- * if size == line_size, normal (non-interpolating) delay
- * in clm2xen.c, if size=0 and max-size unset, max-size=1 (line_size here)
- */
- dly *gen;
- if (dly_free_list)
- {
- gen = dly_free_list;
- dly_free_list = gen->next;
- }
- else gen = (dly *)malloc(sizeof(dly));
- gen->core = &DELAY_CLASS;
- gen->loc = 0;
- gen->size = size;
- gen->zsize = line_size;
- gen->zdly = ((line_size != size) || (type != MUS_INTERP_NONE));
- if (gen->zdly)
- {
- gen->del = ztap;
- gen->delt = zdelt;
- if (gen->size == 0)
- gen->delu = delay_unmodulated_zero;
- else gen->delu = zdelay_unmodulated;
- }
- else
- {
- gen->del = dtap;
- gen->delt = delt;
- if (gen->size == 0)
- gen->delu = delay_unmodulated_zero;
- else gen->delu = mus_delay_unmodulated_noz;
- }
- gen->type = type;
- if (preloaded_line)
- {
- gen->line = preloaded_line;
- gen->line_allocated = false;
- }
- else
- {
- gen->line = (mus_float_t *)calloc((line_size <= 0) ? 1 : line_size, sizeof(mus_float_t));
- gen->line_allocated = true;
- }
- gen->zloc = line_size - size;
- gen->filt = NULL;
- gen->filt_allocated = false;
- gen->xscl = 0.0;
- gen->yscl = 0.0;
- gen->yn1 = 0.0;
- gen->runf = NULL;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_delay(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_DELAY));
- }
-
-
- /* ---------------- comb ---------------- */
-
- mus_float_t mus_comb(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- return(mus_delay(ptr, input + (gen->yscl * mus_tap(ptr, pm)), pm));
- /* mus.lisp has 0 in place of the final pm -- the question is whether the delay
- should interpolate as well as the tap. There is a subtle difference in
- output (the pm case is low-passed by the interpolation ("average")),
- but I don't know if there's a standard here, or what people expect.
- We're doing the outer-level interpolation in notch and all-pass.
- Should mus.lisp be changed?
- */
- else return(mus_delay_unmodulated(ptr, input + (gen->line[gen->loc] * gen->yscl)));
- }
-
-
- mus_float_t mus_comb_unmodulated(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- return(mus_delay_unmodulated(ptr, input + (gen->line[gen->zloc] * gen->yscl)));
- return(mus_delay_unmodulated(ptr, input + (gen->line[gen->loc] * gen->yscl)));
- }
-
-
- mus_float_t mus_comb_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
-
- result = gen->line[gen->loc];
- gen->line[gen->loc] = input + (result * gen->yscl);
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
-
- return(result);
- }
-
-
- static char *describe_comb(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u,%u, %s]: %s",
- mus_name(ptr),
- gen->yscl,
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u, %s]: %s",
- mus_name(ptr),
- gen->yscl,
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class COMB_CLASS = {
- MUS_COMB,
- (char *)S_comb,
- &free_delay,
- &describe_comb,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_comb,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_comb(mus_float_t scaler, int size, mus_float_t *line, int line_size, mus_interp_t type)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, line_size, type);
- if (gen)
- {
- gen->core = &COMB_CLASS;
- gen->yscl = scaler;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- bool mus_is_comb(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_COMB));
- }
-
-
-
- /* ---------------- comb-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_any **gens;
- mus_float_t (*cmbf)(mus_any *ptr, mus_float_t input);
- } cmb_bank;
-
-
- static void free_comb_bank(mus_any *ptr)
- {
- cmb_bank *f = (cmb_bank *)ptr;
- if (f->gens) {free(f->gens); f->gens = NULL;}
- free(ptr);
- }
-
-
- static mus_any *cmb_bank_copy(mus_any *ptr)
- {
- cmb_bank *g, *p;
- int i;
-
- p = (cmb_bank *)ptr;
- g = (cmb_bank *)malloc(sizeof(cmb_bank));
- memcpy((void *)g, (void *)ptr, sizeof(cmb_bank));
- g->gens = (mus_any **)malloc(p->size * sizeof(mus_any *));
- for (i = 0; i < p->size; i++)
- g->gens[i] = mus_copy(p->gens[i]);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_comb_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_comb_bank(ptr, input));
- }
-
-
- static mus_long_t comb_bank_length(mus_any *ptr)
- {
- return(((cmb_bank *)ptr)->size);
- }
-
-
- static void comb_bank_reset(mus_any *ptr)
- {
- cmb_bank *f = (cmb_bank *)ptr;
- int i;
- for (i = 0; i < f->size; i++)
- mus_reset(f->gens[i]);
- }
-
-
- static bool comb_bank_equalp(mus_any *p1, mus_any *p2)
- {
- cmb_bank *f1 = (cmb_bank *)p1;
- cmb_bank *f2 = (cmb_bank *)p2;
- int i, size;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- size = f1->size;
-
- for (i = 0; i < size; i++)
- if (!delay_equalp(f1->gens[i], f2->gens[i]))
- return(false);
-
- /* now check the locals... */
- return(true);
- }
-
-
- static char *describe_comb_bank(mus_any *ptr)
- {
- cmb_bank *gen = (cmb_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class COMB_BANK_CLASS = {
- MUS_COMB_BANK,
- (char *)S_comb_bank,
- &free_comb_bank,
- &describe_comb_bank,
- &comb_bank_equalp,
- 0, 0,
- &comb_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_comb_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &comb_bank_reset,
- 0, &cmb_bank_copy
- };
-
-
- static mus_float_t comb_bank_any(mus_any *combs, mus_float_t inval)
- {
- int i;
- mus_float_t sum = 0.0;
- cmb_bank *c = (cmb_bank *)combs;
- for (i = 0; i < c->size; i++)
- sum += mus_comb_unmodulated_noz(c->gens[i], inval);
- return(sum);
- }
-
- static mus_float_t comb_bank_4(mus_any *combs, mus_float_t inval)
- {
- cmb_bank *c = (cmb_bank *)combs;
- mus_any **gs;
- gs = c->gens;
- return(mus_comb_unmodulated_noz(gs[0], inval) +
- mus_comb_unmodulated_noz(gs[1], inval) +
- mus_comb_unmodulated_noz(gs[2], inval) +
- mus_comb_unmodulated_noz(gs[3], inval));
- }
-
- static mus_float_t comb_bank_6(mus_any *combs, mus_float_t inval)
- {
- cmb_bank *c = (cmb_bank *)combs;
- mus_any **gs;
- gs = c->gens;
- return(mus_comb_unmodulated_noz(gs[0], inval) +
- mus_comb_unmodulated_noz(gs[1], inval) +
- mus_comb_unmodulated_noz(gs[2], inval) +
- mus_comb_unmodulated_noz(gs[3], inval) +
- mus_comb_unmodulated_noz(gs[4], inval) +
- mus_comb_unmodulated_noz(gs[5], inval));
- }
-
-
- mus_any *mus_make_comb_bank(int size, mus_any **combs)
- {
- cmb_bank *gen;
- int i;
-
- gen = (cmb_bank *)malloc(sizeof(cmb_bank));
- gen->core = &COMB_BANK_CLASS;
- gen->size = size;
-
- gen->gens = (mus_any **)malloc(size * sizeof(mus_any *));
- for (i = 0; i < size; i++)
- gen->gens[i] = combs[i];
-
- if (size == 4)
- gen->cmbf = comb_bank_4;
- else
- {
- if (size == 6)
- gen->cmbf = comb_bank_6;
- else gen->cmbf = comb_bank_any;
- }
-
- return((mus_any *)gen);
- }
-
- bool mus_is_comb_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_COMB_BANK));
- }
-
- mus_float_t mus_comb_bank(mus_any *combs, mus_float_t inval)
- {
- cmb_bank *gen = (cmb_bank *)combs;
- return((gen->cmbf)(combs, inval));
- }
-
-
-
-
- /* ---------------- notch ---------------- */
-
- static char *describe_notch(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u,%u, %s]: %s",
- mus_name(ptr),
- gen->xscl,
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u, %s]: %s",
- mus_name(ptr),
- gen->xscl,
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class NOTCH_CLASS = {
- MUS_NOTCH,
- (char *)S_notch,
- &free_delay,
- &describe_notch,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- 0, 0,
- &mus_notch,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_float_t mus_notch(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- dly *gen = (dly *)ptr;
- return((input * gen->xscl) + mus_delay(ptr, input, pm));
- }
-
-
- mus_float_t mus_notch_unmodulated(mus_any *ptr, mus_float_t input)
- {
- return((input * ((dly *)ptr)->xscl) + mus_delay_unmodulated(ptr, input));
- }
-
- #if 0
- static mus_float_t mus_notch_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->loc] + (input * gen->xscl);
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
- #endif
-
- bool mus_is_notch(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NOTCH));
- }
-
-
- mus_any *mus_make_notch(mus_float_t scaler, int size, mus_float_t *line, int line_size, mus_interp_t type)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, line_size, type);
- if (gen)
- {
- gen->core = &NOTCH_CLASS;
- gen->xscl = scaler;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_float_t mus_all_pass(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- mus_float_t din;
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- din = input + (gen->yscl * mus_tap(ptr, pm));
- else din = input + (gen->yscl * gen->line[gen->loc]);
- return(mus_delay(ptr, din, pm) + (gen->xscl * din));
- }
-
-
- mus_float_t mus_all_pass_unmodulated(mus_any *ptr, mus_float_t input)
- {
- mus_float_t din;
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- din = input + (gen->yscl * gen->line[gen->zloc]);
- else din = input + (gen->yscl * gen->line[gen->loc]);
- return(mus_delay_unmodulated(ptr, din) + (gen->xscl * din));
- }
-
-
- mus_float_t mus_all_pass_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- mus_float_t result, din;
- dly *gen = (dly *)ptr;
- unsigned int loc;
- loc = gen->loc++;
- din = input + (gen->yscl * gen->line[loc]);
- result = gen->line[loc] + (gen->xscl * din);
- gen->line[loc] = din;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
-
-
- bool mus_is_all_pass(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ALL_PASS));
- }
-
-
- static char *describe_all_pass(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s feedback: %.3f, feedforward: %.3f, line[%u,%u, %s]:%s",
- mus_name(ptr),
- gen->yscl,
- gen->xscl,
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s feedback: %.3f, feedforward: %.3f, line[%u, %s]:%s",
- mus_name(ptr),
- gen->yscl,
- gen->xscl,
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class ALL_PASS_CLASS = {
- MUS_ALL_PASS,
- (char *)S_all_pass,
- &free_delay,
- &describe_all_pass,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_all_pass,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_all_pass(mus_float_t backward, mus_float_t forward, int size, mus_float_t *line, int line_size, mus_interp_t type)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, line_size, type);
- if (gen)
- {
- gen->core = &ALL_PASS_CLASS;
- gen->xscl = forward;
- gen->yscl = backward;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- /* ---------------- all_pass-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_any **gens;
- mus_float_t (*apf)(mus_any *ptr, mus_float_t input);
- } allp_bank;
-
-
- static void free_all_pass_bank(mus_any *ptr)
- {
- allp_bank *f = (allp_bank *)ptr;
- if (f->gens) {free(f->gens); f->gens = NULL;}
- free(ptr);
- }
-
-
- static mus_any *allp_bank_copy(mus_any *ptr)
- {
- allp_bank *g, *p;
- int i;
-
- p = (allp_bank *)ptr;
- g = (allp_bank *)malloc(sizeof(allp_bank));
- memcpy((void *)g, (void *)ptr, sizeof(allp_bank));
- g->gens = (mus_any **)malloc(p->size * sizeof(mus_any *));
- for (i = 0; i < p->size; i++)
- g->gens[i] = mus_copy(p->gens[i]);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_all_pass_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_all_pass_bank(ptr, input));
- }
-
-
- static mus_long_t all_pass_bank_length(mus_any *ptr)
- {
- return(((allp_bank *)ptr)->size);
- }
-
-
- static void all_pass_bank_reset(mus_any *ptr)
- {
- allp_bank *f = (allp_bank *)ptr;
- int i;
- for (i = 0; i < f->size; i++)
- mus_reset(f->gens[i]);
- }
-
-
- static bool all_pass_bank_equalp(mus_any *p1, mus_any *p2)
- {
- allp_bank *f1 = (allp_bank *)p1;
- allp_bank *f2 = (allp_bank *)p2;
- int i, size;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- size = f1->size;
-
- for (i = 0; i < size; i++)
- if (!delay_equalp(f1->gens[i], f2->gens[i]))
- return(false);
-
- return(true);
- }
-
-
- static char *describe_all_pass_bank(mus_any *ptr)
- {
- allp_bank *gen = (allp_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class ALL_PASS_BANK_CLASS = {
- MUS_ALL_PASS_BANK,
- (char *)S_all_pass_bank,
- &free_all_pass_bank,
- &describe_all_pass_bank,
- &all_pass_bank_equalp,
- 0, 0,
- &all_pass_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_all_pass_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &all_pass_bank_reset,
- 0, &allp_bank_copy
- };
-
-
- static mus_float_t all_pass_bank_3(mus_any *all_passes, mus_float_t inval)
- {
- allp_bank *c = (allp_bank *)all_passes;
- mus_any **gs;
- gs = c->gens;
- return(mus_all_pass_unmodulated_noz(gs[2], mus_all_pass_unmodulated_noz(gs[1], mus_all_pass_unmodulated_noz(gs[0], inval))));
- }
-
- static mus_float_t all_pass_bank_4(mus_any *all_passes, mus_float_t inval)
- {
- allp_bank *c = (allp_bank *)all_passes;
- mus_any **gs;
- gs = c->gens;
- return(mus_all_pass_unmodulated_noz(gs[3], mus_all_pass_unmodulated_noz(gs[2], mus_all_pass_unmodulated_noz(gs[1], mus_all_pass_unmodulated_noz(gs[0], inval)))));
- }
-
- static mus_float_t all_pass_bank_any(mus_any *all_passs, mus_float_t inval)
- {
- int i;
- mus_float_t sum = inval;
- allp_bank *c = (allp_bank *)all_passs;
- for (i = 0; i < c->size; i++)
- sum = mus_all_pass_unmodulated_noz(c->gens[i], sum);
- return(sum);
- }
-
-
- mus_any *mus_make_all_pass_bank(int size, mus_any **all_passs)
- {
- allp_bank *gen;
- int i;
-
- gen = (allp_bank *)malloc(sizeof(allp_bank));
- gen->core = &ALL_PASS_BANK_CLASS;
- gen->size = size;
-
- gen->gens = (mus_any **)malloc(size * sizeof(mus_any *));
- for (i = 0; i < size; i++)
- gen->gens[i] = all_passs[i];
-
- if (size == 3)
- gen->apf = all_pass_bank_3;
- else
- {
- if (size == 4)
- gen->apf = all_pass_bank_4;
- else gen->apf = all_pass_bank_any;
- }
-
- return((mus_any *)gen);
- }
-
-
- bool mus_is_all_pass_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ALL_PASS_BANK));
- }
-
-
- mus_float_t mus_all_pass_bank(mus_any *all_passes, mus_float_t inval)
- {
- allp_bank *gen = (allp_bank *)all_passes;
- return((gen->apf)(all_passes, inval));
- }
-
-
-
-
- /* ---------------- moving-average ---------------- */
-
- bool mus_is_moving_average(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVING_AVERAGE));
- }
-
-
- mus_float_t mus_moving_average(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t output;
- output = mus_delay_unmodulated_noz(ptr, input);
- gen->xscl += (input - output);
- return(gen->xscl * gen->yscl); /* xscl=sum, yscl=1/n */
- }
-
-
- static mus_float_t run_mus_moving_average(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_moving_average(ptr, input));}
-
-
- static void moving_average_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- delay_reset(ptr);
- gen->xscl = 0.0;
- }
-
-
- static char *describe_moving_average(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %.3f, line[%u]:%s",
- mus_name(ptr),
- gen->xscl * gen->yscl,
- gen->size,
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class MOVING_AVERAGE_CLASS = {
- MUS_MOVING_AVERAGE,
- (char *)S_moving_average,
- &free_delay,
- &describe_moving_average,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &run_mus_moving_average,
- MUS_DELAY_LINE,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &moving_average_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_moving_average(int size, mus_float_t *line)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, size, MUS_INTERP_NONE);
- if (gen)
- {
- int i;
- gen->core = &MOVING_AVERAGE_CLASS;
- gen->xscl = 0.0;
- for (i = 0; i < size; i++)
- gen->xscl += gen->line[i];
- gen->yscl = 1.0 / (mus_float_t)size;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
- mus_any *mus_make_moving_average_with_initial_sum(int size, mus_float_t *line, mus_float_t sum)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, size, MUS_INTERP_NONE);
- if (gen)
- {
- gen->core = &MOVING_AVERAGE_CLASS;
- gen->xscl = sum;
- gen->yscl = 1.0 / (mus_float_t)size;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- /* -------- moving-max -------- */
-
- bool mus_is_moving_max(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVING_MAX));
- }
-
-
- mus_float_t mus_moving_max(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t output, abs_input;
-
- abs_input = fabs(input);
- output = mus_delay_unmodulated_noz(ptr, abs_input);
- if (abs_input >= gen->xscl)
- gen->xscl = abs_input;
- else
- {
- if (output >= gen->xscl)
- {
- unsigned int i;
- for (i = 0; i < gen->size; i++)
- if (gen->line[i] > abs_input)
- abs_input = gen->line[i];
- gen->xscl = abs_input;
- }
- }
- return(gen->xscl);
- }
-
- static mus_float_t run_mus_moving_max(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_moving_max(ptr, input));}
-
-
- static void moving_max_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- delay_reset(ptr);
- gen->xscl = 0.0;
- }
-
-
- static char *describe_moving_max(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %.3f, line[%u]:%s",
- mus_name(ptr),
- gen->xscl,
- gen->size,
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class MOVING_MAX_CLASS = {
- MUS_MOVING_MAX,
- (char *)S_moving_max,
- &free_delay,
- &describe_moving_max,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &run_mus_moving_max,
- MUS_DELAY_LINE,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &moving_max_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_moving_max(int size, mus_float_t *line)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, size, MUS_INTERP_NONE);
- if (gen)
- {
- int i;
- gen->core = &MOVING_MAX_CLASS;
- gen->xscl = 0.0;
- for (i = 0; i < size; i++)
- if (fabs(gen->line[i]) > gen->xscl)
- gen->xscl = fabs(gen->line[i]);
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- /* -------- moving-norm -------- */
-
- bool mus_is_moving_norm(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVING_NORM));
- }
-
-
- mus_float_t mus_moving_norm(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t output, abs_input;
-
- abs_input = fabs(input);
- if (abs_input < 0.01) abs_input = 0.01; /* 0.01 sets the max norm output (~100) -- maybe a parameter to make-norm? */
- output = mus_moving_max(ptr, abs_input);
- gen->y1 = output + (gen->yscl * gen->y1);
-
- return(gen->norm / gen->y1);
- }
-
-
- static mus_float_t run_mus_moving_norm(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_moving_norm(ptr, input));}
-
-
- static void moving_norm_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- delay_reset(ptr);
- gen->xscl = 0.0;
- gen->y1 = 0.0;
- }
-
-
- static char *describe_moving_norm(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s, max %.3f, y1 %.3f, weight %.3f, line[%u]:%s",
- mus_name(ptr),
- gen->xscl, gen->y1, gen->yscl,
- gen->size,
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class MOVING_NORM_CLASS = {
- MUS_MOVING_NORM,
- (char *)S_moving_norm,
- &free_delay,
- &describe_moving_norm,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &run_mus_moving_norm,
- MUS_DELAY_LINE,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &moving_norm_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_moving_norm(int size, mus_float_t *line, mus_float_t norm)
- {
- dly *gen;
- gen = (dly *)mus_make_moving_max(size, line);
- if (gen)
- {
- gen->core = &MOVING_NORM_CLASS;
-
- gen->yscl = (mus_float_t)size / (size + 1.0); /* one-pole -b1 = -feedback so this is a lowpass filter */
- gen->norm = norm * (size + 1.0);
- gen->yn1 = 1.0 / size;
- gen->y1 = size + 1.0;
-
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
-
-
-
- /* ---------------------------------------- filtered-comb ---------------------------------------- */
-
- static void filtered_comb_reset(mus_any *ptr)
- {
- dly *fc = (dly *)ptr;
- delay_reset(ptr);
- mus_reset(fc->filt);
- }
-
-
- static bool filtered_comb_equalp(mus_any *p1, mus_any *p2)
- {
- return((delay_equalp(p1, p2)) &&
- (mus_equalp(((dly *)p1)->filt,
- ((dly *)p2)->filt)));
- }
-
-
- static char *describe_filtered_comb(mus_any *ptr)
- {
- char *comb_str, *filter_str, *res;
- int len;
- comb_str = describe_comb(ptr);
- filter_str = mus_describe(((dly *)ptr)->filt);
- len = strlen(comb_str) + strlen(filter_str) + 64;
- res = (char *)malloc(len * sizeof(char));
- snprintf(res, len, "%s, filter: [%s]", comb_str, filter_str);
- if (comb_str) free(comb_str);
- if (filter_str) free(filter_str);
- return(res);
- }
-
-
- bool mus_is_filtered_comb(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILTERED_COMB));
- }
-
-
- mus_float_t mus_filtered_comb(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- dly *fc = (dly *)ptr;
- if (fc->zdly)
- return(mus_delay(ptr,
- input + (fc->yscl *
- fc->runf(fc->filt,
- mus_tap(ptr, pm),
- 0.0)),
- pm));
- return(mus_delay_unmodulated(ptr,
- input + (fc->yscl *
- fc->runf(fc->filt, fc->line[fc->loc], 0.0))));
- }
-
-
- mus_float_t mus_filtered_comb_unmodulated(mus_any *ptr, mus_float_t input)
- {
- dly *fc = (dly *)ptr;
- return(mus_delay_unmodulated(ptr,
- input + (fc->yscl *
- fc->runf(fc->filt, fc->line[fc->loc], 0.0))));
- }
-
-
- static mus_any_class FILTERED_COMB_CLASS = {
- MUS_FILTERED_COMB,
- (char *)S_filtered_comb,
- &free_delay,
- &describe_filtered_comb,
- &filtered_comb_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_filtered_comb,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &filtered_comb_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_filtered_comb(mus_float_t scaler, int size, mus_float_t *line, int line_size, mus_interp_t type, mus_any *filt)
- {
- dly *fc;
- fc = (dly *)mus_make_comb(scaler, size, line, line_size, type);
- if (fc)
- {
- fc->core = &FILTERED_COMB_CLASS;
- if (filt)
- fc->filt = filt;
- else
- {
- fc->filt = mus_make_one_zero(1.0, 0.0);
- fc->filt_allocated = true;
- }
- fc->runf = mus_run_function(fc->filt);
- return((mus_any *)fc);
- }
- else return(NULL);
- }
-
-
- /* ---------------- filtered-comb-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_any **gens;
- mus_float_t (*cmbf)(mus_any *ptr, mus_float_t input);
- } fltcmb_bank;
-
-
- static void free_filtered_comb_bank(mus_any *ptr)
- {
- fltcmb_bank *f = (fltcmb_bank *)ptr;
- if (f->gens) {free(f->gens); f->gens = NULL;}
- free(ptr);
- }
-
-
- static mus_any *fltcmb_bank_copy(mus_any *ptr)
- {
- fltcmb_bank *g, *p;
- int i;
-
- p = (fltcmb_bank *)ptr;
- g = (fltcmb_bank *)malloc(sizeof(fltcmb_bank));
- memcpy((void *)g, (void *)ptr, sizeof(fltcmb_bank));
- g->gens = (mus_any **)malloc(p->size * sizeof(mus_any *));
- for (i = 0; i < p->size; i++)
- g->gens[i] = mus_copy(p->gens[i]);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_filtered_comb_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_filtered_comb_bank(ptr, input));
- }
-
-
- static mus_long_t filtered_comb_bank_length(mus_any *ptr)
- {
- return(((fltcmb_bank *)ptr)->size);
- }
-
-
- static void filtered_comb_bank_reset(mus_any *ptr)
- {
- fltcmb_bank *f = (fltcmb_bank *)ptr;
- int i;
- for (i = 0; i < f->size; i++)
- mus_reset(f->gens[i]);
- }
-
-
- static bool filtered_comb_bank_equalp(mus_any *p1, mus_any *p2)
- {
- fltcmb_bank *f1 = (fltcmb_bank *)p1;
- fltcmb_bank *f2 = (fltcmb_bank *)p2;
- int i, size;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- size = f1->size;
-
- for (i = 0; i < size; i++)
- if (!filtered_comb_equalp(f1->gens[i], f2->gens[i]))
- return(false);
-
- return(true);
- }
-
-
- static char *describe_filtered_comb_bank(mus_any *ptr)
- {
- fltcmb_bank *gen = (fltcmb_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class FILTERED_COMB_BANK_CLASS = {
- MUS_FILTERED_COMB_BANK,
- (char *)S_filtered_comb_bank,
- &free_filtered_comb_bank,
- &describe_filtered_comb_bank,
- &filtered_comb_bank_equalp,
- 0, 0,
- &filtered_comb_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_filtered_comb_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &filtered_comb_bank_reset,
- 0, &fltcmb_bank_copy
- };
-
-
- static mus_float_t filtered_comb_one_zero(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->loc];
- gen->line[gen->loc] = input + mus_one_zero(gen->filt, result); /* gen->yscl folded into one_zero coeffs via smp_scl */
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
-
-
- static mus_float_t filtered_comb_bank_8(mus_any *combs, mus_float_t inval)
- {
- fltcmb_bank *c = (fltcmb_bank *)combs;
- mus_any **gs;
- gs = c->gens;
- return(filtered_comb_one_zero(gs[0], inval) +
- filtered_comb_one_zero(gs[1], inval) +
- filtered_comb_one_zero(gs[2], inval) +
- filtered_comb_one_zero(gs[3], inval) +
- filtered_comb_one_zero(gs[4], inval) +
- filtered_comb_one_zero(gs[5], inval) +
- filtered_comb_one_zero(gs[6], inval) +
- filtered_comb_one_zero(gs[7], inval));
- }
-
- static mus_float_t filtered_comb_bank_any(mus_any *filtered_combs, mus_float_t inval)
- {
- int i;
- mus_float_t sum = 0.0;
- fltcmb_bank *c = (fltcmb_bank *)filtered_combs;
- for (i = 0; i < c->size; i++)
- sum += mus_filtered_comb_unmodulated(c->gens[i], inval);
- return(sum);
- }
-
- static void smp_scl(mus_any *ptr, mus_float_t scl);
-
- mus_any *mus_make_filtered_comb_bank(int size, mus_any **filtered_combs)
- {
- fltcmb_bank *gen;
- int i;
- bool zdly = false, oz = true;
-
- gen = (fltcmb_bank *)malloc(sizeof(fltcmb_bank));
- gen->core = &FILTERED_COMB_BANK_CLASS;
- gen->size = size;
-
- gen->gens = (mus_any **)malloc(size * sizeof(mus_any *));
- for (i = 0; i < size; i++)
- {
- gen->gens[i] = filtered_combs[i];
- zdly = (zdly) || (((dly *)(filtered_combs[i]))->zdly);
- oz = (oz) && (mus_is_one_zero(((dly *)(filtered_combs[i]))->filt));
- }
-
- if ((size == 8) &&
- (oz) &&
- (!zdly))
- {
- gen->cmbf = filtered_comb_bank_8;
- for (i = 0; i < 8; i++)
- {
- dly *d;
- d = (dly *)gen->gens[i];
- smp_scl(d->filt, d->yscl);
- }
- }
- else gen->cmbf = filtered_comb_bank_any;
-
- return((mus_any *)gen);
- }
-
-
- bool mus_is_filtered_comb_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILTERED_COMB_BANK));
- }
-
-
- mus_float_t mus_filtered_comb_bank(mus_any *filtered_combs, mus_float_t inval)
- {
- fltcmb_bank *gen = (fltcmb_bank *)filtered_combs;
- return((gen->cmbf)(filtered_combs, inval));
- }
-
-
- mus_any *mus_bank_generator(mus_any *g, int i)
- {
- if (mus_is_comb_bank(g))
- return(((cmb_bank *)g)->gens[i]);
- if (mus_is_all_pass_bank(g))
- return(((allp_bank *)g)->gens[i]);
- if (mus_is_filtered_comb_bank(g))
- return(((fltcmb_bank *)g)->gens[i]);
- return(NULL);
- }
-
-
-
-
- /* ---------------- sawtooth et al ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t current_value;
- mus_float_t freq, phase, base, width;
- } sw;
-
-
- static void free_sw(mus_any *ptr) {free(ptr);}
-
- static mus_any *sw_copy(mus_any *ptr)
- {
- sw *g;
- g = (sw *)malloc(sizeof(sw));
- memcpy((void *)g, (void *)ptr, sizeof(sw));
- return((mus_any *)g);
- }
-
-
- mus_float_t mus_sawtooth_wave(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
- result = gen->current_value;
- gen->phase += (gen->freq + fm);
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- }
- gen->current_value = gen->base * (gen->phase - M_PI);
- return(result);
- }
-
-
- static mus_float_t run_sawtooth_wave(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_sawtooth_wave(ptr, fm));}
-
- bool mus_is_sawtooth_wave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SAWTOOTH_WAVE));
- }
-
-
- static mus_float_t sw_freq(mus_any *ptr) {return(mus_radians_to_hz(((sw *)ptr)->freq));}
- static mus_float_t sw_set_freq(mus_any *ptr, mus_float_t val) {((sw *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t sw_increment(mus_any *ptr) {return(((sw *)ptr)->freq);}
- static mus_float_t sw_set_increment(mus_any *ptr, mus_float_t val) {((sw *)ptr)->freq = val; return(val);}
-
- static mus_float_t sw_phase(mus_any *ptr) {return(fmod(((sw *)ptr)->phase, TWO_PI));}
- static mus_float_t sw_set_phase(mus_any *ptr, mus_float_t val) {((sw *)ptr)->phase = val; return(val);}
-
- static mus_float_t sw_width(mus_any *ptr) {return((((sw *)ptr)->width) / ( 2 * M_PI));}
- static mus_float_t sw_set_width(mus_any *ptr, mus_float_t val) {((sw *)ptr)->width = (2 * M_PI * val); return(val);}
-
- static mus_float_t sawtooth_scaler(mus_any *ptr) {return(((sw *)ptr)->base * M_PI);}
- static mus_float_t sawtooth_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = val / M_PI; return(val);}
-
-
- static bool sw_equalp(mus_any *p1, mus_any *p2)
- {
- sw *s1, *s2;
- s1 = (sw *)p1;
- s2 = (sw *)p2;
- return((p1 == p2) ||
- ((s1) && (s2) &&
- (s1->core->type == s2->core->type) &&
- (s1->freq == s2->freq) &&
- (s1->phase == s2->phase) &&
- (s1->base == s2->base) &&
- (s1->current_value == s2->current_value)));
- }
-
-
- static char *describe_sw(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, amp: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_scaler(ptr));
- return(describe_buffer);
- }
-
-
- static void sawtooth_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = M_PI;
- gen->current_value = 0.0;
- }
-
-
- static mus_any_class SAWTOOTH_WAVE_CLASS = {
- MUS_SAWTOOTH_WAVE,
- (char *)S_sawtooth_wave,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &sawtooth_scaler,
- &sawtooth_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_sawtooth_wave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &sawtooth_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_sawtooth_wave(mus_float_t freq, mus_float_t amp, mus_float_t phase) /* M_PI as initial phase, normally */
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &SAWTOOTH_WAVE_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = (amp / M_PI);
- gen->phase = phase;
- gen->current_value = gen->base * (gen->phase - M_PI);
- return((mus_any *)gen);
- }
-
-
- mus_float_t mus_square_wave(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
- result = gen->current_value;
- gen->phase += (gen->freq + fm);
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- }
- if (gen->phase < gen->width)
- gen->current_value = gen->base;
- else gen->current_value = 0.0;
- return(result);
- }
-
-
- bool mus_is_square_wave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SQUARE_WAVE));
- }
-
-
- static mus_float_t run_square_wave(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_square_wave(ptr, fm));}
-
- static mus_float_t square_wave_scaler(mus_any *ptr) {return(((sw *)ptr)->base);}
- static mus_float_t square_wave_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = val; return(val);}
-
-
- static void square_wave_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = 0.0;
- gen->current_value = gen->base;
- }
-
-
- static mus_any_class SQUARE_WAVE_CLASS = {
- MUS_SQUARE_WAVE,
- (char *)S_square_wave,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &square_wave_scaler,
- &square_wave_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_square_wave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0,
- &sw_width, &sw_set_width,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &square_wave_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_square_wave(mus_float_t freq, mus_float_t amp, mus_float_t phase)
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &SQUARE_WAVE_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = amp;
- gen->phase = phase;
- gen->width = M_PI;
- if (gen->phase < gen->width)
- gen->current_value = gen->base;
- else gen->current_value = 0.0;
- return((mus_any *)gen);
- }
-
-
- mus_float_t mus_triangle_wave(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
-
- result = gen->current_value;
- gen->phase += (gen->freq + fm);
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- }
- if (gen->phase < (M_PI / 2.0))
- gen->current_value = gen->base * gen->phase;
- else
- if (gen->phase < (M_PI * 1.5))
- gen->current_value = gen->base * (M_PI - gen->phase);
- else gen->current_value = gen->base * (gen->phase - TWO_PI);
- return(result);
- }
-
-
- mus_float_t mus_triangle_wave_unmodulated(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
-
- result = gen->current_value;
- gen->phase += gen->freq;
- TRY_AGAIN:
- if (gen->phase < (M_PI / 2.0))
- gen->current_value = gen->base * gen->phase;
- else
- {
- if (gen->phase < (M_PI * 1.5))
- gen->current_value = gen->base * (M_PI - gen->phase);
- else
- {
- if (gen->phase < TWO_PI)
- gen->current_value = gen->base * (gen->phase - TWO_PI);
- else
- {
- gen->phase -= TWO_PI;
- goto TRY_AGAIN;
- }
- }
- }
- return(result);
- }
-
-
- bool mus_is_triangle_wave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TRIANGLE_WAVE));
- }
-
-
- static mus_float_t run_triangle_wave(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_triangle_wave(ptr, fm));}
-
- static mus_float_t triangle_wave_scaler(mus_any *ptr) {return(((sw *)ptr)->base * M_PI_2);}
- static mus_float_t triangle_wave_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = (val * 2.0 / M_PI); return(val);}
-
-
- static void triangle_wave_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = 0.0;
- gen->current_value = 0.0;
- }
-
-
- static mus_any_class TRIANGLE_WAVE_CLASS = {
- MUS_TRIANGLE_WAVE,
- (char *)S_triangle_wave,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &triangle_wave_scaler,
- &triangle_wave_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_triangle_wave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &triangle_wave_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_triangle_wave(mus_float_t freq, mus_float_t amp, mus_float_t phase)
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &TRIANGLE_WAVE_CLASS;
- if (freq < 0.0)
- {
- freq = -freq;
- phase += M_PI;
- if (phase > TWO_PI) phase -= TWO_PI;
- }
- gen->freq = mus_hz_to_radians(freq);
- gen->base = (2.0 * amp / M_PI);
- gen->phase = phase;
- if (gen->phase < M_PI_2)
- gen->current_value = gen->base * gen->phase;
- else
- if (gen->phase < (M_PI * 1.5))
- gen->current_value = gen->base * (M_PI - gen->phase);
- else gen->current_value = gen->base * (gen->phase - TWO_PI);
- return((mus_any *)gen);
- }
-
-
- mus_float_t mus_pulse_train(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->current_value = gen->base;
- }
- else gen->current_value = 0.0;
- gen->phase += (gen->freq + fm);
- return(gen->current_value);
- }
-
-
- mus_float_t mus_pulse_train_unmodulated(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- /* here unfortunately, we might get any phase: (pulse-train p (+ (pulse-train p) -1.0))
- */
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->current_value = gen->base;
- }
- else gen->current_value = 0.0;
- gen->phase += gen->freq;
- return(gen->current_value);
- }
-
-
- bool mus_is_pulse_train(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_PULSE_TRAIN));
- }
-
-
- static mus_float_t run_pulse_train(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_pulse_train(ptr, fm));}
-
- static mus_float_t pulse_train_scaler(mus_any *ptr) {return(((sw *)ptr)->base);}
- static mus_float_t pulse_train_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = val; return(val);}
-
-
- static void pulse_train_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = TWO_PI;
- gen->current_value = 0.0;
- }
-
-
- static mus_any_class PULSE_TRAIN_CLASS = {
- MUS_PULSE_TRAIN,
- (char *)S_pulse_train,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &pulse_train_scaler,
- &pulse_train_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_pulse_train,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &pulse_train_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_pulse_train(mus_float_t freq, mus_float_t amp, mus_float_t phase) /* TWO_PI initial phase, normally */
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &PULSE_TRAIN_CLASS;
- if (freq < 0.0) freq = -freq;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = amp;
- gen->phase = phase;
- gen->current_value = 0.0;
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- rand, rand_interp ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, phase, base, incr, norm;
- mus_float_t output;
- mus_float_t *distribution;
- int distribution_size;
- mus_float_t (*ran_unmod)(mus_any *ptr);
- } noi;
-
-
- /* rand taken from the ANSI C standard (essentially the same as the Cmix form used earlier) */
-
- static unsigned long randx = 1;
- #define INVERSE_MAX_RAND 0.0000610351563
- #define INVERSE_MAX_RAND2 0.000030517579
-
-
- void mus_set_rand_seed(unsigned long val) {randx = val;}
-
- unsigned long mus_rand_seed(void) {return(randx);}
-
-
- static mus_float_t next_random(void)
- {
- randx = randx * 1103515245 + 12345;
- return((mus_float_t)((unsigned int)(randx >> 16) & 32767));
- }
-
-
- mus_float_t mus_random(mus_float_t amp) /* -amp to amp as mus_float_t */
- {
- return(amp * (next_random() * INVERSE_MAX_RAND - 1.0));
- }
-
-
- mus_float_t mus_frandom(mus_float_t amp) /* 0.0 to amp as mus_float_t */
- {
- return(amp * next_random() * INVERSE_MAX_RAND2);
- }
-
-
- int mus_irandom(int amp)
- {
- return((int)(amp * next_random() * INVERSE_MAX_RAND2));
- }
-
-
- static mus_float_t random_any(noi *gen) /* -amp to amp possibly through distribution */
- {
- if (gen->distribution)
- return(gen->base * mus_array_interp(gen->distribution,
- next_random() * INVERSE_MAX_RAND2 * gen->distribution_size,
- gen->distribution_size));
- return(gen->base * (next_random() * INVERSE_MAX_RAND - 1.0));
- }
-
-
- mus_float_t mus_rand(mus_any *ptr, mus_float_t fm)
- {
- noi *gen = (noi *)ptr;
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->output = random_any(gen);
- }
- gen->phase += (gen->freq + fm);
- return(gen->output);
- }
-
-
- static mus_float_t zero_unmodulated(mus_any *ptr) {return(0.0);}
-
- mus_float_t mus_rand_unmodulated(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- if (gen->phase >= TWO_PI)
- {
- gen->phase -= TWO_PI;
- gen->output = random_any(gen);
- }
- gen->phase += gen->freq;
- return(gen->output);
- }
-
-
- mus_float_t mus_rand_interp(mus_any *ptr, mus_float_t fm)
- {
- /* fm can change the increment step during a ramp */
- noi *gen = (noi *)ptr;
- gen->output += gen->incr;
- if (gen->output > gen->base)
- gen->output = gen->base;
- else
- {
- if (gen->output < -gen->base)
- gen->output = -gen->base;
- }
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->incr = (random_any(gen) - gen->output) / (ceil(TWO_PI / (gen->freq + fm)));
- }
- gen->phase += (gen->freq + fm);
- return(gen->output);
- }
-
-
- mus_float_t mus_rand_interp_unmodulated(mus_any *ptr)
- {
- return(((noi *)ptr)->ran_unmod(ptr));
- }
-
-
- mus_float_t (*mus_rand_interp_unmodulated_function(mus_any *g))(mus_any *gen);
- mus_float_t (*mus_rand_interp_unmodulated_function(mus_any *g))(mus_any *gen)
- {
- if (mus_is_rand_interp(g))
- return(((noi *)g)->ran_unmod);
- return(NULL);
- }
-
- static mus_float_t rand_interp_unmodulated_with_distribution(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- gen->output += gen->incr;
- if (gen->phase >= TWO_PI)
- {
- gen->phase -= TWO_PI;
- gen->incr = (random_any(gen) - gen->output) / (ceil(TWO_PI / gen->freq));
- }
- gen->phase += gen->freq;
- return(gen->output);
- }
-
-
- static mus_float_t rand_interp_unmodulated(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- gen->output += gen->incr;
- gen->phase += gen->freq;
- if (gen->phase >= TWO_PI)
- {
- gen->phase -= TWO_PI;
- randx = randx * 1103515245 + 12345;
- gen->incr = ((gen->base * ((mus_float_t)((unsigned int)(randx >> 16) & 32767) * INVERSE_MAX_RAND - 1.0)) - gen->output) * gen->norm;
- }
- return(gen->output);
- }
-
-
- static mus_float_t run_rand(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rand(ptr, fm));}
- static mus_float_t run_rand_interp(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rand_interp(ptr, fm));}
-
-
- bool mus_is_rand(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RAND));
- }
-
- bool mus_is_rand_interp(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RAND_INTERP));
- }
-
-
- static void free_noi(mus_any *ptr) {free(ptr);}
-
- static mus_any *noi_copy(mus_any *ptr)
- {
- noi *g;
- g = (noi *)malloc(sizeof(noi));
- memcpy((void *)g, (void *)ptr, sizeof(noi));
- /* if ptr->distribution, it comes from elsewhere -- we don't touch it here,
- * and in clm2xen, we merely wrap it.
- */
- return((mus_any *)g);
- }
-
- static mus_float_t noi_freq(mus_any *ptr) {return(mus_radians_to_hz(((noi *)ptr)->freq));}
- static mus_float_t noi_set_freq(mus_any *ptr, mus_float_t val)
- {
- if (val < 0.0) val = -val;
- ((noi *)ptr)->freq = mus_hz_to_radians(val);
- return(val);
- }
-
- static mus_float_t interp_noi_set_freq(mus_any *ptr, mus_float_t val)
- {
- noi *gen = (noi *)ptr;
- if (val < 0.0) val = -val;
- gen->freq = mus_hz_to_radians(val);
- if (gen->freq != 0.0)
- gen->norm = 1.0 / (ceil(TWO_PI / gen->freq));
- return(val);
- }
-
- static mus_float_t noi_increment(mus_any *ptr) {return(((noi *)ptr)->freq);}
- static mus_float_t noi_set_increment(mus_any *ptr, mus_float_t val) {((noi *)ptr)->freq = val; return(val);}
-
- static mus_float_t noi_incr(mus_any *ptr) {return(((noi *)ptr)->incr);}
- static mus_float_t noi_set_incr(mus_any *ptr, mus_float_t val) {((noi *)ptr)->incr = val; return(val);}
-
- static mus_float_t noi_phase(mus_any *ptr) {return(fmod(((noi *)ptr)->phase, TWO_PI));}
- static mus_float_t noi_set_phase(mus_any *ptr, mus_float_t val) {((noi *)ptr)->phase = val; return(val);}
-
- static mus_float_t noi_scaler(mus_any *ptr) {return(((noi *)ptr)->base);}
- static mus_float_t noi_set_scaler(mus_any *ptr, mus_float_t val) {((noi *)ptr)->base = val; return(val);} /* rand, not rand-interp */
-
- static mus_float_t *noi_data(mus_any *ptr) {return(((noi *)ptr)->distribution);}
- static mus_long_t noi_length(mus_any *ptr) {return(((noi *)ptr)->distribution_size);}
-
-
- static mus_float_t randi_set_scaler(mus_any *ptr, mus_float_t val)
- {
- noi *gen = (noi *)ptr;
- if (val == 0.0)
- gen->ran_unmod = zero_unmodulated;
- else
- {
- if (gen->base == 0.0)
- {
- if (gen->distribution)
- gen->ran_unmod = rand_interp_unmodulated_with_distribution;
- else gen->ran_unmod = rand_interp_unmodulated;
- }
- }
- gen->base = val;
- return(val);
- }
-
- static void noi_reset(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- gen->phase = 0.0;
- gen->output = 0.0;
- }
-
-
- static bool noi_equalp(mus_any *p1, mus_any *p2)
- {
- noi *g1 = (noi *)p1;
- noi *g2 = (noi *)p2;
- return((p1 == p2) ||
- ((g1) && (g2) &&
- (g1->core->type == g2->core->type) &&
- (g1->freq == g2->freq) &&
- (g1->phase == g2->phase) &&
- (g1->output == g2->output) &&
- (g1->incr == g2->incr) &&
- (g1->base == g2->base) &&
- (g1->distribution_size == g2->distribution_size) &&
- (g1->distribution == g2->distribution)));
- }
-
-
- static char *describe_noi(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (mus_is_rand(ptr))
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, amp: %.3f%s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_scaler(ptr),
- (gen->distribution) ? ", with distribution envelope" : "");
- else
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, amp: %.3f, incr: %.3f, curval: %.3f%s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_scaler(ptr),
- gen->incr,
- gen->output,
- (gen->distribution) ? ", with distribution envelope" : "");
- return(describe_buffer);
- }
-
-
- static mus_any_class RAND_CLASS = {
- MUS_RAND,
- (char *)S_rand,
- &free_noi,
- &describe_noi,
- &noi_equalp,
- &noi_data, 0,
- &noi_length, 0,
- &noi_freq,
- &noi_set_freq,
- &noi_phase,
- &noi_set_phase,
- &noi_scaler,
- &noi_set_scaler,
- &noi_increment, /* this is the phase increment, not the incr field */
- &noi_set_increment,
- &run_rand,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &noi_incr, &noi_set_incr,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &noi_reset,
- 0, &noi_copy
- };
-
-
- static mus_any_class RAND_INTERP_CLASS = {
- MUS_RAND_INTERP,
- (char *)S_rand_interp,
- &free_noi,
- &describe_noi,
- &noi_equalp,
- &noi_data, 0,
- &noi_length, 0,
- &noi_freq,
- &interp_noi_set_freq,
- &noi_phase,
- &noi_set_phase,
- &noi_scaler,
- &randi_set_scaler,
- &noi_increment, /* phase increment, not incr field */
- &noi_set_increment,
- &run_rand_interp,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &noi_incr, &noi_set_incr, /* incr field == mus_offset method */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &noi_reset,
- 0, &noi_copy
- };
-
-
- mus_any *mus_make_rand(mus_float_t freq, mus_float_t base)
- {
- noi *gen;
- gen = (noi *)calloc(1, sizeof(noi));
- gen->core = &RAND_CLASS;
- if (freq < 0.0) freq = -freq;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = base;
- gen->incr = 0.0;
- gen->output = random_any(gen); /* this was always starting at 0.0 (changed 23-Dec-06) */
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_rand_with_distribution(mus_float_t freq, mus_float_t base, mus_float_t *distribution, int distribution_size)
- {
- noi *gen;
- gen = (noi *)mus_make_rand(freq, base);
- gen->distribution = distribution;
- gen->distribution_size = distribution_size;
- gen->output = random_any(gen);
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_rand_interp(mus_float_t freq, mus_float_t base)
- {
- noi *gen;
- gen = (noi *)calloc(1, sizeof(noi));
- gen->core = &RAND_INTERP_CLASS;
- /* gen->distribution = NULL; */
- if (freq < 0.0) freq = -freq;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = base;
- gen->incr = mus_random(base) * freq / sampling_rate;
- gen->output = 0.0;
- if (gen->freq != 0.0)
- gen->norm = 1.0 / (ceil(TWO_PI / gen->freq));
- else gen->norm = 1.0;
- gen->ran_unmod = ((base == 0.0) ? zero_unmodulated : rand_interp_unmodulated);
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_rand_interp_with_distribution(mus_float_t freq, mus_float_t base, mus_float_t *distribution, int distribution_size)
- {
- noi *gen;
- gen = (noi *)mus_make_rand_interp(freq, base);
- gen->distribution = distribution;
- gen->distribution_size = distribution_size;
- gen->ran_unmod = ((base == 0.0) ? zero_unmodulated : rand_interp_unmodulated_with_distribution);
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- simple filters ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t xs[3];
- mus_float_t ys[3];
- mus_float_t x1, x2, y1, y2;
- } smpflt;
-
-
- static void free_smpflt(mus_any *ptr) {free(ptr);}
-
- static mus_any *smpflt_copy(mus_any *ptr)
- {
- smpflt *g;
- g = (smpflt *)malloc(sizeof(smpflt));
- memcpy((void *)g, (void *)ptr, sizeof(smpflt));
- return((mus_any *)g);
- }
-
-
- static bool smpflt_equalp(mus_any *p1, mus_any *p2)
- {
- smpflt *g1 = (smpflt *)p1;
- smpflt *g2 = (smpflt *)p2;
- return((p1 == p2) ||
- ((g1->core->type == g2->core->type) &&
- (g1->xs[0] == g2->xs[0]) &&
- (g1->xs[1] == g2->xs[1]) &&
- (g1->xs[2] == g2->xs[2]) &&
- (g1->ys[1] == g2->ys[1]) &&
- (g1->ys[2] == g2->ys[2]) &&
- (g1->x1 == g2->x1) &&
- (g1->x2 == g2->x2) &&
- (g1->y1 == g2->y1) &&
- (g1->y2 == g2->y2)));
- }
-
-
- static char *describe_smpflt(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- switch (gen->core->type)
- {
- case MUS_ONE_ZERO:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, a1: %.3f, x1: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->xs[1], gen->x1);
- break;
-
- case MUS_ONE_POLE:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, b1: %.3f, y1: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->ys[1], gen->y1);
- break;
-
- case MUS_TWO_ZERO:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, a1: %.3f, a2: %.3f, x1: %.3f, x2: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->xs[1], gen->xs[2], gen->x1, gen->x2);
- break;
-
- case MUS_TWO_POLE:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, b1: %.3f, b2: %.3f, y1: %.3f, y2: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->ys[1], gen->ys[2], gen->y1, gen->y2);
- break;
- }
- return(describe_buffer);
- }
-
-
- mus_float_t mus_one_zero(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- mus_float_t result;
- result = (gen->xs[0] * input) + (gen->xs[1] * gen->x1);
- gen->x1 = input;
- return(result);
- }
-
-
- static mus_float_t run_one_zero(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_one_zero(ptr, input));}
-
- static mus_long_t one_length(mus_any *ptr) {return(1);}
- static mus_long_t two_length(mus_any *ptr) {return(2);}
-
- static mus_float_t smp_xcoeff(mus_any *ptr, int index) {return(((smpflt *)ptr)->xs[index]);}
- static mus_float_t smp_set_xcoeff(mus_any *ptr, int index, mus_float_t val) {((smpflt *)ptr)->xs[index] = val; return(val);}
-
- static mus_float_t smp_ycoeff(mus_any *ptr, int index) {return(((smpflt *)ptr)->ys[index]);}
- static mus_float_t smp_set_ycoeff(mus_any *ptr, int index, mus_float_t val) {((smpflt *)ptr)->ys[index] = val; return(val);}
-
- static mus_float_t *smp_xcoeffs(mus_any *ptr) {return(((smpflt *)ptr)->xs);}
- static mus_float_t *smp_ycoeffs(mus_any *ptr) {return(((smpflt *)ptr)->ys);}
-
- static void smp_scl(mus_any *ptr, mus_float_t scl) {smpflt *g = (smpflt *)ptr; g->xs[0] *= scl; g->xs[1] *= scl;}
-
- static void smpflt_reset(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->x1 = 0.0;
- gen->x2 = 0.0;
- gen->y1 = 0.0;
- gen->y2 = 0.0;
- }
-
-
- static mus_any_class ONE_ZERO_CLASS = {
- MUS_ONE_ZERO,
- (char *)S_one_zero,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &one_length, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_one_zero,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0,
- 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_one_zero(mus_float_t a0, mus_float_t a1)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &ONE_ZERO_CLASS;
- gen->xs[0] = a0;
- gen->xs[1] = a1;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_one_zero(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ONE_ZERO));
- }
-
-
- mus_float_t mus_one_pole(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->y1 = (gen->xs[0] * input) - (gen->ys[1] * gen->y1);
- return(gen->y1);
- }
-
- /* incrementer: (make-one-pole 1.0 -1.0) */
-
- static mus_float_t run_one_pole(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_one_pole(ptr, input));}
-
-
- static mus_any_class ONE_POLE_CLASS = {
- MUS_ONE_POLE,
- (char *)S_one_pole,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &one_length, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- &run_one_pole,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &smp_ycoeff, &smp_set_ycoeff,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_one_pole(mus_float_t a0, mus_float_t b1)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &ONE_POLE_CLASS;
- gen->xs[0] = a0;
- gen->ys[1] = b1;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_one_pole(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ONE_POLE));
- }
-
-
- mus_float_t mus_two_zero(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- mus_float_t result;
- result = (gen->xs[0] * input) + (gen->xs[1] * gen->x1) + (gen->xs[2] * gen->x2);
- gen->x2 = gen->x1;
- gen->x1 = input;
- return(result);
- }
-
-
- static mus_float_t run_two_zero(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_two_zero(ptr, input));}
-
-
- static mus_float_t two_zero_radius(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(sqrt(gen->xs[2]));
- }
-
-
- static mus_float_t two_zero_set_radius(mus_any *ptr, mus_float_t new_radius)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->xs[1] = -2.0 * new_radius * cos(mus_hz_to_radians(mus_frequency(ptr)));
- gen->xs[2] = new_radius * new_radius;
- return(new_radius);
- }
-
-
- static mus_float_t two_zero_frequency(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(mus_radians_to_hz(acos(gen->xs[1] / (-2.0 * two_zero_radius(ptr)))));
- }
-
-
- static mus_float_t two_zero_set_frequency(mus_any *ptr, mus_float_t new_freq)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->xs[1] = -2.0 * mus_scaler(ptr) * cos(mus_hz_to_radians(new_freq));
- return(new_freq);
- }
-
-
- static mus_any_class TWO_ZERO_CLASS = {
- MUS_TWO_ZERO,
- (char *)S_two_zero,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &two_length, 0,
- &two_zero_frequency, &two_zero_set_frequency,
- 0, 0,
- &two_zero_radius, &two_zero_set_radius,
- 0, 0,
- &run_two_zero,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_two_zero(mus_float_t a0, mus_float_t a1, mus_float_t a2)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &TWO_ZERO_CLASS;
- gen->xs[0] = a0;
- gen->xs[1] = a1;
- gen->xs[2] = a2;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_two_zero(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TWO_ZERO));
- }
-
-
- mus_any *mus_make_two_zero_from_frequency_and_radius(mus_float_t frequency, mus_float_t radius)
- {
- return(mus_make_two_zero(1.0, -2.0 * radius * cos(mus_hz_to_radians(frequency)), radius * radius));
- }
-
-
- mus_float_t mus_two_pole(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- mus_float_t result;
- result = (gen->xs[0] * input) - (gen->ys[1] * gen->y1) - (gen->ys[2] * gen->y2);
- gen->y2 = gen->y1;
- gen->y1 = result;
- return(result);
- }
-
-
- static mus_float_t run_two_pole(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_two_pole(ptr, input));}
-
-
- static mus_float_t two_pole_radius(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(sqrt(gen->ys[2]));
- }
-
-
- static mus_float_t two_pole_set_radius(mus_any *ptr, mus_float_t new_radius)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->ys[1] = -2.0 * new_radius * cos(mus_hz_to_radians(mus_frequency(ptr)));
- gen->ys[2] = new_radius * new_radius;
- return(new_radius);
- }
-
-
- static mus_float_t two_pole_frequency(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(mus_radians_to_hz(acos(gen->ys[1] / (-2.0 * two_pole_radius(ptr)))));
- }
-
-
- static mus_float_t two_pole_set_frequency(mus_any *ptr, mus_float_t new_freq)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->ys[1] = -2.0 * mus_scaler(ptr) * cos(mus_hz_to_radians(new_freq));
- return(new_freq);
- }
-
-
- static mus_any_class TWO_POLE_CLASS = {
- MUS_TWO_POLE,
- (char *)S_two_pole,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &two_length, 0,
- &two_pole_frequency, &two_pole_set_frequency,
- 0, 0,
- &two_pole_radius, &two_pole_set_radius,
- 0, 0,
- &run_two_pole,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &smp_ycoeff, &smp_set_ycoeff,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_two_pole(mus_float_t a0, mus_float_t b1, mus_float_t b2)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &TWO_POLE_CLASS;
- gen->xs[0] = a0;
- gen->ys[1] = b1;
- gen->ys[2] = b2;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_two_pole(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TWO_POLE));
- }
-
-
- mus_any *mus_make_two_pole_from_frequency_and_radius(mus_float_t frequency, mus_float_t radius)
- {
- return(mus_make_two_pole(1.0, -2.0 * radius * cos(mus_hz_to_radians(frequency)), radius * radius));
- }
-
-
-
- /* ---------------- formant ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t frequency, radius;
- mus_float_t x1, x2, y1, y2;
- mus_float_t rr, gain, fdbk;
- } frm;
-
-
- static void free_frm(mus_any *ptr) {free(ptr);}
-
-
- static mus_any *frm_copy(mus_any *ptr)
- {
- frm *g;
- g = (frm *)malloc(sizeof(frm));
- memcpy((void *)g, (void *)ptr, sizeof(frm));
- return((mus_any *)g);
- }
-
-
- bool mus_is_formant(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FORMANT));
- }
-
-
- static void frm_reset(mus_any *ptr)
- {
- frm *gen = (frm *)ptr;
- gen->x1 = 0.0;
- gen->x2 = 0.0;
- gen->y1 = 0.0;
- gen->y2 = 0.0;
- }
-
-
- static bool frm_equalp(mus_any *p1, mus_any *p2)
- {
- frm *g1 = (frm *)p1;
- frm *g2 = (frm *)p2;
- return((p1 == p2) ||
- ((g1->core->type == g2->core->type) &&
- (g1->radius == g2->radius) &&
- (g1->frequency == g2->frequency) &&
- (g1->x1 == g2->x1) &&
- (g1->x2 == g2->x2) &&
- (g1->y1 == g2->y1) &&
- (g1->y2 == g2->y2)));
- }
-
-
- static char *describe_formant(mus_any *ptr)
- {
- frm *gen = (frm *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, radius: %.3f",
- mus_name(ptr),
- mus_radians_to_hz(gen->frequency),
- gen->radius);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_formant(mus_any *ptr, mus_float_t input)
- {
- frm *gen = (frm *)ptr;
- mus_float_t x0, y0;
- x0 = gen->gain * input;
- y0 = x0 - gen->x2 + (gen->fdbk * gen->y1) - (gen->rr * gen->y2);
- gen->y2 = gen->y1;
- gen->y1 = y0;
- gen->x2 = gen->x1;
- gen->x1 = x0;
- return(y0);
- }
-
-
- static mus_float_t run_formant(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_formant(ptr, input));}
-
-
- static void mus_set_formant_radius_and_frequency_in_radians(mus_any *ptr, mus_float_t radius, mus_float_t freq_in_radians)
- {
- frm *gen = (frm *)ptr;
- gen->radius = radius;
- gen->frequency = freq_in_radians;
- gen->rr = radius * radius;
- gen->gain = (1.0 - gen->rr) * 0.5;
- gen->fdbk = 2.0 * radius * cos(freq_in_radians);
- }
-
-
- void mus_set_formant_radius_and_frequency(mus_any *ptr, mus_float_t radius, mus_float_t freq_in_hz)
- {
- mus_set_formant_radius_and_frequency_in_radians(ptr, radius, mus_hz_to_radians(freq_in_hz));
- }
-
-
- static mus_float_t formant_frequency(mus_any *ptr) {return(mus_radians_to_hz(((frm *)ptr)->frequency));}
-
- mus_float_t mus_set_formant_frequency(mus_any *ptr, mus_float_t freq_in_hz)
- {
- frm *gen = (frm *)ptr;
- mus_float_t fw;
- fw = mus_hz_to_radians(freq_in_hz);
- gen->frequency = fw;
- gen->fdbk = 2.0 * gen->radius * cos(fw);
- return(freq_in_hz);
- }
-
-
- mus_float_t mus_formant_with_frequency(mus_any *ptr, mus_float_t input, mus_float_t freq_in_radians)
- {
- frm *gen = (frm *)ptr;
- if (gen->frequency != freq_in_radians)
- {
- gen->frequency = freq_in_radians;
- gen->fdbk = 2.0 * gen->radius * cos(freq_in_radians);
- }
- return(mus_formant(ptr, input));
- }
-
-
- static mus_float_t formant_radius(mus_any *ptr) {return(((frm *)ptr)->radius);}
-
- static mus_float_t formant_set_radius(mus_any *ptr, mus_float_t val)
- {
- mus_set_formant_radius_and_frequency_in_radians(ptr, val, ((frm *)ptr)->frequency);
- return(val);
- }
-
-
- static mus_any_class FORMANT_CLASS = {
- MUS_FORMANT,
- (char *)S_formant,
- &free_frm,
- &describe_formant,
- &frm_equalp,
- 0, 0,
- &two_length, 0,
- &formant_frequency, &mus_set_formant_frequency,
- 0, 0,
- &formant_radius, &formant_set_radius,
- 0, 0,
- &run_formant,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &frm_reset,
- 0, &frm_copy
- };
-
-
- mus_any *mus_make_formant(mus_float_t frequency, mus_float_t radius)
- {
- frm *gen;
- gen = (frm *)calloc(1, sizeof(frm));
- gen->core = &FORMANT_CLASS;
- mus_set_formant_radius_and_frequency((mus_any *)gen, radius, frequency);
- return((mus_any *)gen);
- }
-
-
- /* ---------------- formant-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size, mctr;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *rr, *fdbk, *gain;
- mus_float_t c1, c2;
- mus_float_t (*one_input)(mus_any *fbank, mus_float_t inval);
- mus_float_t (*many_inputs)(mus_any *fbank, mus_float_t *inval);
- } frm_bank;
-
-
- static void free_formant_bank(mus_any *ptr)
- {
- frm_bank *f = (frm_bank *)ptr;
- if (f->x0) {free(f->x0); f->x0 = NULL;}
- if (f->x1) {free(f->x1); f->x1 = NULL;}
- if (f->x2) {free(f->x2); f->x2 = NULL;}
- if (f->y0) {free(f->y0); f->y0 = NULL;}
- if (f->y1) {free(f->y1); f->y1 = NULL;}
- if (f->y2) {free(f->y2); f->y2 = NULL;}
- if (f->rr) {free(f->rr); f->rr = NULL;}
- if (f->fdbk) {free(f->fdbk); f->fdbk = NULL;}
- if (f->gain) {free(f->gain); f->gain = NULL;}
- free(ptr);
- }
-
- static mus_any *frm_bank_copy(mus_any *ptr)
- {
- frm_bank *g, *p;
- int bytes;
-
- p = (frm_bank *)ptr;
- g = (frm_bank *)malloc(sizeof(frm_bank));
- memcpy((void *)g, (void *)ptr, sizeof(frm_bank));
- bytes = g->size * sizeof(mus_float_t);
-
- g->x0 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x0), (void *)(p->x0), bytes);
- g->x1 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x1), (void *)(p->x1), bytes);
- g->x2 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x2), (void *)(p->x2), bytes);
- g->y0 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y0), (void *)(p->y0), bytes);
- g->y1 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y1), (void *)(p->y1), bytes);
- g->y2 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y2), (void *)(p->y2), bytes);
-
- g->rr = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->rr), (void *)(p->rr), bytes);
- g->fdbk = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->fdbk), (void *)(p->fdbk), bytes);
- g->gain = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->gain), (void *)(p->gain), bytes);
-
- return((mus_any *)g);
- }
-
- static mus_float_t run_formant_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_formant_bank(ptr, input));
- }
-
-
- static mus_long_t formant_bank_length(mus_any *ptr)
- {
- return(((frm_bank *)ptr)->size);
- }
-
-
- static void formant_bank_reset(mus_any *ptr)
- {
- frm_bank *f = (frm_bank *)ptr;
- int size;
- size = f->size * sizeof(mus_float_t);
- memset((void *)(f->x0), 0, size);
- memset((void *)(f->x1), 0, size);
- memset((void *)(f->x2), 0, size);
- memset((void *)(f->y0), 0, size);
- memset((void *)(f->y1), 0, size);
- memset((void *)(f->y2), 0, size);
- }
-
-
- static bool formant_bank_equalp(mus_any *p1, mus_any *p2)
- {
- frm_bank *f1 = (frm_bank *)p1;
- frm_bank *f2 = (frm_bank *)p2;
- #if 0
- int i, size;
- #endif
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- #if 0
- size = f1->size;
- for (i = 0; i < size; i++)
- if (!frm_equalp(f1->gens[i], f2->gens[i]))
- return(false);
- #endif
- /* now check the locals... */
- return(true);
- }
-
-
- static char *describe_formant_bank(mus_any *ptr)
- {
- frm_bank *gen = (frm_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d", mus_name(ptr), gen->size);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_formant_bank(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- return(bank->one_input(fbank, inval));
- }
-
- mus_float_t mus_formant_bank_with_inputs(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- return(bank->many_inputs(fbank, inval));
- }
-
-
- static mus_float_t fb_one_with_amps(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
- amps = bank->amps;
- size4 = bank->size - 4;
-
- i = 0;
- while (i <= size4)
- {
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_one_without_amps(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
-
- for (i = 0; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_many_with_amps(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
- amps = bank->amps;
-
- for (i = 0; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_many_without_amps(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
-
- for (i = 0; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_one_with_amps_c1_c2(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- amps = bank->amps;
- size4 = bank->size - 4;
-
- bank->mctr++;
-
- rr = bank->c1;
- gain = (bank->c2 * inval);
- x0[0] = gain;
-
- if (bank->mctr < 3)
- {
- i = 0;
- while (i <= size4)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- /* in isolation this looks like the x0[i]-x2[i] business could be handled outside the loop
- * by a single float, but formant-bank can be called in the same do-loop both with and
- * without multiple inputs, so fb_one has to be completely compatible sample-by-sample
- * with fb_many. Since we can't predict here when we'll need bank->x2, we can't collapse
- * this calculation.
- *
- * If we know we've had 2 fb_one calls just before this one, then x2[i] are all the same,
- * x0[i] will all be the same in this loop, so x0[i] - x2[i] can be collapsed, but
- * we still need to set x0[0]=gain: enter mctr.
- *
- * So in the current case, we can save x0[0]=gain -> x1 -> x2, then in fm_many
- * mctr=1 -- x2 is ok, x1[0] needs to be propagated
- * mctr>1 -- x2 and x1 need propagation
- * On the other side, if mctr>=3, then x2[i] was not set, so don't access it.
- */
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- }
- }
- else
- {
- mus_float_t g2;
- g2 = gain - x2[0];
- i = 0;
- while (i <= size4)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- }
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_many_with_amps_c1_c2(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- amps = bank->amps;
- size4 = bank->size - 4;
-
- if (bank->mctr > 0)
- {
- if (bank->mctr == 1)
- {
- for (i = 1; i < bank->size; i++) x1[i] = x1[0];
- }
- else
- {
- for (i = 1; i < bank->size; i++) {x1[i] = x1[0]; x2[i] = x2[0];}
- }
- bank->mctr = 0;
- }
- rr = bank->c1;
- gain = bank->c2;
-
- i = 0;
- while (i <= size4)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
-
- static mus_float_t fb_one_without_amps_c1_c2(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- size4 = bank->size - 4;
-
- bank->mctr++;
-
- rr = bank->c1;
- gain = (bank->c2 * inval);
- x0[0] = gain;
-
- if (bank->mctr < 3)
- {
- i = 0;
- while (i <= size4)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- }
- }
- else
- {
- mus_float_t g2;
- g2 = gain - x2[0];
- i = 0;
- while (i <= size4)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- }
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
-
- static mus_float_t fb_many_without_amps_c1_c2(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- size4 = bank->size - 4;
-
- if (bank->mctr > 0)
- {
- if (bank->mctr == 1)
- {
- for (i = 1; i < bank->size; i++) x1[i] = x1[0];
- }
- else
- {
- for (i = 1; i < bank->size; i++) {x1[i] = x1[0]; x2[i] = x2[0];}
- }
- bank->mctr = 0;
- }
-
- rr = bank->c1;
- gain = bank->c2;
-
- i = 0;
- while (i <= size4)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
-
- static mus_any_class FORMANT_BANK_CLASS = {
- MUS_FORMANT_BANK,
- (char *)S_formant_bank,
- &free_formant_bank,
- &describe_formant_bank,
- &formant_bank_equalp,
- 0, 0,
- &formant_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_formant_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &formant_bank_reset,
- 0, &frm_bank_copy
- };
-
-
- mus_any *mus_make_formant_bank(int size, mus_any **formants, mus_float_t *amps)
- {
- frm_bank *gen;
- int i;
-
- gen = (frm_bank *)malloc(sizeof(frm_bank));
- gen->core = &FORMANT_BANK_CLASS;
- gen->size = size;
- gen->mctr = 0;
-
- gen->x0 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->x1 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->x2 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y0 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y1 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y2 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->amps = amps;
-
- gen->rr = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- gen->fdbk = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- gen->gain = (mus_float_t *)malloc(size * sizeof(mus_float_t));
-
- if (amps)
- {
- gen->one_input = fb_one_with_amps;
- gen->many_inputs = fb_many_with_amps;
- }
- else
- {
- gen->one_input = fb_one_without_amps;
- gen->many_inputs = fb_many_without_amps;
- }
-
- for (i = 0; i < size; i++)
- {
- frm *g;
- g = (frm *)formants[i];
- gen->rr[i] = g->rr;
- gen->fdbk[i] = g->fdbk;
- gen->gain[i] = g->gain;
- /* one case: 1.0 val 0.0 throughout
- * also c1 x c2
- */
- }
- gen->c1 = gen->rr[0];
- gen->c2 = gen->gain[0];
- for (i = 1; i < size; i++)
- if ((gen->rr[i] != gen->c1) ||
- (gen->gain[i] != gen->c2))
- return((mus_any *)gen);
-
- if (amps)
- {
- gen->one_input = fb_one_with_amps_c1_c2;
- gen->many_inputs = fb_many_with_amps_c1_c2;
- }
- else
- {
- gen->one_input = fb_one_without_amps_c1_c2;
- gen->many_inputs = fb_many_without_amps_c1_c2;
- }
-
- return((mus_any *)gen);
- }
-
- bool mus_is_formant_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FORMANT_BANK));
- }
-
-
-
- /* ---------------- firmant ---------------- */
-
- static char *describe_firmant(mus_any *ptr)
- {
- frm *gen = (frm *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, radius: %.3f",
- mus_name(ptr),
- mus_radians_to_hz(gen->frequency),
- gen->radius);
- return(describe_buffer);
- }
-
- static mus_float_t firmant_frequency(mus_any *ptr) {return(mus_radians_to_hz(((frm *)ptr)->frequency));}
-
- static mus_float_t firmant_set_frequency(mus_any *ptr, mus_float_t freq_in_hz)
- {
- frm *gen = (frm *)ptr;
- mus_float_t fw;
- fw = mus_hz_to_radians(freq_in_hz);
- gen->frequency = fw;
- gen->fdbk = 2.0 * sin(gen->frequency * 0.5);
- return(freq_in_hz);
- }
-
- static mus_float_t firmant_radius(mus_any *ptr) {return(((frm *)ptr)->radius);}
-
- static mus_float_t firmant_set_radius(mus_any *ptr, mus_float_t radius)
- {
- frm *gen = (frm *)ptr;
- gen->radius = radius;
- gen->gain = 1.0 - radius * radius;
- return(radius);
- }
-
-
- bool mus_is_firmant(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FIRMANT));
- }
-
-
- mus_float_t mus_firmant(mus_any *ptr, mus_float_t input)
- {
- frm *gen = (frm *)ptr;
- mus_float_t xn1, yn1;
- xn1 = gen->gain * input + gen->radius * (gen->x1 - gen->fdbk * gen->y1);
- yn1 = gen->radius * (gen->fdbk * xn1 + gen->y1);
- gen->x1 = xn1;
- gen->y1 = yn1;
- return(yn1);
- }
-
-
- mus_float_t mus_firmant_with_frequency(mus_any *ptr, mus_float_t input, mus_float_t freq_in_radians)
- {
- frm *gen = (frm *)ptr;
- gen->frequency = freq_in_radians;
- gen->fdbk = 2.0 * sin(gen->frequency * 0.5);
- return(mus_firmant(ptr, input));
- }
-
-
- static mus_float_t run_firmant(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_firmant(ptr, input));}
-
-
- static mus_any_class FIRMANT_CLASS = {
- MUS_FIRMANT,
- (char *)S_firmant,
- &free_frm,
- &describe_firmant,
- &frm_equalp,
- 0, 0,
- &two_length, 0,
- &firmant_frequency, &firmant_set_frequency,
- 0, 0,
- &firmant_radius, &firmant_set_radius,
- 0, 0,
- &run_firmant,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &frm_reset,
- 0, &frm_copy
- };
-
-
- mus_any *mus_make_firmant(mus_float_t frequency, mus_float_t radius)
- {
- frm *gen;
- gen = (frm *)calloc(1, sizeof(frm));
- gen->core = &FIRMANT_CLASS;
- gen->frequency = mus_hz_to_radians(frequency);
- gen->radius = radius;
- gen->fdbk = 2.0 * sin(gen->frequency * 0.5);
- gen->gain = 1.0 - radius * radius;
- return((mus_any *)gen);
- }
-
-
-
-
- /* ---------------- filter ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int order, allocated_size, loc;
- bool state_allocated;
- mus_float_t *x, *y, *state;
- mus_float_t (*filtw)(mus_any *ptr, mus_float_t fm);
- } flt;
-
-
- mus_float_t mus_filter(mus_any *ptr, mus_float_t input)
- {
- return((((flt *)ptr)->filtw)(ptr, input));
- }
-
-
- static mus_float_t filter_eight(mus_any *ptr, mus_float_t input)
- {
- /* oddly enough, this separated form is faster than the interleaved version below, or is valgrind confused?
- */
- flt *gen = (flt *)ptr;
- mus_float_t xout;
- mus_float_t *state, *ts, *ts1, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 1);
- ts1 = (mus_float_t *)(state + gen->order);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- xout = (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- return(xout + ((*ts1) * (*x)));
-
- /*
- * flt *gen = (flt *)ptr;
- * mus_float_t xout;
- * mus_float_t *state, *ts, *y, *x;
- *
- * x = (mus_float_t *)(gen->x + 1);
- * y = (mus_float_t *)(gen->y + 1);
- * state = (mus_float_t *)(gen->state + gen->loc);
- * ts = (mus_float_t *)(state + gen->order - 1);
- *
- * gen->loc++;
- * if (gen->loc == gen->order)
- * gen->loc = 0;
- *
- * xout = (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x);
- * input -= ((*ts--) * (*y));
- *
- * state[0] = input;
- * state[gen->order] = input;
- * return(xout + ((*ts) * gen->x[0]));
- */
- }
-
-
- static mus_float_t filter_four(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t xout;
- mus_float_t *state, *ts, *ts1, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 1);
- ts1 = (mus_float_t *)(state + gen->order);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- xout = (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- return(xout + ((*ts1) * (*x)));
-
- /*
- * flt *gen = (flt *)ptr;
- * mus_float_t xout;
- * mus_float_t *state, *ts, *y, *x;
- *
- * x = (mus_float_t *)(gen->x + 1);
- * y = (mus_float_t *)(gen->y + 1);
- * state = (mus_float_t *)(gen->state + gen->loc);
- * ts = (mus_float_t *)(state + gen->order - 1);
- *
- * gen->loc++;
- * if (gen->loc == gen->order)
- * gen->loc = 0;
- *
- * xout = (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- *
- * state[0] = input;
- * state[gen->order] = input;
- * return(xout + ((*ts) * gen->x[0]));
- */
- }
-
-
- static mus_float_t filter_two(mus_any *ptr, mus_float_t input)
- {
- /* here the mus_float_t-delay form is not faster, but use it for consistency */
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *y, *x;
-
- x = gen->x;
- y = gen->y;
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 2);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- state[0] = input - ((ts[1] * y[1]) + (ts[0] * y[2]));
- state[gen->order] = state[0];
-
- return((ts[0] * x[2]) + (ts[1] * x[1]) + (ts[2] * x[0]));
- }
-
-
- static mus_float_t filter_lt_10(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t xout = 0.0;
- mus_float_t *state, *state1, *ts, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- state1 = (mus_float_t *)(state + 1);
- ts = (mus_float_t *)(state + gen->order - 1);
-
- while (ts > state1)
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- ts = (mus_float_t *)(state + gen->order);
-
- while (ts > state1)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- }
-
-
- static mus_float_t filter_ge_10(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t xout = 0.0;
- mus_float_t *state, *state1, *state11, *ts, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- state1 = (mus_float_t *)(state + 1);
- state11 = (mus_float_t *)(state + 11);
- ts = (mus_float_t *)(state + gen->order - 1);
-
- while (ts >= state11)
- {
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- }
- while (ts > state1)
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- ts = (mus_float_t *)(state + gen->order);
- while (ts >= state11)
- {
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- }
- while (ts > state1)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- }
-
-
- mus_float_t mus_fir_filter(mus_any *ptr, mus_float_t input)
- {
- return((((flt *)ptr)->filtw)(ptr, input));
- }
-
-
- static mus_float_t fir_n(mus_any *ptr, mus_float_t input)
- {
- mus_float_t xout = 0.0;
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *x, *end;
-
- x = (mus_float_t *)(gen->x);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order);
-
- (*state) = input;
- (*ts) = input;
- state++;
- end = (mus_float_t *)(state + 4);
-
- while (ts > end)
- {
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- }
- while (ts > state)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- }
-
-
- static mus_float_t fir_ge_20(mus_any *ptr, mus_float_t input)
- {
- mus_float_t xout = 0.0;
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *x, *end;
-
- x = (mus_float_t *)(gen->x);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order);
- end = (mus_float_t *)(state + 20);
-
- (*state) = input;
- (*ts) = input;
- state++;
-
- while (ts >= end)
- {
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- }
- while (ts > state)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return((ts == state) ? (xout + ((*ts) * (*x))) : xout);
- }
-
-
- mus_float_t mus_iir_filter(mus_any *ptr, mus_float_t input)
- {
- return((((flt *)ptr)->filtw)(ptr, input));
- }
-
-
- static mus_float_t iir_n(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *y;
-
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 1);
-
- while (ts > state)
- input -= ((*ts--) * (*y++));
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- state[0] = input;
- state[gen->order] = input;
-
- return(input);
- }
-
-
- static mus_float_t run_filter(mus_any *ptr, mus_float_t input, mus_float_t unused) {return((((flt *)ptr)->filtw)(ptr, input));}
-
- bool mus_is_filter(mus_any *ptr)
- {
- return((ptr) &&
- ((ptr->core->type == MUS_FILTER) ||
- (ptr->core->type == MUS_FIR_FILTER) ||
- (ptr->core->type == MUS_IIR_FILTER)));
- }
-
-
- bool mus_is_fir_filter(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FIR_FILTER));
- }
-
- bool mus_is_iir_filter(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_IIR_FILTER));
- }
-
-
- static mus_float_t *filter_data(mus_any *ptr) {return(((flt *)ptr)->state);}
- static mus_long_t filter_length(mus_any *ptr) {return(((flt *)ptr)->order);}
-
- static mus_float_t *filter_xcoeffs(mus_any *ptr) {return(((flt *)ptr)->x);}
- static mus_float_t *filter_ycoeffs(mus_any *ptr) {return(((flt *)ptr)->y);}
-
-
- mus_float_t *mus_filter_set_xcoeffs(mus_any *ptr, mus_float_t *new_data)
- {
- /* needed by Snd if filter order increased during play */
- flt *gen = (flt *)ptr;
- mus_float_t *old_data;
- old_data = gen->x;
- gen->x = new_data;
- return(old_data);
- }
-
-
- mus_float_t *mus_filter_set_ycoeffs(mus_any *ptr, mus_float_t *new_data)
- {
- flt *gen = (flt *)ptr;
- mus_float_t *old_data;
- old_data = gen->y;
- gen->y = new_data;
- return(old_data);
- }
-
-
- static mus_long_t filter_set_length(mus_any *ptr, mus_long_t val)
- {
- /* just resets order if order < allocated size */
- flt *gen = (flt *)ptr;
- if ((val > 0) && (val <= gen->allocated_size))
- gen->order = (int)val;
- return((mus_long_t)(gen->order));
- }
-
-
- static void set_filter_function(flt *gen);
-
- int mus_filter_set_order(mus_any *ptr, int order)
- {
- /* resets order and fixes state array if needed (coeffs arrays should be handled separately by set_x|ycoeffs above) */
- /* returns either old order or -1 if state array can't be reallocated */
- flt *gen = (flt *)ptr;
- int old_order;
- if ((order > gen->allocated_size) &&
- (!(gen->state_allocated)))
- return(-1);
- old_order = gen->order;
- gen->order = order;
- if (order > gen->allocated_size)
- {
- int i;
- gen->allocated_size = order;
- gen->state = (mus_float_t *)realloc(gen->state, order * 2 * sizeof(mus_float_t));
- for (i = old_order; i < order; i++)
- {
- gen->state[i] = 0.0; /* try to minimize click */
- gen->state[i + order] = 0.0; /* just a guess */
- }
- }
- set_filter_function(gen);
- return(old_order);
- }
-
-
- static mus_float_t filter_xcoeff(mus_any *ptr, int index)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->x)) return((mus_float_t)mus_error(MUS_NO_XCOEFFS, S_mus_xcoeff ": no xcoeffs"));
- if ((index >= 0) && (index < gen->order))
- return(gen->x[index]);
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_mus_xcoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static mus_float_t filter_set_xcoeff(mus_any *ptr, int index, mus_float_t val)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->x)) return((mus_float_t)mus_error(MUS_NO_XCOEFFS, S_set S_mus_xcoeff ": no xcoeffs"));
- if ((index >= 0) && (index < gen->order))
- {
- gen->x[index] = val;
- return(val);
- }
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_set S_mus_xcoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static mus_float_t filter_ycoeff(mus_any *ptr, int index)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->y)) return((mus_float_t)mus_error(MUS_NO_YCOEFFS, S_mus_ycoeff ": no ycoeffs"));
- if ((index >= 0) && (index < gen->order))
- return(gen->y[index]);
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_mus_ycoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static mus_float_t filter_set_ycoeff(mus_any *ptr, int index, mus_float_t val)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->y)) return((mus_float_t)mus_error(MUS_NO_YCOEFFS, S_set S_mus_ycoeff ": no ycoeffs"));
- if ((index >= 0) && (index < gen->order))
- {
- gen->y[index] = val;
- return(val);
- }
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_set S_mus_ycoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static void free_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- if ((gen->state) && (gen->state_allocated)) free(gen->state);
- free(gen);
- }
-
- static mus_any *flt_copy(mus_any *ptr)
- {
- flt *g, *p;
- int bytes;
-
- p = (flt *)ptr;
- g = (flt *)malloc(sizeof(flt));
- memcpy((void *)g, (void *)ptr, sizeof(flt));
-
- /* we have to make a new state array -- otherwise the original and copy step on each other */
- bytes = p->order * 2 * sizeof(mus_float_t);
- g->state_allocated = true;
- g->state = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->state), (void *)(p->state), bytes);
- return((mus_any *)g);
- }
-
-
- static bool filter_equalp(mus_any *p1, mus_any *p2)
- {
- flt *f1, *f2;
- f1 = (flt *)p1;
- f2 = (flt *)p2;
- if (p1 == p2) return(true);
- return(((p1->core)->type == (p2->core)->type) &&
- ((mus_is_filter(p1)) || (mus_is_fir_filter(p1)) || (mus_is_iir_filter(p1))) &&
- (f1->order == f2->order) &&
- ((!(f1->x)) || (!(f2->x)) || (clm_arrays_are_equal(f1->x, f2->x, f1->order))) &&
- ((!(f1->y)) || (!(f2->y)) || (clm_arrays_are_equal(f1->y, f2->y, f1->order))) &&
- (clm_arrays_are_equal(f1->state, f2->state, f1->order)));
- }
-
-
- static char *describe_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- char *xstr = NULL, *ystr = NULL;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- xstr = float_array_to_string(gen->x, gen->order, 0);
- ystr = float_array_to_string(gen->y, gen->order, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s order: %d, xs: %s, ys: %s",
- mus_name(ptr),
- gen->order,
- xstr, ystr);
- if (xstr) free(xstr);
- if (ystr) free(ystr);
- return(describe_buffer);
- }
-
-
- static char *describe_fir_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- char *xstr = NULL;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- xstr = float_array_to_string(gen->x, gen->order, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s order: %d, xs: %s",
- mus_name(ptr),
- gen->order,
- xstr);
- if (xstr) free(xstr);
- return(describe_buffer);
- }
-
-
- static char *describe_iir_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- char *ystr = NULL;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- ystr = float_array_to_string(gen->y, gen->order, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s order: %d, ys: %s",
- mus_name(ptr),
- gen->order,
- ystr);
- if (ystr) free(ystr);
- return(describe_buffer);
- }
-
-
- static void filter_reset(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- memset((void *)(gen->state), 0, gen->allocated_size * 2 * sizeof(mus_float_t));
- }
-
-
- static mus_any_class FILTER_CLASS = {
- MUS_FILTER,
- (char *)S_filter,
- &free_filter,
- &describe_filter,
- &filter_equalp,
- &filter_data, 0,
- &filter_length,
- &filter_set_length,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_filter,
- MUS_FULL_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &filter_xcoeff, &filter_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &filter_ycoeff, &filter_set_ycoeff,
- &filter_xcoeffs, &filter_ycoeffs,
- &filter_reset,
- 0, &flt_copy
- };
-
-
- static mus_any_class FIR_FILTER_CLASS = {
- MUS_FIR_FILTER,
- (char *)S_fir_filter,
- &free_filter,
- &describe_fir_filter,
- &filter_equalp,
- &filter_data, 0,
- &filter_length,
- &filter_set_length,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_filter,
- MUS_FULL_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &filter_xcoeff, &filter_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &filter_xcoeffs, 0,
- &filter_reset,
- 0, &flt_copy
- };
-
-
- static mus_any_class IIR_FILTER_CLASS = {
- MUS_IIR_FILTER,
- (char *)S_iir_filter,
- &free_filter,
- &describe_iir_filter,
- &filter_equalp,
- &filter_data, 0,
- &filter_length,
- &filter_set_length,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_filter,
- MUS_FULL_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &filter_ycoeff, &filter_set_ycoeff,
- 0, &filter_ycoeffs,
- &filter_reset,
- 0, &flt_copy
- };
-
-
- static void set_filter_function(flt *gen)
- {
- /* choose the run-time function based on the current filter order and type */
- int order;
- order = gen->order - 1;
- if (gen->core == &FILTER_CLASS)
- {
- if (order == 2)
- gen->filtw = filter_two;
- else
- {
- if (order == 8)
- gen->filtw = filter_eight;
- else
- {
- if (order == 4)
- gen->filtw = filter_four;
- else
- {
- if (order >= 10)
- gen->filtw = filter_ge_10;
- else gen->filtw = filter_lt_10;
- }
- }
- }
- }
- else
- {
- if (gen->core == &FIR_FILTER_CLASS)
- {
- if (order >= 20)
- gen->filtw = fir_ge_20;
- else gen->filtw = fir_n;
- }
- else gen->filtw = iir_n;
- }
- }
-
-
- static mus_any *make_filter(mus_any_class *cls, const char *name, int order, mus_float_t *xcoeffs, mus_float_t *ycoeffs, mus_float_t *state)
- {
- /* if state is null, it is allocated locally, otherwise it's size should be at least 2 * order.
- */
- if (order <= 0)
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_filter ": %s order = %d?", name, order);
- else
- {
- flt *gen;
- gen = (flt *)malloc(sizeof(flt));
- if (state)
- {
- gen->state = state;
- gen->state_allocated = false;
- }
- else
- {
- gen->state = (mus_float_t *)calloc(order * 2, sizeof(mus_float_t));
- gen->state_allocated = true;
- }
- gen->loc = 0;
-
- if (cls == &FILTER_CLASS)
- {
- if (!ycoeffs)
- cls = &FIR_FILTER_CLASS;
- else
- {
- if (!xcoeffs)
- cls = &IIR_FILTER_CLASS;
- }
- }
- gen->core = cls;
- gen->order = order;
- gen->allocated_size = order;
- gen->x = xcoeffs;
- gen->y = ycoeffs;
- gen->filtw = NULL;
- set_filter_function(gen);
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_any *mus_make_filter(int order, mus_float_t *xcoeffs, mus_float_t *ycoeffs, mus_float_t *state)
- {
- return(make_filter(&FILTER_CLASS, S_make_filter, order, xcoeffs, ycoeffs, state));
- }
-
-
- mus_any *mus_make_fir_filter(int order, mus_float_t *xcoeffs, mus_float_t *state)
- {
- return(make_filter(&FIR_FILTER_CLASS, S_make_fir_filter, order, xcoeffs, NULL, state));
- }
-
-
- mus_any *mus_make_iir_filter(int order, mus_float_t *ycoeffs, mus_float_t *state)
- {
- return(make_filter(&IIR_FILTER_CLASS, S_make_iir_filter, order, NULL, ycoeffs, state));
- }
-
-
- mus_float_t *mus_make_fir_coeffs(int order, mus_float_t *envl, mus_float_t *aa)
- {
- /* envl = evenly sampled freq response, has order samples */
- int n, i, j, jj;
- mus_float_t scl;
- mus_float_t *a;
-
- n = order;
- if (n <= 0) return(aa);
- if (aa)
- a = aa;
- else a = (mus_float_t *)calloc(order + 1, sizeof(mus_float_t));
- if (!a) return(NULL);
- if (!(is_power_of_2(order)))
- {
- int m;
- mus_float_t am, q, xt0, x;
- m = (n + 1) / 2;
- am = 0.5 * (n + 1) - 1.0;
- scl = 2.0 / (mus_float_t)n;
- q = TWO_PI / (mus_float_t)n;
- xt0 = envl[0] * 0.5;
- for (j = 0, jj = n - 1; j < m; j++, jj--)
- {
- mus_float_t xt, qj;
- #if HAVE_SINCOS
- double s1, c1, s2, c2, qj1;
- xt = xt0;
- qj = q * (am - j);
- sincos(qj, &s1, &c1);
- qj1 = qj * 2.0;
- for (i = 1, x = qj; i < m; i += 2, x += qj1)
- {
- sincos(x, &s2, &c2);
- xt += (envl[i] * c2);
- if (i < (m - 1))
- xt += (envl[i + 1] * (c1 * c2 - s1 * s2));
- }
- #else
- xt = xt0;
- qj = q * (am - j);
- for (i = 1, x = qj; i < m; i++, x += qj)
- xt += (envl[i] * cos(x));
- #endif
- a[j] = xt * scl;
- a[jj] = a[j];
- }
- }
- else /* use fft if it's easy to match -- there must be a way to handle non-power-of-2 orders here
- * stretch envl to a power of 2, fft, subsample?
- */
- {
- mus_float_t *rl, *im;
- mus_long_t fsize;
- int lim;
- mus_float_t offset;
-
- fsize = 2 * order; /* checked power of 2 above */
- rl = (mus_float_t *)calloc(fsize, sizeof(mus_float_t));
- im = (mus_float_t *)calloc(fsize, sizeof(mus_float_t));
- lim = order / 2;
- memcpy((void *)rl, (void *)envl, lim * sizeof(mus_float_t));
-
- mus_fft(rl, im, fsize, 1);
-
- scl = 4.0 / fsize;
- offset = -2.0 * envl[0] / fsize;
- for (i = 0; i < fsize; i++)
- rl[i] = rl[i] * scl + offset;
- for (i = 1, j = lim - 1, jj = lim; i < order; i += 2, j--, jj++)
- {
- a[j] = rl[i];
- a[jj] = rl[i];
- }
- free(rl);
- free(im);
- }
-
- return(a);
- }
-
-
-
- /* ---------------- one-pole-all-pass ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_float_t coeff;
- mus_float_t *x, *y;
- mus_float_t (*f)(mus_any *ptr, mus_float_t input);
- } onepall;
-
-
- static void free_onepall(mus_any *ptr)
- {
- onepall *f = (onepall *)ptr;
- if (f->x) {free(f->x); f->x = NULL;}
- if (f->y) {free(f->y); f->y = NULL;}
- free(ptr);
- }
-
- static mus_any *onepall_copy(mus_any *ptr)
- {
- onepall *g, *p;
- int bytes;
-
- p = (onepall *)ptr;
- g = (onepall *)malloc(sizeof(onepall));
- memcpy((void *)g, (void *)ptr, sizeof(onepall));
-
- bytes = g->size * sizeof(mus_float_t);
- g->x = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x), (void *)(p->x), bytes);
- g->y = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y), (void *)(p->y), bytes);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_onepall(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return((((onepall *)ptr)->f)(ptr, input));
- }
-
-
- static mus_long_t onepall_length(mus_any *ptr)
- {
- return(((onepall *)ptr)->size);
- }
-
-
- static void onepall_reset(mus_any *ptr)
- {
- onepall *f = (onepall *)ptr;
- int size;
- size = f->size;
- memset((void *)(f->x), 0, size * sizeof(mus_float_t));
- memset((void *)(f->y), 0, size * sizeof(mus_float_t));
- }
-
-
- static bool onepall_equalp(mus_any *p1, mus_any *p2)
- {
- onepall *f1 = (onepall *)p1;
- onepall *f2 = (onepall *)p2;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- if (f1->coeff != f2->coeff) return(false);
-
- return((mus_arrays_are_equal(f1->x, f2->x, float_equal_fudge_factor, f1->size)) &&
- (mus_arrays_are_equal(f1->y, f2->y, float_equal_fudge_factor, f1->size)));
- }
-
-
- static char *describe_onepall(mus_any *ptr)
- {
- onepall *gen = (onepall *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d, coeff: %f",
- mus_name(ptr),
- gen->size,
- gen->coeff);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_one_pole_all_pass(mus_any *ptr, mus_float_t input)
- {
- return((((onepall *)ptr)->f)(ptr, input));
- }
-
- static mus_float_t one_pole_all_pass_n(mus_any *f, mus_float_t input)
- {
- onepall *p = (onepall *)f;
- int i;
- mus_float_t coeff, y0;
- mus_float_t *x, *y;
-
- x = p->x;
- y = p->y;
- coeff = p->coeff;
-
- y0 = input;
- for (i = 0; i < p->size; i++)
- {
- y[i] = x[i] + (coeff * (y0 - y[i]));
- x[i] = y0;
- y0 = y[i];
- }
- return(y0);
- }
-
- static mus_float_t one_pole_all_pass_8(mus_any *f, mus_float_t input)
- {
- onepall *p = (onepall *)f;
- mus_float_t coeff;
- mus_float_t *x, *y;
-
- x = p->x;
- y = p->y;
- coeff = p->coeff;
-
- y[0] = x[0] + (coeff * (input - y[0])); x[0] = input;
- y[1] = x[1] + (coeff * (y[0] - y[1])); x[1] = y[0];
- y[2] = x[2] + (coeff * (y[1] - y[2])); x[2] = y[1];
- y[3] = x[3] + (coeff * (y[2] - y[3])); x[3] = y[2];
- y[4] = x[4] + (coeff * (y[3] - y[4])); x[4] = y[3];
- y[5] = x[5] + (coeff * (y[4] - y[5])); x[5] = y[4];
- y[6] = x[6] + (coeff * (y[5] - y[6])); x[6] = y[5];
- y[7] = x[7] + (coeff * (y[6] - y[7])); x[7] = y[6];
-
- return(y[7]);
- }
-
- static mus_float_t one_pole_all_pass_1(mus_any *f, mus_float_t input)
- {
- onepall *p = (onepall *)f;
-
- p->y[0] = p->x[0] + (p->coeff * (input - p->y[0]));
- p->x[0] = input;
- return(p->y[0]);
- }
-
-
- static mus_any_class ONE_POLE_ALL_PASS_CLASS = {
- MUS_ONE_POLE_ALL_PASS,
- (char *)S_one_pole_all_pass,
- &free_onepall,
- &describe_onepall,
- &onepall_equalp,
- 0, 0,
- &onepall_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_onepall,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &onepall_reset,
- 0, &onepall_copy
- };
-
-
- mus_any *mus_make_one_pole_all_pass(int size, mus_float_t coeff)
- {
- onepall *gen;
-
- gen = (onepall *)malloc(sizeof(onepall));
- gen->core = &ONE_POLE_ALL_PASS_CLASS;
- gen->size = size;
-
- gen->x = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->coeff = coeff;
-
- if (size == 1)
- gen->f = one_pole_all_pass_1;
- else
- {
- if (size == 8)
- gen->f = one_pole_all_pass_8;
- else gen->f = one_pole_all_pass_n;
- }
-
- return((mus_any *)gen);
- }
-
-
- bool mus_is_one_pole_all_pass(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ONE_POLE_ALL_PASS));
- }
-
-
-
- /* ---------------- env ---------------- */
-
- typedef enum {MUS_ENV_LINEAR, MUS_ENV_EXPONENTIAL, MUS_ENV_STEP} mus_env_t;
-
- typedef struct {
- mus_any_class *core;
- mus_float_t rate, current_value, base, offset, scaler, power, init_y, init_power, original_scaler, original_offset;
- mus_long_t loc, end;
- mus_env_t style;
- int index, size;
- mus_float_t *original_data;
- mus_float_t *rates;
- mus_long_t *locs;
- mus_float_t (*env_func)(mus_any *g);
- void *next;
- void (*free_env)(mus_any *ptr);
- } seg;
-
- /* I used to use exp directly, but:
-
- (define (texp1 start end num)
- (let* ((ls (log start))
- (le (log end))
- (cf (exp (/ (- le ls) (1- num))))
- (max-diff 0.0)
- (xstart start))
- (do ((i 0 (+ i 1)))
- ((= i num)
- max-diff)
- (let ((val1 (* start (exp (* (/ i (1- num)) (- le ls)))))
- (val2 xstart))
- (set! xstart (* xstart cf))
- (set! max-diff (max max-diff (abs (- val1 val2))))))))
-
- returns:
-
- :(texp1 1.0 3.0 1000000)
- 2.65991229042584e-10
- :(texp1 1.0 10.0 100000000)
- 2.24604939091932e-8
- :(texp1 10.0 1000.0 100000000)
- 4.11786902532185e-6
- :(texp1 1.0 1.1 100000000)
- 1.28246036013024e-9
- :(texp1 10.0 1000.0 1000000000)
- 4.39423240550241e-5
-
- so the repeated multiply version is more than accurate enough
- */
-
-
- bool mus_is_env(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ENV));
- }
-
-
- mus_float_t mus_env(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- return((*(gen->env_func))(ptr));
- }
-
-
- mus_float_t (*mus_env_function(mus_any *g))(mus_any *gen)
- {
- if (mus_is_env(g))
- return(((seg *)g)->env_func);
- return(NULL);
- }
-
-
- static mus_float_t mus_env_step(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- mus_float_t val;
- val = gen->current_value;
- if (gen->loc == 0)
- {
- gen->index++;
- gen->loc = gen->locs[gen->index] - gen->locs[gen->index - 1];
- gen->rate = gen->rates[gen->index];
- gen->current_value = gen->rate;
- }
- gen->loc--;
- return(val);
- }
-
-
- static mus_float_t mus_env_line(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- return(gen->current_value);
- }
-
-
- static mus_float_t mus_env_linear(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- mus_float_t val;
-
- val = gen->current_value;
- if (gen->loc == 0)
- {
- /* we can save about 10% total env time by checking here that we're on the last segment,
- * and setting gen->env_func to a version of mus_env_linear that does not watch gen->loc.
- * In any case, this code is strange -- change anything and it is 20% slower, sez callgrind.
- */
- gen->index++;
- gen->loc = gen->locs[gen->index] - gen->locs[gen->index - 1];
- gen->rate = gen->rates[gen->index];
- }
- gen->current_value += gen->rate;
- gen->loc--;
- return(val);
- }
-
-
- static mus_float_t mus_env_exponential(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- mus_float_t val;
- val = gen->current_value;
- if (gen->loc == 0)
- {
- gen->index++;
- gen->loc = gen->locs[gen->index] - gen->locs[gen->index - 1];
- gen->rate = gen->rates[gen->index];
- }
- gen->power *= gen->rate;
- gen->current_value = gen->offset + (gen->scaler * gen->power);
- gen->loc--;
- return(val);
- }
-
-
- static mus_float_t run_env(mus_any *ptr, mus_float_t unused1, mus_float_t unused2)
- {
- return(mus_env(ptr));
- }
-
-
- static void canonicalize_env(seg *e, const mus_float_t *data, int pts, mus_long_t dur, mus_float_t scaler)
- {
- int i, j, pts2;
- mus_float_t xscl, cur_loc, x1, y1, xdur;
- mus_long_t samps, pre_loc;
-
- /* pts > 1 if we get here, so the loop below is always exercised */
-
- pts2 = pts * 2;
- xdur = data[pts2 - 2] - data[0];
- if (xdur > 0.0)
- xscl = (mus_float_t)(dur - 1) / xdur;
- else xscl = 1.0;
- e->locs[pts - 2] = e->end;
-
- x1 = data[0];
- y1 = data[1];
- pre_loc = 0;
-
- for (j = 0, i = 2, cur_loc = 0.0; i < pts2; i += 2, j++)
- {
- mus_float_t cur_dx, x0, y0;
- x0 = x1;
- x1 = data[i];
- y0 = y1;
- y1 = data[i + 1];
-
- cur_dx = xscl * (x1 - x0);
- if (cur_dx < 1.0)
- cur_loc += 1.0;
- else cur_loc += cur_dx;
-
- switch (e->style)
- {
- case MUS_ENV_LINEAR:
- e->locs[j] = (mus_long_t)(cur_loc + 0.5);
- samps = e->locs[j] - pre_loc;
- pre_loc = e->locs[j];
-
- if (samps == 0)
- e->rates[j] = 0.0;
- else e->rates[j] = scaler * (y1 - y0) / (mus_float_t)samps;
- break;
-
- case MUS_ENV_EXPONENTIAL:
- e->locs[j] = (mus_long_t)(cur_loc + 0.5);
- samps = e->locs[j] - pre_loc;
- pre_loc = e->locs[j];
-
- if (samps == 0)
- e->rates[j] = 1.0;
- else e->rates[j] = exp((y1 - y0) / (mus_float_t)samps);
- break;
-
- case MUS_ENV_STEP:
- e->locs[j] = (mus_long_t)cur_loc; /* this is the change boundary (confusing...) */
- e->rates[j] = e->offset + (scaler * y0);
- break;
- }
- }
-
- e->locs[pts - 1] = 1000000000;
- e->locs[pts] = 1000000000; /* guard cell at end to make bounds check simpler */
- }
-
-
- static mus_float_t *fixup_exp_env(seg *e, const mus_float_t *data, int pts, mus_float_t offset, mus_float_t scaler, mus_float_t base)
- {
- mus_float_t min_y, max_y, val = 0.0, tmp = 0.0, b1;
- int len, i;
- bool flat;
- mus_float_t *result = NULL;
-
- if ((base <= 0.0) ||
- (base == 1.0))
- return(NULL);
-
- min_y = offset + scaler * data[1];
- max_y = min_y;
- len = pts * 2;
-
- /* fill "result" with x and (offset+scaler*y) */
-
- result = (mus_float_t *)malloc(len * sizeof(mus_float_t));
- result[0] = data[0];
- result[1] = min_y;
-
- for (i = 2; i < len; i += 2)
- {
- tmp = offset + scaler * data[i + 1];
- result[i] = data[i];
- result[i + 1] = tmp;
- if (tmp < min_y) min_y = tmp;
- if (tmp > max_y) max_y = tmp;
- }
-
- b1 = base - 1.0;
- flat = (min_y == max_y);
- if (!flat)
- val = 1.0 / (max_y - min_y);
-
- /* now logify result */
- for (i = 1; i < len; i += 2)
- {
- if (flat)
- tmp = 1.0;
- else tmp = val * (result[i] - min_y);
- result[i] = log(1.0 + (tmp * b1));
- }
-
- e->scaler = (max_y - min_y) / b1;
- e->offset = min_y;
- return(result);
- }
-
-
- static bool env_equalp(mus_any *p1, mus_any *p2)
- {
- seg *e1 = (seg *)p1;
- seg *e2 = (seg *)p2;
- if (p1 == p2) return(true);
- return((e1) && (e2) &&
- (e1->core->type == e2->core->type) &&
- (e1->loc == e2->loc) &&
- (e1->end == e2->end) &&
- (e1->style == e2->style) &&
- (e1->index == e2->index) &&
- (e1->size == e2->size) &&
-
- (e1->rate == e2->rate) &&
- (e1->base == e2->base) &&
- (e1->power == e2->power) &&
- (e1->current_value == e2->current_value) &&
- (e1->scaler == e2->scaler) &&
- (e1->offset == e2->offset) &&
- (e1->init_y == e2->init_y) &&
- (e1->init_power == e2->init_power) &&
- (clm_arrays_are_equal(e1->original_data, e2->original_data, e1->size * 2)));
- }
-
-
- static char *describe_env(mus_any *ptr)
- {
- char *str = NULL;
- seg *e = (seg *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s, pass: %lld (dur: %lld), index: %d, scaler: %.4f, offset: %.4f, data: %s",
- mus_name(ptr),
- ((e->style == MUS_ENV_LINEAR) ? "linear" : ((e->style == MUS_ENV_EXPONENTIAL) ? "exponential" : "step")),
- (e->locs) ? (e->locs[e->index] - e->loc) : -1,
- e->end + 1,
- e->index,
- e->original_scaler,
- e->original_offset,
- str = float_array_to_string(e->original_data, e->size * 2, 0));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static seg *e2_free_list = NULL, *e3_free_list = NULL, *e4_free_list = NULL;
-
- static void free_env_gen(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- (*(ptr->free_env))(pt);
- }
-
- static void fe2(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- ptr->next = e2_free_list;
- e2_free_list = ptr;
- }
-
- static void fe3(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- ptr->next = e3_free_list;
- e3_free_list = ptr;
- }
-
- static void fe4(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- ptr->next = e4_free_list;
- e4_free_list = ptr;
- }
-
- static void ferest(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- if (ptr->locs) {free(ptr->locs); ptr->locs = NULL;}
- if (ptr->rates) {free(ptr->rates); ptr->rates = NULL;}
- free(ptr);
- }
-
- static mus_any *seg_copy(mus_any *ptr)
- {
- seg *e = NULL, *p;
- p = (seg *)ptr;
-
- switch (p->size) /* "npts" */
- {
- case 1:
- e = (seg *)malloc(sizeof(seg));
- memcpy((void *)e, (void *)ptr, sizeof(seg));
- return((mus_any *)e);
-
- case 2: if (e2_free_list) {e = e2_free_list; e2_free_list = (seg *)(e->next);} break;
- case 3: if (e3_free_list) {e = e3_free_list; e3_free_list = (seg *)(e->next);} break;
- case 4: if (e4_free_list) {e = e4_free_list; e4_free_list = (seg *)(e->next);} break;
- default: break;
- }
-
- if (!e)
- {
- e = (seg *)malloc(sizeof(seg));
- memcpy((void *)e, (void *)ptr, sizeof(seg));
- if (p->rates)
- {
- int bytes;
- bytes = p->size * sizeof(mus_float_t);
- e->rates = (mus_float_t *)malloc(bytes);
- memcpy((void *)(e->rates), (void *)(p->rates), bytes);
-
- bytes = (p->size + 1) * sizeof(mus_long_t);
- e->locs = (mus_long_t *)malloc(bytes);
- memcpy((void *)(e->locs), (void *)(p->locs), bytes);
- }
- }
- else
- {
- mus_float_t *r;
- mus_long_t *l;
- int bytes;
-
- bytes = p->size * sizeof(mus_float_t);
- r = e->rates;
- memcpy((void *)r, (void *)(p->rates), bytes);
-
- bytes = (p->size + 1) * sizeof(mus_long_t);
- l = e->locs;
- memcpy((void *)l, (void *)(p->locs), bytes);
-
- memcpy((void *)e, (void *)ptr, sizeof(seg));
- e->rates = r;
- e->locs = l;
- }
- return((mus_any *)e);
- }
-
- static mus_float_t *env_data(mus_any *ptr) {return(((seg *)ptr)->original_data);} /* mus-data */
-
- static mus_float_t env_scaler(mus_any *ptr) {return(((seg *)ptr)->original_scaler);} /* "mus_float_t" for mus-scaler */
-
- static mus_float_t env_offset(mus_any *ptr) {return(((seg *)ptr)->original_offset);}
-
- int mus_env_breakpoints(mus_any *ptr) {return(((seg *)ptr)->size);}
-
- static mus_long_t env_length(mus_any *ptr) {return((((seg *)ptr)->end + 1));} /* this needs to match the :length arg to make-env (changed to +1, 20-Feb-08) */
-
- static mus_float_t env_current_value(mus_any *ptr) {return(((seg *)ptr)->current_value);}
-
- mus_long_t *mus_env_passes(mus_any *gen) {return(((seg *)gen)->locs);}
-
- mus_float_t *mus_env_rates(mus_any *gen) {return(((seg *)gen)->rates);}
-
- static int env_position(mus_any *ptr) {return(((seg *)ptr)->index);}
-
- mus_float_t mus_env_offset(mus_any *gen) {return(((seg *)gen)->offset);}
-
- mus_float_t mus_env_scaler(mus_any *gen) {return(((seg *)gen)->scaler);}
-
- mus_float_t mus_env_initial_power(mus_any *gen) {return(((seg *)gen)->init_power);}
-
- static void env_set_location(mus_any *ptr, mus_long_t val);
-
- static mus_long_t seg_set_pass(mus_any *ptr, mus_long_t val) {env_set_location(ptr, val); return(val);}
-
- static mus_long_t seg_pass(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- return(gen->locs[gen->index] - gen->loc);
- }
-
-
- static mus_float_t env_increment(mus_any *rd)
- {
- if (((seg *)rd)->style == MUS_ENV_STEP)
- return(0.0);
- return(((seg *)rd)->base);
- }
-
-
- static void env_reset(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- gen->current_value = gen->init_y;
- gen->index = 0;
- gen->loc = gen->locs[0];
- gen->rate = gen->rates[0];
- gen->power = gen->init_power;
- }
-
-
- static void rebuild_env(seg *e, mus_float_t scl, mus_float_t off, mus_long_t end)
- {
- seg *new_e;
-
- new_e = (seg *)mus_make_env(e->original_data, e->size, scl, off, e->base, 0.0, end, NULL);
- if (e->locs) free(e->locs);
- if (e->rates) free(e->rates);
- e->locs = new_e->locs;
- e->rates = new_e->rates;
-
- e->init_y = new_e->init_y;
- e->init_power = new_e->init_power;
- env_reset((mus_any *)e);
-
- free(new_e);
- }
-
-
- static mus_float_t env_set_scaler(mus_any *ptr, mus_float_t val)
- {
- seg *e;
- e = (seg *)ptr;
- rebuild_env(e, val, e->original_offset, e->end);
- e->original_scaler = val;
- return(val);
- }
-
-
- static mus_float_t env_set_offset(mus_any *ptr, mus_float_t val)
- {
- seg *e;
- e = (seg *)ptr;
- rebuild_env(e, e->original_scaler, val, e->end);
- e->original_offset = val;
- return(val);
- }
-
-
- static mus_long_t env_set_length(mus_any *ptr, mus_long_t val)
- {
- seg *e;
- e = (seg *)ptr;
- rebuild_env(e, e->original_scaler, e->original_offset, val - 1);
- e->end = val - 1;
- return(val);
- }
-
-
- static mus_any_class ENV_CLASS = {
- MUS_ENV,
- (char *)S_env,
- &free_env_gen,
- &describe_env,
- &env_equalp,
- &env_data, /* mus-data -> original breakpoints */
- 0,
- &env_length, &env_set_length,
- 0, 0,
- &env_current_value, 0, /* mus-phase?? -- used in snd-sig.c, but this needs a better access point */
- &env_scaler, &env_set_scaler,
- &env_increment,
- 0,
- &run_env,
- MUS_NOT_SPECIAL,
- NULL,
- &env_position,
- &env_offset, &env_set_offset,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &seg_pass, &seg_set_pass,
- 0,
- 0, 0, 0, 0,
- &env_reset,
- 0, &seg_copy
- };
-
-
- mus_any *mus_make_env(mus_float_t *brkpts, int npts, mus_float_t scaler, mus_float_t offset, mus_float_t base, mus_float_t duration, mus_long_t end, mus_float_t *ignored)
- {
- /* brkpts are not freed by the new env gen when it is freed, but should be protected during its existence */
- int i;
- mus_long_t dur_in_samples;
- mus_float_t *edata;
- seg *e = NULL;
- void (*fe_release)(mus_any *ptr);
-
- for (i = 2; i < npts * 2; i += 2)
- if (brkpts[i - 2] >= brkpts[i])
- {
- char *temp = NULL;
- mus_error(MUS_BAD_ENVELOPE, S_make_env ": env at breakpoint %d: x axis value: %f <= previous x value: %f (env: %s)",
- i / 2, brkpts[i], brkpts[i - 2],
- temp = float_array_to_string(brkpts, npts * 2, 0)); /* minor memleak here */
- if (temp) free(temp);
- return(NULL);
- }
-
- switch (npts)
- {
- case 1:
- e = (seg *)calloc(1, sizeof(seg));
- e->core = &ENV_CLASS;
- e->current_value = offset + scaler * brkpts[1];
- e->env_func = mus_env_line;
- e->original_data = brkpts;
- e->free_env = ferest;
- return((mus_any *)e);
-
- case 2:
- if (e2_free_list)
- {
- e = e2_free_list;
- e2_free_list = (seg *)(e->next);
- }
- fe_release = fe2;
- break;
-
- case 3:
- if (e3_free_list)
- {
- e = e3_free_list;
- e3_free_list = (seg *)(e->next);
- }
- fe_release = fe3;
- break;
-
- case 4:
- if (e4_free_list)
- {
- e = e4_free_list;
- e4_free_list = (seg *)(e->next);
- }
- fe_release = fe4;
- break;
-
- default:
- fe_release = ferest;
- break;
- }
-
- if (!e)
- {
- e = (seg *)malloc(sizeof(seg));
- e->core = &ENV_CLASS;
- e->size = npts;
- e->rates = (mus_float_t *)malloc(npts * sizeof(mus_float_t));
- e->locs = (mus_long_t *)malloc((npts + 1) * sizeof(mus_long_t));
- }
-
- e->free_env = fe_release;
- e->original_data = brkpts;
-
- if (duration != 0.0)
- dur_in_samples = (mus_long_t)(duration * sampling_rate);
- else dur_in_samples = (end + 1);
-
- e->init_y = offset + scaler * brkpts[1];
- e->current_value = e->init_y;
- e->rate = 0.0;
- e->offset = offset;
- e->scaler = scaler;
- e->original_offset = offset;
- e->original_scaler = scaler;
- e->base = base;
- e->end = (dur_in_samples - 1);
- e->loc = 0;
- e->index = 0;
-
- if (base == 1.0)
- {
- e->style = MUS_ENV_LINEAR;
- if ((npts == 2) &&
- (brkpts[1] == brkpts[3]))
- e->env_func = mus_env_line;
- else e->env_func = mus_env_linear;
- e->power = 0.0;
- e->init_power = 0.0;
- canonicalize_env(e, brkpts, npts, dur_in_samples, scaler);
- e->rates[npts - 1] = 0.0;
- }
- else
- {
- if (base == 0.0)
- {
- e->style = MUS_ENV_STEP;
- e->env_func = mus_env_step;
- e->power = 0.0;
- e->init_power = 0.0;
- canonicalize_env(e, brkpts, npts, dur_in_samples, scaler);
- e->rates[npts - 1] = e->offset + (scaler * brkpts[npts * 2 - 1]); /* stick at last value, which in this case is the value (not an increment) */
- }
- else
- {
- e->style = MUS_ENV_EXPONENTIAL;
- e->env_func = mus_env_exponential;
- edata = fixup_exp_env(e, brkpts, npts, offset, scaler, base);
- if (edata == NULL)
- {
- free(e);
- return(NULL);
- }
- canonicalize_env(e, edata, npts, dur_in_samples, 1.0);
- e->rates[npts - 1] = 1.0;
- e->power = exp(edata[1]);
- e->init_power = e->power;
- e->offset -= e->scaler;
- free(edata);
- }
- }
-
- e->rate = e->rates[0];
- e->loc = e->locs[0];
- return((mus_any *)e);
- }
-
- /* one way to make an impulse: (make-env '(0 1 1 0) :length 1 :base 0.0)
- * a counter: (make-env '(0 0 1 1) :length 21 :scaler 20) -- length = 1+scaler
- */
-
-
- static void env_set_location(mus_any *ptr, mus_long_t val)
- {
- seg *gen = (seg *)ptr;
- mus_long_t ctr = 0, loc;
-
- loc = gen->locs[gen->index] - gen->loc;
- if (loc == val) return;
-
- if (loc > val)
- mus_reset(ptr);
- else ctr = loc;
-
- while ((gen->index < (gen->size - 1)) && /* this was gen->size */
- (ctr < val))
- {
- mus_long_t samps;
- if (val > gen->locs[gen->index])
- samps = gen->locs[gen->index] - ctr;
- else samps = val - ctr;
-
- switch (gen->style)
- {
- case MUS_ENV_LINEAR:
- gen->current_value += (samps * gen->rate);
- break;
-
- case MUS_ENV_STEP:
- gen->current_value = gen->rate;
- break;
-
- case MUS_ENV_EXPONENTIAL:
- gen->power *= exp(samps * log(gen->rate));
- gen->current_value = gen->offset + (gen->scaler * gen->power);
- break;
- }
-
- ctr += samps;
- if (ctr < val)
- {
- gen->index++;
- if (gen->index < gen->size)
- gen->rate = gen->rates[gen->index];
- }
- }
- gen->loc = gen->locs[gen->index] - ctr;
- }
-
-
- mus_float_t mus_env_interp(mus_float_t x, mus_any *ptr)
- {
- /* the accuracy depends on the duration here -- more samples = more accurate */
- seg *gen = (seg *)ptr;
- env_set_location(ptr, (mus_long_t)((x * (gen->end + 1)) / (gen->original_data[gen->size * 2 - 2])));
- return(gen->current_value);
- }
-
-
- mus_float_t mus_env_any(mus_any *e, mus_float_t (*connect_points)(mus_float_t val))
- {
- /* "env_any" is supposed to mimic "out-any" */
- seg *gen = (seg *)e;
- mus_float_t *pts;
- int pt, size;
- mus_float_t y0, y1, new_val, val;
- mus_float_t scaler, offset;
-
- scaler = gen->original_scaler;
- offset = gen->original_offset;
- size = gen->size;
-
- if (size <= 1)
- return(offset + scaler * connect_points(0.0));
-
- pts = gen->original_data;
- pt = gen->index;
- if (pt >= (size - 1)) pt = size - 2;
- if (pts[pt * 2 + 1] <= pts[pt * 2 + 3])
- {
- y0 = pts[pt * 2 + 1];
- y1 = pts[pt * 2 + 3];
- }
- else
- {
- y1 = pts[pt * 2 + 1];
- y0 = pts[pt * 2 + 3];
- }
-
- val = (mus_env(e) - offset) / scaler;
- new_val = connect_points( (val - y0) / (y1 - y0));
- return(offset + scaler * (y0 + new_val * (y1 - y0)));
- }
-
-
- /* ---------------- pulsed-env ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_any *e, *p;
- bool gens_allocated;
- } plenv;
-
-
- static void free_pulsed_env(mus_any *ptr)
- {
- plenv *g;
- g = (plenv *)ptr;
- if (g->gens_allocated)
- {
- mus_free(g->e);
- mus_free(g->p);
- }
- free(ptr);
- }
-
- static mus_any *plenv_copy(mus_any *ptr)
- {
- plenv *g, *p;
- p = (plenv *)ptr;
- g = (plenv *)malloc(sizeof(plenv));
- memcpy((void *)g, (void *)ptr, sizeof(plenv));
- g->gens_allocated = true;
- g->e = mus_copy(p->e);
- g->p = mus_copy(p->p);
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_pulsed_env(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_pulsed_env(ptr, input));
- }
-
-
- static void pulsed_env_reset(mus_any *ptr)
- {
- plenv *pl = (plenv *)ptr;
- mus_reset(pl->e);
- mus_reset(pl->p);
- }
-
-
- static bool pulsed_env_equalp(mus_any *p1, mus_any *p2)
- {
- plenv *f1 = (plenv *)p1;
- plenv *f2 = (plenv *)p2;
-
- if (f1 == f2) return(true);
- return((env_equalp(f1->e, f2->e)) &&
- (sw_equalp(f1->p, f2->p)));
- }
-
-
- static char *describe_pulsed_env(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s",
- mus_name(ptr));
- return(describe_buffer);
- }
-
- static mus_any_class PULSED_ENV_CLASS = {
- MUS_PULSED_ENV,
- (char *)S_pulsed_env,
- &free_pulsed_env,
- &describe_pulsed_env,
- &pulsed_env_equalp,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_pulsed_env,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &pulsed_env_reset,
- 0, &plenv_copy
- };
-
-
- mus_any *mus_make_pulsed_env(mus_any *e, mus_any *p)
- {
- plenv *gen;
-
- gen = (plenv *)malloc(sizeof(plenv));
- gen->core = &PULSED_ENV_CLASS;
- gen->e = e;
- gen->p = p;
- gen->gens_allocated = false;
- return((mus_any *)gen);
- }
-
- bool mus_is_pulsed_env(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_PULSED_ENV));
- }
-
- mus_float_t mus_pulsed_env(mus_any *g, mus_float_t inval)
- {
- plenv *pl = (plenv *)g;
- mus_float_t pt_val;
- pt_val = mus_pulse_train(pl->p, inval);
- if (pt_val > 0.1)
- mus_reset(pl->e);
- return(mus_env(pl->e));
- }
-
-
- mus_float_t mus_pulsed_env_unmodulated(mus_any *g)
- {
- plenv *pl = (plenv *)g;
- mus_float_t pt_val;
- pt_val = mus_pulse_train_unmodulated(pl->p);
- if (pt_val > 0.1)
- mus_reset(pl->e);
- return(mus_env(pl->e));
- }
-
-
-
-
- /* ---------------- input/output ---------------- */
-
- static mus_float_t mus_read_sample(mus_any *fd, mus_long_t frample, int chan)
- {
- if ((check_gen(fd, "mus-read-sample")) &&
- ((fd->core)->read_sample))
- return(((*(fd->core)->read_sample))(fd, frample, chan));
- return((mus_float_t)mus_error(MUS_NO_SAMPLE_INPUT,
- ":can't find %s's sample input function",
- mus_name(fd)));
- }
-
-
- char *mus_file_name(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_file_name)) &&
- (gen->core->file_name))
- return((*(gen->core->file_name))(gen));
- else mus_error(MUS_NO_FILE_NAME, "can't get %s's file name", mus_name(gen));
- return(NULL);
- }
-
-
- bool mus_is_input(mus_any *gen)
- {
- return((gen) &&
- (gen->core->extended_type == MUS_INPUT));
- }
-
-
- bool mus_is_output(mus_any *gen)
- {
- return((gen) &&
- (gen->core->extended_type == MUS_OUTPUT));
- }
-
-
-
- /* ---------------- file->sample ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int chan;
- int dir;
- mus_long_t loc;
- char *file_name;
- int chans;
- mus_float_t **ibufs, **saved_data;
- mus_float_t *sbuf;
- mus_long_t data_start, data_end, file_end;
- mus_long_t file_buffer_size;
- mus_float_t (*reader)(mus_any *ptr);
- } rdin;
-
-
- static char *describe_file_to_sample(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static bool rdin_equalp(mus_any *p1, mus_any *p2)
- {
- rdin *r1 = (rdin *)p1;
- rdin *r2 = (rdin *)p2;
- return((p1 == p2) ||
- ((r1) && (r2) &&
- (r1->core->type == r2->core->type) &&
- (r1->chan == r2->chan) &&
- (r1->loc == r2->loc) &&
- (r1->dir == r2->dir) &&
- (r1->file_name) &&
- (r2->file_name) &&
- (strcmp(r1->file_name, r2->file_name) == 0)));
- }
-
-
- static void free_file_to_sample(mus_any *p)
- {
- rdin *ptr = (rdin *)p;
- if (ptr->core->end) ((*ptr->core->end))(p);
- free(ptr->file_name);
- free(ptr);
- }
-
- static mus_long_t make_ibufs(rdin *gen)
- {
- int i;
- mus_long_t len;
- len = gen->file_end + 1;
- if (len > gen->file_buffer_size)
- len = gen->file_buffer_size;
-
- gen->ibufs = (mus_float_t **)malloc(gen->chans * sizeof(mus_float_t *));
- for (i = 0; i < gen->chans; i++)
- gen->ibufs[i] = (mus_float_t *)malloc(len * sizeof(mus_float_t));
-
- return(len);
- }
-
- static mus_any *rdin_copy(mus_any *ptr)
- {
- rdin *g, *p;
- p = (rdin *)ptr;
- g = (rdin *)malloc(sizeof(rdin));
- memcpy((void *)g, (void *)ptr, sizeof(rdin));
- g->file_name = mus_strdup(p->file_name);
- if (p->ibufs)
- {
- int i;
- mus_long_t len;
- len = make_ibufs(g);
- for (i = 0; i < g->chans; i++)
- memcpy((void *)(g->ibufs[i]), (void *)(p->ibufs[i]), len * sizeof(mus_float_t));
- }
- return((mus_any *)g);
- }
-
- static mus_long_t file_to_sample_length(mus_any *ptr) {return((((rdin *)ptr)->file_end));}
-
- static int file_to_sample_channels(mus_any *ptr) {return((int)(((rdin *)ptr)->chans));}
-
- static mus_float_t file_to_sample_increment(mus_any *rd) {return((mus_float_t)(((rdin *)rd)->dir));}
- static mus_float_t file_to_sample_set_increment(mus_any *rd, mus_float_t val) {((rdin *)rd)->dir = (int)val; return(val);}
-
- static char *file_to_sample_file_name(mus_any *ptr) {return(((rdin *)ptr)->file_name);}
-
- static void no_reset(mus_any *ptr) {}
-
- static mus_float_t mus_in_any_from_file(mus_any *ptr, mus_long_t samp, int chan)
- {
- /* check in-core buffer bounds,
- * if needed read new buffer (taking into account dir)
- * return mus_float_t at samp (frample)
- */
- rdin *gen = (rdin *)ptr;
-
- if (chan >= gen->chans)
- return(0.0);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- return((mus_float_t)(gen->ibufs[chan][samp - gen->data_start]));
-
- if ((samp >= 0) &&
- (samp < gen->file_end))
- {
- /* got to read it from the file */
- int fd;
- mus_long_t newloc;
- /* read in first buffer start either at samp (dir > 0) or samp-bufsize (dir < 0) */
-
- if (samp >= gen->data_start) /* gen dir is irrelevant here (see grev in clm23.scm) */
- newloc = samp;
- else newloc = (mus_long_t)(samp - (gen->file_buffer_size * .75));
- /* The .75 in the backwards read is trying to avoid reading the full buffer on
- * nearly every sample when we're oscillating around the
- * nominal buffer start/end (in src driven by an oscil for example)
- */
- if (newloc < 0) newloc = 0;
- gen->data_start = newloc;
- gen->data_end = newloc + gen->file_buffer_size - 1;
- fd = mus_sound_open_input(gen->file_name);
- if (fd == -1)
- return((mus_float_t)mus_error(MUS_CANT_OPEN_FILE,
- "open(%s) -> %s",
- gen->file_name, STRERROR(errno)));
- else
- {
- if (gen->ibufs == NULL)
- make_ibufs(gen);
- mus_file_seek_frample(fd, gen->data_start);
-
- if ((gen->data_start + gen->file_buffer_size) >= gen->file_end)
- mus_file_read_chans(fd, gen->data_start, gen->file_end - gen->data_start, gen->chans, gen->ibufs, gen->ibufs);
- else mus_file_read_chans(fd, gen->data_start, gen->file_buffer_size, gen->chans, gen->ibufs, gen->ibufs);
-
- /* we have to check file_end here because chunked files can have trailing chunks containing
- * comments or whatever. io.c (mus_file_read_*) merely calls read, and translates bytes --
- * if it gets fewer than requested, it zeros from the point where the incoming file data stopped,
- * but that can be far beyond the actual end of the sample data! It is at this level that
- * we know how much data is actually supposed to be in the file.
- *
- * Also, file_end is the number of framples, so we should not read samp # file_end (see above).
- */
-
- mus_sound_close_input(fd);
- if (gen->data_end > gen->file_end) gen->data_end = gen->file_end;
- }
-
- return((mus_float_t)(gen->ibufs[chan][samp - gen->data_start]));
- }
-
- return(0.0);
- }
-
-
- static mus_float_t run_file_to_sample(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- /* mus_read_sample here? */
- return(mus_in_any_from_file(ptr, (int)arg1, (int)arg2));
- }
-
-
- static int file_to_sample_end(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- if (gen)
- {
- if (gen->ibufs)
- {
- int i;
- for (i = 0; i < gen->chans; i++)
- if (gen->ibufs[i])
- free(gen->ibufs[i]);
- free(gen->ibufs);
- gen->ibufs = NULL;
- gen->sbuf = NULL;
- }
- }
- return(0);
- }
-
-
- static mus_any_class FILE_TO_SAMPLE_CLASS = {
- MUS_FILE_TO_SAMPLE,
- (char *)S_file_to_sample,
- &free_file_to_sample,
- &describe_file_to_sample,
- &rdin_equalp,
- 0, 0,
- &file_to_sample_length, 0,
- 0, 0, 0, 0,
- 0, 0,
- &file_to_sample_increment,
- &file_to_sample_set_increment,
- &run_file_to_sample,
- MUS_INPUT,
- NULL,
- &file_to_sample_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- &mus_in_any_from_file,
- 0,
- &file_to_sample_file_name,
- &file_to_sample_end,
- 0, /* location */
- 0, /* set_location */
- 0, /* channel */
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdin_copy
- };
-
-
- bool mus_is_file_to_sample(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILE_TO_SAMPLE));
- }
-
-
- mus_any *mus_make_file_to_sample_with_buffer_size(const char *filename, mus_long_t buffer_size)
- {
- rdin *gen;
-
- if (filename == NULL)
- mus_error(MUS_NO_FILE_NAME_PROVIDED, S_make_file_to_sample " requires a file name");
- else
- {
- gen = (rdin *)calloc(1, sizeof(rdin));
- gen->core = &FILE_TO_SAMPLE_CLASS;
-
- gen->file_name = (char *)malloc((strlen(filename) + 1) * sizeof(char));
- strcpy(gen->file_name, filename);
- gen->data_end = -1; /* force initial read */
-
- gen->chans = mus_sound_chans(gen->file_name);
- if (gen->chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_make_file_to_sample ": %s chans: %d", filename, gen->chans);
-
- gen->file_end = mus_sound_framples(gen->file_name);
- if (gen->file_end < 0)
- mus_error(MUS_NO_LENGTH, S_make_file_to_sample ": %s framples: %lld", filename, gen->file_end);
-
- if (buffer_size < gen->file_end)
- gen->file_buffer_size = buffer_size;
- else gen->file_buffer_size = gen->file_end;
-
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_any *mus_make_file_to_sample(const char *filename)
- {
- return(mus_make_file_to_sample_with_buffer_size(filename, clm_file_buffer_size));
- }
-
-
- mus_float_t mus_file_to_sample(mus_any *ptr, mus_long_t samp, int chan)
- {
- rdin *gen = (rdin *)ptr;
-
- if (chan >= gen->chans)
- return(0.0);
-
- /* redundant in a sense, but saves the call overhead of mus_in_any_from_file */
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- return((mus_float_t)(gen->ibufs[chan][samp - gen->data_start]));
-
- return(mus_in_any_from_file(ptr, samp, chan));
- }
-
-
-
- /* ---------------- readin ---------------- */
-
- /* readin reads only the desired channel and increments the location by the direction
- * it inherits from and specializes the file_to_sample class
- */
-
- static char *describe_readin(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s[chan %d], loc: %lld, dir: %d",
- mus_name(ptr),
- gen->file_name, gen->chan, gen->loc, gen->dir);
- return(describe_buffer);
- }
-
-
- static void free_readin(mus_any *p)
- {
- rdin *ptr = (rdin *)p;
- if (ptr->core->end) ((*ptr->core->end))(p);
- free(ptr->file_name);
- free(ptr);
- }
-
- static mus_float_t run_readin(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(((rdin *)ptr)->reader(ptr));}
- static mus_float_t readin_to_sample(mus_any *ptr, mus_long_t samp, int chan) {return(((rdin *)ptr)->reader(ptr));}
-
- static mus_float_t rd_increment(mus_any *ptr) {return((mus_float_t)(((rdin *)ptr)->dir));}
- static mus_float_t rd_set_increment(mus_any *ptr, mus_float_t val) {((rdin *)ptr)->dir = (int)val; return(val);}
-
- static mus_long_t rd_location(mus_any *rd) {return(((rdin *)rd)->loc);}
- static mus_long_t rd_set_location(mus_any *rd, mus_long_t loc) {((rdin *)rd)->loc = loc; return(loc);}
-
- static int rd_channel(mus_any *rd) {return(((rdin *)rd)->chan);}
-
- static mus_any_class READIN_CLASS = {
- MUS_READIN,
- (char *)S_readin,
- &free_readin,
- &describe_readin,
- &rdin_equalp,
- 0, 0,
- &file_to_sample_length, 0,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- &rd_increment,
- &rd_set_increment,
- &run_readin,
- MUS_INPUT,
- NULL,
- &file_to_sample_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- &readin_to_sample,
- 0,
- &file_to_sample_file_name,
- &file_to_sample_end,
- &rd_location,
- &rd_set_location,
- &rd_channel,
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdin_copy
- };
-
-
- bool mus_is_readin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_READIN));
- }
-
-
- mus_float_t mus_readin(mus_any *ptr)
- {
- return(((rdin *)ptr)->reader(ptr));
- }
-
-
- static mus_float_t safe_readin(mus_any *ptr)
- {
- mus_float_t res;
- rdin *rd = (rdin *)ptr;
-
- if ((rd->loc < rd->file_end) &&
- (rd->loc >= 0))
- res = rd->sbuf[rd->loc];
- else res = 0.0;
- rd->loc += rd->dir;
- return(res);
- }
-
-
- static mus_float_t readin(mus_any *ptr)
- {
- mus_float_t res;
- rdin *rd = (rdin *)ptr;
-
- if ((rd->loc <= rd->data_end) &&
- (rd->loc >= rd->data_start))
- res = rd->sbuf[rd->loc - rd->data_start];
- else
- {
- if ((rd->loc < 0) || (rd->loc >= rd->file_end))
- res = 0.0;
- else res = mus_in_any_from_file(ptr, rd->loc, rd->chan);
- }
-
- rd->loc += rd->dir;
- return(res);
- }
-
-
- mus_any *mus_make_readin_with_buffer_size(const char *filename, int chan, mus_long_t start, int direction, mus_long_t buffer_size)
- {
- rdin *gen;
- if (chan >= mus_sound_chans(filename))
- mus_error(MUS_NO_SUCH_CHANNEL, S_make_readin ": %s, chan: %d, but chans: %d", filename, chan, mus_sound_chans(filename));
-
- gen = (rdin *)mus_make_file_to_sample(filename);
- if (gen)
- {
- gen->core = &READIN_CLASS;
- gen->loc = start;
- gen->dir = direction;
- gen->chan = chan;
- /* the saved data option does not save us anything in file_to_sample above */
- gen->saved_data = mus_sound_saved_data(filename);
- if (!gen->saved_data)
- {
- char *str;
- str = mus_expand_filename(filename);
- if (str)
- {
- gen->saved_data = mus_sound_saved_data(str);
- free(str);
- }
- }
- if (gen->saved_data)
- {
- gen->file_buffer_size = gen->file_end;
- gen->sbuf = gen->saved_data[chan];
- gen->reader = safe_readin;
- gen->data_start = 0;
- gen->data_end = gen->file_end;
- }
- else
- {
- gen->ibufs = (mus_float_t **)calloc(gen->chans, sizeof(mus_float_t *));
- if (buffer_size > gen->file_end)
- {
- gen->file_buffer_size = gen->file_end;
- gen->reader = safe_readin;
- gen->ibufs[chan] = (mus_float_t *)malloc(gen->file_buffer_size * sizeof(mus_float_t));
- mus_in_any_from_file((mus_any *)gen, 0, chan);
- }
- else
- {
- gen->file_buffer_size = buffer_size;
- gen->reader = readin;
- gen->ibufs[chan] = (mus_float_t *)malloc(gen->file_buffer_size * sizeof(mus_float_t));
- }
- gen->sbuf = gen->ibufs[chan];
- }
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
- /* it would be easy to extend readin to read from a float-vector by using the saved_data and safe_readin
- * business above -- just need mus_make_readin_from_float_vector or something.
- */
-
-
- mus_long_t mus_set_location(mus_any *gen, mus_long_t loc)
- {
- if ((check_gen(gen, S_set S_mus_location)) &&
- (gen->core->set_location))
- return((*(gen->core->set_location))(gen, loc));
- return((mus_long_t)mus_error(MUS_NO_LOCATION, "can't set %s's location", mus_name(gen)));
- }
-
-
-
- /* ---------------- in-any ---------------- */
-
- mus_float_t mus_in_any(mus_long_t samp, int chan, mus_any *IO)
- {
- if (IO) return(mus_read_sample(IO, samp, chan));
- return(0.0);
- }
-
-
- bool mus_in_any_is_safe(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- return((gen) &&
- ((gen->core->read_sample == mus_in_any_from_file) ||
- (gen->core->read_sample == readin_to_sample)));
- }
-
-
-
- /* ---------------- file->frample ---------------- */
-
- /* also built on file->sample */
-
- static char *describe_file_to_frample(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static mus_float_t run_file_to_frample(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_error(MUS_NO_RUN, "no run method for file->frample");
- return(0.0);
- }
-
-
- static mus_any_class FILE_TO_FRAMPLE_CLASS = {
- MUS_FILE_TO_FRAMPLE,
- (char *)S_file_to_frample,
- &free_file_to_sample,
- &describe_file_to_frample,
- &rdin_equalp,
- 0, 0,
- &file_to_sample_length, 0,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- &file_to_sample_increment, /* allow backward reads */
- &file_to_sample_set_increment,
- &run_file_to_frample,
- MUS_INPUT,
- NULL,
- &file_to_sample_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- &mus_in_any_from_file,
- 0,
- &file_to_sample_file_name,
- &file_to_sample_end,
- 0, /* location */
- 0, /* set_location */
- 0, /* channel */
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdin_copy
- };
-
-
- mus_any *mus_make_file_to_frample_with_buffer_size(const char *filename, mus_long_t buffer_size)
- {
- rdin *gen;
- gen = (rdin *)mus_make_file_to_sample_with_buffer_size(filename, buffer_size);
- if (gen)
- {
- gen->core = &FILE_TO_FRAMPLE_CLASS;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_any *mus_make_file_to_frample(const char *filename)
- {
- return(mus_make_file_to_frample_with_buffer_size(filename, clm_file_buffer_size));
- }
-
-
- bool mus_is_file_to_frample(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILE_TO_FRAMPLE));
- }
-
-
- mus_float_t *mus_file_to_frample(mus_any *ptr, mus_long_t samp, mus_float_t *f)
- {
- rdin *gen = (rdin *)ptr;
- int i;
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- {
- mus_long_t pos;
- pos = samp - gen->data_start;
- f[0] = gen->ibufs[0][pos];
- for (i = 1; i < gen->chans; i++)
- f[i] = gen->ibufs[i][pos];
- }
- else
- {
- if ((samp < 0) ||
- (samp >= gen->file_end))
- {
- for (i = 0; i < gen->chans; i++)
- f[i] = 0.0;
- }
- else
- {
- f[0] = mus_in_any_from_file(ptr, samp, 0);
- for (i = 1; i < gen->chans; i++)
- f[i] = mus_in_any_from_file(ptr, samp, i);
- }
- }
- return(f);
- }
-
-
-
- /* ---------------- sample->file ---------------- */
-
- /* in all output functions, the assumption is that we're adding to whatever already exists */
- /* also, the "end" methods need to flush the output buffer */
-
- /* rdout struct is in clm.h */
-
- static char *describe_sample_to_file(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static bool sample_to_file_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static void free_sample_to_file(mus_any *p)
- {
- rdout *ptr = (rdout *)p;
- if (ptr->core->end) ((*ptr->core->end))(p);
- free(ptr->file_name);
- free(ptr);
- }
-
- static mus_any *rdout_copy(mus_any *ptr)
- {
- rdout *g, *p;
- p = (rdout *)ptr;
- g = (rdout *)malloc(sizeof(rdout));
- memcpy((void *)g, (void *)ptr, sizeof(rdout));
- g->file_name = mus_strdup(p->file_name);
- if (p->obufs)
- {
- int i;
- mus_long_t bytes;
- bytes = clm_file_buffer_size * sizeof(mus_float_t);
- g->obufs = (mus_float_t **)malloc(g->chans * sizeof(mus_float_t *));
- for (i = 0; i < g->chans; i++)
- {
- g->obufs[i] = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->obufs[i]), (void *)(p->obufs[i]), bytes);
- }
- g->obuf0 = g->obufs[0];
- if (g->chans > 1)
- g->obuf1 = g->obufs[1];
- else g->obuf1 = NULL;
- }
- return((mus_any *)g);
- }
-
- static int sample_to_file_channels(mus_any *ptr) {return((int)(((rdout *)ptr)->chans));}
-
- static mus_long_t bufferlen(mus_any *ptr) {return(clm_file_buffer_size);}
-
- static mus_long_t set_bufferlen(mus_any *ptr, mus_long_t len) {clm_file_buffer_size = len; return(len);}
-
- static char *sample_to_file_file_name(mus_any *ptr) {return(((rdout *)ptr)->file_name);}
-
- static int sample_to_file_end(mus_any *ptr);
-
- static mus_float_t run_sample_to_file(mus_any *ptr, mus_float_t arg1, mus_float_t arg2) {mus_error(MUS_NO_RUN, "no run method for sample->file"); return(0.0);}
-
- static mus_any_class SAMPLE_TO_FILE_CLASS = {
- MUS_SAMPLE_TO_FILE,
- (char *)S_sample_to_file,
- &free_sample_to_file,
- &describe_sample_to_file,
- &sample_to_file_equalp,
- 0, 0,
- &bufferlen, &set_bufferlen, /* does this have any effect on the current gen? */
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- 0, 0,
- &run_sample_to_file,
- MUS_OUTPUT,
- NULL,
- &sample_to_file_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- &mus_out_any_to_file,
- &sample_to_file_file_name,
- &sample_to_file_end,
- 0, 0, 0,
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdout_copy
- };
-
-
- static int *sample_type_zero = NULL;
-
- int mus_sample_type_zero(mus_sample_t samp_type)
- {
- return(sample_type_zero[samp_type]);
- }
-
-
- static void flush_buffers(rdout *gen)
- {
- int fd;
-
- if ((gen->obufs == NULL) ||
- (mus_file_probe(gen->file_name) == 0) ||
- (gen->chans == 0))
- return; /* can happen if output abandoned, then later mus_free called via GC sweep */
-
- fd = mus_sound_open_input(gen->file_name);
- if (fd == -1)
- {
- /* no output yet, so open the output file and write the current samples (no need to add to existing samples in this case) */
- fd = mus_sound_open_output(gen->file_name,
- (int)sampling_rate,
- gen->chans,
- gen->output_sample_type,
- gen->output_header_type,
- NULL);
- if (fd == -1)
- mus_error(MUS_CANT_OPEN_FILE,
- "open(%s) -> %s",
- gen->file_name, STRERROR(errno));
- else
- {
- mus_file_write(fd, 0, gen->out_end, gen->chans, gen->obufs);
- mus_sound_close_output(fd, (gen->out_end + 1) * gen->chans * mus_bytes_per_sample(mus_sound_sample_type(gen->file_name)));
- }
- }
- else
- {
- /* get existing samples, add new output, write back to output */
- mus_float_t **addbufs = NULL;
- int i;
- mus_sample_t sample_type;
- mus_long_t current_file_framples, framples_to_add;
-
- sample_type = mus_sound_sample_type(gen->file_name);
- current_file_framples = mus_sound_framples(gen->file_name);
- /* this is often 0 (brand-new file) */
-
- if (current_file_framples > gen->data_start)
- {
- bool allocation_failed = false;
- addbufs = (mus_float_t **)calloc(gen->chans, sizeof(mus_float_t *));
-
- for (i = 0; i < gen->chans; i++)
- {
- /* clm_file_buffer_size may be too large, but it's very hard to tell that
- * in advance. In Linux, malloc returns a non-null pointer even when
- * there's no memory available, so you have to touch the memory to force
- * the OS to deal with it, then the next allocation returns null.
- */
- addbufs[i] = (mus_float_t *)malloc(clm_file_buffer_size * sizeof(mus_float_t));
- if (addbufs[i])
- addbufs[i][0] = 0.0;
- else
- {
- allocation_failed = true;
- break;
- }
- }
-
- if (allocation_failed)
- {
- mus_long_t old_file_buffer_size = 0;
-
- /* first clean up the mess we made */
- for (i = 0; i < gen->chans; i++)
- if (addbufs[i])
- {
- free(addbufs[i]);
- addbufs[i] = NULL;
- }
- free(addbufs);
-
- /* it would take a lot of screwing around to find the biggest clm_file_buffer_size we could handle,
- * and it might fail on the next call (if more chans), so we'll throw an error. We could get
- * say 1024 samps per chan, then run through a loop outputting the current buffer, but geez...
- */
- /* but... if we hit this in with-sound, mus_error calls (eventually) s7_error which sees the
- * dynamic-wind and tries to call mus-close, which tries to flush the buffers and we have
- * an infinite loop. So, we need to clean up right now.
- */
- mus_sound_close_input(fd);
- old_file_buffer_size = clm_file_buffer_size;
- clm_file_buffer_size = MUS_DEFAULT_FILE_BUFFER_SIZE;
- mus_error(MUS_MEMORY_ALLOCATION_FAILED, S_mus_file_buffer_size " (%lld) is too large: we can't allocate the output buffers!", old_file_buffer_size);
- return;
- }
- }
-
- framples_to_add = gen->out_end - gen->data_start;
-
- /* if the caller reset clm_file_buffer_size during a run, framples_to_add might be greater than the assumed buffer size,
- * so we need to complain and fix up the limits. In CLM, the size is set in sound.lisp, begin-with-sound.
- * In Snd via mus_set_file_buffer_size in clm2xen.c. The initial default is set in mus_initialize
- * called in CLM by clm-initialize-links via in cmus.c, and in Snd in clm2xen.c when the module is setup.
- */
- if (framples_to_add >= clm_file_buffer_size)
- {
- mus_print("clm-file-buffer-size changed? %lld <= %lld (start: %lld, end: %lld, %lld)",
- clm_file_buffer_size, framples_to_add, gen->data_start, gen->data_end, gen->out_end);
-
- framples_to_add = clm_file_buffer_size - 1;
- /* this means we drop samples -- the other choice (short of throwing an error) would
- * be to read/allocate the bigger size.
- */
- }
- if (addbufs)
- {
- mus_file_seek_frample(fd, gen->data_start);
- mus_file_read(fd, gen->data_start, framples_to_add + 1, gen->chans, addbufs);
- }
- mus_sound_close_input(fd); /* close previous mus_sound_open_input */
-
- fd = mus_sound_reopen_output(gen->file_name, gen->chans, sample_type,
- mus_sound_header_type(gen->file_name),
- mus_sound_data_location(gen->file_name));
-
- if ((current_file_framples < gen->data_start) &&
- (sample_type_zero[sample_type] != 0))
- {
- /* we're about to create a gap in the output file. mus_file_seek_frample calls lseek which (man lseek):
- *
- * "The lseek function allows the file offset to be set beyond the end of
- * the existing end-of-file of the file (but this does not change the size
- * of the file). If data is later written at this point, subsequent reads
- * of the data in the gap return bytes of zeros (until data is actually
- * written into the gap)."
- *
- * but 0 bytes in a file are not interpreted as sound samples of 0 in several sample types.
- * for example, mus-mulaw 0 => -.98, whereas sound sample 0 is a byte of 255.
- * see the table at the end of this file (sample_type_zero) for the other cases.
- *
- * So, we need to write explicit sample-type 0 values in those cases where machine 0's
- * won't be sample type 0. sample_type_zero[type] != 0 signals we have such a
- * case, and returns the nominal zero value. For unsigned shorts, we also need to
- * take endianess into account.
- */
-
- mus_long_t filler, current_samps, bytes, bps;
- unsigned char *zeros;
- #define MAX_ZERO_SAMPLES 65536
-
- bps = mus_bytes_per_sample(sample_type);
- filler = gen->data_start - current_file_framples;
- mus_file_seek_frample(fd, current_file_framples);
-
- if (filler > MAX_ZERO_SAMPLES)
- bytes = MAX_ZERO_SAMPLES * bps * gen->chans;
- else bytes = filler * bps * gen->chans;
-
- zeros = (unsigned char *)malloc(bytes);
- if (bps == 1)
- memset((void *)zeros, sample_type_zero[sample_type], bytes);
- else /* it has to be a short */
- {
- int df, i, b1, b2;
- df = sample_type_zero[sample_type];
- b1 = df >> 8;
- b2 = df & 0xff;
- for (i = 0; i < bytes; i += 2)
- {
- zeros[i] = b2;
- zeros[i + 1] = b1;
- }
- }
- /* (with-sound (:sample-type mus-ulshort) (fm-violin 10 1 440 .1)) */
- while (filler > 0)
- {
- ssize_t wbytes;
- if (filler > MAX_ZERO_SAMPLES)
- current_samps = MAX_ZERO_SAMPLES;
- else
- {
- current_samps = filler;
- bytes = current_samps * bps * gen->chans;
- }
- wbytes = write(fd, zeros, bytes);
- if (wbytes != bytes) fprintf(stderr, "%s[%d]: write trouble\n", __func__, __LINE__);
- filler -= current_samps;
- }
- free(zeros);
- }
-
- if (addbufs)
- {
- int j;
- /* fill/write output buffers with current data added to saved data */
- for (j = 0; j < gen->chans; j++)
- {
- mus_float_t *adder, *vals;
- mus_long_t add4;
- adder = addbufs[j];
- vals = gen->obufs[j];
- add4 = framples_to_add - 4;
- i = 0;
- while (i <= add4)
- {
- adder[i] += vals[i];
- i++;
- adder[i] += vals[i];
- i++;
- adder[i] += vals[i];
- i++;
- adder[i] += vals[i];
- i++;
- }
- for (; i <= framples_to_add; i++)
- adder[i] += vals[i];
- }
-
- mus_file_seek_frample(fd, gen->data_start);
- mus_file_write(fd, 0, framples_to_add, gen->chans, addbufs);
- for (i = 0; i < gen->chans; i++)
- free(addbufs[i]);
- free(addbufs);
- }
- else
- {
- /* output currently empty, so just flush out the gen->obufs */
- mus_file_seek_frample(fd, gen->data_start);
- mus_file_write(fd, 0, framples_to_add, gen->chans, gen->obufs);
- }
-
- if (current_file_framples <= gen->out_end)
- current_file_framples = gen->out_end + 1;
- mus_sound_close_output(fd, current_file_framples * gen->chans * mus_bytes_per_sample(sample_type));
- }
- }
-
-
- mus_any *mus_sample_to_file_add(mus_any *out1, mus_any *out2)
- {
- mus_long_t min_framples;
- rdout *dest = (rdout *)out1;
- rdout *in_coming = (rdout *)out2;
- int chn, min_chans;
-
- min_chans = dest->chans;
- if (in_coming->chans < min_chans) min_chans = in_coming->chans;
- min_framples = in_coming->out_end;
-
- for (chn = 0; chn < min_chans; chn++)
- {
- mus_long_t i;
- for (i = 0; i < min_framples; i++)
- dest->obufs[chn][i] += in_coming->obufs[chn][i];
- memset((void *)(in_coming->obufs[chn]), 0, min_framples * sizeof(mus_float_t));
- }
-
- if (min_framples > dest->out_end)
- dest->out_end = min_framples;
-
- in_coming->out_end = 0;
- in_coming->data_start = 0;
-
- return((mus_any*)dest);
- }
-
-
- mus_float_t mus_out_any_to_file(mus_any *ptr, mus_long_t samp, int chan, mus_float_t val)
- {
- rdout *gen = (rdout *)ptr;
- if (!ptr) return(val);
-
- if ((chan >= gen->chans) || /* checking for (val == 0.0) here appears to make no difference overall */
- (!(gen->obufs)))
- return(val);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- gen->obufs[chan][samp - gen->data_start] += val;
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obufs[chan][0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- return(val);
- }
-
-
- static void mus_out_chans_to_file(rdout *gen, mus_long_t samp, int chans, mus_float_t *vals)
- {
- int i;
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- {
- mus_long_t pos;
- pos = samp - gen->data_start;
- for (i = 0; i < chans; i++)
- gen->obufs[i][pos] += vals[i];
- }
- else
- {
- int j;
- if (samp < 0) return;
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- for (i = 0; i < chans; i++)
- gen->obufs[i][0] += vals[i];
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- }
-
-
- static mus_float_t mus_outa_to_file(mus_any *ptr, mus_long_t samp, mus_float_t val)
- {
- rdout *gen = (rdout *)ptr;
- if (!ptr) return(val);
-
- if ((!(gen->obuf0)) ||
- (!(gen->obufs)))
- return(val);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- gen->obuf0[samp - gen->data_start] += val;
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obuf0[0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- return(val);
- }
-
-
- static mus_float_t mus_outb_to_file(mus_any *ptr, mus_long_t samp, mus_float_t val)
- {
- rdout *gen = (rdout *)ptr;
- if (!ptr) return(val);
-
- if ((!(gen->obuf1)) ||
- (!(gen->obufs)))
- return(val);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- gen->obuf1[samp - gen->data_start] += val;
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obuf1[0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- return(val);
- }
-
-
- static int sample_to_file_end(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- if ((gen) && (gen->obufs))
- {
- if (gen->chans > 0)
- {
- int i;
- flush_buffers(gen); /* this forces the error handling stuff, unlike in free reader case */
- for (i = 0; i < gen->chans; i++)
- if (gen->obufs[i])
- free(gen->obufs[i]);
- }
- free(gen->obufs);
- gen->obufs = NULL;
- gen->obuf0 = NULL;
- gen->obuf1 = NULL;
- }
- return(0);
- }
-
-
- bool mus_is_sample_to_file(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SAMPLE_TO_FILE));
- }
-
-
- static mus_any *mus_make_sample_to_file_with_comment_1(const char *filename, int out_chans,
- mus_sample_t samp_type, mus_header_t head_type, const char *comment, bool reopen)
- {
- if (filename == NULL)
- mus_error(MUS_NO_FILE_NAME_PROVIDED, S_make_sample_to_file " requires a file name");
- else
- {
- int fd;
- if (out_chans <= 0)
- return(NULL);
- if (reopen)
- fd = mus_sound_reopen_output(filename, out_chans, samp_type, head_type, mus_sound_data_location(filename));
- else fd = mus_sound_open_output(filename, (int)sampling_rate, out_chans, samp_type, head_type, comment);
- if (fd == -1)
- mus_error(MUS_CANT_OPEN_FILE,
- S_make_sample_to_file ": open(%s) -> %s",
- filename, STRERROR(errno));
- else
- {
- rdout *gen;
- int i;
-
- gen = (rdout *)calloc(1, sizeof(rdout));
- gen->core = &SAMPLE_TO_FILE_CLASS;
- gen->file_name = (char *)calloc(strlen(filename) + 1, sizeof(char));
- strcpy(gen->file_name, filename);
- gen->data_start = 0;
- gen->data_end = clm_file_buffer_size - 1;
- gen->out_end = 0;
- gen->chans = out_chans;
- gen->output_sample_type = samp_type;
- gen->output_header_type = head_type;
- gen->obufs = (mus_float_t **)malloc(gen->chans * sizeof(mus_float_t *));
- for (i = 0; i < gen->chans; i++)
- gen->obufs[i] = (mus_float_t *)calloc(clm_file_buffer_size, sizeof(mus_float_t));
- gen->obuf0 = gen->obufs[0];
- if (out_chans > 1)
- gen->obuf1 = gen->obufs[1];
- else gen->obuf1 = NULL;
-
- /* clear previous, if any */
- if (mus_file_close(fd) != 0)
- mus_error(MUS_CANT_CLOSE_FILE,
- S_make_sample_to_file ": close(%d, %s) -> %s",
- fd, gen->file_name, STRERROR(errno));
-
- return((mus_any *)gen);
- }
- }
- return(NULL);
- }
-
-
- mus_any *mus_continue_sample_to_file(const char *filename)
- {
- return(mus_make_sample_to_file_with_comment_1(filename,
- mus_sound_chans(filename),
- mus_sound_sample_type(filename),
- mus_sound_header_type(filename),
- NULL,
- true));
- }
-
-
- mus_any *mus_make_sample_to_file_with_comment(const char *filename, int out_chans, mus_sample_t samp_type, mus_header_t head_type, const char *comment)
- {
- return(mus_make_sample_to_file_with_comment_1(filename, out_chans, samp_type, head_type, comment, false));
- }
-
-
- mus_float_t mus_sample_to_file(mus_any *fd, mus_long_t samp, int chan, mus_float_t val)
- {
- /* return(mus_write_sample(ptr, samp, chan, val)); */
- if ((fd) &&
- ((fd->core)->write_sample))
- return(((*(fd->core)->write_sample))(fd, samp, chan, val));
- mus_error(MUS_NO_SAMPLE_OUTPUT,
- S_sample_to_file ": can't find %s's sample output function",
- mus_name(fd));
- return(val);
- }
-
-
- int mus_close_file(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- if ((mus_is_output(ptr)) && (gen->obufs)) sample_to_file_end(ptr);
- return(0);
- }
-
-
- /* ---------------- out-any ---------------- */
-
- mus_float_t mus_out_any(mus_long_t samp, mus_float_t val, int chan, mus_any *IO)
- {
- if ((IO) &&
- (samp >= 0))
- {
- if ((IO->core)->write_sample)
- return(((*(IO->core)->write_sample))(IO, samp, chan, val));
- mus_error(MUS_NO_SAMPLE_OUTPUT,
- "can't find %s's sample output function",
- mus_name(IO));
- }
- return(val);
- }
-
-
- mus_float_t mus_safe_out_any_to_file(mus_long_t samp, mus_float_t val, int chan, mus_any *IO)
- {
- rdout *gen = (rdout *)IO;
- if (chan >= gen->chans) /* checking for (val == 0.0) here appears to make no difference overall */
- return(val);
- /* does this need to check obufs? */
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- {
- gen->obufs[chan][samp - gen->data_start] += val;
- if (samp > gen->out_end)
- gen->out_end = samp;
- }
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obufs[chan][0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
- return(val);
-
- }
-
-
- bool mus_out_any_is_safe(mus_any *IO)
- {
- rdout *gen = (rdout *)IO;
- return((gen) &&
- (gen->obufs) &&
- (gen->core->write_sample == mus_out_any_to_file));
- }
-
-
-
- /* ---------------- frample->file ---------------- */
-
- static char *describe_frample_to_file(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static mus_float_t run_frample_to_file(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_error(MUS_NO_RUN, "no run method for frample->file");
- return(0.0);
- }
-
-
- static mus_any_class FRAMPLE_TO_FILE_CLASS = {
- MUS_FRAMPLE_TO_FILE,
- (char *)S_frample_to_file,
- &free_sample_to_file,
- &describe_frample_to_file,
- &sample_to_file_equalp,
- 0, 0,
- &bufferlen, &set_bufferlen,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- 0, 0,
- &run_frample_to_file,
- MUS_OUTPUT,
- NULL,
- &sample_to_file_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- &mus_out_any_to_file,
- &sample_to_file_file_name,
- &sample_to_file_end,
- 0, 0, 0,
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdout_copy
- };
-
-
- mus_any *mus_make_frample_to_file_with_comment(const char *filename, int chans, mus_sample_t samp_type, mus_header_t head_type, const char *comment)
- {
- rdout *gen = NULL;
- gen = (rdout *)mus_make_sample_to_file_with_comment(filename, chans, samp_type, head_type, comment);
- if (gen) gen->core = &FRAMPLE_TO_FILE_CLASS;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_frample_to_file(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FRAMPLE_TO_FILE));
- }
-
-
- mus_float_t *mus_frample_to_file(mus_any *ptr, mus_long_t samp, mus_float_t *data)
- {
- rdout *gen = (rdout *)ptr;
- if (!gen) return(data);
-
- if (gen->chans == 1)
- mus_outa_to_file(ptr, samp, data[0]);
- else
- {
- if (gen->chans == 2)
- {
- mus_outa_to_file(ptr, samp, data[0]);
- mus_outb_to_file(ptr, samp, data[1]);
- }
- else mus_out_chans_to_file(gen, samp, gen->chans, data);
- }
- return(data);
- }
-
-
- mus_any *mus_continue_frample_to_file(const char *filename)
- {
- rdout *gen = NULL;
- gen = (rdout *)mus_continue_sample_to_file(filename);
- if (gen) gen->core = &FRAMPLE_TO_FILE_CLASS;
- return((mus_any *)gen);
- }
-
-
- mus_float_t *mus_frample_to_frample(mus_float_t *matrix, int mx_chans, mus_float_t *in_samps, int in_chans, mus_float_t *out_samps, int out_chans)
- {
- /* in->out conceptually, so left index is in_chan, it (j below) steps by out_chans */
- int i, j, offset;
- if (mx_chans < out_chans) out_chans = mx_chans;
- if (mx_chans < in_chans) in_chans = mx_chans;
- for (i = 0; i < out_chans; i++)
- {
- out_samps[i] = in_samps[0] * matrix[i];
- for (j = 1, offset = mx_chans; j < in_chans; j++, offset += mx_chans)
- out_samps[i] += in_samps[j] * matrix[offset + i];
- }
- return(out_samps);
- }
-
-
-
- /* ---------------- locsig ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_any *outn_writer;
- mus_any *revn_writer;
- mus_float_t *outf, *revf;
- mus_float_t *outn;
- mus_float_t *revn;
- int chans, rev_chans;
- mus_interp_t type;
- mus_float_t reverb;
- bool safe_output;
- void *closure;
- void (*locsig_func)(mus_any *ptr, mus_long_t loc, mus_float_t val);
- void (*detour)(mus_any *ptr, mus_long_t loc);
- } locs;
-
-
- static bool locsig_equalp(mus_any *p1, mus_any *p2)
- {
- locs *g1 = (locs *)p1;
- locs *g2 = (locs *)p2;
- if (p1 == p2) return(true);
- return((g1) && (g2) &&
- (g1->core->type == g2->core->type) &&
- (g1->chans == g2->chans) &&
- (clm_arrays_are_equal(g1->outn, g2->outn, g1->chans)) &&
- (((bool)(g1->revn != NULL)) == ((bool)(g2->revn != NULL))) &&
- ((!(g1->revn)) || (clm_arrays_are_equal(g1->revn, g2->revn, g1->rev_chans))));
- }
-
-
- static char *describe_locsig(mus_any *ptr)
- {
- char *str;
- int i, lim = 16;
- locs *gen = (locs *)ptr;
-
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s chans %d, outn: [",
- mus_name(ptr),
- gen->chans);
- str = (char *)malloc(STR_SIZE * sizeof(char));
-
- if (gen->outn)
- {
- if (gen->chans - 1 < lim) lim = gen->chans - 1;
- for (i = 0; i < lim; i++)
- {
- snprintf(str, STR_SIZE, "%.3f ", gen->outn[i]);
- if ((strlen(describe_buffer) + strlen(str)) < (DESCRIBE_BUFFER_SIZE - 16))
- strcat(describe_buffer, str);
- else break;
- }
- if (gen->chans - 1 > lim) strcat(describe_buffer, "...");
- snprintf(str, STR_SIZE, "%.3f]", gen->outn[gen->chans - 1]);
- strcat(describe_buffer, str);
- }
- else
- {
- strcat(describe_buffer, "nil!]");
- }
-
- if ((gen->rev_chans > 0) && (gen->revn))
- {
- strcat(describe_buffer, ", revn: [");
- lim = 16;
- if (gen->rev_chans - 1 < lim) lim = gen->rev_chans - 1;
- for (i = 0; i < lim; i++)
- {
- snprintf(str, STR_SIZE, "%.3f ", gen->revn[i]);
- if ((strlen(describe_buffer) + strlen(str)) < (DESCRIBE_BUFFER_SIZE - 16))
- strcat(describe_buffer, str);
- else break;
- }
- if (gen->rev_chans - 1 > lim) strcat(describe_buffer, "...");
- snprintf(str, STR_SIZE, "%.3f]", gen->revn[gen->rev_chans - 1]);
- strcat(describe_buffer, str);
- }
-
- snprintf(str, STR_SIZE, ", interp: %s", interp_type_to_string(gen->type));
- strcat(describe_buffer, str);
- free(str);
- return(describe_buffer);
- }
-
-
- static void free_locsig(mus_any *p)
- {
- locs *ptr = (locs *)p;
- if (ptr->outn)
- {
- free(ptr->outn);
- ptr->outn = NULL;
- }
- if (ptr->revn)
- {
- free(ptr->revn);
- ptr->revn = NULL;
- }
- if (ptr->outf) free(ptr->outf);
- ptr->outf = NULL;
- if (ptr->revf) free(ptr->revf);
- ptr->revf = NULL;
- ptr->outn_writer = NULL;
- ptr->revn_writer = NULL;
- ptr->chans = 0;
- ptr->rev_chans = 0;
- free(ptr);
- }
-
- static mus_any *locs_copy(mus_any *ptr)
- {
- locs *g, *p;
- int bytes;
- p = (locs *)ptr;
- g = (locs *)malloc(sizeof(locs));
- memcpy((void *)g, (void *)ptr, sizeof(locs));
- bytes = g->chans * sizeof(mus_float_t);
- if (p->outn)
- {
- g->outn = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->outn), (void *)(p->outn), bytes);
- }
- if (p->outf)
- {
- g->outf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->outf), (void *)(p->outf), bytes);
- }
- bytes = g->rev_chans * sizeof(mus_float_t);
- if (p->revn)
- {
- g->revn = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->revn), (void *)(p->revn), bytes);
- }
- if (p->revf)
- {
- g->revf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->revf), (void *)(p->revf), bytes);
- }
- return((mus_any *)g);
- }
-
- static mus_long_t locsig_length(mus_any *ptr) {return(((locs *)ptr)->chans);}
-
- static int locsig_channels(mus_any *ptr) {return(((locs *)ptr)->chans);}
-
- static mus_float_t *locsig_data(mus_any *ptr) {return(((locs *)ptr)->outn);}
-
- static mus_float_t *locsig_xcoeffs(mus_any *ptr) {return(((locs *)ptr)->revn);}
-
- mus_float_t *mus_locsig_outf(mus_any *ptr) {return(((locs *)ptr)->outf);} /* clm2xen.c */
- mus_float_t *mus_locsig_revf(mus_any *ptr) {return(((locs *)ptr)->revf);}
-
- void *mus_locsig_closure(mus_any *ptr) {return(((locs *)ptr)->closure);}
- static void *locsig_set_closure(mus_any *ptr, void *e) {((locs *)ptr)->closure = e; return(e);}
-
- void mus_locsig_set_detour(mus_any *ptr, void (*detour)(mus_any *ptr, mus_long_t val))
- {
- locs *gen = (locs *)ptr;
- gen->detour = detour;
- }
-
-
- static void locsig_reset(mus_any *ptr)
- {
- locs *gen = (locs *)ptr;
- if (gen->outn) memset((void *)(gen->outn), 0, gen->chans * sizeof(mus_float_t));
- if (gen->revn) memset((void *)(gen->revn), 0, gen->rev_chans * sizeof(mus_float_t));
- }
-
-
- static mus_float_t locsig_xcoeff(mus_any *ptr, int index)
- {
- locs *gen = (locs *)ptr;
- if (gen->revn)
- return(gen->revn[index]);
- return(0.0);
- }
-
-
- static mus_float_t locsig_set_xcoeff(mus_any *ptr, int index, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- if (gen->revn)
- gen->revn[index] = val;
- return(val);
- }
-
-
- static mus_any *locsig_warned = NULL;
- /* these locsig error messages are a pain -- using the output pointer in the wan hope that
- * subsequent runs will use a different output generator.
- */
-
- mus_float_t mus_locsig_ref(mus_any *ptr, int chan)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->chans))
- return(gen->outn[chan]);
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_ref ": chan %d >= %d",
- chan, gen->chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(0.0);
- }
-
-
- mus_float_t mus_locsig_set(mus_any *ptr, int chan, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->chans))
- gen->outn[chan] = val;
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_set ": chan %d >= %d",
- chan, gen->chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(val);
- }
-
-
- mus_float_t mus_locsig_reverb_ref(mus_any *ptr, int chan)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->rev_chans))
- return(gen->revn[chan]);
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_reverb_ref ": chan %d, but this locsig has %d reverb chans",
- chan, gen->rev_chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(0.0);
- }
-
-
- mus_float_t mus_locsig_reverb_set(mus_any *ptr, int chan, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->rev_chans))
- gen->revn[chan] = val;
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_reverb_set ": chan %d >= %d",
- chan, gen->rev_chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(val);
- }
-
-
- static mus_float_t run_locsig(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_locsig(ptr, (mus_long_t)arg1, arg2);
- return(arg2);
- }
-
-
- static mus_any_class LOCSIG_CLASS = {
- MUS_LOCSIG,
- (char *)S_locsig,
- &free_locsig,
- &describe_locsig,
- &locsig_equalp,
- &locsig_data, 0,
- &locsig_length,
- 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_locsig,
- MUS_OUTPUT,
- &mus_locsig_closure,
- &locsig_channels,
- 0, 0, 0, 0,
- &locsig_xcoeff, &locsig_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &locsig_xcoeffs, 0,
- &locsig_reset,
- &locsig_set_closure, /* the method name is set_environ (clm2xen.c) */
- &locs_copy
- };
-
-
- bool mus_is_locsig(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_LOCSIG));
- }
-
-
- static void mus_locsig_fill(mus_float_t *arr, int chans, mus_float_t degree, mus_float_t scaler, mus_interp_t type)
- {
- if (chans == 1)
- arr[0] = scaler;
- else
- {
- mus_float_t deg, pos, frac, degs_per_chan;
- int left, right;
- /* this used to check for degree < 0.0 first, but as Michael Klingbeil noticed, that
- * means that in the stereo case, the location can jump to 90 => click.
- */
- if (chans == 2)
- {
- /* there's no notion of a circle of speakers here, so we don't have to equate, for example, -90 and 270 */
- if (degree > 90.0)
- deg = 90.0;
- else
- {
- if (degree < 0.0)
- deg = 0.0;
- else deg = degree;
- }
- degs_per_chan = 90.0;
- }
- else
- {
- deg = fmod(degree, 360.0);
- if (deg < 0.0)
- {
- /* -0.0 is causing trouble when mus_float_t == float */
- if (deg < -0.0000001)
- deg += 360.0; /* C's fmod can return negative results when modulus is positive */
- else deg = 0.0;
- }
- degs_per_chan = 360.0 / chans;
- }
- pos = deg / degs_per_chan;
- left = (int)pos; /* floor(pos) */
- right = left + 1;
- if (right >= chans) right = 0;
- frac = pos - left;
- if (type == MUS_INTERP_LINEAR)
- {
- arr[left] = scaler * (1.0 - frac);
- arr[right] = scaler * frac;
- }
- else
- {
- mus_float_t ldeg, c, s;
- ldeg = M_PI_2 * (0.5 - frac);
- scaler *= sqrt(2.0) / 2.0;
- c = cos(ldeg);
- s = sin(ldeg);
- arr[left] = scaler * (c + s);
- arr[right] = scaler * (c - s);
- }
- }
- }
-
-
- static void mus_locsig_mono_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- }
-
-
- static void mus_locsig_mono(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- mus_outa_to_file(gen->revn_writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_stereo_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- mus_outb_to_file(gen->outn_writer, loc, val * gen->outn[1]);
- }
-
-
- static void mus_locsig_stereo(mus_any *ptr, mus_long_t loc, mus_float_t val) /* but mono rev */
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- mus_outb_to_file(gen->outn_writer, loc, val * gen->outn[1]);
- mus_outa_to_file(gen->revn_writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_any(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
- for (i = 0; i < gen->chans; i++)
- {
- gen->outf[i] = val * gen->outn[i];
- if (writer)
- mus_out_any_to_file((mus_any *)writer, loc, i, gen->outf[i]);
- }
- writer = (rdout *)(gen->revn_writer);
- for (i = 0; i < gen->rev_chans; i++)
- {
- gen->revf[i] = val * gen->revn[i];
- if (writer)
- mus_out_any_to_file((mus_any *)writer, loc, i, gen->revf[i]);
- }
- }
-
- static void mus_locsig_safe_mono_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- /* here we know in each safe case that obufs fits loc chans and the output gen is ok */
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->outn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
- }
-
-
- static void mus_locsig_safe_mono(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->outn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
-
- writer = (rdout *)(gen->revn_writer);
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->revn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_safe_stereo_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- writer->obufs[0][pos] += (val * gen->outn[0]);
- writer->obufs[1][pos] += (val * gen->outn[1]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
- mus_outb_to_file((mus_any *)writer, loc, val * gen->outn[1]);
- }
- }
-
- static void mus_locsig_safe_stereo(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- writer->obufs[0][pos] += (val * gen->outn[0]);
- writer->obufs[1][pos] += (val * gen->outn[1]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
- mus_outb_to_file((mus_any *)writer, loc, val * gen->outn[1]);
- }
-
- writer = (rdout *)(gen->revn_writer);
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->revn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_detour(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- /* here we let the closure data decide what to do with the output */
- locs *gen = (locs *)ptr;
- if (gen->detour)
- {
- int i;
- for (i = 0; i < gen->chans; i++)
- gen->outf[i] = val * gen->outn[i];
-
- for (i = 0; i < gen->rev_chans; i++)
- gen->revf[i] = val * gen->revn[i];
-
- (*(gen->detour))(ptr, loc);
- }
- }
-
- static void mus_locsig_any_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
- for (i = 0; i < gen->chans; i++)
- {
- gen->outf[i] = val * gen->outn[i];
- if (writer)
- mus_out_any_to_file((mus_any *)writer, loc, i, gen->outf[i]);
- }
- }
-
- static void mus_locsig_safe_any_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- for (i = 0; i < gen->chans; i++)
- writer->obufs[i][pos] += (val * gen->outn[i]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- for (i = 0; i < gen->chans; i++)
- mus_safe_out_any_to_file(loc, val * gen->outn[i], i, (mus_any *)writer);
- }
- }
-
-
- static void mus_locsig_safe_any(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- for (i = 0; i < gen->chans; i++)
- writer->obufs[i][pos] += (val * gen->outn[i]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- for (i = 0; i < gen->chans; i++)
- mus_safe_out_any_to_file(loc, val * gen->outn[i], i, (mus_any *)writer);
- }
-
- writer = (rdout *)(gen->revn_writer);
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- for (i = 0; i < gen->rev_chans; i++)
- writer->obufs[i][pos] += (val * gen->revn[i]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- for (i = 0; i < gen->rev_chans; i++)
- mus_safe_out_any_to_file(loc, val * gen->revn[i], i, (mus_any *)writer);
- }
- }
-
-
- mus_any *mus_make_locsig(mus_float_t degree, mus_float_t distance, mus_float_t reverb,
- int chans, mus_any *output, /* direct signal output */
- int rev_chans, mus_any *revput, /* reverb output */
- mus_interp_t type)
- {
- locs *gen;
- mus_float_t dist;
- if (chans <= 0)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_locsig ": chans: %d", chans);
- return(NULL);
- }
- if (isnan(degree))
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_locsig ": degree: %f", degree);
- return(NULL);
- }
-
- gen = (locs *)calloc(1, sizeof(locs));
- gen->core = &LOCSIG_CLASS;
- gen->outf = (mus_float_t *)calloc(chans, sizeof(mus_float_t));
-
- gen->type = type;
- gen->reverb = reverb;
- gen->safe_output = false;
- if (distance > 1.0)
- dist = 1.0 / distance;
- else dist = 1.0;
-
- if (mus_is_output(output))
- gen->outn_writer = output;
- gen->chans = chans;
- gen->outn = (mus_float_t *)calloc(gen->chans, sizeof(mus_float_t));
- mus_locsig_fill(gen->outn, gen->chans, degree, dist, type);
-
- if (mus_is_output(revput))
- gen->revn_writer = revput;
- gen->rev_chans = rev_chans;
- if (gen->rev_chans > 0)
- {
- gen->revn = (mus_float_t *)calloc(gen->rev_chans, sizeof(mus_float_t));
- gen->revf = (mus_float_t *)calloc(gen->rev_chans, sizeof(mus_float_t));
- mus_locsig_fill(gen->revn, gen->rev_chans, degree, (reverb * sqrt(dist)), type);
- }
-
- /* now choose the output function based on chans, and reverb
- */
- if ((output == NULL) && (revput == NULL))
- gen->locsig_func = mus_locsig_detour;
- else
- {
- gen->locsig_func = mus_locsig_any;
-
- if ((mus_is_output(output)) &&
- (mus_out_any_is_safe(output)) &&
- (mus_channels(output) == chans))
- {
- if (rev_chans > 0)
- {
- if ((rev_chans == 1) &&
- (mus_is_output(revput)) &&
- (mus_out_any_is_safe(revput)) &&
- (mus_channels(revput) == 1))
- {
- gen->safe_output = true;
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_safe_mono; break;
- case 2: gen->locsig_func = mus_locsig_safe_stereo; break;
- default: gen->locsig_func = mus_locsig_safe_any; break;
- }
- }
- }
- else
- {
- gen->safe_output = true;
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_safe_mono_no_reverb; break;
- case 2: gen->locsig_func = mus_locsig_safe_stereo_no_reverb; break;
- default: gen->locsig_func = mus_locsig_safe_any_no_reverb; break;
- }
- }
- }
- else
- {
- if (rev_chans > 0)
- {
- if (rev_chans == 1)
- {
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_mono; break;
- case 2: gen->locsig_func = mus_locsig_stereo; break;
- default: gen->locsig_func = mus_locsig_any; break;
- }
- }
- }
- else
- {
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_mono_no_reverb; break;
- case 2: gen->locsig_func = mus_locsig_stereo_no_reverb; break;
- default: gen->locsig_func = mus_locsig_any_no_reverb; break;
- }
- }
- }
- }
- return((mus_any *)gen);
- }
-
- void mus_locsig(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- (*(gen->locsig_func))(ptr, loc, val);
- }
-
- int mus_locsig_channels(mus_any *ptr)
- {
- return(((locs *)ptr)->chans);
- }
-
- int mus_locsig_reverb_channels(mus_any *ptr)
- {
- return(((locs *)ptr)->rev_chans);
- }
-
-
- void mus_move_locsig(mus_any *ptr, mus_float_t degree, mus_float_t distance)
- {
- locs *gen = (locs *)ptr;
- mus_float_t dist;
-
- if (distance > 1.0)
- dist = 1.0 / distance;
- else dist = 1.0;
-
- if (gen->rev_chans > 0)
- {
- if (gen->rev_chans > 2)
- memset((void *)(gen->revn), 0, gen->rev_chans * sizeof(mus_float_t));
- mus_locsig_fill(gen->revn, gen->rev_chans, degree, (gen->reverb * sqrt(dist)), gen->type);
- }
- if (gen->chans > 2)
- memset((void *)(gen->outn), 0, gen->chans * sizeof(mus_float_t));
- mus_locsig_fill(gen->outn, gen->chans, degree, dist, gen->type);
- }
-
-
-
- /* ---------------- move-sound ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_any *outn_writer;
- mus_any *revn_writer;
- mus_float_t *outf, *revf;
- int out_channels, rev_channels;
- mus_long_t start, end;
- mus_any *doppler_delay, *doppler_env, *rev_env;
- mus_any **out_delays, **out_envs, **rev_envs;
- int *out_map;
- bool free_arrays, free_gens;
- void *closure;
- void (*detour)(mus_any *ptr, mus_long_t loc);
- } dloc;
-
-
- static bool move_sound_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
- int mus_move_sound_channels(mus_any *ptr) {return(((dloc *)ptr)->out_channels);}
- int mus_move_sound_reverb_channels(mus_any *ptr) {return(((dloc *)ptr)->rev_channels);}
- static mus_long_t move_sound_length(mus_any *ptr) {return(((dloc *)ptr)->out_channels);} /* need both because return types differ */
- static void move_sound_reset(mus_any *ptr) {}
-
- mus_float_t *mus_move_sound_outf(mus_any *ptr) {return(((dloc *)ptr)->outf);}
- mus_float_t *mus_move_sound_revf(mus_any *ptr) {return(((dloc *)ptr)->revf);}
-
- void *mus_move_sound_closure(mus_any *ptr) {return(((dloc *)ptr)->closure);}
- static void *move_sound_set_closure(mus_any *ptr, void *e) {((dloc *)ptr)->closure = e; return(e);}
-
- void mus_move_sound_set_detour(mus_any *ptr, void (*detour)(mus_any *ptr, mus_long_t val))
- {
- dloc *gen = (dloc *)ptr;
- gen->detour = detour;
- }
-
-
- static char *describe_move_sound(mus_any *ptr)
- {
- dloc *gen = (dloc *)ptr;
- char *dopdly = NULL, *dopenv = NULL, *revenv = NULL;
- char *outdlys = NULL, *outenvs = NULL, *revenvs = NULL;
- char *outmap = NULL;
- char *starts = NULL;
- char *str1 = NULL, *str2 = NULL, *str3 = NULL;
- char *allstr = NULL;
- int len;
-
- starts = mus_format("%s start: %lld, end: %lld, out chans %d, rev chans: %d",
- mus_name(ptr),
- gen->start,
- gen->end,
- gen->out_channels,
- gen->rev_channels);
- dopdly = mus_format("doppler %s", str1 = mus_describe(gen->doppler_delay));
- dopenv = mus_format("doppler %s", str2 = mus_describe(gen->doppler_env));
- revenv = mus_format("global reverb %s", str3 = mus_describe(gen->rev_env));
- outdlys = clm_array_to_string(gen->out_delays, gen->out_channels, "out_delays", " ");
- outenvs = clm_array_to_string(gen->out_envs, gen->out_channels, "out_envs", " ");
- revenvs = clm_array_to_string(gen->rev_envs, gen->rev_channels, "rev_envs", " ");
- outmap = int_array_to_string(gen->out_map, gen->out_channels, "out_map");
-
- len = 64 + strlen(starts) + strlen(dopdly) + strlen(dopenv) + strlen(revenv) +
- strlen(outdlys) + strlen(outenvs) + strlen(revenvs) + strlen(outmap);
- allstr = (char *)malloc(len * sizeof(char));
- snprintf(allstr, len, "%s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n free: arrays: %s, gens: %s\n",
- starts, dopdly, dopenv, revenv, outdlys, outenvs, revenvs, outmap,
- (gen->free_arrays) ? "true" : "false",
- (gen->free_gens) ? "true" : "false");
- if (str1) free(str1);
- if (str2) free(str2);
- if (str3) free(str3);
- free(starts);
- free(dopdly);
- free(dopenv);
- free(revenv);
- free(outdlys);
- free(outenvs);
- free(revenvs);
- free(outmap);
- return(allstr);
- }
-
-
- static void free_move_sound(mus_any *p)
- {
- dloc *ptr = (dloc *)p;
- if (ptr->free_gens)
- {
- int i;
- /* free everything except outer arrays and IO stuff */
- if (ptr->doppler_delay) mus_free(ptr->doppler_delay);
- if (ptr->doppler_env) mus_free(ptr->doppler_env);
- if (ptr->rev_env) mus_free(ptr->rev_env);
- if (ptr->out_delays)
- for (i = 0; i < ptr->out_channels; i++)
- if (ptr->out_delays[i]) mus_free(ptr->out_delays[i]);
- if (ptr->out_envs)
- for (i = 0; i < ptr->out_channels; i++)
- if (ptr->out_envs[i]) mus_free(ptr->out_envs[i]);
- if (ptr->rev_envs)
- for (i = 0; i < ptr->rev_channels; i++)
- if (ptr->rev_envs[i]) mus_free(ptr->rev_envs[i]);
- }
-
- if (ptr->free_arrays)
- {
- /* free outer arrays */
- if (ptr->out_envs) {free(ptr->out_envs); ptr->out_envs = NULL;}
- if (ptr->rev_envs) {free(ptr->rev_envs); ptr->rev_envs = NULL;}
- if (ptr->out_delays) {free(ptr->out_delays); ptr->out_delays = NULL;}
- if (ptr->out_map) free(ptr->out_map);
- }
-
- /* we created these in make_move_sound, so it should always be safe to free them */
- if (ptr->outf) free(ptr->outf);
- if (ptr->revf) free(ptr->revf);
- free(ptr);
- }
-
- static mus_any *dloc_copy(mus_any *ptr)
- {
- dloc *g, *p;
- int i, bytes;
- p = (dloc *)ptr;
- g = (dloc *)malloc(sizeof(dloc));
- memcpy((void *)g, (void *)ptr, sizeof(dloc));
-
- if (p->outf)
- {
- bytes = p->out_channels * sizeof(mus_float_t);
- g->outf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->outf), (void *)(p->outf), bytes);
- }
- if (p->revf)
- {
- bytes = p->rev_channels * sizeof(mus_float_t);
- g->revf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->revf), (void *)(p->revf), bytes);
- }
-
- g->free_arrays = true;
- g->free_gens = true;
- if (p->doppler_delay) g->doppler_delay = mus_copy(p->doppler_delay);
- if (p->doppler_env) g->doppler_env = mus_copy(p->doppler_env);
- if (p->rev_env) g->rev_env = mus_copy(p->rev_env);
- if (p->out_envs)
- {
- g->out_envs = (mus_any **)malloc(p->out_channels * sizeof(mus_any *));
- for (i = 0; i < p->out_channels; i++) g->out_envs[i] = mus_copy(p->out_envs[i]);
- }
- if (p->rev_envs)
- {
- g->rev_envs = (mus_any **)malloc(p->rev_channels * sizeof(mus_any *));
- for (i = 0; i < p->rev_channels; i++) g->rev_envs[i] = mus_copy(p->rev_envs[i]);
- }
- if (p->out_delays)
- {
- g->out_delays = (mus_any **)malloc(p->out_channels * sizeof(mus_any *));
- for (i = 0; i < p->out_channels; i++) g->out_delays[i] = mus_copy(p->out_delays[i]);
- }
- if (p->out_map)
- {
- bytes = p->out_channels * sizeof(int);
- g->out_map = (int *)malloc(bytes);
- memcpy((void *)(g->out_map), (void *)(p->out_map), bytes);
- }
-
- return((mus_any *)g);
- }
-
- bool mus_is_move_sound(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVE_SOUND));
- }
-
-
- mus_float_t mus_move_sound(mus_any *ptr, mus_long_t loc, mus_float_t uval)
- {
- dloc *gen = (dloc *)ptr;
- mus_float_t val;
- int chan;
-
- if (loc > gen->end) val = 0.0; else val = uval;
-
- /* initial silence */
- if (loc < gen->start)
- {
- mus_delay_unmodulated(gen->doppler_delay, val);
- /* original calls out_any here with 0.0 -- a no-op */
- return(val);
- }
-
- /* doppler */
- if (gen->doppler_delay)
- val = mus_delay(gen->doppler_delay, val, mus_env(gen->doppler_env));
-
- /* direct signal */
- for (chan = 0; chan < gen->out_channels; chan++)
- {
- mus_float_t sample;
- sample = val * mus_env(gen->out_envs[chan]);
- if (gen->out_delays[chan])
- sample = mus_delay_unmodulated(gen->out_delays[chan], sample);
- gen->outf[gen->out_map[chan]] = sample;
- }
-
- /* reverb */
- if ((gen->rev_env) &&
- (gen->revf))
- {
- val *= mus_env(gen->rev_env);
- if (gen->rev_envs)
- {
- if (gen->rev_channels == 1)
- gen->revf[0] = val * mus_env(gen->rev_envs[0]);
- else
- {
- for (chan = 0; chan < gen->rev_channels; chan++)
- gen->revf[gen->out_map[chan]] = val * mus_env(gen->rev_envs[chan]);
- }
- }
- else gen->revf[0] = val;
-
- if (gen->revn_writer)
- mus_frample_to_file(gen->revn_writer, loc, gen->revf);
- }
-
- /* file output */
- if (gen->outn_writer)
- mus_frample_to_file(gen->outn_writer, loc, gen->outf);
-
- if (gen->detour)
- (*(gen->detour))(ptr, loc);
- return(uval);
- }
-
-
- static mus_float_t run_move_sound(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_move_sound(ptr, (mus_long_t)arg1, arg2);
- return(arg2);
- }
-
-
- static mus_any_class MOVE_SOUND_CLASS = {
- MUS_MOVE_SOUND,
- (char *)S_move_sound,
- &free_move_sound,
- &describe_move_sound,
- &move_sound_equalp,
- 0, 0,
- &move_sound_length,
- 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_move_sound,
- MUS_OUTPUT,
- &mus_move_sound_closure,
- &mus_move_sound_channels,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &move_sound_reset,
- &move_sound_set_closure,
- &dloc_copy
- };
-
-
- mus_any *mus_make_move_sound(mus_long_t start, mus_long_t end, int out_channels, int rev_channels,
- mus_any *doppler_delay, mus_any *doppler_env, mus_any *rev_env,
- mus_any **out_delays, mus_any **out_envs, mus_any **rev_envs,
- int *out_map, mus_any *output, mus_any *revput, bool free_arrays, bool free_gens)
- {
- /* most of these args come to us in a list at the lisp/xen level ("dlocs" struct is actually a list)
- * so the make-move-sound function in lisp/xen is (make-move-sound dloc-list output revout)
- * where the trailing args mimic locsig.
- */
- dloc *gen;
- if (out_channels <= 0)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_move_sound ": out chans: %d", out_channels);
- return(NULL);
- }
- gen = (dloc *)calloc(1, sizeof(dloc));
- gen->core = &MOVE_SOUND_CLASS;
-
- gen->start = start;
- gen->end = end;
- gen->out_channels = out_channels;
- gen->rev_channels = rev_channels;
- gen->doppler_delay = doppler_delay;
- gen->doppler_env = doppler_env;
- gen->rev_env = rev_env;
- gen->out_delays = out_delays;
- gen->out_envs = out_envs;
- gen->rev_envs = rev_envs;
- gen->out_map = out_map;
-
- /* default is to free only what we make ourselves */
- gen->free_gens = free_gens;
- gen->free_arrays = free_arrays;
-
- gen->outf = (mus_float_t *)calloc(out_channels, sizeof(mus_float_t));
- if (mus_is_output(output))
- gen->outn_writer = output;
-
- if (rev_channels > 0)
- {
- if (mus_is_output(revput))
- gen->revn_writer = revput;
- gen->revf = (mus_float_t *)calloc(rev_channels, sizeof(mus_float_t));
- }
-
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- src ---------------- */
-
- /* sampling rate conversion */
- /* taken from sweep_srate.c of Perry Cook. To quote Perry:
- *
- * 'The conversion is performed by sinc interpolation.
- * J. O. Smith and P. Gossett, "A Flexible Sampling-Rate Conversion Method,"
- * Proc. of the IEEE Conference on Acoustics, Speech, and Signal Processing, San Diego, CA, March, 1984.
- * There are essentially two cases, one where the conversion factor
- * is less than one, and the sinc table is used as is yielding a sound
- * which is band limited to the 1/2 the new sampling rate (we don't
- * want to create bandwidth where there was none). The other case
- * is where the conversion factor is greater than one and we 'warp'
- * the sinc table to make the final cutoff equal to the original sampling
- * rate /2. Warping the sinc table is based on the similarity theorem
- * of the time and frequency domain, stretching the time domain (sinc
- * table) causes shrinking in the frequency domain.'
- *
- * we also scale the amplitude if interpolating to take into account the broadened sinc
- * this means that isolated pulses get scaled by 1/src, but that's a dumb special case
- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t (*feeder)(void *arg, int direction);
- mus_float_t (*block_feeder)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- mus_float_t x;
- mus_float_t incr, width_1;
- int width, lim, start, sinc4;
- int len;
- mus_float_t *data, *sinc_table, *coeffs;
- void *closure;
- } sr;
-
-
- #define SRC_SINC_DENSITY 2000
- #define SRC_SINC_WIDTH 10
- #define SRC_SINC_WINDOW_SIZE 8000
-
- static mus_float_t **sinc_tables = NULL;
- static int *sinc_widths = NULL;
- static int sincs = 0;
- static mus_float_t *sinc = NULL, *sinc_window = NULL;
- static int sinc_size = 0;
-
- void mus_clear_sinc_tables(void)
- {
- if (sincs)
- {
- int i;
- for (i = 0; i < sincs; i++)
- if (sinc_tables[i])
- free(sinc_tables[i]);
- free(sinc_tables);
- sinc_tables = NULL;
-
- free(sinc_window);
- sinc_window = NULL;
- free(sinc_widths);
- sinc_widths = NULL;
- sincs = 0;
- }
- }
-
-
- static int init_sinc_table(int width)
- {
- int i, size, padded_size, loc;
- mus_float_t win_freq, win_phase;
- #if HAVE_SINCOS
- double sn, snp, cs, csp;
- #endif
-
- if (width > sinc_size)
- {
- int old_end;
- mus_float_t sinc_phase, sinc_freq;
- if (sinc_size == 0)
- old_end = 1;
- else old_end = sinc_size * SRC_SINC_DENSITY + 4;
- padded_size = width * SRC_SINC_DENSITY + 4;
- if (sinc_size == 0)
- {
- sinc = (mus_float_t *)malloc(padded_size * sizeof(mus_float_t));
- sinc[0] = 1.0;
- }
- else sinc = (mus_float_t *)realloc(sinc, padded_size * sizeof(mus_float_t));
- sinc_size = width;
- sinc_freq = M_PI / (mus_float_t)SRC_SINC_DENSITY;
- sinc_phase = old_end * sinc_freq;
- #if HAVE_SINCOS
- sincos(sinc_freq, &sn, &cs);
- if (old_end == 1)
- {
- sinc[1] = sin(sinc_phase) / (2.0 * sinc_phase);
- old_end++;
- sinc_phase += sinc_freq;
- }
- for (i = old_end; i < padded_size;)
- {
- sincos(sinc_phase, &snp, &csp);
- sinc[i] = snp / (2.0 * sinc_phase);
- i++;
- sinc_phase += sinc_freq;
- sinc[i] = (snp * cs + csp * sn) / (2.0 * sinc_phase);
- i++;
- sinc_phase += sinc_freq;
- }
- #else
- for (i = old_end; i < padded_size; i++, sinc_phase += sinc_freq)
- sinc[i] = sin(sinc_phase) / (2.0 * sinc_phase);
- #endif
- }
-
- for (i = 0; i < sincs; i++)
- if (sinc_widths[i] == width)
- return(i);
-
- if (sincs == 0)
- {
- mus_float_t ph, incr;
- incr = M_PI / SRC_SINC_WINDOW_SIZE;
- sinc_window = (mus_float_t *)calloc(SRC_SINC_WINDOW_SIZE + 16, sizeof(mus_float_t));
- for (i = 0, ph = 0.0; i < SRC_SINC_WINDOW_SIZE; i++, ph += incr)
- sinc_window[i] = 1.0 + cos(ph);
-
- sinc_tables = (mus_float_t **)calloc(8, sizeof(mus_float_t *));
- sinc_widths = (int *)calloc(8, sizeof(int));
- sincs = 8;
- loc = 0;
- }
- else
- {
- loc = -1;
- for (i = 0; i < sincs; i++)
- if (sinc_widths[i] == 0)
- {
- loc = i;
- break;
- }
- if (loc == -1)
- {
- sinc_tables = (mus_float_t **)realloc(sinc_tables, (sincs + 8) * sizeof(mus_float_t *));
- sinc_widths = (int *)realloc(sinc_widths, (sincs + 8) * sizeof(int));
- for (i = sincs; i < (sincs + 8); i++)
- {
- sinc_widths[i] = 0;
- sinc_tables[i] = NULL;
- }
- loc = sincs;
- sincs += 8;
- }
- }
-
- sinc_widths[loc] = width;
- size = width * SRC_SINC_DENSITY;
- padded_size = size + 4;
- win_freq = (mus_float_t)SRC_SINC_WINDOW_SIZE / (mus_float_t)size;
-
- sinc_tables[loc] = (mus_float_t *)malloc(padded_size * 2 * sizeof(mus_float_t));
- sinc_tables[loc][padded_size] = 1.0;
-
- for (i = 1, win_phase = win_freq; i < padded_size; i++, win_phase += win_freq)
- {
- mus_float_t val;
- val = sinc[i] * sinc_window[(int)win_phase];
- sinc_tables[loc][padded_size + i] = val;
- sinc_tables[loc][padded_size - i] = val;
- }
-
- return(loc);
- }
-
-
- bool mus_is_src(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SRC));
- }
-
-
- static void free_src_gen(mus_any *srptr)
- {
- sr *srp = (sr *)srptr;
- if (srp->data) free(srp->data);
- if (srp->coeffs) free(srp->coeffs);
- free(srp);
- }
-
- static mus_any *sr_copy(mus_any *ptr)
- {
- sr *g, *p;
- int bytes;
-
- p = (sr *)ptr;
- g = (sr *)malloc(sizeof(sr));
- memcpy((void *)g, (void *)ptr, sizeof(sr));
-
- bytes = (2 * g->lim + 1) * sizeof(mus_float_t);
- g->data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->data), (void *)(p->data), bytes);
-
- if (p->coeffs)
- {
- bytes = p->lim * sizeof(mus_float_t);
- g->coeffs = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->coeffs), (void *)(p->coeffs), bytes);
- }
- return((mus_any *)g);
- }
-
- static bool src_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_src(mus_any *ptr)
- {
- sr *gen = (sr *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s width: %d, x: %.3f, incr: %.3f, sinc table len: %d",
- mus_name(ptr),
- gen->width, gen->x, gen->incr, gen->len);
- return(describe_buffer);
- }
-
-
- static mus_long_t src_length(mus_any *ptr) {return(((sr *)ptr)->width);}
- static mus_float_t run_src_gen(mus_any *srptr, mus_float_t sr_change, mus_float_t unused) {return(mus_src(srptr, sr_change, NULL));}
-
- static void *src_closure(mus_any *rd) {return(((sr *)rd)->closure);}
- static void *src_set_closure(mus_any *rd, void *e) {((sr *)rd)->closure = e; return(e);}
-
- static mus_float_t src_increment(mus_any *rd) {return(((sr *)rd)->incr);}
- static mus_float_t src_set_increment(mus_any *rd, mus_float_t val) {((sr *)rd)->incr = val; return(val);}
-
- static mus_float_t *src_sinc_table(mus_any *rd) {return(((sr *)rd)->sinc_table);}
-
- static void src_reset(mus_any *ptr)
- {
- sr *gen = (sr *)ptr;
- memset((void *)(gen->data), 0, (gen->lim + 1) * sizeof(mus_float_t));
- gen->x = 0.0;
- /* center the data if possible */
- if (gen->feeder)
- {
- int i, dir = 1;
- if (gen->incr < 0.0) dir = -1;
- for (i = gen->width - 1; i < gen->lim; i++)
- gen->data[i] = gen->feeder(gen->closure, dir);
- }
- gen->start = 0;
- }
-
- void mus_src_init(mus_any *ptr)
- {
- sr *srp = (sr *)ptr;
- if (srp->feeder)
- {
- int i, dir = 1;
- if (srp->incr < 0.0) dir = -1;
- for (i = srp->width - 1; i < srp->lim; i++)
- {
- srp->data[i] = srp->feeder(srp->closure, dir);
- srp->data[i + srp->lim] = srp->data[i];
- }
- }
- }
-
- static mus_any_class SRC_CLASS = {
- MUS_SRC,
- (char *)S_src,
- &free_src_gen,
- &describe_src,
- &src_equalp,
- &src_sinc_table, 0,
- &src_length, /* sinc width actually */
- 0,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- &src_increment,
- &src_set_increment,
- &run_src_gen,
- MUS_NOT_SPECIAL,
- &src_closure,
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &src_reset,
- &src_set_closure,
- &sr_copy
- };
-
-
- mus_any *mus_make_src_with_init(mus_float_t (*input)(void *arg, int direction), mus_float_t srate, int width, void *closure, void (*init)(void *p, mus_any *g))
- {
- /* besides 1, 2, .5, other common cases: 1.5, 3
- */
-
- if (fabs(srate) > MUS_MAX_CLM_SRC)
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_src ": srate arg invalid: %f", srate);
- else
- {
- if ((width < 0) || (width > MUS_MAX_CLM_SINC_WIDTH))
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_src ": width arg invalid: %d", width);
- else
- {
- sr *srp;
- int wid, loc;
-
- if (width <= 0) width = SRC_SINC_WIDTH;
- if (width < (int)(fabs(srate) * 2))
- wid = (int)(ceil(fabs(srate)) * 2);
- else wid = width;
- if ((srate == 2.0) &&
- ((wid & 1) != 0))
- wid++;
-
- srp = (sr *)calloc(1, sizeof(sr));
- srp->core = &SRC_CLASS;
- srp->x = 0.0;
- srp->feeder = input;
- srp->block_feeder = NULL;
- srp->closure = closure;
- srp->incr = srate;
- srp->width = wid;
- srp->lim = 2 * wid;
- srp->start = 0;
- srp->len = wid * SRC_SINC_DENSITY;
- srp->width_1 = 1.0 - wid;
- srp->sinc4 = srp->width * SRC_SINC_DENSITY + 4;
- srp->data = (mus_float_t *)calloc(2 * srp->lim + 1, sizeof(mus_float_t));
- loc = init_sinc_table(wid);
- srp->sinc_table = sinc_tables[loc];
- srp->coeffs = NULL;
-
- if (init)
- init(closure, (mus_any *)srp);
-
- if (srp->feeder)
- {
- int i, dir = 1;
- if (srate < 0.0) dir = -1;
- for (i = wid - 1; i < srp->lim; i++)
- {
- srp->data[i] = srp->feeder(closure, dir);
- srp->data[i + srp->lim] = srp->data[i];
- }
- /* was i = 0 here but we want the incoming data centered */
- }
- return((mus_any *)srp);
- }
- }
- return(NULL);
- }
-
- mus_any *mus_make_src(mus_float_t (*input)(void *arg, int direction), mus_float_t srate, int width, void *closure)
- {
- return(mus_make_src_with_init(input, srate, width, closure, NULL));
- }
-
- mus_float_t mus_src(mus_any *srptr, mus_float_t sr_change, mus_float_t (*input)(void *arg, int direction))
- {
- sr *srp = (sr *)srptr;
- mus_float_t sum, zf, srx, factor;
- int lim, loc, xi;
- bool int_ok;
- mus_float_t *data, *sinc_table;
-
- lim = srp->lim;
- loc = srp->start;
- data = srp->data;
- sinc_table = srp->sinc_table;
-
- if (sr_change > MUS_MAX_CLM_SRC)
- sr_change = MUS_MAX_CLM_SRC;
- else
- {
- if (sr_change < -MUS_MAX_CLM_SRC)
- sr_change = -MUS_MAX_CLM_SRC;
- }
- srx = srp->incr + sr_change;
-
- if (srp->x >= 1.0)
- {
- int i, fsx, dir = 1;
-
- if (srx < 0.0) dir = -1;
- fsx = (int)(srp->x);
- srp->x -= fsx;
-
- if (input) {srp->feeder = input; srp->block_feeder = NULL;}
-
- data[loc] = srp->feeder(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
-
- for (i = 1; i < fsx; i++)
- {
- /* there are two copies of the circular data buffer back-to-back so that we can
- * run the convolution below without worrying about the buffer end.
- */
- data[loc] = srp->feeder(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
- }
- srp->start = loc; /* next time around we start here */
- }
-
- /* now loc = beginning of data */
-
- /* if (srx == 0.0) srx = 0.01; */ /* can't decide about this ... */
- if (srx < 0.0) srx = -srx;
- if (srx > 1.0)
- {
- factor = 1.0 / srx;
- /* this is not exact since we're sampling the sinc and so on, but it's close over a wide range */
- zf = factor * (mus_float_t)SRC_SINC_DENSITY;
- xi = (int)(zf + 0.5);
-
- /* (let ((e (make-env '(0 1 1 1.1) :length 11))) (src-channel e))
- */
- /* we're comparing adding xi lim times to zf and if there's no difference, using the int case */
- if (fabs((xi - zf) * lim) > 2.0) int_ok = false; else int_ok = true;
- }
- else
- {
- factor = 1.0;
- zf = (mus_float_t)SRC_SINC_DENSITY;
- xi = SRC_SINC_DENSITY;
- int_ok = true;
- }
-
- sum = 0.0;
- if (int_ok)
- {
- int sinc_loc, sinc_incr, last, last10, xs;
-
- xs = (int)(zf * (srp->width_1 - srp->x));
- sinc_loc = xs + srp->sinc4;
- sinc_incr = xi;
- last = loc + lim;
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[sinc_loc];
- }
- else
- {
- mus_float_t sinc_loc, sinc_incr, x;
- int last, last10;
-
- x = zf * (srp->width_1 - srp->x);
- sinc_loc = x + srp->sinc4;
- sinc_incr = zf;
- last = loc + lim;
-
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[(int)sinc_loc];
- }
-
- srp->x += srx;
- return(sum * factor);
- }
-
-
- void mus_src_to_buffer(mus_any *srptr, mus_float_t (*input)(void *arg, int direction), mus_float_t *out_data, mus_long_t dur)
- {
- /* sr_change = 0.0
- */
- sr *srp = (sr *)srptr;
- mus_float_t sum, x, zf, srx, factor, sincx, srpx;
- int lim, i, xi, xs, dir = 1;
- bool int_ok;
- mus_long_t k;
- mus_float_t *data, *sinc_table;
-
- lim = srp->lim;
- sincx = (mus_float_t)SRC_SINC_DENSITY;
- data = srp->data;
- sinc_table = srp->sinc_table;
- srx = srp->incr;
- srpx = srp->x;
- if (srx < 0.0)
- {
- dir = -1;
- srx = -srx;
- }
- if (srx > 1.0)
- {
- factor = 1.0 / srx;
- /* this is not exact since we're sampling the sinc and so on, but it's close over a wide range */
- zf = factor * sincx;
- xi = (int)zf;
- if (fabs((xi - zf) * lim) > 2.0) int_ok = false; else int_ok = true;
- }
- else
- {
- factor = 1.0;
- zf = sincx;
- xi = SRC_SINC_DENSITY;
- int_ok = true;
- }
-
- for (k = 0; k < dur; k++)
- {
- int loc;
- loc = srp->start;
- if (srpx >= 1.0)
- {
- int fsx;
- /* modf here is very slow??! */
- fsx = (int)srpx;
- srpx -= fsx;
-
- data[loc] = input(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
-
- for (i = 1; i < fsx; i++)
- {
- /* there are two copies of the circular data buffer back-to-back so that we can
- * run the convolution below without worrying about the buffer end.
- */
- data[loc] = input(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
- }
- srp->start = loc; /* next time around we start here */
- }
-
- sum = 0.0;
- if (int_ok)
- {
- int sinc_loc, sinc_incr, last, last10;
-
- xs = (int)(zf * (srp->width_1 - srpx));
- sinc_loc = xs + srp->sinc4;
- sinc_incr = xi;
- last = loc + lim;
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[sinc_loc];
- }
- else
- {
- mus_float_t sinc_loc, sinc_incr;
- int last, last10;
-
- x = zf * (srp->width_1 - srpx);
- sinc_loc = x + srp->sinc4;
- sinc_incr = zf;
- last = loc + lim;
-
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[(int)sinc_loc];
- }
- srpx += srx;
- out_data[k] = sum * factor;
- }
- srp->x = srpx;
- }
-
-
- /* it was a cold, rainy day...
- * and on an even colder day, I changed this to use a circular data buffer, rather than memmove
- * then changed yet again to use straight buffers
- */
-
- mus_float_t *mus_src_20(mus_any *srptr, mus_float_t *in_data, mus_long_t dur)
- {
- sr *srp = (sr *)srptr;
- mus_float_t sum;
- int lim, i, width, wid1, wid10, xs, xi;
- mus_long_t k, dur2;
- mus_float_t *out_data, *ldata, *coeffs;
-
- dur2 = dur / 2 + 1;
- if ((dur & 1) != 0) dur2++;
- out_data = (mus_float_t *)malloc(dur2 * sizeof(mus_float_t));
-
- lim = srp->lim; /* 2 * width so it's even */
- width = srp->width;
-
- coeffs = (mus_float_t *)malloc(lim * sizeof(mus_float_t));
- if ((width & 1) != 0)
- xs = (int)((2 + width) * (SRC_SINC_DENSITY / 2)) + 4; /* Humph -- looks like crap -- maybe if odd width use the real one above, or insist on even width */
- else xs = (int)((1 + width) * (SRC_SINC_DENSITY / 2)) + 4;
- xi = SRC_SINC_DENSITY; /* skip a location (coeff=0.0) */
-
- for (i = 0; i < width; i++, xs += xi)
- coeffs[i] = srp->sinc_table[xs];
-
- for (i = 0; i < lim; i++)
- in_data[i] = srp->data[i];
-
- ldata = (mus_float_t *)in_data;
- wid10 = width - 10;
- wid1 = width - 1;
-
- for (k = 0; k < dur2; k++, ldata += 2)
- {
- int j;
- sum = ldata[wid1];
- i = 0;
- j = 0;
- while (i <= wid10)
- {
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- }
- for (; i < width; i++, j += 2)
- sum += (ldata[j] * coeffs[i]);
- out_data[k] = sum * 0.5;
- }
-
- free(coeffs);
- return(out_data);
- }
-
-
- mus_float_t *mus_src_05(mus_any *srptr, mus_float_t *in_data, mus_long_t dur)
- {
- sr *srp = (sr *)srptr;
- mus_float_t sum;
- int lim, i, width, wid1, wid10, xs, xi;
- mus_long_t k, dur2;
- mus_float_t *out_data, *ldata, *coeffs;
-
- dur2 = dur * 2;
- out_data = (mus_float_t *)malloc((dur2 + 1) * sizeof(mus_float_t));
- out_data[dur2] = 0.0;
-
- lim = srp->lim;
- width = srp->width;
-
- coeffs = (mus_float_t *)malloc(lim * sizeof(mus_float_t));
- xs = (SRC_SINC_DENSITY / 2) + 4;
- xi = SRC_SINC_DENSITY;
-
- for (i = 0; i < lim; i++, xs += xi)
- coeffs[i] = srp->sinc_table[xs];
-
- for (i = 0; i < lim; i++)
- in_data[i] = srp->data[i];
-
- ldata = (mus_float_t *)in_data;
- wid10 = lim - 10;
- wid1 = width - 1;
-
- for (k = 0; k < dur2; k += 2)
- {
- out_data[k] = ldata[wid1];
-
- sum = 0.0;
- i = 0;
- while (i <= wid10)
- {
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- }
- for (; i < lim; i++)
- sum += (ldata[i] * coeffs[i]);
- out_data[k + 1] = sum;
-
- ldata++;
- }
-
- free(coeffs);
- return(out_data);
- }
-
-
-
-
- /* ---------------- granulate ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t (*rd)(void *arg, int direction);
- mus_float_t (*block_rd)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- int s20;
- int s50;
- int rmp;
- mus_float_t amp;
- int cur_out;
- int input_hop;
- int ctr;
- int output_hop;
- mus_float_t *out_data; /* output buffer */
- int out_data_len;
- mus_float_t *in_data; /* input buffer */
- int in_data_len;
- void *closure;
- int (*edit)(void *closure);
- mus_float_t *grain; /* grain data */
- int grain_len;
- bool first_samp;
- unsigned long randx; /* gen-local random number seed */
- } grn_info;
-
-
- bool mus_is_granulate(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_GRANULATE));
- }
-
-
- static bool granulate_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_granulate(mus_any *ptr)
- {
- grn_info *gen = (grn_info *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s expansion: %.3f (%d/%d), scaler: %.3f, length: %.3f secs (%d samps), ramp: %.3f",
- mus_name(ptr),
- (mus_float_t)(gen->output_hop) / (mus_float_t)(gen->input_hop),
- gen->input_hop, gen->output_hop,
- gen->amp,
- (mus_float_t)(gen->grain_len) / (mus_float_t)sampling_rate, gen->grain_len,
- (mus_float_t)(gen->rmp) / (mus_float_t)sampling_rate);
- return(describe_buffer);
- }
-
-
- static void free_granulate(mus_any *ptr)
- {
- grn_info *gen = (grn_info *)ptr;
- if (gen->out_data) free(gen->out_data);
- if (gen->in_data) free(gen->in_data);
- if (gen->grain) free(gen->grain);
- free(gen);
- }
-
- static mus_any *grn_info_copy(mus_any *ptr)
- {
- grn_info *g, *p;
- int bytes;
-
- p = (grn_info *)ptr;
- g = (grn_info *)malloc(sizeof(grn_info));
- memcpy((void *)g, (void *)ptr, sizeof(grn_info));
-
- bytes = g->out_data_len * sizeof(mus_float_t);
- g->out_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->out_data), (void *)(p->out_data), bytes);
-
- bytes = g->in_data_len * sizeof(mus_float_t);
- g->in_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->in_data), (void *)(p->in_data), bytes);
- g->grain = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->grain), (void *)(p->grain), bytes);
-
- return((mus_any *)g);
- }
-
- static mus_long_t grn_length(mus_any *ptr) {return(((grn_info *)ptr)->grain_len);}
-
- static mus_long_t grn_set_length(mus_any *ptr, mus_long_t val)
- {
- grn_info *gen = ((grn_info *)ptr);
- if ((val > 0) && (val < gen->out_data_len))
- gen->grain_len = (int)val; /* larger -> segfault */
- return(gen->grain_len);
- }
-
- static mus_float_t grn_scaler(mus_any *ptr) {return(((grn_info *)ptr)->amp);}
- static mus_float_t grn_set_scaler(mus_any *ptr, mus_float_t val) {((grn_info *)ptr)->amp = val; return(val);}
-
- static mus_float_t grn_frequency(mus_any *ptr) {return(((mus_float_t)((grn_info *)ptr)->output_hop) / (mus_float_t)sampling_rate);}
- static mus_float_t grn_set_frequency(mus_any *ptr, mus_float_t val) {((grn_info *)ptr)->output_hop = (int)((mus_float_t)sampling_rate * val); return(val);}
-
- static void *grn_closure(mus_any *rd) {return(((grn_info *)rd)->closure);}
- static void *grn_set_closure(mus_any *rd, void *e) {((grn_info *)rd)->closure = e; return(e);}
-
- static mus_float_t grn_increment(mus_any *ptr)
- {
- grn_info *gen = ((grn_info *)ptr);
- return(((mus_float_t)(gen->output_hop)) / ((mus_float_t)(gen->input_hop)));
- }
-
- static mus_float_t grn_set_increment(mus_any *ptr, mus_float_t val)
- {
- grn_info *gen = ((grn_info *)ptr);
- if (val != 0.0)
- gen->input_hop = (int)(gen->output_hop / val);
- return(val);
- }
-
- static mus_long_t grn_hop(mus_any *ptr) {return(((grn_info *)ptr)->output_hop);}
- static mus_long_t grn_set_hop(mus_any *ptr, mus_long_t val) {((grn_info *)ptr)->output_hop = (int)val; return(val);}
-
- static mus_long_t grn_ramp(mus_any *ptr) {return(((grn_info *)ptr)->rmp);}
-
- static mus_long_t grn_set_ramp(mus_any *ptr, mus_long_t val)
- {
- grn_info *gen = (grn_info *)ptr;
- if (val < (gen->grain_len * .5))
- gen->rmp = (int)val;
- return(val);
- }
-
- static mus_float_t *granulate_data(mus_any *ptr) {return(((grn_info *)ptr)->grain);}
- int mus_granulate_grain_max_length(mus_any *ptr) {return(((grn_info *)ptr)->in_data_len);}
-
- static mus_long_t grn_location(mus_any *ptr) {return((mus_long_t)(((grn_info *)ptr)->randx));}
- static mus_long_t grn_set_location(mus_any *ptr, mus_long_t val) {((grn_info *)ptr)->randx = (unsigned long)val; return(val);}
-
- static mus_float_t run_granulate(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(mus_granulate(ptr, NULL));}
-
-
- static void grn_reset(mus_any *ptr)
- {
- grn_info *gen = (grn_info *)ptr;
- gen->cur_out = 0;
- gen->ctr = 0;
- memset((void *)(gen->out_data), 0, gen->out_data_len * sizeof(mus_float_t));
- memset((void *)(gen->in_data), 0, gen->in_data_len * sizeof(mus_float_t));
- memset((void *)(gen->grain), 0, gen->in_data_len * sizeof(mus_float_t));
- gen->first_samp = true;
- }
-
-
- static int grn_irandom(grn_info *spd, int amp)
- {
- /* gen-local next_random */
- spd->randx = spd->randx * 1103515245 + 12345;
- return((int)(amp * INVERSE_MAX_RAND2 * ((mus_float_t)((unsigned int)(spd->randx >> 16) & 32767))));
- }
-
-
- static mus_any_class GRANULATE_CLASS = {
- MUS_GRANULATE,
- (char *)S_granulate,
- &free_granulate,
- &describe_granulate,
- &granulate_equalp,
- &granulate_data, 0,
- &grn_length, /* segment-length */
- &grn_set_length,
- &grn_frequency, /* spd-out */
- &grn_set_frequency,
- 0, 0,
- &grn_scaler, /* segment-scaler */
- &grn_set_scaler,
- &grn_increment,
- &grn_set_increment,
- &run_granulate,
- MUS_NOT_SPECIAL,
- &grn_closure,
- 0,
- 0, 0, 0, 0, 0, 0,
- &grn_hop, &grn_set_hop,
- &grn_ramp, &grn_set_ramp,
- 0, 0, 0, 0,
- &grn_location, &grn_set_location, /* local randx */
- 0, 0, 0, 0, 0,
- &grn_reset,
- &grn_set_closure,
- &grn_info_copy
- };
-
-
- mus_any *mus_make_granulate(mus_float_t (*input)(void *arg, int direction),
- mus_float_t expansion, mus_float_t length, mus_float_t scaler,
- mus_float_t hop, mus_float_t ramp, mus_float_t jitter, int max_size,
- int (*edit)(void *closure),
- void *closure)
- {
- grn_info *spd;
- int outlen;
- outlen = (int)(sampling_rate * (hop + length));
- if (max_size > outlen) outlen = max_size;
- if (expansion <= 0.0)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_granulate ": expansion must be > 0.0: %f", expansion);
- return(NULL);
- }
- if (outlen <= 0)
- {
- mus_error(MUS_NO_LENGTH, S_make_granulate ": size is %d (hop: %f, segment-length: %f)?", outlen, hop, length);
- return(NULL);
- }
- if ((hop * sampling_rate) < expansion)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_granulate ": expansion (%f) must be < hop * srate (%f)", expansion, hop * sampling_rate);
- return(NULL);
- }
- spd = (grn_info *)malloc(sizeof(grn_info));
- spd->core = &GRANULATE_CLASS;
- spd->cur_out = 0;
- spd->ctr = 0;
- spd->grain_len = (int)(ceil(length * sampling_rate));
- spd->rmp = (int)(ramp * spd->grain_len);
- spd->amp = scaler;
- spd->output_hop = (int)(hop * sampling_rate);
- spd->input_hop = (int)((mus_float_t)(spd->output_hop) / expansion);
- spd->s20 = 2 * (int)(jitter * sampling_rate * hop); /* was *.05 here and *.02 below */
- /* added "2 *" 21-Mar-05 and replaced irandom with (grn)mus_irandom below */
- spd->s50 = (int)(jitter * sampling_rate * hop * 0.4);
- spd->out_data_len = outlen;
- spd->out_data = (mus_float_t *)calloc(spd->out_data_len, sizeof(mus_float_t));
- spd->in_data_len = outlen + spd->s20 + 1;
- spd->in_data = (mus_float_t *)malloc(spd->in_data_len * sizeof(mus_float_t));
- spd->rd = input;
- spd->block_rd = NULL;
- spd->closure = closure;
- spd->edit = edit;
- spd->grain = (mus_float_t *)malloc(spd->in_data_len * sizeof(mus_float_t));
- spd->first_samp = true;
- spd->randx = mus_rand_seed(); /* caller can override this via the mus_location method */
- next_random();
- return((mus_any *)spd);
- }
-
-
- void mus_granulate_set_edit_function(mus_any *ptr, int (*edit)(void *closure))
- {
- grn_info *gen = (grn_info *)ptr;
- if (!(gen->grain))
- gen->grain = (mus_float_t *)calloc(gen->in_data_len, sizeof(mus_float_t));
- gen->edit = edit;
- }
-
-
- mus_float_t mus_granulate_with_editor(mus_any *ptr, mus_float_t (*input)(void *arg, int direction), int (*edit)(void *closure))
- {
- /* in_data_len is the max grain size (:maxsize arg), not the current grain size
- * out_data_len is the size of the output buffer
- * grain_len is the current grain size
- * cur_out is the out_data buffer location where we need to add in the next grain
- * ctr is where we are now in out_data
- */
- grn_info *spd = (grn_info *)ptr;
- mus_float_t result = 0.0;
-
- if (spd->ctr < spd->out_data_len)
- result = spd->out_data[spd->ctr]; /* else return 0.0 */
- spd->ctr++;
-
- if (spd->ctr >= spd->cur_out) /* time for next grain */
- {
- /* set up edit/input functions and possible outside-accessible grain array */
- int i;
- int (*spd_edit)(void *closure) = edit;
- if (input) {spd->rd = input; spd->block_rd = NULL;}
- if (spd_edit == NULL) spd_edit = spd->edit;
-
- if (spd->first_samp)
- {
- /* fill up in_data, out_data is already cleared */
- if (spd->block_rd)
- spd->block_rd(spd->closure, 1, spd->in_data, 0, spd->in_data_len);
- else
- {
- for (i = 0; i < spd->in_data_len; i++)
- spd->in_data[i] = spd->rd(spd->closure, 1);
- }
- }
- else
- {
-
- /* align output buffer to flush the data we've already output, and zero out new trailing portion */
- if (spd->cur_out >= spd->out_data_len)
- {
- /* entire buffer has been output, and in fact we've been sending 0's for awhile to fill out hop */
- memset((void *)(spd->out_data), 0, spd->out_data_len * sizeof(mus_float_t)); /* so zero the entire thing (it's all old) */
- }
- else
- {
- /* move yet-un-output data to 0, zero trailers */
- int good_samps;
- good_samps = (spd->out_data_len - spd->cur_out);
- memmove((void *)(spd->out_data), (void *)(spd->out_data + spd->cur_out), good_samps * sizeof(mus_float_t));
- memset((void *)(spd->out_data + good_samps), 0, spd->cur_out * sizeof(mus_float_t)); /* must be cur_out trailing samples to 0 */
- }
-
- /* align input buffer */
- if (spd->input_hop > spd->in_data_len)
- {
- /* need to flush enough samples to accommodate the fact that the hop is bigger than our data buffer */
- for (i = spd->in_data_len; i < spd->input_hop; i++) spd->rd(spd->closure, 1);
- /* then get a full input buffer */
- if (spd->block_rd)
- spd->block_rd(spd->closure, 1, spd->in_data, 0, spd->in_data_len);
- else
- {
- for (i = 0; i < spd->in_data_len; i++)
- spd->in_data[i] = spd->rd(spd->closure, 1);
- }
- }
- else
- {
- /* align input buffer with current input hop location */
- int good_samps;
- good_samps = (spd->in_data_len - spd->input_hop);
- memmove((void *)(spd->in_data), (void *)(spd->in_data + spd->input_hop), good_samps * sizeof(mus_float_t));
- if (spd->block_rd)
- spd->block_rd(spd->closure, 1, spd->in_data, good_samps, spd->in_data_len);
- else
- {
- for (i = good_samps; i < spd->in_data_len; i++)
- spd->in_data[i] = spd->rd(spd->closure, 1);
- }
- }
- }
-
- /* create current grain */
- {
- int lim, curstart, j;
-
- lim = spd->grain_len;
- curstart = grn_irandom(spd, spd->s20); /* start location in input buffer */
- if ((curstart + spd->grain_len) > spd->in_data_len)
- lim = (spd->in_data_len - curstart);
- if (lim > spd->grain_len)
- lim = spd->grain_len;
- else
- {
- if (lim < spd->grain_len)
- memset((void *)(spd->grain), 0, (spd->grain_len - lim) * sizeof(mus_float_t));
- }
- if (spd->rmp > 0)
- {
- int steady_end, up_end;
- mus_float_t amp = 0.0, incr;
- steady_end = (spd->grain_len - spd->rmp);
- incr = (mus_float_t)(spd->amp) / (mus_float_t)(spd->rmp);
- up_end = spd->rmp;
- if (up_end > lim) up_end = lim;
- for (i = 0, j = curstart; i < up_end; i++, j++)
- {
- spd->grain[i] = (amp * spd->in_data[j]);
- amp += incr;
- }
- if (steady_end > lim) steady_end = lim;
- for (; i < steady_end; i++, j++)
- spd->grain[i] = (amp * spd->in_data[j]);
- for (; i < lim; i++, j++)
- {
- spd->grain[i] = (amp * spd->in_data[j]);
- amp -= incr;
- }
- }
- else
- {
- /* ramp is 0.0, so just scale the input buffer by the current amp */
- if (spd->amp == 1.0)
- memcpy((void *)(spd->grain), (void *)(spd->in_data + curstart), lim * sizeof(mus_float_t));
- else
- {
- for (i = 0, j = curstart; i < lim; i++, j++)
- spd->grain[i] = (spd->amp * spd->in_data[j]);
- }
- }
- }
-
- /* add new grain into output buffer */
- {
- int new_len;
- if (spd_edit)
- {
- new_len = (*spd_edit)(spd->closure);
- if (new_len <= 0)
- new_len = spd->grain_len;
- else
- {
- if (new_len > spd->out_data_len)
- new_len = spd->out_data_len;
- }
- }
- else new_len = spd->grain_len;
- if (new_len > spd->out_data_len) /* can be off-by-one here if hop is just barely greater then 0.0 (user is screwing around...) */
- new_len = spd->out_data_len;
- for (i = 0; i < new_len; i++)
- spd->out_data[i] += spd->grain[i];
- }
-
- /* set location of next grain calculation */
- spd->ctr = 0;
- spd->cur_out = spd->output_hop + grn_irandom(spd, 2 * spd->s50) - (spd->s50 >> 1);
- /* this form suggested by Marc Lehmann */
- /* "2 *" added 21-Mar-05 and irandom replaced with mus_irandom, grn_irandom 28-Feb-06 */
- /* use of gen-local random sequence suggested by Kjetil Matheussen (to keep multi-channel grns in sync) */
- if (spd->cur_out < 0) spd->cur_out = 0;
-
- if (spd->first_samp)
- {
- spd->first_samp = false;
- spd->ctr = 1;
- return(spd->out_data[0]);
- }
- }
- return(result);
- }
-
-
- mus_float_t mus_granulate(mus_any *ptr, mus_float_t (*input)(void *arg, int direction))
- {
- return(mus_granulate_with_editor(ptr, input, NULL));
- }
-
-
-
- /* ---------------- Fourier transform ---------------- */
-
- /* fft of mus_float_t data in zero-based arrays
- */
-
- static void mus_big_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is);
-
- #if HAVE_FFTW3 && HAVE_COMPLEX_TRIG
-
- static fftw_complex *c_in_data = NULL, *c_out_data = NULL;
- static fftw_plan c_r_plan, c_i_plan;
- static int last_c_fft_size = 0;
-
- static void mus_fftw_with_imag(mus_float_t *rl, mus_float_t *im, int n, int dir)
- {
- int i, n4;
-
- if (n != last_c_fft_size)
- {
- if (c_in_data)
- {
- fftw_free(c_in_data);
- fftw_free(c_out_data);
- fftw_destroy_plan(c_r_plan);
- fftw_destroy_plan(c_i_plan);
- }
- c_in_data = (fftw_complex *)fftw_malloc(n * sizeof(fftw_complex)); /* rl/im data is mus_float_t */
- c_out_data = (fftw_complex *)fftw_malloc(n * sizeof(fftw_complex));
- c_r_plan = fftw_plan_dft_1d(n, c_in_data, c_out_data, FFTW_FORWARD, FFTW_ESTIMATE);
- c_i_plan = fftw_plan_dft_1d(n, c_in_data, c_out_data, FFTW_BACKWARD, FFTW_ESTIMATE);
- last_c_fft_size = n;
- }
-
- n4 = n - 4;
- i = 0;
- while (i <= n4)
- {
- /* adding code to avoid this loop saves essentially nothing, mainly because the great majority of the calls
- * are actually handling two real arrays at once -- the imag=0 case is 1/10 of the total. In the zero case,
- * the savings here is about 10%, but that is swamped by the fft itself (say 5-10 in c*).
- * using the new split array code (see below) saves essentially nothing -- perhaps 1 to 2% overall.
- */
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- }
- for (; i < n; i++)
- c_in_data[i] = rl[i] + _Complex_I * im[i];
-
- if (dir == -1)
- fftw_execute(c_r_plan);
- else fftw_execute(c_i_plan);
-
- i = 0;
- while (i <= n4)
- {
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- }
- for (; i < n; i++)
- {
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- }
- }
-
-
- void mus_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is)
- {
- /* simple timing tests indicate fftw is slightly faster than mus_fft in this context
- */
- if (n < (1 << 30))
- mus_fftw_with_imag(rl, im, n, is);
- else mus_big_fft(rl, im, n, is);
- }
-
- #else
-
- static void mus_scramble(mus_float_t *rl, mus_float_t *im, int n)
- {
- /* bit reversal */
-
- int i, j;
- mus_float_t vr, vi;
- j = 0;
- for (i = 0; i < n; i++)
- {
- int m;
- if (j > i)
- {
- vr = rl[j];
- vi = im[j];
- rl[j] = rl[i];
- im[j] = im[i];
- rl[i] = vr;
- im[i] = vi;
- }
- m = n >> 1;
- while ((m >= 2) && (j >= m))
- {
- j -= m;
- m = m >> 1;
- }
- j += m;
- }
- }
-
-
- void mus_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is)
- {
- /* standard fft: real part in rl, imaginary in im,
- * rl and im are zero-based.
- * see fxt/simplfft/fft.c (Joerg Arndt)
- */
- int m, j, mh, ldm, lg, i, i2, j2, imh;
- mus_float_t u, vr, vi, angle;
-
- if (n >= (1 << 30))
- {
- mus_big_fft(rl, im, n, is);
- return;
- }
-
- imh = (int)(log(n + 1) / log(2.0));
- mus_scramble(rl, im, n);
- m = 2;
- ldm = 1;
- mh = n >> 1;
- angle = (M_PI * is);
- for (lg = 0; lg < imh; lg++)
- {
- mus_float_t c, s, ur, ui;
- c = cos(angle);
- s = sin(angle);
- ur = 1.0;
- ui = 0.0;
- for (i2 = 0; i2 < ldm; i2++)
- {
- i = i2;
- j = i2 + ldm;
- for (j2 = 0; j2 < mh; j2++)
- {
- vr = ur * rl[j] - ui * im[j];
- vi = ur * im[j] + ui * rl[j];
- rl[j] = rl[i] - vr;
- im[j] = im[i] - vi;
- rl[i] += vr;
- im[i] += vi;
- i += m;
- j += m;
- }
- u = ur;
- ur = (ur * c) - (ui * s);
- ui = (ui * c) + (u * s);
- }
- mh >>= 1;
- ldm = m;
- angle *= 0.5;
- m <<= 1;
- }
- }
- #endif
-
-
- static void mus_big_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is)
- {
- mus_long_t m, j, mh, ldm, i, i2, j2;
- int imh, lg;
- mus_float_t u, vr, vi, angle;
-
- imh = (int)(log(n + 1) / log(2.0));
-
- j = 0;
- for (i = 0; i < n; i++)
- {
- if (j > i)
- {
- vr = rl[j];
- vi = im[j];
- rl[j] = rl[i];
- im[j] = im[i];
- rl[i] = vr;
- im[i] = vi;
- }
- m = n >> 1;
- while ((m >= 2) && (j >= m))
- {
- j -= m;
- m = m >> 1;
- }
- j += m;
- }
-
- m = 2;
- ldm = 1;
- mh = n >> 1;
- angle = (M_PI * is);
- for (lg = 0; lg < imh; lg++)
- {
- mus_float_t c, s, ur, ui;
- c = cos(angle);
- s = sin(angle);
- ur = 1.0;
- ui = 0.0;
- for (i2 = 0; i2 < ldm; i2++)
- {
- i = i2;
- j = i2 + ldm;
- for (j2 = 0; j2 < mh; j2++)
- {
- vr = ur * rl[j] - ui * im[j];
- vi = ur * im[j] + ui * rl[j];
- rl[j] = rl[i] - vr;
- im[j] = im[i] - vi;
- rl[i] += vr;
- im[i] += vi;
- i += m;
- j += m;
- }
- u = ur;
- ur = (ur * c) - (ui * s);
- ui = (ui * c) + (u * s);
- }
- mh >>= 1;
- ldm = m;
- angle *= 0.5;
- m <<= 1;
- }
- }
-
-
- #if HAVE_GSL
- #include <gsl/gsl_sf_bessel.h>
-
- mus_float_t mus_bessi0(mus_float_t x)
- {
- gsl_sf_result res;
- gsl_sf_bessel_I0_e(x, &res);
- return((mus_float_t)(res.val));
- }
-
- #else
-
- mus_float_t mus_bessi0(mus_float_t x)
- {
- if (x == 0.0) return(1.0);
- if (fabs(x) <= 15.0)
- {
- mus_float_t z, denominator, numerator;
- z = x * x;
- numerator = (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z *
- 0.210580722890567e-22 + 0.380715242345326e-19) +
- 0.479440257548300e-16) + 0.435125971262668e-13) +
- 0.300931127112960e-10) + 0.160224679395361e-7) +
- 0.654858370096785e-5) + 0.202591084143397e-2) +
- 0.463076284721000e0) + 0.754337328948189e2) +
- 0.830792541809429e4) + 0.571661130563785e6) +
- 0.216415572361227e8) + 0.356644482244025e9) +
- 0.144048298227235e10);
- denominator = (z * (z * (z - 0.307646912682801e4) +
- 0.347626332405882e7) - 0.144048298227235e10);
- return(-numerator / denominator);
- }
- return(1.0);
- }
- #endif
-
-
- #if HAVE_COMPLEX_TRIG || HAVE_GSL
- static mus_float_t ultraspherical(int n, mus_float_t x, mus_float_t lambda)
- {
- /* this is also the algorithm used in gsl gegenbauer.c -- slow but not as bad as using the binomials! */
- mus_float_t fn1, fn2 = 1.0, fn = 1.0;
- int k;
- if (n == 0) return(1.0);
- if (lambda == 0.0)
- fn1 = 2.0 * x;
- else fn1 = 2.0 * x * lambda;
- if (n == 1) return(fn1);
- for (k = 2; k <= n; k++)
- {
- fn = ((2.0 * x * (k + lambda - 1.0) * fn1) - ((k + (2.0 * lambda) - 2.0) * fn2)) / (mus_float_t)k;
- fn2 = fn1;
- fn1 = fn;
- }
- return(fn);
- }
- #endif
-
-
- bool mus_is_fft_window(int val)
- {
- switch (val)
- {
- case MUS_RECTANGULAR_WINDOW: case MUS_HANN_WINDOW: case MUS_WELCH_WINDOW: case MUS_PARZEN_WINDOW:
- case MUS_BARTLETT_WINDOW: case MUS_HAMMING_WINDOW: case MUS_BLACKMAN2_WINDOW: case MUS_BLACKMAN3_WINDOW:
- case MUS_BLACKMAN4_WINDOW: case MUS_EXPONENTIAL_WINDOW: case MUS_RIEMANN_WINDOW: case MUS_KAISER_WINDOW:
- case MUS_CAUCHY_WINDOW: case MUS_POISSON_WINDOW: case MUS_GAUSSIAN_WINDOW: case MUS_TUKEY_WINDOW:
- case MUS_DOLPH_CHEBYSHEV_WINDOW: case MUS_HANN_POISSON_WINDOW: case MUS_CONNES_WINDOW:
- case MUS_SAMARAKI_WINDOW: case MUS_ULTRASPHERICAL_WINDOW: case MUS_BARTLETT_HANN_WINDOW:
- case MUS_BOHMAN_WINDOW: case MUS_FLAT_TOP_WINDOW: case MUS_BLACKMAN5_WINDOW: case MUS_BLACKMAN6_WINDOW:
- case MUS_BLACKMAN7_WINDOW: case MUS_BLACKMAN8_WINDOW: case MUS_BLACKMAN9_WINDOW: case MUS_BLACKMAN10_WINDOW:
- case MUS_RV2_WINDOW: case MUS_RV3_WINDOW: case MUS_RV4_WINDOW: case MUS_MLT_SINE_WINDOW:
- case MUS_PAPOULIS_WINDOW: case MUS_DPSS_WINDOW: case MUS_SINC_WINDOW:
- return(true);
- break;
- }
- return(false);
- }
-
-
- #if HAVE_GSL
- #include <gsl/gsl_version.h>
- #if ((GSL_MAJOR_VERSION >= 1) && (GSL_MINOR_VERSION >= 9))
- #include <gsl/gsl_math.h>
- #include <gsl/gsl_eigen.h>
- #define HAVE_GSL_EIGEN_NONSYMMV_WORKSPACE 1
- #endif
- #endif
-
-
- static mus_float_t sqr(mus_float_t x) {return(x * x);}
-
-
- mus_float_t *mus_make_fft_window_with_window(mus_fft_window_t type, mus_long_t size, mus_float_t beta, mus_float_t mu, mus_float_t *window)
- {
- /* mostly taken from
- * Fredric J. Harris, "On the Use of Windows for Harmonic Analysis with the
- * Discrete Fourier Transform," Proceedings of the IEEE, Vol. 66, No. 1,
- * January 1978.
- *
- * Albert H. Nuttall, "Some Windows with Very Good Sidelobe Behaviour",
- * IEEE Transactions of Acoustics, Speech, and Signal Processing, Vol. ASSP-29,
- * No. 1, February 1981, pp 84-91
- */
-
- mus_long_t i, j, midn, midp1;
- mus_float_t freq, rate, angle = 0.0, cx;
- if (window == NULL) return(NULL);
-
- midn = size >> 1;
- midp1 = (size + 1) / 2;
- freq = TWO_PI / (mus_float_t)size;
- rate = 1.0 / (mus_float_t)midn;
-
- switch (type)
- {
- case MUS_RECTANGULAR_WINDOW:
- for (i = 0; i < size; i++)
- window[i] = 1.0;
- break;
-
- case MUS_WELCH_WINDOW:
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = 1.0 - sqr((mus_float_t)(i - midn) / (mus_float_t)midp1);
- window[j] = window[i];
- }
- break;
-
- case MUS_CONNES_WINDOW:
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = sqr(1.0 - sqr((mus_float_t)(i - midn) / (mus_float_t)midp1));
- window[j] = window[i];
- }
- break;
-
- case MUS_PARZEN_WINDOW:
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = 1.0 - fabs((mus_float_t)(i - midn) / (mus_float_t)midp1);
- window[j] = window[i];
- }
- break;
-
- case MUS_BARTLETT_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += rate)
- {
- window[i] = angle;
- window[j] = angle;
- }
- break;
-
- case MUS_BARTLETT_HANN_WINDOW:
- {
- mus_float_t ramp;
- rate *= 0.5;
- /* this definition taken from mathworks docs: they use size - 1 throughout -- this makes very little
- * difference unless you're using a small window. I decided to be consistent with all the other
- * windows, and besides, this way actually peaks at 1.0 (which matlab misses)
- */
- for (i = 0, j = size - 1, angle = -M_PI, ramp = 0.5; i <= midn; i++, j--, angle += freq, ramp -= rate)
- {
- window[i] = 0.62 - 0.48 * ramp + 0.38 * cos(angle);
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_BOHMAN_WINDOW:
- {
- mus_float_t ramp;
- /* definition from diracdelta docs and "DSP Handbook" -- used in bispectrum ("minimum bispectrum bias supremum") */
- for (i = 0, j = size - 1, angle = M_PI, ramp = 0.0; i <= midn; i++, j--, angle -= freq, ramp += rate)
- {
- window[i] = ramp * cos(angle) + (sin(angle) / M_PI);
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_HANN_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = 0.5 - 0.5 * cos(angle);
- window[j] = window[i];
- }
- break;
-
- /* Rife-Vincent windows are an elaboration of this (Hann = RV1) */
-
- case MUS_RV2_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = .375 - 0.5 * cos(angle) + .125 * cos(2 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_RV3_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = (10.0 / 32.0) -
- (15.0 / 32.0) * cos(angle) +
- (6.0 / 32.0) * cos(2 * angle) -
- (1.0 / 32.0) * cos(3 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_RV4_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = (35.0 / 128.0) -
- (56.0 / 128.0) * cos(angle) +
- (28.0 / 128.0) * cos(2 * angle) -
- (8.0 / 128.0) * cos(3 * angle) +
- (1.0 / 128.0) * cos(4 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_HAMMING_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = 0.54 - 0.46 * cos(angle);
- window[j] = window[i];
- }
- break;
-
- /* Blackman 1 is the same as Hamming */
-
- case MUS_BLACKMAN2_WINDOW: /* using Chebyshev polynomial equivalents here (this is also given as .42 .5 .08) */
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- { /* (+ 0.42323 (* -0.49755 (cos a)) (* 0.07922 (cos (* a 2)))) */
- /* "A Family...": .42438 .49341 .078279 */
- cx = cos(angle);
- window[i] = .34401 + (cx * (-.49755 + (cx * .15844)));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN3_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- { /* (+ 0.35875 (* -0.48829 (cos a)) (* 0.14128 (cos (* a 2))) (* -0.01168 (cos (* a 3)))) */
- /* (+ 0.36336 (* 0.48918 (cos a)) (* 0.13660 (cos (* a 2))) (* 0.01064 (cos (* a 3)))) is "Nuttall" window? */
- /* "A Family...": .36358 .489177 .136599 .0106411 */
-
- cx = cos(angle);
- window[i] = .21747 + (cx * (-.45325 + (cx * (.28256 - (cx * .04672)))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN4_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- { /* (+ 0.287333 (* -0.44716 (cos a)) (* 0.20844 (cos (* a 2))) (* -0.05190 (cos (* a 3))) (* 0.005149 (cos (* a 4)))) */
- /* "A Family...": .32321 .471492 .175534 .0284969 .001261357 */
- cx = cos(angle);
- window[i] = .084037 + (cx * (-.29145 + (cx * (.375696 + (cx * (-.20762 + (cx * .041194)))))));
- window[j] = window[i];
- }
- break;
-
- /* "A Family of Cosine-Sum Windows..." Albrecht */
-
- case MUS_BLACKMAN5_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .293557 -.451935 .201416 -.047926 .00502619 -.000137555 */
- /* partials->polynomial -> -0.196389809 -0.308844775 0.3626224697 -0.188952908 0.0402095206 -0.002200880, then fixup constant */
- cx = cos(angle);
- window[i] = 0.097167 +
- (cx * (-.3088448 +
- (cx * (.3626224 +
- (cx * (-.1889530 +
- (cx * (.04020952 +
- (cx * -.0022008)))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN6_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2712203 -.4334446 .2180041 -.0657853 .010761867 -.0007700127 .00001368088 */
- /* partials->polynomial -> -0.207255900 -0.239938736 0.3501594961
- * -0.247740954 0.0854382589 -0.012320203 0.0004377882
- */
- cx = cos(angle);
- window[i] = 0.063964353 +
- (cx * (-0.239938736 +
- (cx * (0.3501594961 +
- (cx * (-0.247740954 +
- (cx * (0.0854382589 +
- (cx * (-0.012320203 +
- (cx * 0.0004377882)))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN7_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2533176 -.4163269 .2288396 -.08157508 .017735924 -.0020967027 .00010677413 -.0000012807 */
- /* partials->polynomial -> -0.211210445 -0.182076216 0.3177137375 -0.284437984
- * 0.1367622316 -0.033403806 0.0034167722 -0.000081965
- */
- cx = cos(angle);
- window[i] = 0.04210723 +
- (cx * (-0.18207621 +
- (cx * (0.3177137375 +
- (cx * (-0.284437984 +
- (cx * (0.1367622316 +
- (cx * (-0.033403806 +
- (cx * (0.0034167722 +
- (cx * -0.000081965)))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN8_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2384331 -.4005545 .2358242 -.09527918 .025373955 -.0041524329 .00036856041 -.00001384355 .0000001161808 */
- /* partials->polynomial -> -0.210818693 -0.135382235 0.2752871215 -0.298843294 0.1853193194
- * -0.064888448 0.0117641902 -0.000885987 0.0000148711
- */
- cx = cos(angle);
- window[i] = 0.027614462 +
- (cx * (-0.135382235 +
- (cx * (0.2752871215 +
- (cx * (-0.298843294 +
- (cx * (0.1853193194 +
- (cx * (-0.064888448 +
- (cx * (0.0117641902 +
- (cx * (-0.000885987 +
- (cx * 0.0000148711)))))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN9_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2257345 -.3860122 .2401294 -.1070542 .03325916 -.00687337 .0008751673 -.0000600859 .000001710716 -.00000001027272 */
- /* partials->polynomial -> -0.207743675 -0.098795950 0.2298837751 -0.294112951 0.2243389785
- * -0.103248745 0.0275674108 -0.003839580 0.0002189716 -0.000002630
- */
- cx = cos(angle);
- window[i] = 0.01799071953 +
- (cx * (-0.098795950 +
- (cx * (0.2298837751 +
- (cx * (-0.294112951 +
- (cx * (0.2243389785 +
- (cx * (-0.103248745 +
- (cx * (0.0275674108 +
- (cx * (-0.003839580 +
- (cx * (0.0002189716 +
- (cx * -0.000002630)))))))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN10_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2151527 -.3731348 .2424243 -.1166907 .04077422 -.01000904 .0016398069 -.0001651660 .000008884663 -.000000193817 .00000000084824 */
- /* partials->polynomial -> -0.203281015 -0.071953468 0.1878870875 -0.275808066
- * 0.2489042133 -0.141729787 0.0502002984 -0.010458985 0.0011361511 -0.000049617 0.0000004343
- */
- cx = cos(angle);
- window[i] = 0.0118717384 +
- (cx * (-0.071953468 +
- (cx * (0.1878870875 +
- (cx * (-0.275808066 +
- (cx * (0.2489042133 +
- (cx * (-0.141729787 +
- (cx * (0.0502002984 +
- (cx * (-0.010458985 +
- (cx * (0.0011361511 +
- (cx * (-0.000049617 +
- (cx * 0.0000004343)))))))))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_FLAT_TOP_WINDOW:
- /* this definition taken from mathworks docs -- see above */
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = 0.2156 - 0.4160 * cos(angle) + 0.2781 * cos(2 * angle) - 0.0836 * cos(3 * angle) + 0.0069 * cos(4 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_EXPONENTIAL_WINDOW:
- {
- mus_float_t expn, expsum = 1.0;
- expn = log(2) / (mus_float_t)midn + 1.0;
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = expsum - 1.0;
- window[j] = window[i];
- expsum *= expn;
- }
- }
- break;
-
- case MUS_KAISER_WINDOW:
- {
- mus_float_t I0beta;
- I0beta = mus_bessi0(beta); /* Harris multiplies beta by pi */
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = mus_bessi0(beta * sqrt(1.0 - sqr(angle))) / I0beta;
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_CAUCHY_WINDOW:
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = 1.0 / (1.0 + sqr(beta * angle));
- window[j] = window[i];
- }
- break;
-
- case MUS_POISSON_WINDOW:
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = exp((-beta) * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_HANN_POISSON_WINDOW:
- /* Hann * Poisson -- from JOS */
- {
- mus_float_t angle1;
- for (i = 0, j = size - 1, angle = 1.0, angle1 = 0.0; i <= midn; i++, j--, angle -= rate, angle1 += freq)
- {
- window[i] = exp((-beta) * angle) * (0.5 - 0.5 * cos(angle1));
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_RIEMANN_WINDOW:
- {
- mus_float_t sr1;
- sr1 = TWO_PI / (mus_float_t)size;
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- if (i == midn)
- window[i] = 1.0;
- else
- {
- cx = sr1 * (midn - i);
- window[i] = sin(cx) / cx;
- }
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_GAUSSIAN_WINDOW:
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = exp(-.5 * sqr(beta * angle));
- window[j] = window[i];
- }
- break;
-
- case MUS_TUKEY_WINDOW:
- cx = midn * (1.0 - beta);
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- if (i >= cx)
- window[i] = 1.0;
- else window[i] = .5 * (1.0 - cos(M_PI * i / cx));
- window[j] = window[i];
- }
- break;
-
- case MUS_MLT_SINE_WINDOW:
- {
- mus_float_t scl;
- scl = M_PI / (mus_float_t)size;
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = sin((i + 0.5) * scl);
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_PAPOULIS_WINDOW:
- {
- int n2;
- n2 = size / 2;
- for (i = -n2; i < n2; i++)
- {
- mus_float_t ratio, pratio;
- ratio = (mus_float_t)i / (mus_float_t)n2;
- pratio = M_PI * ratio;
- window[i + n2] = (fabs(sin(pratio)) / M_PI) + (cos(pratio) * (1.0 - fabs(ratio)));
- }
- }
- break;
-
- case MUS_SINC_WINDOW:
- {
- mus_float_t scl;
- scl = 2 * M_PI / (size - 1);
- for (i = -midn, j = 0; i < midn; i++, j++)
- {
- if (i == 0)
- window[j] = 1.0;
- else window[j] = sin(i * scl) / (i * scl);
- }
- }
- break;
-
- case MUS_DPSS_WINDOW:
- #if HAVE_GSL_EIGEN_NONSYMMV_WORKSPACE
- {
- /* from Verma, Bilbao, Meng, "The Digital Prolate Spheroidal Window"
- * output checked using Julius Smith's dpssw.m, although my "beta" is different
- */
- double *data; /* "double" for gsl func */
- double cw, n1, pk = 0.0;
-
- cw = cos(2 * M_PI * beta);
- n1 = (size - 1) * 0.5;
- if ((mus_long_t)(size * size * sizeof(double)) > mus_max_malloc())
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_fft_window ": dpss window requires size^2 * 8 bytes, but that exceeds the current mus-max-malloc amount");
- return(window);
- }
-
- data = (double *)calloc(size * size, sizeof(double));
- for (i = 0; i < size; i++)
- {
- double n2;
- n2 = n1 - i;
- data[i * size + i] = cw * n2 * n2;
- if (i < (size - 1))
- data[i * (size + 1) + 1] = 0.5 * (i + 1) * (size - 1 - i);
- if (i > 0)
- data[i * (size + 1) - 1] = 0.5 * i * (size - i);
- }
- {
- gsl_vector_complex_view evec_i;
- gsl_matrix_view m = gsl_matrix_view_array(data, size, size);
- gsl_vector_complex *eval = gsl_vector_complex_alloc(size);
- gsl_matrix_complex *evec = gsl_matrix_complex_alloc(size, size);
-
- gsl_eigen_nonsymmv_workspace *w = gsl_eigen_nonsymmv_alloc(size);
- gsl_eigen_nonsymmv(&m.matrix, eval, evec, w);
- gsl_eigen_nonsymmv_free(w);
-
- gsl_eigen_nonsymmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_DESC);
- evec_i = gsl_matrix_complex_column(evec, 0);
-
- for (j = 0; j < size; j++)
- window[j] = GSL_REAL(gsl_vector_complex_get(&evec_i.vector, j));
-
- gsl_vector_complex_free(eval);
- gsl_matrix_complex_free(evec);
- }
-
- for (i = 0; i < size; i++)
- if (fabs(window[i]) > fabs(pk))
- pk = window[i];
- if (pk != 0.0)
- for (i = 0; i < size; i++)
- window[i] /= pk;
-
- free(data);
- }
- #else
- mus_error(MUS_NO_SUCH_FFT_WINDOW, S_make_fft_window ": DPSS window needs GSL");
- #endif
- break;
-
- case MUS_ULTRASPHERICAL_WINDOW:
- case MUS_SAMARAKI_WINDOW:
- case MUS_DOLPH_CHEBYSHEV_WINDOW:
- /* "Design of Ultraspherical Window Functions with Prescribed Spectral Characteristics", Bergen and Antoniou, EURASIP JASP 2004 */
- if (type == MUS_ULTRASPHERICAL_WINDOW)
- {
- if (mu == 0.0)
- type = MUS_DOLPH_CHEBYSHEV_WINDOW;
- else
- {
- if (mu == 1.0)
- type = MUS_SAMARAKI_WINDOW;
- }
- }
-
- #if HAVE_COMPLEX_TRIG
- {
- mus_float_t *rl, *im;
- mus_float_t pk = 0.0;
- mus_float_t alpha;
-
- freq = M_PI / (mus_float_t)size;
- if (beta < 0.2) beta = 0.2;
- alpha = creal(ccosh(cacosh(pow(10.0, beta)) / (mus_float_t)size));
-
- rl = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- im = (mus_float_t *)calloc(size, sizeof(mus_float_t));
-
- for (i = 0, angle = 0.0; i < size; i++, angle += freq)
- {
- switch (type)
- {
- case MUS_DOLPH_CHEBYSHEV_WINDOW:
- rl[i] = creal(ccos(cacos(alpha * cos(angle)) * size)); /* here is Tn (Chebyshev polynomial first kind) */
- break;
-
- case MUS_SAMARAKI_WINDOW:
- /* Samaraki window uses Un instead */
- rl[i] = creal(csin(cacos(alpha * cos(angle)) * (size + 1.0)) / csin(cacos(alpha * cos(angle))));
- break;
-
- case MUS_ULTRASPHERICAL_WINDOW:
- /* Cn here */
- rl[i] = ultraspherical(size, alpha * cos(angle), mu);
- break;
-
- default:
- break;
- }
- }
-
- mus_fft(rl, im, size, -1); /* can be 1 here */
-
- pk = 0.0;
- for (i = 0; i < size; i++)
- if (pk < rl[i])
- pk = rl[i];
- if ((pk != 0.0) && (pk != 1.0))
- {
- for (i = 0, j = size / 2; i < size; i++)
- {
- window[i] = rl[j++] / pk;
- if (j == size) j = 0;
- }
- }
- else
- {
- memcpy((void *)window, (void *)rl, size * sizeof(mus_float_t));
- }
-
- free(rl);
- free(im);
- }
- #else
- #if HAVE_GSL
- {
- mus_float_t *rl, *im;
- mus_float_t pk;
- mus_float_t alpha;
-
- freq = M_PI / (mus_float_t)size;
- if (beta < 0.2) beta = 0.2;
- alpha = GSL_REAL(gsl_complex_cosh(
- gsl_complex_mul_real(
- gsl_complex_arccosh_real(pow(10.0, beta)),
- (mus_float_t)(1.0 / (mus_float_t)size))));
-
- rl = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- im = (mus_float_t *)calloc(size, sizeof(mus_float_t));
-
- for (i = 0, angle = 0.0; i < size; i++, angle += freq)
- {
- switch (type)
- {
- case MUS_DOLPH_CHEBYSHEV_WINDOW:
- rl[i] = GSL_REAL(gsl_complex_cos(
- gsl_complex_mul_real(
- gsl_complex_arccos_real(alpha * cos(angle)),
- (mus_float_t)size)));
- break;
-
- case MUS_SAMARAKI_WINDOW:
- rl[i] = GSL_REAL(gsl_complex_div(
- gsl_complex_sin(
- gsl_complex_mul_real(
- gsl_complex_arccos_real(alpha * cos(angle)),
- (mus_float_t)(size + 1.0))),
- gsl_complex_sin(
- gsl_complex_arccos_real(alpha * cos(angle)))));
- break;
-
- case MUS_ULTRASPHERICAL_WINDOW:
- rl[i] = ultraspherical(size, alpha * cos(angle), mu);
- break;
-
- default:
- break;
- }
-
- }
-
- mus_fft(rl, im, size, -1); /* can be 1 here */
-
- pk = 0.0;
- for (i = 0; i < size; i++)
- if (pk < rl[i])
- pk = rl[i];
- if ((pk != 0.0) && (pk != 1.0))
- {
- for (i = 0, j = size / 2; i < size; i++)
- {
- window[i] = rl[j++] / pk;
- if (j == size) j = 0;
- }
- }
- else
- {
- memcpy((void *)window, (void *)rl, size * sizeof(mus_float_t));
- }
- free(rl);
- free(im);
- }
- #else
- mus_error(MUS_NO_SUCH_FFT_WINDOW, S_make_fft_window ": Dolph-Chebyshev, Samaraki, and Ultraspherical windows need complex trig support");
- #endif
- #endif
- break;
-
- default:
- mus_error(MUS_NO_SUCH_FFT_WINDOW, S_make_fft_window ": unknown fft data window: %d", (int)type);
- break;
- }
- return(window);
- }
-
-
- mus_float_t *mus_make_fft_window(mus_fft_window_t type, mus_long_t size, mus_float_t beta)
- {
- return(mus_make_fft_window_with_window(type, size, beta, 0.0, (mus_float_t *)calloc(size, sizeof(mus_float_t))));
- }
-
-
- static const char *fft_window_names[MUS_NUM_FFT_WINDOWS] =
- {"Rectangular", "Hann", "Welch", "Parzen", "Bartlett", "Hamming", "Blackman2", "Blackman3", "Blackman4",
- "Exponential", "Riemann", "Kaiser", "Cauchy", "Poisson", "Gaussian", "Tukey", "Dolph-Chebyshev", "Hann-Poisson", "Connes",
- "Samaraki", "Ultraspherical", "Bartlett-Hann", "Bohman", "Flat-top",
- "Blackman5", "Blackman6", "Blackman7", "Blackman8", "Blackman9", "Blackman10",
- "Rife-Vincent2", "Rife-Vincent3", "Rife-Vincent4", "MLT Sine", "Papoulis", "DPSS (Slepian)", "Sinc"
- };
-
-
- const char *mus_fft_window_name(mus_fft_window_t win)
- {
- if (mus_is_fft_window((int)win))
- return(fft_window_names[(int)win]);
- return("unknown");
- }
-
-
- const char **mus_fft_window_names(void)
- {
- return(fft_window_names);
- }
-
-
- mus_float_t *mus_spectrum(mus_float_t *rdat, mus_float_t *idat, mus_float_t *window, mus_long_t n, mus_spectrum_t type)
- {
- mus_long_t i;
- mus_float_t maxa, lowest;
-
- if (window)
- {
- for (i = 0; i < n; i++)
- rdat[i] *= window[i];
- }
- memset((void *)idat, 0, n * sizeof(mus_float_t));
- mus_fft(rdat, idat, n, 1);
-
- lowest = 0.000001;
- maxa = 0.0;
- n = n / 2;
- for (i = 0; i < n; i++)
- {
- mus_float_t val;
- val = rdat[i] * rdat[i] + idat[i] * idat[i];
- if (val < lowest)
- rdat[i] = 0.001;
- else
- {
- rdat[i] = sqrt(val);
- if (rdat[i] > maxa) maxa = rdat[i];
- }
- }
- if (maxa > 0.0)
- {
- maxa = 1.0 / maxa;
- if (type == MUS_SPECTRUM_IN_DB)
- {
- mus_float_t todb;
- todb = 20.0 / log(10.0);
- for (i = 0; i < n; i++)
- rdat[i] = todb * log(rdat[i] * maxa);
- }
- else
- {
- if (type == MUS_SPECTRUM_NORMALIZED)
- for (i = 0; i < n; i++)
- rdat[i] *= maxa;
- }
- }
- return(rdat);
- }
-
-
- mus_float_t *mus_autocorrelate(mus_float_t *data, mus_long_t n)
- {
- mus_float_t *im;
- mus_float_t fscl;
- mus_long_t i, n2;
-
- n2 = n / 2;
- fscl = 1.0 / (mus_float_t)n;
- im = (mus_float_t *)calloc(n, sizeof(mus_float_t));
-
- mus_fft(data, im, n, 1);
- for (i = 0; i < n; i++)
- data[i] = data[i] * data[i] + im[i] * im[i];
- memset((void *)im, 0, n * sizeof(mus_float_t));
-
- mus_fft(data, im, n, -1);
- for (i = 0; i <= n2; i++)
- data[i] *= fscl;
- for (i = n2 + 1; i < n; i++)
- data[i] = 0.0;
-
- free(im);
- return(data);
- }
-
-
- mus_float_t *mus_correlate(mus_float_t *data1, mus_float_t *data2, mus_long_t n)
- {
- mus_float_t *im1, *im2;
- mus_long_t i;
- mus_float_t fscl;
-
- im1 = (mus_float_t *)calloc(n, sizeof(mus_float_t));
- im2 = (mus_float_t *)calloc(n, sizeof(mus_float_t));
-
- mus_fft(data1, im1, n, 1);
- mus_fft(data2, im2, n, 1);
-
- for (i = 0; i < n; i++)
- {
- mus_float_t tmp1, tmp2, tmp3, tmp4;
- tmp1 = data1[i] * data2[i];
- tmp2 = im1[i] * im2[i];
- tmp3 = data1[i] * im2[i];
- tmp4 = data2[i] * im1[i];
- data1[i] = tmp1 + tmp2;
- im1[i] = tmp3 - tmp4;
- }
-
- mus_fft(data1, im1, n, -1);
- fscl = 1.0 / (mus_float_t)n;
- for (i = 0; i < n; i++)
- data1[i] *= fscl;
-
- free(im1);
- free(im2);
-
- return(data1);
- }
-
-
- mus_float_t *mus_cepstrum(mus_float_t *data, mus_long_t n)
- {
- mus_float_t *rl, *im;
- mus_float_t fscl, lowest;
- mus_long_t i;
-
- lowest = 0.00000001;
- fscl = 2.0 / (mus_float_t)n;
-
- rl = (mus_float_t *)malloc(n * sizeof(mus_float_t));
- im = (mus_float_t *)calloc(n, sizeof(mus_float_t));
- memcpy((void *)rl, (void *)data, n * sizeof(mus_float_t));
-
- mus_fft(rl, im, n, 1);
-
- for (i = 0; i < n; i++)
- {
- rl[i] = rl[i] * rl[i] + im[i] * im[i];
- if (rl[i] < lowest)
- rl[i] = -10.0;
- else rl[i] = log(sqrt(rl[i]));
- }
- memset((void *)im, 0, n * sizeof(mus_float_t));
-
- mus_fft(rl, im, n, -1);
-
- for (i = 0; i < n; i++)
- if (fabs(rl[i]) > fscl)
- fscl = fabs(rl[i]);
-
- if (fscl > 0.0)
- for (i = 0; i < n; i++)
- data[i] = rl[i] / fscl;
-
- free(rl);
- free(im);
- return(data);
- }
-
-
-
- /* ---------------- convolve ---------------- */
-
- mus_float_t *mus_convolution(mus_float_t *rl1, mus_float_t *rl2, mus_long_t n)
- {
- /* convolves two real arrays.
- * rl1 and rl2 are assumed to be set up correctly for the convolution
- * (that is, rl1 (the "signal") is zero-padded by length of
- * (non-zero part of) rl2 and rl2 is stored in wrap-around order)
- * We treat rl2 as the imaginary part of the first fft, then do
- * the split, scaling, and (complex) spectral multiply in one step.
- * result in rl1
- */
-
- mus_long_t j, n2;
- mus_float_t invn;
-
- mus_fft(rl1, rl2, n, 1);
-
- n2 = n >> 1;
- invn = 0.25 / (mus_float_t)n;
- rl1[0] = ((rl1[0] * rl2[0]) / (mus_float_t)n);
- rl2[0] = 0.0;
-
- for (j = 1; j <= n2; j++)
- {
- mus_long_t nn2;
- mus_float_t rem, rep, aim, aip;
-
- nn2 = n - j;
- rep = (rl1[j] + rl1[nn2]);
- rem = (rl1[j] - rl1[nn2]);
- aip = (rl2[j] + rl2[nn2]);
- aim = (rl2[j] - rl2[nn2]);
-
- rl1[j] = invn * (rep * aip + aim * rem);
- rl2[j] = invn * (aim * aip - rep * rem);
- rl1[nn2] = rl1[j];
- rl2[nn2] = -rl2[j];
- }
-
- mus_fft(rl1, rl2, n, -1);
- return(rl1);
- }
-
-
- typedef struct {
- mus_any_class *core;
- mus_float_t (*feeder)(void *arg, int direction);
- mus_float_t (*block_feeder)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- mus_long_t fftsize, fftsize2, ctr, filtersize;
- mus_float_t *rl1, *rl2, *buf, *filter;
- void *closure;
- } conv;
-
-
- static bool convolve_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_convolve(mus_any *ptr)
- {
- conv *gen = (conv *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %lld",
- mus_name(ptr),
- gen->fftsize);
- return(describe_buffer);
- }
-
-
- static void free_convolve(mus_any *ptr)
- {
- conv *gen = (conv *)ptr;
- if (gen->rl1) free(gen->rl1);
- if (gen->rl2) free(gen->rl2);
- if (gen->buf) free(gen->buf);
- free(gen);
- }
-
- static mus_any *conv_copy(mus_any *ptr)
- {
- conv *g, *p;
- int bytes;
-
- p = (conv *)ptr;
- g = (conv *)malloc(sizeof(conv));
- memcpy((void *)g, (void *)ptr, sizeof(conv));
- bytes = g->fftsize * sizeof(mus_float_t);
- g->rl1 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->rl1), (void *)(p->rl1), bytes);
- g->rl2 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->rl2), (void *)(p->rl2), bytes);
- g->buf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->buf), (void *)(p->buf), bytes);
- return((mus_any *)g);
- }
-
-
- static mus_long_t conv_length(mus_any *ptr) {return(((conv *)ptr)->fftsize);}
- static mus_float_t run_convolve(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(mus_convolve(ptr, NULL));}
-
- static void *conv_closure(mus_any *rd) {return(((conv *)rd)->closure);}
- static void *conv_set_closure(mus_any *rd, void *e) {((conv *)rd)->closure = e; return(e);}
-
- static void convolve_reset(mus_any *ptr)
- {
- conv *gen = (conv *)ptr;
- gen->ctr = gen->fftsize2;
- memset((void *)(gen->rl1), 0, gen->fftsize * sizeof(mus_float_t));
- memset((void *)(gen->rl2), 0, gen->fftsize * sizeof(mus_float_t));
- memset((void *)(gen->buf), 0, gen->fftsize * sizeof(mus_float_t));
- }
-
-
- static mus_any_class CONVOLVE_CLASS = {
- MUS_CONVOLVE,
- (char *)S_convolve,
- &free_convolve,
- &describe_convolve,
- &convolve_equalp,
- 0, 0,
- &conv_length,
- 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_convolve,
- MUS_NOT_SPECIAL,
- &conv_closure,
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &convolve_reset,
- &conv_set_closure,
- &conv_copy
- };
-
-
- mus_float_t mus_convolve(mus_any *ptr, mus_float_t (*input)(void *arg, int direction))
- {
- conv *gen = (conv *)ptr;
- mus_float_t result;
- if (gen->ctr >= gen->fftsize2)
- {
- mus_long_t i, N;
- size_t bytes;
-
- N = gen->fftsize2;
- bytes = N * sizeof(mus_float_t);
-
- if (input) {gen->feeder = input; gen->block_feeder = NULL;}
- memset((void *)(gen->rl2), 0, bytes * 2);
- memcpy((void *)(gen->rl2), (void *)(gen->filter), gen->filtersize * sizeof(mus_float_t));
-
- memcpy((void *)(gen->buf), (void *)(gen->buf + N), bytes);
- memset((void *)(gen->buf + N), 0, bytes);
- memset((void *)(gen->rl1 + N), 0, bytes);
-
- if (gen->block_feeder)
- gen->block_feeder(gen->closure, 1, gen->rl1, 0, N);
- else
- {
- for (i = 0; i < N;)
- {
- gen->rl1[i] = gen->feeder(gen->closure, 1); i++;
- gen->rl1[i] = gen->feeder(gen->closure, 1); i++;
- }
- }
-
- mus_convolution(gen->rl1, gen->rl2, gen->fftsize);
-
- for (i = 0; i < N;)
- {
- gen->buf[i] += gen->rl1[i]; i++;
- gen->buf[i] += gen->rl1[i]; i++;
- }
- memcpy((void *)(gen->buf + N), (void *)(gen->rl1 + N), bytes);
- gen->ctr = 0;
- }
- result = gen->buf[gen->ctr];
- gen->ctr++;
- return(result);
- }
-
-
- bool mus_is_convolve(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_CONVOLVE));
- }
-
-
- mus_any *mus_make_convolve(mus_float_t (*input)(void *arg, int direction), mus_float_t *filter, mus_long_t fftsize, mus_long_t filtersize, void *closure)
- {
- conv *gen = NULL;
- gen = (conv *)malloc(sizeof(conv));
- gen->core = &CONVOLVE_CLASS;
- gen->feeder = input;
- gen->block_feeder = NULL;
- gen->closure = closure;
- gen->filter = filter;
- if (filter)
- {
- mus_long_t i;
- bool all_zero = true;
- for (i = 0; i < filtersize; i++)
- if (fabs(filter[i]) != 0.0) /* I'm getting -0.000 != 0.000 */
- {
- all_zero = false;
- break;
- }
- if (all_zero)
- mus_print("make_convolve: filter contains only 0.0.");
- }
- gen->filtersize = filtersize;
- gen->fftsize = fftsize;
- gen->fftsize2 = gen->fftsize / 2;
- gen->ctr = gen->fftsize2;
- gen->rl1 = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- gen->rl2 = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- gen->buf = (mus_float_t *)calloc(fftsize, sizeof(mus_float_t));
- return((mus_any *)gen);
- }
-
-
- void mus_convolve_files(const char *file1, const char *file2, mus_float_t maxamp, const char *output_file)
- {
- mus_long_t file1_len, file2_len, outlen, totallen;
- int file1_chans, file2_chans, output_chans;
- mus_float_t *data1, *data2;
- const char *errmsg = NULL;
- mus_float_t maxval = 0.0;
- mus_long_t i, fftlen;
-
- file1_len = mus_sound_framples(file1);
- file2_len = mus_sound_framples(file2);
- if ((file1_len <= 0) || (file2_len <= 0)) return;
-
- file1_chans = mus_sound_chans(file1);
- if (file1_chans <= 0) mus_error(MUS_NO_CHANNELS, S_convolve_files ": %s chans: %d", file1, file1_chans);
- file2_chans = mus_sound_chans(file2);
- if (file2_chans <= 0) mus_error(MUS_NO_CHANNELS, S_convolve_files ": %s chans: %d", file2, file2_chans);
- output_chans = file1_chans;
- if (file2_chans > output_chans) output_chans = file2_chans;
-
- fftlen = (mus_long_t)(pow(2.0, (int)ceil(log(file1_len + file2_len + 1) / log(2.0))));
- outlen = file1_len + file2_len + 1;
- totallen = outlen * output_chans;
-
- data1 = (mus_float_t *)calloc(fftlen, sizeof(mus_float_t));
- data2 = (mus_float_t *)calloc(fftlen, sizeof(mus_float_t));
-
- if (output_chans == 1)
- {
- mus_float_t *samps;
- samps = (mus_float_t *)calloc(fftlen, sizeof(mus_float_t));
-
- mus_file_to_array(file1, 0, 0, file1_len, samps);
- for (i = 0; i < file1_len; i++) data1[i] = samps[i];
- mus_file_to_array(file2, 0, 0, file2_len, samps);
- for (i = 0; i < file2_len; i++) data2[i] = samps[i];
-
- mus_convolution(data1, data2, fftlen);
-
- for (i = 0; i < outlen; i++)
- if (maxval < fabs(data1[i]))
- maxval = fabs(data1[i]);
-
- if (maxval > 0.0)
- {
- maxval = maxamp / maxval;
- for (i = 0; i < outlen; i++) data1[i] *= maxval;
- }
-
- for (i = 0; i < outlen; i++) samps[i] = data1[i];
- errmsg = mus_array_to_file_with_error(output_file, samps, outlen, mus_sound_srate(file1), 1);
-
- free(samps);
- }
- else
- {
- mus_float_t *samps;
- mus_float_t *outdat = NULL;
- int c1 = 0, c2 = 0, chan;
-
- samps = (mus_float_t *)calloc(totallen, sizeof(mus_float_t));
- outdat = (mus_float_t *)malloc(totallen * sizeof(mus_float_t));
-
- for (chan = 0; chan < output_chans; chan++)
- {
- mus_long_t j, k;
-
- mus_file_to_array(file1, c1, 0, file1_len, samps);
- for (k = 0; k < file1_len; k++) data1[k] = samps[k];
- mus_file_to_array(file2, c2, 0, file2_len, samps);
- for (k = 0; k < file2_len; k++) data2[k] = samps[k];
-
- mus_convolution(data1, data2, fftlen);
-
- for (j = chan, k = 0; j < totallen; j += output_chans, k++) outdat[j] = data1[k];
- c1++;
- if (c1 >= file1_chans) c1 = 0;
- c2++;
- if (c2 >= file2_chans) c2 = 0;
-
- memset((void *)data1, 0, fftlen * sizeof(mus_float_t));
- memset((void *)data2, 0, fftlen * sizeof(mus_float_t));
- }
-
- for (i = 0; i < totallen; i++)
- if (maxval < fabs(outdat[i]))
- maxval = fabs(outdat[i]);
-
- if (maxval > 0.0)
- {
- maxval = maxamp / maxval;
- for (i = 0; i < totallen; i++) outdat[i] *= maxval;
- }
-
- for (i = 0; i < totallen; i++)
- samps[i] = outdat[i];
-
- errmsg = mus_array_to_file_with_error(output_file, samps, totallen, mus_sound_srate(file1), output_chans);
- free(samps);
- free(outdat);
- }
-
- free(data1);
- free(data2);
-
- if (errmsg)
- mus_error(MUS_CANT_OPEN_FILE, S_convolve_files ": %s", errmsg);
- }
-
-
-
- /* ---------------- phase-vocoder ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t pitch;
- mus_float_t (*input)(void *arg, int direction);
- mus_float_t (*block_input)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- void *closure;
- bool (*analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction));
- int (*edit)(void *arg);
- mus_float_t (*synthesize)(void *arg);
- int outctr, interp, filptr, N, D, topN;
- mus_float_t *win, *ampinc, *amps, *freqs, *phases, *phaseinc, *lastphase, *in_data;
-
- mus_float_t sum1;
- bool calc;
- #if HAVE_SINCOS
- double *cs, *sn;
- bool *sc_safe;
- int *indices;
- #endif
- } pv_info;
-
-
- bool mus_is_phase_vocoder(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_PHASE_VOCODER));
- }
-
-
- static bool phase_vocoder_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_phase_vocoder(mus_any *ptr)
- {
- char *arr = NULL;
- pv_info *gen = (pv_info *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s outctr: %d, interp: %d, filptr: %d, N: %d, D: %d, in_data: %s",
- mus_name(ptr),
- gen->outctr, gen->interp, gen->filptr, gen->N, gen->D,
- arr = float_array_to_string(gen->in_data, gen->N, 0));
- if (arr) free(arr);
- return(describe_buffer);
- }
-
-
- static void free_phase_vocoder(mus_any *ptr)
- {
- pv_info *gen = (pv_info *)ptr;
- if (gen->in_data) free(gen->in_data);
- if (gen->amps) free(gen->amps);
- if (gen->freqs) free(gen->freqs);
- if (gen->phases) free(gen->phases);
- if (gen->win) free(gen->win);
- if (gen->phaseinc) free(gen->phaseinc);
- if (gen->lastphase) free(gen->lastphase);
- if (gen->ampinc) free(gen->ampinc);
- #if HAVE_SINCOS
- if (gen->indices) free(gen->indices);
- if (gen->sn) free(gen->sn);
- if (gen->cs) free(gen->cs);
- if (gen->sc_safe) free(gen->sc_safe);
- #endif
- free(gen);
- }
-
-
- static mus_any *pv_info_copy(mus_any *ptr)
- {
- pv_info *g, *p;
- int bytes;
-
- p = (pv_info *)ptr;
- g = (pv_info *)malloc(sizeof(pv_info));
- memcpy((void *)g, (void *)ptr, sizeof(pv_info));
-
- bytes = p->N * sizeof(mus_float_t);
- g->freqs = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->freqs), (void *)(p->freqs), bytes);
- g->ampinc = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->ampinc), (void *)(p->ampinc), bytes);
- g->win = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->win), (void *)(p->win), bytes);
- if (p->in_data)
- {
- g->in_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->in_data), (void *)(p->in_data), bytes);
- }
-
- bytes = (p->N / 2) * sizeof(mus_float_t);
- g->amps = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->amps), (void *)(p->amps), bytes);
- g->phases = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->phases), (void *)(p->phases), bytes);
- g->lastphase = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->lastphase), (void *)(p->lastphase), bytes);
- g->phaseinc = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->phaseinc), (void *)(p->phaseinc), bytes);
-
- #if HAVE_SINCOS
- bytes = (p->N / 2) * sizeof(int);
- g->indices = (int *)malloc(bytes);
- memcpy((void *)(g->indices), (void *)(p->indices), bytes);
-
- bytes = p->N * sizeof(double);
- g->sn = (double *)malloc(bytes);
- memcpy((void *)(g->sn), (void *)(p->sn), bytes);
- g->cs = (double *)malloc(bytes);
- memcpy((void *)(g->cs), (void *)(p->cs), bytes);
-
- bytes = p->N * sizeof(bool);
- g->sc_safe = (bool *)malloc(bytes);
- memcpy((void *)(g->sc_safe), (void *)(p->sc_safe), bytes);
- #endif
-
- return((mus_any *)g);
- }
-
-
- static mus_long_t pv_length(mus_any *ptr) {return(((pv_info *)ptr)->N);}
-
- static mus_long_t pv_hop(mus_any *ptr) {return(((pv_info *)ptr)->D);}
- static mus_long_t pv_set_hop(mus_any *ptr, mus_long_t val) {((pv_info *)ptr)->D = (int)val; return(val);}
-
- static mus_float_t pv_frequency(mus_any *ptr) {return(((pv_info *)ptr)->pitch);}
- static mus_float_t pv_set_frequency(mus_any *ptr, mus_float_t val) {((pv_info *)ptr)->pitch = val; return(val);}
-
- static void *pv_closure(mus_any *rd) {return(((pv_info *)rd)->closure);}
- static void *pv_set_closure(mus_any *rd, void *e) {((pv_info *)rd)->closure = e; return(e);}
-
- mus_float_t *mus_phase_vocoder_amp_increments(mus_any *ptr) {return(((pv_info *)ptr)->ampinc);}
- mus_float_t *mus_phase_vocoder_amps(mus_any *ptr) {return(((pv_info *)ptr)->amps);}
-
- mus_float_t *mus_phase_vocoder_freqs(mus_any *ptr) {return(((pv_info *)ptr)->freqs);}
- mus_float_t *mus_phase_vocoder_phases(mus_any *ptr) {return(((pv_info *)ptr)->phases);}
- mus_float_t *mus_phase_vocoder_phase_increments(mus_any *ptr) {return(((pv_info *)ptr)->phaseinc);}
-
- static mus_long_t pv_outctr(mus_any *ptr) {return((mus_long_t)(((pv_info *)ptr)->outctr));} /* mus_location wrapper */
- static mus_long_t pv_set_outctr(mus_any *ptr, mus_long_t val) {((pv_info *)ptr)->outctr = (int)val; return(val);}
-
- static mus_float_t run_phase_vocoder(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(mus_phase_vocoder(ptr, NULL));}
-
- static mus_float_t pv_increment(mus_any *rd) {return((mus_float_t)(((pv_info *)rd)->interp));}
- static mus_float_t pv_set_increment(mus_any *rd, mus_float_t val) {((pv_info *)rd)->interp = (int)val; return(val);}
-
-
- static void pv_reset(mus_any *ptr)
- {
- pv_info *gen = (pv_info *)ptr;
- if (gen->in_data) free(gen->in_data);
- gen->in_data = NULL;
- gen->outctr = gen->interp;
- gen->filptr = 0;
- memset((void *)(gen->ampinc), 0, gen->N * sizeof(mus_float_t));
- memset((void *)(gen->freqs), 0, gen->N * sizeof(mus_float_t));
- memset((void *)(gen->amps), 0, (gen->N / 2) * sizeof(mus_float_t));
- memset((void *)(gen->phases), 0, (gen->N / 2) * sizeof(mus_float_t));
- memset((void *)(gen->lastphase), 0, (gen->N / 2) * sizeof(mus_float_t));
- memset((void *)(gen->phaseinc), 0, (gen->N / 2) * sizeof(mus_float_t));
- }
-
-
- static mus_any_class PHASE_VOCODER_CLASS = {
- MUS_PHASE_VOCODER,
- (char *)S_phase_vocoder,
- &free_phase_vocoder,
- &describe_phase_vocoder,
- &phase_vocoder_equalp,
- 0, 0,
- &pv_length, 0,
- &pv_frequency,
- &pv_set_frequency,
- 0, 0,
- 0, 0,
- &pv_increment,
- &pv_set_increment,
- &run_phase_vocoder,
- MUS_NOT_SPECIAL,
- &pv_closure,
- 0,
- 0, 0, 0, 0, 0, 0,
- &pv_hop, &pv_set_hop,
- 0, 0,
- 0, 0, 0, 0,
- &pv_outctr, &pv_set_outctr,
- 0, 0, 0, 0, 0,
- &pv_reset,
- &pv_set_closure,
- &pv_info_copy
- };
-
-
- static int pv_last_fftsize = -1;
- static mus_float_t *pv_last_window = NULL;
-
- mus_any *mus_make_phase_vocoder(mus_float_t (*input)(void *arg, int direction),
- int fftsize, int overlap, int interp,
- mus_float_t pitch,
- bool (*analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction)),
- int (*edit)(void *arg),
- mus_float_t (*synthesize)(void *arg),
- void *closure)
- {
- /* order of args is trying to match src, granulate etc
- * the inclusion of pitch and interp provides built-in time/pitch scaling which is 99% of phase-vocoder use
- */
- pv_info *pv;
- int N2, D;
-
- N2 = (int)(fftsize / 2);
- if (N2 == 0) return(NULL);
- D = fftsize / overlap;
- if (D == 0) return(NULL);
-
- pv = (pv_info *)malloc(sizeof(pv_info));
- pv->core = &PHASE_VOCODER_CLASS;
- pv->N = fftsize;
- pv->D = D;
- pv->topN = 0;
- pv->interp = interp;
- pv->outctr = interp;
- pv->filptr = 0;
- pv->pitch = pitch;
- pv->ampinc = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- pv->freqs = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- pv->amps = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->phases = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->lastphase = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->phaseinc = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->in_data = NULL;
- pv->input = input;
- pv->block_input = NULL;
- pv->closure = closure;
- pv->analyze = analyze;
- pv->edit = edit;
- pv->synthesize = synthesize;
- pv->calc = true;
-
- if ((fftsize == pv_last_fftsize) && (pv_last_window))
- {
- pv->win = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- memcpy((void *)(pv->win), (const void *)pv_last_window, fftsize * sizeof(mus_float_t));
- }
- else
- {
- int i;
- mus_float_t scl;
- if (pv_last_window) free(pv_last_window);
- pv_last_fftsize = fftsize;
- pv_last_window = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- pv->win = mus_make_fft_window(MUS_HAMMING_WINDOW, fftsize, 0.0);
- scl = 2.0 / (0.54 * (mus_float_t)fftsize);
- for (i = 0; i < fftsize; i++)
- pv->win[i] *= scl;
- memcpy((void *)pv_last_window, (const void *)(pv->win), fftsize * sizeof(mus_float_t));
- }
-
- #if HAVE_SINCOS
- /* in some cases, sincos is slower than sin+cos? Callgrind is seriously confused by it!
- * in Linux at least, sincos is faster than sin+sin -- in my timing tests, although
- * callgrind is crazy, the actual runtimes are about 25% faster (sincos vs sin+sin).
- */
- pv->cs = (double *)malloc(fftsize * sizeof(double));
- pv->sn = (double *)malloc(fftsize * sizeof(double));
- pv->sc_safe = (bool *)calloc(fftsize, sizeof(bool));
- pv->indices = (int *)malloc(N2 * sizeof(int));
- #endif
- return((mus_any *)pv);
- }
-
-
- mus_float_t mus_phase_vocoder_with_editors(mus_any *ptr,
- mus_float_t (*input)(void *arg, int direction),
- bool (*analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction)),
- int (*edit)(void *arg),
- mus_float_t (*synthesize)(void *arg))
- {
- pv_info *pv = (pv_info *)ptr;
- int N2, i;
- mus_float_t sum, sum1;
- mus_float_t (*pv_synthesize)(void *arg) = synthesize;
-
- if (pv_synthesize == NULL) pv_synthesize = pv->synthesize;
- N2 = pv->N / 2;
-
- if (pv->outctr >= pv->interp)
- {
- mus_float_t scl;
- bool (*pv_analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction)) = analyze;
- int (*pv_edit)(void *arg) = edit;
-
- if (pv_analyze == NULL) pv_analyze = pv->analyze;
- if (pv_edit == NULL) pv_edit = pv->edit;
- if (input) {pv->input = input; pv->block_input = NULL;}
- pv->outctr = 0;
-
- if ((pv_analyze == NULL) ||
- ((*pv_analyze)(pv->closure, pv->input)))
- {
- int buf;
- memset((void *)(pv->freqs), 0, pv->N * sizeof(mus_float_t));
- if (pv->in_data == NULL)
- {
- pv->in_data = (mus_float_t *)malloc(pv->N * sizeof(mus_float_t));
- if (pv->block_input)
- pv->block_input(pv->closure, 1, pv->in_data, 0, pv->N);
- else
- {
- for (i = 0; i < pv->N; i++)
- pv->in_data[i] = pv->input(pv->closure, 1);
- }
- }
- else
- {
- int j;
- /* if back-to-back here we could omit a lot of data movement or just use a circle here! */
- for (i = 0, j = pv->D; j < pv->N; i++, j++)
- pv->in_data[i] = pv->in_data[j];
-
- if (pv->block_input)
- pv->block_input(pv->closure, 1, pv->in_data, pv->N - pv->D, pv->N);
- else
- {
- for (i = pv->N - pv->D; i < pv->N; i++)
- pv->in_data[i] = pv->input(pv->closure, 1);
- }
- }
- buf = pv->filptr % pv->N;
- for (i = 0; i < pv->N; i++)
- {
- pv->ampinc[buf++] = pv->win[i] * pv->in_data[i];
- if (buf >= pv->N) buf = 0;
- }
- pv->filptr += pv->D;
- mus_fft(pv->ampinc, pv->freqs, pv->N, 1);
- mus_rectangular_to_polar(pv->ampinc, pv->freqs, N2);
- }
-
- if ((pv_edit == NULL) ||
- ((*pv_edit)(pv->closure)))
- {
- mus_float_t pscl, kscl, ks;
- pscl = 1.0 / (mus_float_t)(pv->D);
- kscl = TWO_PI / (mus_float_t)(pv->N);
- for (i = 0, ks = 0.0; i < N2; i++, ks += kscl)
- {
- mus_float_t diff;
- diff = pv->freqs[i] - pv->lastphase[i];
- pv->lastphase[i] = pv->freqs[i];
- while (diff > M_PI) diff -= TWO_PI;
- while (diff < -M_PI) diff += TWO_PI;
- pv->freqs[i] = pv->pitch * (diff * pscl + ks);
- }
- }
- /* it's possible to build the endpoint waveforms here and interpolate, but there is no savings.
- * other pvocs use ifft rather than sin-bank, but then they have to make excuses.
- * Something I didn't expect -- the algorithm above focusses on the active frequency!
- * For example, the 4 or so bins around a given peak all tighten
- * to 4 bins running at almost exactly the same frequency (the center).
- */
-
- scl = 1.0 / (mus_float_t)(pv->interp);
- #if HAVE_SINCOS
- pv->topN = 0;
- #else
- pv->topN = N2;
- #endif
-
- for (i = 0; i < N2; i++)
- {
- #if HAVE_SINCOS
- double s, c;
- bool amp_zero;
-
- amp_zero = ((pv->amps[i] < 1e-7) && (pv->ampinc[i] == 0.0));
- if (!amp_zero)
- {
- pv->indices[pv->topN++] = i;
-
- pv->sc_safe[i] = (fabs(pv->freqs[i] - pv->phaseinc[i]) < 0.02); /* .5 is too big, .01 and .03 ok by tests */
- if (pv->sc_safe[i])
- {
- sincos((pv->freqs[i] + pv->phaseinc[i]) * 0.5, &s, &c);
- pv->sn[i] = s;
- pv->cs[i] = c;
- }
- }
-
- if ((!(pv->synthesize)) && (amp_zero))
- {
- pv->phases[i] += (pv->interp * (pv->freqs[i] + pv->phaseinc[i]) * 0.5);
- pv->phaseinc[i] = pv->freqs[i];
- }
- else
- {
- pv->ampinc[i] = scl * (pv->ampinc[i] - pv->amps[i]);
- pv->freqs[i] = scl * (pv->freqs[i] - pv->phaseinc[i]);
- }
- #else
- pv->ampinc[i] = scl * (pv->ampinc[i] - pv->amps[i]);
- pv->freqs[i] = scl * (pv->freqs[i] - pv->phaseinc[i]);
- #endif
- }
- }
-
- pv->outctr++;
- if (pv_synthesize)
- return((*pv_synthesize)(pv->closure));
-
- if (pv->calc)
- {
- mus_float_t *pinc, *frq, *ph, *amp, *panc;
- int topN;
- #if HAVE_SINCOS
- int j;
- double *cs, *sn;
- #endif
-
- topN = pv->topN;
- pinc = pv->phaseinc;
- frq = pv->freqs;
- ph = pv->phases;
- amp = pv->amps;
- panc = pv->ampinc;
- #if HAVE_SINCOS
- cs = pv->cs;
- sn = pv->sn;
- #endif
-
- sum = 0.0;
- sum1 = 0.0;
-
- /* amps can be negative here due to rounding troubles
- * sincos is faster (using shell time command) except in virtualbox running linux on a mac?
- * (callgrind does not handle sincos correctly).
- *
- * this version (22-Jan-14) is slower if no sincos;
- * if sincos, we use sin(a + b) = sin(a)cos(b) + cos(a)sin(b)
- * since sin(b) and cos(b) are constant through the pv->interp (implicit) loop, they are calculated once above.
- * Then here we calculate 2 samples on each run through this loop. I wonder if we could center the true case,
- * and get 3 samples? If 2, the difference is very small (we're taking the midpoint of the phase increment change,
- * so the two are not quite the same). In tests, 10000 samples, channel-distance is ca .15.
- *
- * If the amp zero phase is off (incorrectly incremented above), the effect is a sort of low-pass filter??
- * Are we getting cancellation from the overlap?
- */
-
- #if HAVE_SINCOS
- for (j = 0; j < topN; j++)
- {
- double sx, cx;
-
- i = pv->indices[j];
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- sincos(ph[i], &sx, &cx);
- sum += (amp[i] * sx);
-
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- if (pv->sc_safe[i])
- sum1 += amp[i] * (sx * cs[i] + cx * sn[i]);
- else sum1 += amp[i] * sin(ph[i]);
- }
- #else
- for (i = 0; i < topN; i++)
- {
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- if (amp[i] > 0.0) sum += amp[i] * sin(ph[i]);
-
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- if (amp[i] > 0.0) sum1 += amp[i] * sin(ph[i]);
- }
- #endif
- pv->sum1 = sum1;
- pv->calc = false;
- return(sum);
- }
- pv->calc = true;
- return(pv->sum1);
- }
-
-
- mus_float_t mus_phase_vocoder(mus_any *ptr, mus_float_t (*input)(void *arg, int direction))
- {
- return(mus_phase_vocoder_with_editors(ptr, input, NULL, NULL, NULL));
- }
-
-
- void mus_generator_set_feeders(mus_any *g,
- mus_float_t (*feed)(void *arg, int direction),
- mus_float_t (*block_feed)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end))
- {
- if (mus_is_src(g))
- {
- ((sr *)g)->feeder = feed;
- ((sr *)g)->block_feeder = block_feed;
- }
- else
- {
- if (mus_is_granulate(g))
- {
- ((grn_info *)g)->rd = feed;
- ((grn_info *)g)->block_rd = block_feed;
- }
- else
- {
- if (mus_is_phase_vocoder(g))
- {
- ((pv_info *)g)->input = feed;
- ((pv_info *)g)->block_input = block_feed;
- }
- else
- {
- if (mus_is_convolve(g))
- {
- ((conv *)g)->feeder = feed;
- ((conv *)g)->block_feeder = block_feed;
- }
- }
- }
- }
- }
-
- void mus_generator_copy_feeders(mus_any *dest, mus_any *source)
- {
- if (mus_is_src(dest))
- {
- ((sr *)dest)->feeder = ((sr *)source)->feeder;
- ((sr *)dest)->block_feeder = ((sr *)source)->block_feeder;
- }
- else
- {
- if (mus_is_granulate(dest))
- {
- ((grn_info *)dest)->rd = ((grn_info *)source)->rd;
- ((grn_info *)dest)->block_rd = ((grn_info *)source)->block_rd;
- }
- else
- {
- if (mus_is_phase_vocoder(dest))
- {
- ((pv_info *)dest)->input = ((pv_info *)source)->input;
- ((pv_info *)dest)->block_input = ((pv_info *)source)->block_input;
- }
- else
- {
- if (mus_is_convolve(dest))
- {
- ((conv *)dest)->feeder = ((conv *)source)->feeder;
- ((conv *)dest)->block_feeder = ((conv *)source)->block_feeder;
- }
- }
- }
- }
- }
-
-
-
- /* ---------------- single sideband "suppressed carrier" amplitude modulation (ssb-am) ---------------- */
-
- typedef struct {
- mus_any_class *core;
- bool shift_up;
- mus_float_t *coeffs;
- mus_any *hilbert, *dly;
- #if (!HAVE_SINCOS)
- mus_any *sin_osc, *cos_osc;
- #else
- double phase, freq, sign;
- #endif
- int size;
- } ssbam;
-
-
- bool mus_is_ssb_am(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SSB_AM));
- }
-
- static mus_float_t run_hilbert(flt *gen, mus_float_t input)
- {
- mus_float_t xout = 0.0;
- mus_float_t *state, *ts, *x, *end;
-
- x = (mus_float_t *)(gen->x);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order);
-
- (*state) = input;
- (*ts) = input;
- state += 2;
- end = (mus_float_t *)(state + 20);
-
- while (ts > end)
- {
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- }
- while (ts > state)
- {
- xout += (*ts) * (*x); ts -= 2; x += 2;
- }
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- #if 0
- int i, len;
- mus_float_t val = 0.0;
- len = g->order;
- g->state[0] = insig;
- for (i = 0; i < len; i += 2) val += (g->x[i] * g->state[i]);
- for (i = len - 1; i >= 1; i--) g->state[i] = g->state[i - 1];
- return(val);
- #endif
- }
-
-
- mus_float_t mus_ssb_am_unmodulated(mus_any *ptr, mus_float_t insig)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- return((mus_oscil_unmodulated(gen->cos_osc) * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (mus_oscil_unmodulated(gen->sin_osc) * run_hilbert((flt *)(gen->hilbert), insig)));
- #else
- double cx, sx;
- sincos(gen->phase, &sx, &cx);
- gen->phase += gen->freq;
- return((cx * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (sx * gen->sign * run_hilbert((flt *)(gen->hilbert), insig)));
- #endif
- }
-
-
- mus_float_t mus_ssb_am(mus_any *ptr, mus_float_t insig, mus_float_t fm)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- return((mus_oscil_fm(gen->cos_osc, fm) * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (mus_oscil_fm(gen->sin_osc, fm) * run_hilbert((flt *)(gen->hilbert), insig)));
- #else
- double cx, sx;
- sincos(gen->phase, &sx, &cx);
- gen->phase += (fm + gen->freq);
- return((cx * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (sx * gen->sign * run_hilbert((flt *)(gen->hilbert), insig)));
- #endif
- }
-
-
- static void free_ssb_am(mus_any *ptr)
- {
- ssbam *gen = (ssbam *)ptr;
- mus_free(gen->dly);
- mus_free(gen->hilbert);
- #if (!HAVE_SINCOS)
- mus_free(gen->cos_osc);
- mus_free(gen->sin_osc);
- #endif
- if (gen->coeffs) {free(gen->coeffs); gen->coeffs = NULL;}
- free(ptr);
- }
-
-
- static mus_any *ssbam_copy(mus_any *ptr)
- {
- ssbam *g, *p;
- int bytes;
-
- p = (ssbam *)ptr;
- g = (ssbam *)malloc(sizeof(ssbam));
- memcpy((void *)g, (void *)ptr, sizeof(ssbam));
-
- g->dly = mus_copy(p->dly);
- g->hilbert = mus_copy(p->hilbert);
- #if (!HAVE_SINCOS)
- g->cos_osc = mus_copy(p->cos_osc);
- g->sin_osc = mus_copy(p->sin_osc);
- #endif
-
- bytes = p->size * sizeof(mus_float_t);
- g->coeffs = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->coeffs), (void *)(p->coeffs), bytes);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t ssb_am_freq(mus_any *ptr)
- {
- #if (!HAVE_SINCOS)
- return(mus_radians_to_hz(((osc *)((ssbam *)ptr)->sin_osc)->freq));
- #else
- return(mus_radians_to_hz(((ssbam *)ptr)->freq));
- #endif
- }
-
-
- static mus_float_t ssb_am_set_freq(mus_any *ptr, mus_float_t val)
- {
- ssbam *gen = (ssbam *)ptr;
- mus_float_t rads;
- rads = mus_hz_to_radians(val);
- #if (!HAVE_SINCOS)
- ((osc *)(gen->sin_osc))->freq = rads;
- ((osc *)(gen->cos_osc))->freq = rads;
- #else
- gen->freq = rads;
- #endif
- return(val);
- }
-
-
- static mus_float_t ssb_am_increment(mus_any *ptr)
- {
- #if (!HAVE_SINCOS)
- return(((osc *)((ssbam *)ptr)->sin_osc)->freq);
- #else
- return(((ssbam *)ptr)->freq);
- #endif
- }
-
-
- static mus_float_t ssb_am_set_increment(mus_any *ptr, mus_float_t val)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- ((osc *)(gen->sin_osc))->freq = val;
- ((osc *)(gen->cos_osc))->freq = val;
- #else
- gen->freq = val;
- #endif
- return(val);
- }
-
-
- static mus_float_t ssb_am_phase(mus_any *ptr)
- {
- #if (!HAVE_SINCOS)
- return(fmod(((osc *)((ssbam *)ptr)->cos_osc)->phase - 0.5 * M_PI, TWO_PI));
- #else
- return(fmod(((ssbam *)ptr)->phase, TWO_PI));
- #endif
- }
-
-
- static mus_float_t ssb_am_set_phase(mus_any *ptr, mus_float_t val)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- if (gen->shift_up)
- ((osc *)(gen->sin_osc))->phase = val + M_PI;
- else ((osc *)(gen->sin_osc))->phase = val;
- ((osc *)(gen->cos_osc))->phase = val + 0.5 * M_PI;
- #else
- gen->phase = val;
- #endif
- return(val);
- }
-
-
- static mus_long_t ssb_am_order(mus_any *ptr) {return(mus_order(((ssbam *)ptr)->dly));}
-
- static int ssb_am_interp_type(mus_any *ptr) {return(delay_interp_type(((ssbam *)ptr)->dly));}
-
- static mus_float_t *ssb_am_data(mus_any *ptr) {return(filter_data(((ssbam *)ptr)->hilbert));}
- static mus_float_t ssb_am_run(mus_any *ptr, mus_float_t insig, mus_float_t fm) {return(mus_ssb_am(ptr, insig, fm));}
-
- static mus_float_t *ssb_am_xcoeffs(mus_any *ptr) {return(mus_xcoeffs(((ssbam *)ptr)->hilbert));}
- static mus_float_t ssb_am_xcoeff(mus_any *ptr, int index) {return(mus_xcoeff(((ssbam *)ptr)->hilbert, index));}
- static mus_float_t ssb_am_set_xcoeff(mus_any *ptr, int index, mus_float_t val) {return(mus_set_xcoeff(((ssbam *)ptr)->hilbert, index, val));}
-
-
- static bool ssb_am_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_ssb_am((mus_any *)p1)) &&
- (mus_is_ssb_am((mus_any *)p2)) &&
- (((ssbam *)p1)->shift_up == ((ssbam *)p2)->shift_up) &&
- #if (!HAVE_SINCOS)
- (mus_equalp(((ssbam *)p1)->sin_osc, ((ssbam *)p2)->sin_osc)) &&
- (mus_equalp(((ssbam *)p1)->cos_osc, ((ssbam *)p2)->cos_osc)) &&
- #else
- (((ssbam *)p1)->freq == ((ssbam *)p2)->freq) &&
- (((ssbam *)p1)->phase == ((ssbam *)p2)->phase) &&
- #endif
- (mus_equalp(((ssbam *)p1)->dly, ((ssbam *)p2)->dly)) &&
- (mus_equalp(((ssbam *)p1)->hilbert, ((ssbam *)p2)->hilbert))));
- }
-
-
- static char *describe_ssb_am(mus_any *ptr)
- {
- ssbam *gen = (ssbam *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s shift: %s, sin/cos: %f Hz (%f radians), order: %d",
- mus_name(ptr),
- (gen->shift_up) ? "up" : "down",
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_order(ptr));
- return(describe_buffer);
- }
-
-
- static void ssb_reset(mus_any *ptr)
- {
- ssbam *gen = (ssbam *)ptr;
- ssb_am_set_phase(ptr, 0.0);
- mus_reset(gen->dly);
- mus_reset(gen->hilbert);
- }
-
-
- static mus_any_class SSB_AM_CLASS = {
- MUS_SSB_AM,
- (char *)S_ssb_am,
- &free_ssb_am,
- &describe_ssb_am,
- &ssb_am_equalp,
- &ssb_am_data, 0,
- &ssb_am_order, 0,
- &ssb_am_freq,
- &ssb_am_set_freq,
- &ssb_am_phase,
- &ssb_am_set_phase,
- &fallback_scaler, 0,
- &ssb_am_increment,
- &ssb_am_set_increment,
- &ssb_am_run,
- MUS_NOT_SPECIAL,
- NULL,
- &ssb_am_interp_type,
- 0, 0, 0, 0,
- &ssb_am_xcoeff, &ssb_am_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &ssb_am_xcoeffs, 0,
- &ssb_reset,
- 0, &ssbam_copy
- };
-
-
- static int ssb_am_last_flen = -1;
- static mus_float_t *ssb_am_last_coeffs = NULL;
-
- mus_any *mus_make_ssb_am(mus_float_t freq, int order)
- {
- ssbam *gen;
- int len, flen;
-
- if ((order & 1) == 0) order++; /* if order is even, the first Hilbert coeff is 0.0 */
- gen = (ssbam *)malloc(sizeof(ssbam));
- gen->core = &SSB_AM_CLASS;
-
- if (freq > 0)
- gen->shift_up = true;
- else gen->shift_up = false;
- #if (!HAVE_SINCOS)
- gen->sin_osc = mus_make_oscil(fabs(freq), (gen->shift_up) ? M_PI : 0.0);
- gen->cos_osc = mus_make_oscil(fabs(freq), M_PI * 0.5);
- #else
- if (gen->shift_up) gen->sign = -1.0; else gen->sign = 1.0;
- gen->freq = mus_hz_to_radians(fabs(freq));
- gen->phase = 0.0;
- #endif
- gen->dly = mus_make_delay(order, NULL, order, MUS_INTERP_NONE);
-
- len = order * 2 + 1;
- flen = len + 1; /* even -- need 4 */
- if ((flen & 2) != 0) flen += 2;
- gen->size = flen;
-
- if ((flen == ssb_am_last_flen) && (ssb_am_last_coeffs))
- {
- gen->coeffs = (mus_float_t *)malloc(flen * sizeof(mus_float_t));
- memcpy((void *)(gen->coeffs), (const void *)ssb_am_last_coeffs, flen * sizeof(mus_float_t));
- }
- else
- {
- int i, k;
- gen->coeffs = (mus_float_t *)calloc(flen, sizeof(mus_float_t));
- for (i = -order, k = 0; i <= order; i++, k++)
- {
- mus_float_t denom, num;
- denom = i * M_PI;
- num = 1.0 - cos(denom);
- if (i == 0)
- gen->coeffs[k] = 0.0;
- else gen->coeffs[k] = (num / denom) * (0.54 + (0.46 * cos(denom / order)));
- }
- /* so odd numbered coeffs are zero */
-
- /* can't be too fancy here because there might be several of these gens running in parallel at different sizes */
- if (ssb_am_last_coeffs) free(ssb_am_last_coeffs);
- ssb_am_last_flen = flen;
- ssb_am_last_coeffs = (mus_float_t *)malloc(flen * sizeof(mus_float_t));
- memcpy((void *)(ssb_am_last_coeffs), (const void *)(gen->coeffs), flen * sizeof(mus_float_t));
- }
-
- gen->hilbert = mus_make_fir_filter(flen, gen->coeffs, NULL);
- return((mus_any *)gen);
- }
-
- /* (define (hi) (let ((g (make-ssb-am 100.0))) (ssb-am g 1.0) (ssb-am g 0.0))) */
-
-
-
-
-
- /* ---------------- mus-apply ---------------- */
-
- mus_float_t (*mus_run_function(mus_any *g))(mus_any *gen, mus_float_t arg1, mus_float_t arg2)
- {
- if (g)
- return(g->core->run);
- return(NULL);
- }
-
- mus_float_t mus_apply(mus_any *gen, mus_float_t f1, mus_float_t f2)
- {
- /* what about non-gen funcs such as polynomial, ring_modulate etc? */
- if ((gen) && (gen->core->run))
- return((*(gen->core->run))(gen, f1, f2));
- return(0.0);
- }
-
-
- /* ---------------- mix files ---------------- */
-
- /* a mixing "instrument" along the lines of the mix function in clm */
- /* this is a very commonly used function, so it's worth picking out the special cases for optimization */
-
- #define IDENTITY_MIX 0
- #define IDENTITY_MONO_MIX 1
- #define SCALED_MONO_MIX 2
- #define SCALED_MIX 3
- #define ENVELOPED_MONO_MIX 4
- #define ENVELOPED_MIX 5
- #define ALL_MIX 6
-
- static int mix_file_type(int out_chans, int in_chans, mus_float_t *mx, mus_any ***envs)
- {
- if (envs)
- {
- if ((in_chans == 1) && (out_chans == 1))
- {
- if (envs[0][0])
- return(ENVELOPED_MONO_MIX);
- return(SCALED_MONO_MIX);
- }
- else
- {
- if (mx)
- return(ALL_MIX);
- return(ENVELOPED_MIX);
- }
- }
- if (mx)
- {
- int i, j;
- if ((in_chans == 1) && (out_chans == 1))
- {
- if (mx[0] == 1.0)
- return(IDENTITY_MONO_MIX);
- return(SCALED_MONO_MIX);
- }
- for (i = 0; i < out_chans; i++)
- for (j = 0; j < in_chans; j++)
- if (((i == j) && (mx[i * in_chans + j] != 1.0)) ||
- ((i != j) && (mx[i * in_chans + j] != 0.0)))
- return(SCALED_MIX);
- }
- if ((in_chans == 1) && (out_chans == 1))
- return(IDENTITY_MONO_MIX);
- return(IDENTITY_MIX);
- }
-
-
- void mus_file_mix_with_reader_and_writer(mus_any *outf, mus_any *inf,
- mus_long_t out_start, mus_long_t out_framples, mus_long_t in_start,
- mus_float_t *mx, int mx_chans,
- mus_any ***envs)
- {
- int mixtype, in_chans, out_chans;
- mus_long_t inc, outc, out_end;
- mus_float_t *out_data, *in_data, *local_mx;
-
- out_chans = mus_channels(outf);
- if (out_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", mus_describe(outf), out_chans);
-
- in_chans = mus_channels(inf);
- if (in_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", mus_describe(inf), in_chans);
-
- out_end = out_start + out_framples;
- mixtype = mix_file_type(out_chans, in_chans, mx, envs);
-
- in_data = (mus_float_t *)calloc((in_chans < out_chans) ? out_chans : in_chans, sizeof(mus_float_t));
- out_data = (mus_float_t *)calloc((in_chans < out_chans) ? out_chans : in_chans, sizeof(mus_float_t));
-
- local_mx = mx;
-
- switch (mixtype)
- {
- case ENVELOPED_MONO_MIX:
- {
- mus_any *e;
- e = envs[0][0];
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- mus_file_to_frample(inf, inc, in_data);
- mus_outa_to_file(outf, outc, in_data[0] * mus_env(e));
- }
- }
- break;
-
- case ENVELOPED_MIX:
- if (mx == NULL)
- {
- int i;
- mx_chans = (in_chans < out_chans) ? out_chans : in_chans;
- local_mx = (mus_float_t *)calloc(mx_chans * mx_chans, sizeof(mus_float_t));
- for (i = 0; i < mx_chans; i++)
- local_mx[i * mx_chans + i] = 1.0;
- }
- /* fall through */
-
- case ALL_MIX:
- /* the general case -- possible envs/scalers on every mixer cell */
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- int j, k;
- for (j = 0; j < in_chans; j++)
- for (k = 0; k < out_chans; k++)
- if (envs[j][k])
- local_mx[j * mx_chans + k] = mus_env(envs[j][k]);
- mus_frample_to_file(outf, outc, mus_frample_to_frample(local_mx, mx_chans, mus_file_to_frample(inf, inc, in_data), in_chans, out_data, out_chans));
- }
- if (mx == NULL) free(local_mx);
- break;
-
- case IDENTITY_MONO_MIX:
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- mus_file_to_frample(inf, inc, in_data);
- mus_outa_to_file(outf, outc, in_data[0]);
- }
- break;
-
- case IDENTITY_MIX:
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- mus_frample_to_file(outf, outc, mus_file_to_frample(inf, inc, in_data));
- break;
-
- case SCALED_MONO_MIX:
- {
- mus_float_t scl;
- scl = mx[0];
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- mus_file_to_frample(inf, inc, in_data);
- mus_outa_to_file(outf, outc, scl * in_data[0]);
- }
- }
- break;
-
- case SCALED_MIX:
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- mus_frample_to_file(outf, outc, mus_frample_to_frample(mx, mx_chans, mus_file_to_frample(inf, inc, in_data), in_chans, out_data, out_chans));
- break;
-
- }
- free(in_data);
- free(out_data);
- }
-
-
- void mus_file_mix(const char *outfile, const char *infile,
- mus_long_t out_start, mus_long_t out_framples, mus_long_t in_start,
- mus_float_t *mx, int mx_chans,
- mus_any ***envs)
- {
- int in_chans, out_chans, min_chans, mixtype;
-
- out_chans = mus_sound_chans(outfile);
- if (out_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", outfile, out_chans);
-
- in_chans = mus_sound_chans(infile);
- if (in_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", infile, in_chans);
- if (out_chans > in_chans)
- min_chans = in_chans;
- else min_chans = out_chans;
-
- mixtype = mix_file_type(out_chans, in_chans, mx, envs);
- if (mixtype == ALL_MIX)
- {
- mus_any *inf, *outf;
- /* the general case -- possible envs/scalers on every mixer cell */
- outf = mus_continue_sample_to_file(outfile);
- inf = mus_make_file_to_frample(infile);
- mus_file_mix_with_reader_and_writer(outf, inf, out_start, out_framples, in_start, mx, mx_chans, envs);
- mus_free(inf);
- mus_free(outf);
- }
- else
- {
- mus_long_t j = 0;
- int i, m, ofd, ifd;
- mus_float_t scaler;
- mus_any *e;
- mus_float_t **obufs, **ibufs;
- mus_long_t offk, curoutframples;
-
- /* highly optimizable cases */
- obufs = (mus_float_t **)malloc(out_chans * sizeof(mus_float_t *));
- for (i = 0; i < out_chans; i++)
- obufs[i] = (mus_float_t *)malloc(clm_file_buffer_size * sizeof(mus_float_t));
-
- ibufs = (mus_float_t **)malloc(in_chans * sizeof(mus_float_t *));
- for (i = 0; i < in_chans; i++)
- ibufs[i] = (mus_float_t *)malloc(clm_file_buffer_size * sizeof(mus_float_t));
-
- ifd = mus_sound_open_input(infile);
- mus_file_seek_frample(ifd, in_start);
- mus_file_read(ifd, in_start, clm_file_buffer_size, in_chans, ibufs);
- ofd = mus_sound_reopen_output(outfile,
- out_chans,
- mus_sound_sample_type(outfile),
- mus_sound_header_type(outfile),
- mus_sound_data_location(outfile));
- curoutframples = mus_sound_framples(outfile);
- mus_file_seek_frample(ofd, out_start);
- mus_file_read(ofd, out_start, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start);
-
- switch (mixtype)
- {
- case IDENTITY_MONO_MIX:
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- obufs[0][j] += ibufs[0][j];
- }
- break;
-
- case IDENTITY_MIX:
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- for (i = 0; i < min_chans; i++)
- obufs[i][j] += ibufs[i][j];
- }
- break;
-
- case SCALED_MONO_MIX:
- scaler = mx[0];
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- obufs[0][j] += (mus_float_t)(scaler * ibufs[0][j]);
- }
- break;
-
- case SCALED_MIX:
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size , out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- for (i = 0; i < min_chans; i++)
- for (m = 0; m < in_chans; m++)
- obufs[i][j] += (mus_float_t)(ibufs[m][j] * mx[m * mx_chans + i]);
- }
- break;
-
- case ENVELOPED_MONO_MIX:
- e = envs[0][0];
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- obufs[0][j] += (mus_float_t)(mus_env(e) * ibufs[0][j]);
- }
- break;
-
- case ENVELOPED_MIX:
- e = envs[0][0];
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- scaler = mus_env(e);
- for (i = 0; i < min_chans; i++)
- obufs[i][j] += (mus_float_t)(scaler * ibufs[i][j]);
- }
- break;
- }
-
- if (j > 0)
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- if (curoutframples < (out_framples + out_start))
- curoutframples = out_framples + out_start;
- mus_sound_close_output(ofd, curoutframples * out_chans * mus_bytes_per_sample(mus_sound_sample_type(outfile)));
- mus_sound_close_input(ifd);
- for (i = 0; i < in_chans; i++) free(ibufs[i]);
- free(ibufs);
- for (i = 0; i < out_chans; i++) free(obufs[i]);
- free(obufs);
- }
- }
-
-
-
- /* ---------------- init clm ---------------- */
-
- void mus_initialize(void)
- {
- #define MULAW_ZERO 255
- #define ALAW_ZERO 213
- #define UBYTE_ZERO 128
-
- mus_generator_type = MUS_INITIAL_GEN_TAG;
- sampling_rate = MUS_DEFAULT_SAMPLING_RATE;
- w_rate = (TWO_PI / MUS_DEFAULT_SAMPLING_RATE);
- array_print_length = MUS_DEFAULT_ARRAY_PRINT_LENGTH;
- clm_file_buffer_size = MUS_DEFAULT_FILE_BUFFER_SIZE;
-
- #if HAVE_FFTW3 && HAVE_COMPLEX_TRIG
- last_c_fft_size = 0;
- /* is there a problem if the caller built fftw with --enable-threads?
- * How to tell via configure that we need to initialize the thread stuff in libfftw?
- */
- #endif
-
- sincs = 0;
- locsig_warned = NULL;
-
- sample_type_zero = (int *)calloc(MUS_NUM_SAMPLES, sizeof(int));
- sample_type_zero[MUS_MULAW] = MULAW_ZERO;
- sample_type_zero[MUS_ALAW] = ALAW_ZERO;
- sample_type_zero[MUS_UBYTE] = UBYTE_ZERO;
- #if MUS_LITTLE_ENDIAN
- sample_type_zero[MUS_UBSHORT] = 0x80;
- sample_type_zero[MUS_ULSHORT] = 0x8000;
- #else
- sample_type_zero[MUS_UBSHORT] = 0x8000;
- sample_type_zero[MUS_ULSHORT] = 0x80;
- #endif
- }
|