home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * July 14, 1998
- * Copyright 1998 K. Bradley, Carnegie Mellon University
- *
- * This source code is freely redistributable and may be used for
- * any purpose. This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
- */
-
- /*
- * Sound Tools rate change effect file.
- */
-
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #ifdef HAVE_MALLOC_H
- #include <malloc.h>
- #endif
- #include "st.h"
-
- typedef struct _list {
- int number;
- float *data_buffer;
- struct _list *next;
- } List;
-
- typedef struct polyphase {
-
- unsigned long lcmrate; /* least common multiple of rates */
- unsigned long inskip, outskip; /* LCM increments for I & O rates */
- unsigned long total;
- unsigned long intot, outtot; /* total samples in terms of LCM rate */
- long lastsamp;
-
- float **filt_array;
- float **past_hist;
- float *input_buffer;
- int *filt_len;
-
- List *l1, *l2;
-
- } *poly_t;
-
- /*
- * Process options
- */
-
- /* Options:
-
- -w <nut / ham> : window type
- -width <short / long> : window width
- short = 128 samples
- long = 1024 samples
- <num> num: explicit number
-
- -cutoff <float> : frequency cutoff for base bandwidth.
- Default = 0.95 = 95%
- */
-
- static int win_type = 0;
- static int win_width = 1024;
- static float cutoff = 0.95;
-
- void poly_getopts(effp, n, argv)
- eff_t effp;
- int n;
- char **argv;
- {
- /* 0: nuttall
- 1: hamming */
- win_type = 0;
-
- /* width: short = 128
- long = 1024 (default) */
- win_width = 1024;
-
- /* cutoff: frequency cutoff of base bandwidth in percentage. */
- cutoff = 0.95;
-
- while(n >= 2) {
-
- /* Window type check */
- if(!strcmp(argv[0], "-w")) {
- if(!strcmp(argv[1], "ham"))
- win_type = 1;
- if(!strcmp(argv[1], "nut"))
- win_type = 0;
-
- argv += 2;
- n -= 2;
- continue;
- }
-
- /* Window width check */
- if(!strcmp(argv[0], "-width")) {
- if(!strcmp(argv[1], "short"))
- win_width = 128;
- else if(!strcmp(argv[1], "long"))
- win_width = 1024;
- else
- win_width = atoi(argv[1]);
-
- argv += 2;
- n -= 2;
- continue;
- }
-
- /* Cutoff frequency check */
- if(!strcmp(argv[0], "-cutoff")) {
- cutoff = atof(argv[1]);
- argv += 2;
- n -= 2;
- continue;
- }
-
- fail("Polyphase: unknown argument (%s %s)!", argv[0], argv[1]);
- }
- }
-
- /*
- * Prepare processing.
- */
-
- static int primes[] = {
- 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
- 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
- 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
- 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
- 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
- 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
- 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
- 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
- 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593,
- 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
- 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
- 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827,
- 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
- 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
- };
-
- #ifndef max
- #define max(x,y) ((x > y) ? x : y)
- #endif
-
- List *prime(number)
- int number;
- {
- int j;
- List *element = NULL;
-
- if(number == 1)
- return NULL;
-
- for(j=167;j>= 0;j--) {
- if(number % primes[j] == 0) {
- element = (List *) malloc(sizeof(List));
- element->number = primes[j];
- element->data_buffer = NULL;
- element->next = prime(number / primes[j]);
- break;
- }
- }
-
- if(element == NULL) {
- fail("Number %d too large of a prime.\n",number);
- }
-
- return element;
- }
-
- List *prime_inv(number)
- int number;
- {
- int j;
- List *element = NULL;
-
- if(number == 1)
- return NULL;
-
- for(j=0;j<168;j++) {
- if(number % primes[j] == 0) {
- element = (List *) malloc(sizeof(List));
- element->number = primes[j];
- element->data_buffer = NULL;
- element->next = prime_inv(number / primes[j]);
- break;
- }
- }
-
- if(element == NULL) {
- fail("Number %d too large of a prime.\n",number);
- }
-
- return element;
- }
-
- #ifndef PI
- #define PI 3.14159265358979
- #endif
-
- /* Calculate a Nuttall window of a given length.
- Buffer must already be allocated to appropriate size.
- */
-
- void nuttall(buffer, length)
- float *buffer;
- int length;
- {
- int j;
- double N;
- double N1;
-
- if(buffer == NULL || length < 0)
- fail("Illegal buffer %p or length %d to nuttall.\n", buffer, length);
-
- /* Initial variable setups. */
- N = (double) length - 1.0;
- N1 = N / 2.0;
-
- for(j = 0; j < length; j++) {
- buffer[j] = 0.36335819 +
- 0.4891775 * cos(2*PI*1*(j - N1) / N) +
- 0.1365995 * cos(2*PI*2*(j - N1) / N) +
- 0.0106411 * cos(2*PI*3*(j - N1) / N);
- }
- }
- /* Calculate a Hamming window of given length.
- Buffer must already be allocated to appropriate size.
- */
-
- void hamming(buffer, length)
- float *buffer;
- int length;
- {
- int j;
-
- if(buffer == NULL || length < 0)
- fail("Illegal buffer %p or length %d to hamming.\n",buffer,length);
-
- for(j=0;j<length;j++)
- buffer[j] = 0.5 - 0.46 * cos(2*PI*j/(length-1));
- }
-
- /* Calculate the sinc function properly */
-
- float sinc(value)
- float value;
- {
- return(fabs(value) < 1E-50 ? 1.0 : sin(value) / value);
- }
-
- /* Design a low-pass FIR filter using window technique.
- Length of filter is in length, cutoff frequency in cutoff.
- 0 < cutoff <= 1.0 (normalized frequency)
-
- buffer must already be allocated.
- */
- void fir_design(buffer, length, cutoff)
- float *buffer;
- int length;
- float cutoff;
- {
- int j;
- float sum;
- float *ham_win;
-
- if(buffer == NULL || length < 0 || cutoff < 0 || cutoff > PI)
- fail("Illegal buffer %p, length %d, or cutoff %f.\n",buffer,length,cutoff);
-
- /* Design Hamming window: 43 dB cutoff */
- ham_win = (float *)malloc(sizeof(float) * length);
-
- /* Use the user-option of window type */
- if(win_type == 0)
- nuttall(ham_win, length);
- else
- hamming(ham_win,length);
-
- /* Design filter: windowed sinc function */
- sum = 0.0;
- for(j=0;j<length;j++) {
- buffer[j] = sinc(PI*cutoff*(j-length/2)) * ham_win[j] / (2*cutoff);
- sum += buffer[j];
- }
-
- /* Normalize buffer to have gain of 1.0: prevent roundoff error */
- for(j=0;j<length;j++)
- buffer[j] /= sum;
-
- free((void *) ham_win);
- }
-
-
- void poly_start(effp)
- eff_t effp;
- {
- poly_t rate = (poly_t) effp->priv;
- List *t, *t2;
- int num_l1, num_l2;
- int j,k;
- float f_cutoff;
-
- extern long lcm();
-
- rate->lcmrate = lcm((long)effp->ininfo.rate, (long)effp->outinfo.rate);
-
- /* Cursory check for LCM overflow.
- * If both rate are below 65k, there should be no problem.
- * 16 bits x 16 bits = 32 bits, which we can handle.
- */
-
- rate->inskip = rate->lcmrate / effp->ininfo.rate;
- rate->outskip = rate->lcmrate / effp->outinfo.rate;
-
- /* Find the prime factors of inskip and outskip */
- rate->l1 = prime(rate->inskip);
-
- /* If we're going up, order things backwards. */
- if(effp->ininfo.rate < effp->outinfo.rate)
- rate->l2 = prime_inv(rate->outskip);
- else
- rate->l2 = prime(rate->outskip);
-
- /* Find how many factors there were */
- if(rate->l1 == NULL)
- num_l1 = 0;
- else
- for(num_l1=0, t = rate->l1; t != NULL; num_l1++, t=t->next);
-
- if(rate->l2 == NULL)
- num_l2 = 0;
- else
- for(num_l2=0, t = rate->l2; t != NULL; num_l2++, t=t->next);
-
- k = 0;
- t = rate->l1;
-
- /* Compact the lists to be less than 10 */
- while(k < num_l1 - 1) {
- if(t->number * t->next->number < 10) {
- t->number = t->number * t->next->number;
- t2 = t->next;
- t->next = t->next->next;
- t2->next = NULL;
- free((void *) t2);
- num_l1--;
- } else {
- k++;
- t = t->next;
- }
- }
-
- k = 0;
- t = rate->l2;
-
- while(k < num_l2 - 1) {
- if(t->number * t->next->number < 10) {
- t->number = t->number * t->next->number;
- t2 = t->next;
- t->next = t->next->next;
- t2->next = NULL;
- free((void *) t2);
- num_l2--;
- } else {
- k++;
- t = t->next;
- }
- }
-
- /* l1 and l2 are now lists of the prime factors compacted,
- meaning that they're the lists of up/down sampling we need
- */
-
- /* Stretch them to be the same length by padding with 1 (no-op) */
- if(num_l1 < num_l2) {
- t = rate->l1;
-
- if(t == NULL) {
- rate->l1 = (List *)malloc(sizeof(List));
- rate->l1->next = NULL;
- rate->l1->number = 1;
- rate->l1->data_buffer = NULL;
- t = rate->l1;
- num_l1++;
- }
-
- while(t->next != NULL)
- t = t->next;
-
- for(k=0;k<num_l2-num_l1;k++) {
- t->next = (List *) malloc(sizeof(List));
- t->next->number = 1;
- t->next->data_buffer = NULL;
- t = t->next;
- }
-
- t->next = NULL;
- num_l1 = num_l2;
- } else {
- t = rate->l2;
-
- if(t == NULL) {
- rate->l2 = (List *)malloc(sizeof(List));
- rate->l2->next = NULL;
- rate->l2->number = 1;
- rate->l2->data_buffer = NULL;
- t = rate->l2;
- num_l2++;
- }
-
- /*
- while(t->next != NULL)
- t = t->next;
- */
-
- for(k=0;k<num_l1-num_l2;k++) {
- t = rate->l2;
- rate->l2 = (List *) malloc(sizeof(List));
- rate->l2->number = 1;
- rate->l2->data_buffer = NULL;
- rate->l2->next = t;
- }
-
- /* t->next = NULL; */
- num_l2 = num_l1;
- }
-
- /* l1 and l2 are now the same size. */
- rate->total = num_l1;
-
- report("Poly: input rate %d, output rate %d. %d stages.",effp->ininfo.rate, effp->outinfo.rate,num_l1);
- report("Poly: window: %s size: %d cutoff: %f.", (win_type == 0) ? ("nut") : ("ham"), win_width, cutoff);
-
- for(k=0, t=rate->l1, t2=rate->l2;k<num_l1;k++,t=t->next,t2=t2->next)
- report("Poly: stage %d: Up by %d, down by %d.",k+1,t->number,t2->number);
-
- /* We'll have an array of filters and past history */
- rate->filt_array = (float **) malloc(sizeof(float *) * num_l1);
- rate->past_hist = (float **) malloc(sizeof(float *) * num_l1);
- rate->filt_len = (int *) malloc(sizeof(int) * num_l1);
-
- for(k = 0, t = rate->l1, t2 = rate->l2; k < num_l1; k++) {
-
- rate->filt_len[k] = max(2 * 10 * max(t->number,t2->number), win_width);
- rate->filt_array[k] = (float *) malloc(sizeof(float) * rate->filt_len[k]);
- rate->past_hist[k] = (float *) malloc(sizeof(float) * rate->filt_len[k]);
-
- t->data_buffer = (float *) malloc(sizeof(float) * 1024 * rate->inskip);
-
- for(j = 0; j < rate->filt_len[k]; j++)
- rate->past_hist[k][j] = 0.0;
-
- f_cutoff = (t->number > t2->number) ?
- (float) t->number : (float) t2->number;
-
- fir_design(rate->filt_array[k], rate->filt_len[k]-1, cutoff / f_cutoff);
-
- t = t->next;
- t2 = t2->next;
- }
-
- rate->input_buffer = (float *) malloc(sizeof(float) * 2048);
- }
-
- /*
- * Processed signed long samples from ibuf to obuf.
- * Return number of samples processed.
- */
-
- static float *h;
- static int M, L, N;
-
- void polyphase_init(coef, num_coef, up_rate, down_rate)
- float *coef;
- int num_coef;
- int up_rate;
- int down_rate;
- {
- h = coef;
- M = down_rate;
- L = up_rate;
- N = num_coef;
- }
-
- void polyphase(input, output, past, num_samples_input)
- float *input;
- float *output;
- float *past;
- int num_samples_input;
- {
- int num_output;
- int m,n;
- float sum;
- float inp;
- int base;
- int h_base;
-
- num_output = num_samples_input * L / M;
-
- for(m=0;m<num_output;m++) {
- sum = 0.0;
- base = (int) (m*M/L);
- h_base = (m*M) % L;
-
- for(n=0;n<N / L;n++) {
- if(base - n < 0)
- inp = past[base - n + N];
- else
- inp = input[base - n];
-
- sum += h[n*L + h_base] * inp;
- }
-
- output[m] = sum * L * 0.95;
- }
- }
-
- void poly_flow(effp, ibuf, obuf, isamp, osamp)
- eff_t effp;
- long *ibuf, *obuf;
- int *isamp, *osamp;
- {
- poly_t rate = (poly_t) effp->priv;
- float *temp_buf, *temp_buf2;
- int j,k;
- List *t1, *t2;
- int in_size, out_size;
-
- /* Sanity check: how much can we tolerate? */
- in_size = *isamp;
- out_size = in_size * rate->inskip / rate->outskip;
- if(out_size > *osamp) {
- in_size = *osamp * rate->outskip / rate->inskip;
- *isamp = in_size;
- }
-
- /* Check to see if we're really draining */
- if(ibuf != NULL) {
- for(k=0;k<*isamp;k++)
- rate->input_buffer[k] = (float) (ibuf[k] >> 16);
- } else {
- for(k=0;k<*isamp;k++)
- rate->input_buffer[k] = 0.0;
- }
-
- temp_buf = rate->input_buffer;
-
- t1 = rate->l1;
- t2 = rate->l2;
-
- for(k=0;k<rate->total;k++,t1=t1->next,t2=t2->next) {
-
- polyphase_init(rate->filt_array[k], rate->filt_len[k],
- t1->number,t2->number);
-
- out_size = (in_size) * t1->number / t2->number;
-
- temp_buf2 = t1->data_buffer;
-
- polyphase(temp_buf, temp_buf2, rate->past_hist[k], in_size);
-
- for(j = 0; j < rate->filt_len[k]; j++)
- rate->past_hist[k][j] = temp_buf[j+in_size - rate->filt_len[k]];
-
- in_size = out_size;
-
- temp_buf = temp_buf2;
- }
-
- if(out_size > *osamp)
- out_size = *osamp;
-
- *osamp = out_size;
-
- if(ibuf != NULL) {
- for(k=0;k < out_size;k++)
- obuf[k] = ((int) temp_buf[k]) << 16;
- } else {
-
- /* Wait for all-zero samples to come through.
- Should happen eventually with all-zero
- input */
- int found = 0;
-
- for(k=0; k < out_size; k++) {
- obuf[k] = ((int) temp_buf[k] << 16);
- if(obuf[k] != 0)
- found = 1;
- }
- if(!found)
- *osamp = 0;
- }
- }
-
- /*
- * Process tail of input samples.
- */
- void poly_drain(effp, obuf, osamp)
- eff_t effp;
- long *obuf;
- long *osamp;
- {
- long in_size = 1024;
-
- /* Call "flow" with NULL input. */
- poly_flow(effp, NULL, obuf, &in_size, osamp);
- }
-
- /*
- * Do anything required when you stop reading samples.
- * Don't close input file!
- */
- void poly_stop(effp)
- eff_t effp;
- {
- List *t, *t2;
- poly_t rate = (poly_t) effp->priv;
- int k;
-
- /* Free lists */
- for(t = rate->l1; t != NULL; ) {
- t2 = t->next;
- t->next = NULL;
- if(t->data_buffer != NULL)
- free((void *) t->data_buffer);
- free((void *) t);
- t = t2;
- }
-
- for(t = rate->l2; t != NULL; ) {
- t2 = t->next;
- t->next = NULL;
- if(t->data_buffer != NULL)
- free((void *) t->data_buffer);
- free((void *) t);
- t = t2;
- }
-
- for(k = 0; k < rate->total;k++) {
- free((void *) rate->past_hist[k]);
- free((void *) rate->filt_array[k]);
- }
-
- free((void *) rate->past_hist);
- free((void *) rate->filt_array);
- free((void *) rate->filt_len);
- }
-
-