📄 rotating_speaker.asm
字号:
/*** ROTATING_SPEAKER.ASM ***********************************************************
* *
* AD1819A/ADSP-21065L EZLAB Rotating Speaker Emulation Effect Program *
* Developed using ADSP-21065L EZ-LAB Evaluation Platform *
* *
* I/O Equation: y(n) = [x(n)*sin(2*pi*fc*t)] convolve [ x(n-d(n)) ] *
* *
* *
* ^ ^ *
* sin(2*PI*fc*t) / / *
* | _________/_____ ___/____ *
* | | | | | *
* v | Z^(-D) | | LPF | *
* x(n) -------->O------------>| |-------| H(z) |---> y(n) *
* X | d(n) | | | *
* | | |_______| *
* |_______________| / Variable *
* / Rotating Tap / Cutoff *
* / Center Freq *
* / *
* *
* *
* *
* What the rotating speaker effect does? *
* ------------------------------------- *
* A popular effect used on keyboards and Hammond organs. This effect *
* consists of a combination of the tremolo and vibrato effects, combined *
* a low-pass filter with a variable cutoff frequency. This combination *
* simulates what was done by audio engineers who would actually produce *
* this effect by rotating a speaker cabinet. The resulting sound heard *
* by the ears is a cyclical increase/decrease in volume, a doppler effect *
* from the speaker rotating, and a cyclical drop in high frequencies *
* whenever the speaker is facing away from the listener. *
* *
* NOTE: This first revision only contains the vibrato and tremolo. The *
* variable LPF will be added in a later revision. *
* *
* The signal source is using the MIC inputs *
* The audio data is sent out to the AD1819A Line Outputs *
* *
* *
* John Tomarakos *
* ADI DSP Applications Group *
* Revision 1.0 *
* 11/18/98 *
* *
*****************************************************************************************/
/* ADSP-21065L System Register bit definitions */
#include "def21065l.h"
#include "new65Ldefs.h"
.EXTERN Left_Channel_In;
.EXTERN Right_Channel_In;
.EXTERN Left_Channel_Out;
.EXTERN Right_Channel_Out;
.GLOBAL Init_Tremolo_Vibrato_Buffers;
.GLOBAL Rotating_Speaker_Effect;
.GLOBAL change_speaker_rotate_rate;
.GLOBAL select_tremolo_effect;
.segment /dm rotspeak;
#define WaveTableSize 4000 /* sinusoidal wavetable, 1 period in table of 4000 sine wave elements */
#define D 2000 /* Depth, or TD = D/fs = 1000/48000 = 20.83 msec */
/* increasing depth size D increases pitch variation */
#define Depth D /* Depth is equivalent to time delay of a signal, or delay-line size */
#define D2 Depth/2 /* D/2, used for addig & subtracting delay from tap center */
.var IRQ1_counter = 0x00000003;
.var IRQ2_counter = 0x00000000;
.var wavetbl_counter = 0x00000000;
.var Effect_Ctrl = 0x00000001; /* memory flag that determines which tremolo routine executes */
.var pitch_bend = -6; /* Enter # from -1 to -15. Do not enter 0.*/
/* -1 to -5 - large pitch bend*/
/* -6 to -10 - medium pitch bend */
/* -11 to -15 - small pitch bend */
.var sin_inc = 2; /* wavetable signal frequency ftable = sin_inc * fs = ? Hz */
.var modulation_rate = 3; /* controls how fast the wavetable is updated in the SPORT1 rx ISR */
.var sine_value; /* used for tremolo control */
.var excursion_value; /* used for vibrato delay offset calculation */
.var sine[WaveTableSize] = "sinetbl.dat"; /* min frequency f1 = ftimer/4000 */
.var w[D + 1]; /* delay-line buffer, max delay = D */
.endseg;
.segment /pm pm_code;
/*----------------------------------------------------------------------------------*/
Init_Tremolo_Vibrato_Buffers:
B2 = w; L2 = @w; /* delay-line buffer pointer and length */
m2 = 1;
LCNTR = L2; /* clear delay line buffer to zero */
DO clrDline UNTIL LCE;
clrDline: dm(i2, m2) = 0;
B6 = sine; /* pointer for signal generator */
L6 = @sine; /* get size of sine table lookup */
RTS;
/* ////////////////////////////////////////////////////////////////////////////////////////////// *
* *
* VIBRATO AND TREMOLO ROUTINES *
* *
* ////////////////////////////////////////////////////////////////////////////////////////////// */
Rotating_Speaker_Effect:
r1 = DM(Left_Channel_In);
r1 = ashift r1 by -1;
r2 = DM(Right_Channel_In);
r2 = ashift r2 by -1;
r3 = r2 + r1;
/* generate sine value from wavetable generator if necessary, where r4 = sin(2*pi*fc*t) */
test_wavtbl_update:
/* update sine value from lookup table? Update every 80 SPORT rx interrupts */
/* sweep frequency = 80 * c * 4000 / fs = 96000 /48k = .15 sec */
r11 = DM(modulation_rate); /* count up to 80 interrupts */
r10 = DM(wavetbl_counter); /* get last count from memory */
r10 = r10 + 1; /* increment preset */
comp (r10, r11); /* compare current count to max count */
if ge r10 = r10 - r10; /* if count equals max, reset to zero and start over */
DM(wavetbl_counter) = r10; /* save updated count */
r12 = pass r10; /* test for wave count 0? */
if eq jump update_wavetbl_ptr;
/* if you are here, reuse same sine value for now.. dm(sine_value) remains unchanged */
jump do_vibrato;
/* if necessary, calculate updated pointer to wavetable */
update_wavetbl_ptr:
m6 = dm(sin_inc); /* desired increment sin_inc - frequency f = sin_inc x fs / D */
r7 = dm(i6, m6); /* get next value from sine lookup table */
dm(sine_value) = r7; /* use for tremolo_effect amplitude scaling factor */
r4 = dm(pitch_bend); /* controls scaling of center tap delay offset */
r7 = ashift r7 by r4; /* divide by at least 2 to keep #s between 0.5 and -0.5 */
r6 = D; /* Total Delay Time D = amplitude of sine wave lookup */
r8 = r6 * r7 (SSFR); /* delay multiplication factor */
dm(excursion_value) = r8; /* save to current sine value to be reused above */
do_vibrato:
r2 = dm(excursion_value); /* get previous or newly updated scaled sine value */
r1 = D2; /* get nominal tap center delay */
r4 = r1 + r2; /* r4 = d(n) = D/2 + D * sin(fc*t) */
/* r4 now will be used to set m2 register to fetch time varying delayed sample */
m2 = r4; /* set tap valud for output of circular delay line */
modify(i2, m2); /* go to delayed sample address */
r4 = -r4; /* negate to get back to where we were */
m2 = r4; /* set up to go back to current location after memory access */
r10 = dm(i2, m2); /* get delayed sample */
/* write vibrato output sample to r0 for tremolo routine */
r0 = r10;
/* put input sample from r2 into tap-0 of delay lines */
/* and backshift pointer & update circular delay-line buffer*/
dm(i2, -1) = r3;
which_tremolo_routine:
r4 = DM(Effect_Ctrl);
r4 = pass r4;
if eq jump mono_tremolo_effect; /* if == 1, execute mono tremolo routine */
/* otherwise, execute stereo tremolo routine */
stereo_tremolo_effect:
/* get generated sine value from wavetable generator, where r4 = sin(2*pi*fc*t) */
r4 = dm(sine_value);
r5 = r0 * r4 (SSFR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -