/* ************************************************************************************************** * MONOSTEREO_DELAY.ASM * * * * Slapback ('Doubling') Effect (also called Mono Automatic Double Tracking) * * One popular use of the digital delay is to quickly repeat the input signal with a single * * reflection at unity gain. By making the delay an input signal around 15-40 milliseconds, * * the resulting output produces a "slapback/doubling " effect. The slight differences in the * * delay create the effect of the two parts being played in unison. The effect is created by * * adding a delayed signal together with the original, where a single input source is mixed with * * the delay, and the result is sent to both output channels. With short delays, slapback can * * thicken the sound of an instrument or voice when mixed for a mono result, although * * cancellations can occur from comb filtering side effects when the delay is under 10 ms, * * which will result in a hollow, resonant sound. Longer slapback delay effects were commonly * * used in the 1950's/1960's music industry. * * * * * * Mono ADT I/O Equation and Structure: * * y(n) = x(n) - ax(n - D) * * yLeft(n) = yRight(n) = y(n) * * * * x(n) ------------------------------------------|>------>O--------> y(n) * * | 1/2 ^ * * | | * * | _______________ | * * | | | | * * | | | | * * |-------------->| Z^(-D) |------|>--------| * * | | 1/2 * * |_______________| * * * * * * Stereo Automatic Double Tracking (Stereo Doubling) - "Concert Announcer Simulation" * * Automatic Double Tracking, which is used by audio engineers in the music industry to create * * a sense of spaciousness in stereophonic systems. This effect is set up to playback the * * original "dry" signal in one stereo channel and the delayed signal in the other channel. * * This creates the impression of a stereo effect using a single mono source. By making the * * delay an input signal around 15-40 milliseconds, the resulting output produces a * * "stereo doubling" effect. * * * * * * Stereo ADT I/O Equation and Structure: * * yLeft(n) = x(n) * * yRight(n) = x(n - D) * * * * x(n) --------------------------------------------------|>-----------> yLeft(n) * * | 1/2 * * | * * | _______________ * * | | | * * | | | * * |----------->| Z^(-D) |-----------|>-----------> yRight(n) * * | | 1/2 * * |_______________| * * * * * * * * These effects are great for 'spicing' up an instrument or vocal track, such as compensating * * for a singer who is slightly out of key. To truly simulate a doubling effect, some random * * delay line modulation can be added, since 2 voices are never truely in sync with one another. * * * * IRQ1 pushbutton is used to vary the delay length on-the-fly. * * IRQ2 selects between either Slapback or Stereo Doubling effects. * * * * * *****************************************************************************************************/ /* filtr adaptacyjny z jednym wejsciem powstal w wyniku modyfikacji programu ilustrujacego opoznienie sygnalu akustycznego */ /* ADSP-21060 System Register bit definitions */ #include "def21161.h" //parametry filtru - modyfikowalne!!!!!!!!!!!!!! #define rzad_fir 50 #define krok 0.001 .GLOBAL Init_Delay_Buffer; .GLOBAL process_audio; /* ------------- DATA MEMORY FILTER BUFFERS ---------------------------------*/ .section /dm /NO_INIT dm_delay; /* zastosowano bufor "w" majacy na celu gromadzenie probek wejsciowych w nim dokonywany jest proces "opoznienia" sygnalu poprzez regulacje dlugosci bufora kolowego bufor "w" dzieki swojej wielkosci umozliwia zmiany opoznienia sygnalu poprzez stala -> delay_time <- */ #define DelayLine 1632 /* Depth, or TD = D/fs = 1680/48000 = 35 msec */ .var w[10000]; /* delay-line buffer, max delay = D */ .VAR linia_opozniajaca[rzad_fir]; .var linia_wyjsciowa[rzad_fir]; .section /pm pm_data; .VAR wsp_fir[rzad_fir]; .section /dm IRQ_ctl; //opoznienie sygnalu - modyfikowalne!!!!!!!!!!!!!!!!!!!! /* Reverb Control Parameters, these control 'knobs' are used to change the response on-the-fly */ .VAR delay_time=1000 ; /* controls length (L6 register)of predelay buffer */ /* length value always << max buffer length! */ /* ---------------------------------- PROGRAM MEMORY CODE ------------------------------------- */ .section /pm pm_code; Init_Delay_Buffer: //inicjalizacja buforow cyklicznych //b-adres poczatku bufora cyklicznego //l-dlugosc bufora cyklicznego //m-modyfikator bufora cyklicznego //i-rejestra automatycznie inicjalizowany wraz z inicjalizacja //rejestru b, w nim zawarty jest aktualny obliczony adres adres b0=linia_opozniajaca; l0=@linia_opozniajaca; m0=-1; m1=-2; b2=linia_wyjsciowa; l2=@linia_wyjsciowa; b8=wsp_fir; b9=b8; l8=@wsp_fir; m8=1; l9=l8; f7=krok; f0=0.0; //czyszczenie buforow kolowych lcntr=rzad_fir, do czysc_bufor until lce; dm(i2,m0)=f0; czysc_bufor: dm(i0,m0)=f0, pm(i8,m8)=f0; B6 = w; L6 = @w; /* delay-line buffer pointer and length for ADT Effect */ M6 = 1; LCNTR = L6; /* clear delay line buffer 2 to zero */ DO clrDline UNTIL LCE; clrDline: dm(I6, M6) = 0; rts; Init_Delay_Buffer.end: .EXTERN Left_Channel_In1; .EXTERN Left_Channel_Out0; .EXTERN Right_Channel_In1; .EXTERN Right_Channel_Out0; .EXTERN Left_Channel_Out1; .EXTERN Right_Channel_Out1; .EXTERN Left_Channel_Out2; .EXTERN Right_Channel_Out2; process_audio: /* process right channel input only */ r0 = dm(Left_Channel_In1); /* left input sample */ r1 = dm(Left_Channel_In1); /* right input sample */ L6 = dm(delay_time); /* tap output of circular delay line */ r3 = dm(i6, 0); /* point to d-th tap and put in data register */ /* fetch address with no update */ /* write output samples to AD1836 Multichannel Codec channels */ dm(Left_Channel_Out2) = r0; /* left output sample */ dm(Right_Channel_Out2) = r3; /* zaladowanie sygnalu opoznionego */ /* put input sample into tap-0 of delay line, post-modify address after storage of input */ dm(i6, -1) = r1; /* put value from register r1 into delay line */ /* and decrement address by -1 */ r2=-31; f0 = float r3 by r2; f1 = float r1 by r2; lms_alg: dm(i0,m0)=f0, f4=pm(i8,m8); //magazynuje x(n) w linni opozniajacej, f4=h0(n) f8=f0*f4, f0=dm(i0,m0), f4=pm(i8,m8); //f8= x(n)*h0(n) f0= x(n-1), f4= h1(n)} f12=f0*f4, f0=dm(i0,m0), f4= pm(i8,m8); //f12= x(n-1)*h1(n), f0= x(n-2), f4= h2(n)} lcntr=rzad_fir-3, do fir until lce; fir: f12=f0*f4, f8=f8+f12, f0=dm(i0,m0), f4= pm(i8,m8); //f12= x(n-k)*hk(n), f8= sum, f0= x(n-k-1), f4= hk+1(n)} f12=f0*f4, f8=f8+f12; //f12= x(n-N+1)*hN-1(n)} f13=f8+f12; //f13= y(n)} YYYYYYYY f6=f1-f13; // f6= e(n) } EEEEEEEE dm(i2,m0)=f13; f1=f6*f7, f4=dm(i0,m0); //f1= krok*e(n), f4= x(n)} f0=f1*f4, f12=pm(i8,m8); //f0= krok*e(n)*x(n), f12= h0(n)} lcntr=rzad_fir-1, do modyfikuj_wsp until lce; f8=f0+f12, f4=dm(i0,m0), f12=pm(i8,m8); //f8= hk(n+1)} //f4= x(n-k-1), f12= hk+1(n)} modyfikuj_wsp: f0=f1*f4, pm(i9,m8)=f8; //f0= krok*e(n)*x(n-k-1)} //zapamietanie hk(n+1)} f8=f0+f12, f0=dm(i0,1); //f8= hN-1(n+1)} //i0 -> x(n+1) ulokowanie w linni opozniajacej} pm(i9,m8)=f8; //zapamietanie hN-1(n+1)} /* f13= y(n) f6= e(n) */ r2 = 31; /* scale the result back up to MSBs */ r13 = fix f13 by r2;//y(n) /* convert back to fixed point */ r6 = fix f6 by r2;//e(n) DM(Left_Channel_Out0) = r13; /* send left channel result to AD1836 Left DAC0 */ DM(Right_Channel_Out0) = r6; /* send right channel result to AD1836 Right DAC0 */ rts (db); DM(Left_Channel_Out1) = r13; /* send left channel result to AD1836 Left DAC0 */ DM(Right_Channel_Out1) = r6; /* send right channel result to AD1836 Right DAC0 */ process_audio.end: