[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Octal-dev] soxechos.c - SoX echos.c converted to Octal
From: |
Neil Nelson |
Subject: |
[Octal-dev] soxechos.c - SoX echos.c converted to Octal |
Date: |
Wed, 28 Jun 2000 17:57:33 -0700 |
Although the name soxechos.c is similar to soxecho.c just released,
this program has a decaying reverberation effect; whereas soxecho.c
provided only 1 echo for each of the 7 echo parameter pairs used.
Neil Nelson
/* SOXECHOS.C
*
* This code has been adapted from the SoX echos.c code:
*
* August 24, 1998
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Juergen Mueller And Sundry Contributors are not responsible for
* the consequences of using this software.
*
* Conversion to Octal made by:
*
* Copyright 2000 Neil Nelson <address@hidden> June 28, 2000.
*
* This software is distributed under the terms of the
* GNU General Public License (GPL). Read the included file
* COPYING for more information.
*
*
* From SoX:
* Echos effect for dsp.
*
* Flow diagram scheme for n delays ( 1 <= n <= MAX_ECHOS ):
*
* * gain-in ___
* ibuff --+--------------------------------------------------->| |
* | * decay 1 | |
* | +----------------------------------->| |
* | | * decay 2 | + |
* | | +--------------------->| |
* | | | * decay n | |
* | _________ | _________ | _________ +--->|___|
* | | | | | | | | | | |
* +-->| delay 1 |-+-| delay 2 |-+...-| delay n |--+ | * gain-out
* |_________| |_________| |_________| |
* +----->obuff
*
* Usage:
* echos gain-in gain-out decay-1 delay-1 [decay-2 delay-2 ... decay-n delay-n
]
*
* Where:
* gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume
* gain-out : 0.0 ... volume
* delay-1 ... delay-n : > 0.0 msec
*
* Note:
* when decay is close to 1.0, the samples can begin clipping and the output
* can saturate!
*
* Hint:
* 1 / out-gain > gain-in ( 1 + decay-1 + ... + decay-n )
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "util.h"
#include "machine.h"
#define DYN_RANGE 10
#define MAX_ECHOS 7
#define MAX_DELAY 750 // msec
/* The parameters are: gain_in, gain_out, decay, delay, ... 6 more times */
enum {
ix_gain_in, ix_gain_out,
ix_sxedecay, ix_sxedelay,
ix_sxedecay_1, ix_sxedelay_1,
ix_sxedecay_2, ix_sxedelay_2,
ix_sxedecay_3, ix_sxedelay_3,
ix_sxedecay_4, ix_sxedelay_4,
ix_sxedecay_5, ix_sxedelay_5,
ix_sxedecay_6, ix_sxedelay_6
} param_index;
param_spec sxe_params[] = {
/* Param 1: gain_in. */
{
small,
slider,
"Gain In",
"Gain In",
0, /* 0 gain */
255, /* No attenuation */
200 /* Approx. 200/255 of dynamic range */
},
/* Param 2: gain_out. */
{
small,
slider,
"Gain Out",
"Gain Out",
0, /* 0 gain */
255, /* No attenuation */
200 /* Approx. 200/255 of dynamic range */
},
/* Param 3: sxedecay[0]. */
{
small,
slider,
"Decay 0",
"Decay of Delay 0.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 4: sxedelay[0]. */
{
small,
slider,
"Delay 0",
"Delay 0 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
255 /* 255/255 of MAX_DELAY msec */
},
/* Param 5: sxedecay[1]. */
{
small,
slider,
"Decay 1",
"Decay of Delay 1.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 6: sxedelay[1]. */
{
small,
slider,
"Delay 1",
"Delay 1 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
210 /* 210/255 of MAX_DELAY msec */
},
/* Param 7: sxedecay[2]. */
{
small,
slider,
"Decay 2",
"Decay of Delay 2.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 8: sxedelay[2]. */
{
small,
slider,
"Delay 2",
"Delay 2 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
170 /* 170/255 of MAX_DELAY msec */
},
/* Param 9: sxedecay[3]. */
{
small,
slider,
"Decay 3",
"Decay of Delay 3.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 10: sxedelay[3]. */
{
small,
slider,
"Delay 3",
"Delay 3 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
125 /* 125/255 of MAX_DELAY msec */
},
/* Param 11: sxedecay[4]. */
{
small,
slider,
"Decay 4",
"Decay of Delay 4.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 12: sxedelay[4]. */
{
small,
slider,
"Delay 4",
"Delay 4 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
90 /* 90/255 of MAX_DELAY msec */
},
/* Param 13: sxedecay[5]. */
{
small,
slider,
"Decay 5",
"Decay of Delay 5.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 14: sxedelay[5]. */
{
small,
slider,
"Delay 5",
"Delay 5 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
30 /* 30/255 of MAX_DELAY msec */
},
/* Param 15: sxedecay[6]. */
{
small,
slider,
"Decay 6",
"Decay of Delay 6.",
0,
255, /* 1 */
100 /* Approx. 100/255 of dynamic range */
},
/* Param 16: sxedelay[6]. */
{
small,
slider,
"Delay 6",
"Delay 6 time: 0 to maximum.",
0, /* 0 msec. delay */
255, /* Highest delay of range */
5 /* 5/255 of MAX_DELAY msec */
},
};
/* State of the soxechos */
typedef struct {
float in_gain, out_gain;
float sxedecay[MAX_ECHOS];
float sxedelay[MAX_ECHOS];
long sxesamples[MAX_ECHOS];
long echo_cntr[MAX_ECHOS];
long echo_ptr[MAX_ECHOS];
samp* echo_buf;
long maxanysamples;
int num_delays;
double unit_vol_scale;
double exp_fract_vol;
} sxe_state;
int ox_init(machine_type *t) {
t->long_name = "soxechos (Mueller, Nelson, et al.)";
t->short_name = "soxechos";
t->max_tracks = 1;
t->input_channels = 1;
t->output_channels = 1;
t->num_params = 15;
t->param_specs = sxe_params;
return 1;
}
void ox_create(machine *m) {
sxe_state *s;
int i;
long echo_band_samples;
// long j;
s = (sxe_state*) malloc(sizeof(sxe_state));
m->state = (void *) s;
s->num_delays = MAX_ECHOS;
s->unit_vol_scale = exp((double)DYN_RANGE / 3.0) - 1.0;
s->exp_fract_vol = ((double)DYN_RANGE / 3) / 255.0;
/* Set defaults */
s->in_gain = ((float)exp(200.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->out_gain = ((float)exp(200.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedecay[0] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[0] = 255.0/255.0 * (float)MAX_DELAY;
s->sxedecay[1] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[1] = 210.0/255.0 * (float)MAX_DELAY;
s->sxedecay[2] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[2] = 170.0/255.0 * (float)MAX_DELAY;
s->sxedecay[3] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[3] = 125.0/255.0 * (float)MAX_DELAY;
s->sxedecay[4] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[4] = 90.0/255.0 * (float)MAX_DELAY;
s->sxedecay[5] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[5] = 30.0/255.0 * (float)MAX_DELAY;
s->sxedecay[6] = ((float)exp(100.0 * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
s->sxedelay[6] = 5.0/255.0 * (float)MAX_DELAY;
echo_band_samples = (long)((float)MAX_DELAY * (float)OX_SAMPLING_RATE /
1000.0) + 1;
for(i = 0; i < s->num_delays; i++) {
s->sxesamples[i] = (long)(s->sxedelay[i] * ((float)OX_SAMPLING_RATE) /
1000.0
+ 0.5);
s->echo_cntr[i] = 0;
s->echo_ptr[i] = echo_band_samples * i;
}
s->maxanysamples = (long)((float)echo_band_samples * (float)MAX_ECHOS *
(float)OX_SAMPLING_RATE / 1000.0) + 1;
s->echo_buf = (samp*) malloc(s->maxanysamples * sizeof(samp));
// memset(s->echo_buf, 0, s->maxanysamples * sizeof(samp)); // Unnecessary
// for(j = 0; j < s->maxanysamples; j++) { // Speed this up.
// s->echo_buf[j] = 0.0;
// }
return;
}
void ox_destroy(machine *m) {
free( ((sxe_state*)(m->state)) -> echo_buf);
free(m->state);
m->state = NULL;
return;
}
void ox_update(machine *m) {
sxe_state *s = (sxe_state *) m->state;
param temp;
int i;
temp = m->params[0][ix_gain_in];
if (temp != nochange) {
if (temp < 0) temp = 0;
else if (temp > 255) temp = 255;
s->in_gain = ((float)exp((double)temp * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
}
temp = m->params[0][ix_gain_out];
if (temp != nochange) {
if (temp < 0) temp = 0;
else if (temp > 255) temp = 255;
s->out_gain = ((float)exp((double)temp * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
}
for(i = 0; i < s->num_delays; i++) {
temp = m->params[0][ix_sxedecay + i * 2];
if (temp != nochange) {
if (temp < 0) temp = 0;
else if (temp > 255) temp = 255;
s->sxedecay[i] = ((float)exp((double)temp * s->exp_fract_vol) - 1.0)
/ s->unit_vol_scale;
}
temp = m->params[0][ix_sxedelay + i * 2];
if (temp != nochange) {
if (temp < 1) temp = 0;
else if (temp > 255) temp = 255;
s->sxedelay[i] = (float)temp/255.0 * (float)MAX_DELAY;
s->sxesamples[i] = (long)(s->sxedelay[i] * ((float)OX_SAMPLING_RATE)
/ 1000.0 + 0.5);
s->echo_cntr[i] %= s->sxesamples[i];
}
}
return;
}
const char *ox_desc(int which_param, param value) {
static char temp_string[80];
float user_value;
int i, percent;
sprintf(temp_string, "ERROR");
if (which_param == ix_gain_in || which_param == ix_gain_out) {
if (value < 0) sprintf(temp_string, "Gain must not be less than 0.");
else {
user_value = ((float)value) / 255.0;
percent = (int)(user_value * 100.0 + 0.5);
if (user_value > 1.0)
sprintf(temp_string, "Gain must be not greater than 100%.");
else sprintf(temp_string, "%3.0f%%", percent);
}
}
else {
for(i = 0; i < MAX_ECHOS; i++) {
if (which_param == (ix_sxedecay + i * 2)) {
if (value < 0) sprintf(temp_string, "%s%d%s", "Decay ", i,
" must not be less than 0. 0 removes this delay");
else {
user_value = (float)value / 255.0;
percent = (int)(user_value * 100.0 + 0.5);
if (user_value > 1.0)
sprintf(temp_string, "%s%d%s", "Decay ", i,
"must be not greater than 100%.");
else sprintf(temp_string, "%3.0f%%", percent);
}
}
else if (which_param == (ix_sxedelay + i * 2)) {
if (value < 0) sprintf(temp_string, "%s%d%s", "Delay ", i,
" must not be less than 0.");
else {
user_value = (float)value / 255.0 * (float)MAX_DELAY;
if (user_value > (float)MAX_DELAY)
sprintf(temp_string, "%s%d%s%d%s", "Delay ", i,
" must be not greater than ", MAX_DELAY, " msec.");
else sprintf(temp_string, "%3.0f", user_value);
}
}
}
}
}
int ox_work(machine *m, int block_size) {
sxe_state *s = (sxe_state *) m->state;
samp *mlout, *mlin, *echobuf;
// samp *mrout;
int j;
long i, numdlys;
long *sxsmpls, *echoptr, *echoctr;
float ingain, outgain;
float *sxdecy;
/* Speed-up variables */
mlout = m->lout;
// mrout = m->rout;
mlin = m->lin;
ingain = s->in_gain;
outgain = s->out_gain;
echobuf = s->echo_buf;
echoctr = (long*)s->echo_cntr;
echoptr = (long*)s->echo_ptr;
sxsmpls = (long*)s->sxesamples;
sxdecy = (float*)s->sxedecay;
numdlys = s->num_delays;
for(i = 0; i < block_size; i++) {
/* Compute output first */
mlout[i] = mlin[i] * ingain;
/* Add echoes */
for ( j = 0; j < numdlys; j++ ) {
if (sxdecy[j])
mlout[i] += echobuf[echoptr[j] + echoctr[j]] * sxdecy[j];
}
/* Adjust the output volume */
mlout[i] *= outgain;
/* Mix decay of delays and input */
for ( j = 0; j < numdlys; j++ ) {
if ( j == 0 )
echobuf[echoctr[j] + echoptr[j]] = mlin[i];
else
echobuf[echoctr[j] + echoptr[j]] = echobuf[echoctr[j-1] +
echoptr[j-1]]
+ mlin[i];
}
/* Adjust the counters */
for ( j = 0; j < numdlys; j++ )
echoctr[j] = ( echoctr[j] + 1 ) % sxsmpls[j];
}
return 1;
}
void ox_track(machine *m, int change) {
}
- [Octal-dev] soxechos.c - SoX echos.c converted to Octal,
Neil Nelson <=