Sei sulla pagina 1di 5

Final Project Chorus Effect

EE 113D
Fall 2005
Professor Rajeev Jain
TA Rick Lan
Authors
Anthony Eagen
Jonathan Wuo
Introduction and Background
Digital Signal Processors are commonly used to implement audio effects in the
music world. Cheaper and more precise than analog implementations, a DSP allows a
person to implement audio effects such as echo, reverb, equalization, etc. with precision
and clarity. The focus of our project is to implement the chorus audio effect on the DSP.
The chorus effect is essentially a variable delay echo applied to vocal or musical inputs.
The effect is so named because it gives the illusion that a singer is singing along with two
or more people, resembling a chorus. Because the chorus effect is a variable delay, it
mimics the pitch and timing differences between multiple people singing together.
In order to implement this effect on the DSP, we require the use of the A/D
converter and the D/A converter. Also, the DSP and its memory are used in order to
implement the chorus algorithm that will be applied to the input signal. The input signal
is normally an analog signal, such as music or the input from a microphone. The A/D
converter takes the signal and feeds it to the DSP, where our code is implemented and
applied to the signal, where it is then fed through the D/A converter where we can put the
output into a speaker or analyze it on an oscilloscope.
Project Development
A chorus effect is an echo which is added to the original signal, and then varied
between a maximum and minimum delay at a certain rate. To best way to vary the delay
of the echo is to apply a periodic waveform to the delay, making it rise and fall according
to the waveform. This waveform, called the Low Frequency Oscillator (LFO) is used to
control the chorus sound by changing the waveforms frequency and amplitude. The
Block diagram shown below illustrates how the delay is dependent on the LFO, and how
the input signal is split, delayed, then added to the original signal to create the output
signal.

Figure 1: Chorus Effect Block Diagram

From the block diagram shown before, we can develop a simple algorithm which
we can use to implement our chorus effect.
out[i] = in[i] + in[i - delay(i)]
(1)
From this algorithm we see that in[i] represents the original signal. The second part of
the equation on the right hand side represents the delay, where delay(i) shows that the
delay varies with time. For our purposes, sinusoidal or triangular waveforms are easily
used to vary the delay.
The starting point of our project began with reviewing Experiment B, where we
learned how to apply a delay to an input signal to the DSP. The next step in the design
was to use that delay to create an echo. This was done by using circular addressing,
where we stored the original signal in the register buffers, and then we applied a delay to
the signal. Then we added both the delayed signal and the original signal to achieve a
simple echo effect.
Once the echo effect had been developed, the real task was creating a variable
delay parameter. First, we created the delay parameter in accumulator B. Next, we
needed to create a periodic waveform which could be applied to B so that it would vary
with time. At first we wanted to create a simple lookup table to output a sinusoidal or
triangular wave. However, we decided that the memory requirements would take up too
much space which was needed when storing the original signal. Thus, we decided to
create a triangular wave by using counters. The idea is that at each iteration, a counter
would countdown from a set value, each time incrementing the delay value by a certain
amount which we could control. Once the counter reached zero, it would reset, and begin
to decrement the delay value instead of incrementing it. Once the counter had reached
zero again, the incrementing would begin again, and thus we had a recycling triangular
wave. We could control the delay variation by changing the counter value and the
increment size. With the LFO implementation complete, it was just a matter of applying
it to the delay parameter B, and adding the delay to the original signal.
To implement the variable delay, we use circular addressing again. We would
set a pointer to a value in the original signal, and then increment that by the varying delay
parameter. Then we would take that new delayed value and add it to the original value
and output it. Then we would reset the pointer to its original value, so that no data would
be lost. Thus, with each iteration, the DSP would vary the delay parameter by a little, and
the output would change because of the delay each time. In the end we had a chorus
effect where the output signal would be varying according to how we described its
behavior using the LFO.
Discussion and Results
The implementation of our code works perfectly and we have a fully working
chorus effect which can be altered in frequency and amplitude. To test our chorus effect
we used a function generator to produce a sine wave. When viewed on the oscilloscope,
the chorus effect resembled the sine wave, only it had a noticeable delay, and it also
varied in amplitude and delay length. These effects would vary as a function of time,
thus we had a moving sine wave which appeared to be growing and shrinking as time
passed. The delay length variation is attributed to our program, and the amplitude
variation is a byproduct of the constructive and destructive interference of the delayed

signal added to the original signal. The pictures below show snapshots of the original
signal (yellow) and the chorus effect signal (green), where the chorus signal is obviously
varying in amplitude and delay length.

Figure 2: Snapshots of Delay/Amplitude Variation

From the pictures it is easier to imagine how the output signal was rising and falling as
the delay variation was changed. When applied to a musical clip, the performance of the
chorus effect was as expected. The voice of a single singer was altered to sound as if
multiple people were singing along with the original singer. Thus, the chorus effect had
proven to be effect in mimicking an actual chorus.
The code size issues were not a problem for us, as our code was developed and
written entirely in assembly, and it never reached a size which would cause concern for
us. The biggest problems we had were with memory limitations, coding syntaxes,
conditional statements, and nops. The memory limitations we had were with the size of
the stored original signal. Because we used circular addressing, we had to be sure we had
enough memory to store the input signal so that we could later apply a delay to it. With
coding syntaxes, the difficulties of programming in assembly language were apparent
when trying to adjust and assign values and pointer locations to variables. As with any
new language, there were difficulties in researching and finding the correct conditional
statements to compare values, such as when the counter reached zero. We had a problem
with the counter counting past zero because our conditional statements did not work, and
thus did not reset the counters. We fixed this problem by using two types of comparative
statements, thus creating a double check on the comparison of the counter to the value
zero. Less intuitive than C++, assembly language required us to compare to AR0 only,
instead of using different registers of actual values. Finally, after our code seemed to be
written perfectly, we still had difficulties in making it output what we expected. The
solution turned out to be random insertions of nop commands throughout the code. This
solution, although puzzling and without reason, seemed to allow our code to process
correctly through the DSP and made it output the correct chorus effect.
Conclusion
This project can easily be a stepping stone into the world of audio effects
implemented on the DSP. DSPs are commonly used to implement many different types
of audio effects, and the chorus effect is just one of many. The most important thing we
learned from this project was that programming in assembly is not easy, even if the
algorithm being implemented is simple. Our project consisted of a simple audio effect
with a simple algorithm which could be implemented easily using a user-friendly
programming language such as C++. However, because of the natural of assembly
language, we had to deal with the limited number of accumulators and registers that the
DSP contained, and also with the non-intuitive conditional statements and syntax of
assembly. The purpose of implementing an audio effect on a DSP is that it is cheap and
simple. The drawbacks are limited to its limited capacity, and maybe its inability to
perform multiple audio effects at the same time, or be able to choose which ones we
desire. This project taught us how to create an echo, how to generate a low frequency
adjustable oscillator, and how to combine both of those to produce a chorus effect.
References
Viperrs Audio DSP page - http://users.iafrica.com/k/ku/kurient/dsp/
Harmony Central - http://www.harmony-central.com/Effects/Articles/Chorus/

Code

COUNT
.set 579
; VARIES DELAY EVERY 100 MS
INC
.word 58
; 10 MS VARIATION INCREMENT
NONE
.word -1
; CHANGES STEP VARIATION UP AND DOWN
VALUE .set 9
; NUMBER OF VARIATION STEPS

AR1 = #buffer
; BUFFER TO STORE SIGNAL
bk = #length
A = #0
B=#235
; INITIAL DELAY PARAMETER 40 MS
AR5=#0X2710
; LOCATION FOR CURRENT INPUT
AR2=#COUNT
; VARIATION COUNTER FOR 0.5 HZ CHANGE
AR3=#VALUE
; STEP COUNTER, 10 STEPS BEFORE CHANGING DIRECTION OF
VARIATION
AR4=#1
; VARIATION DIRECTION SET TO UP, +/- TAG
repeat(#length-1)
; zero buffer using
*AR1+% =A
; circular addressing
imr = #240h
; unmask TDM RINT and HPIINT(host port interface)
intm = 0
; globally enable all interrupts

receive: A = #0
; load A with zero
A = trcv
; load A with TDM receive from AIC
AR0=#0
nop
nop
TC=(AR2==AR0)
; ERROR CHECK IF VARIATION COUNTER HAS NOT BEEN RESET
IF(TC) GOTO CHANGE2
; TELLS PROGRAM TO RESET VARIATION COUNTER
IF (*AR2- != 0) GOTO NOCHANGE
; IF VARIATION COUNTER HASN'T REACHED 0, SKIP
FOLLOWING
CHANGE2
AR2=#COUNT
; RESETS VARIATION COUNTER
IF(*AR4 != 0) GOTO SKIP
; ERROR CHECK FOR UP/DOWN DIRECTION
AR4=#1
; RESETS UP DIRECTION
SKIP
MACP(@AR4,INC,B)
; INCREMENTS DELAY PARAMETER 10 MS
AR0=#0
nop
nop
TC=(AR3==AR0)
; ERROR CHECK IF STEP COUNTER HAS NOT EBEN RESET
IF(TC) GOTO CHANGE3
; TELLS PROGRAM TO RESET STEP COUNTER
IF (*AR3- != 0) GOTO NOCHANGE
; IF STEP COUNTER HASN'T REACHED 0, SKIP FOLLOWING
CHANGE3
AR3=B
; TEMPORARILY STORE DELAY PARAMTER IN AR3
B=#0
MACP(@AR4,NONE,B)
; CHANGE DIRECTION OF DELAY VARIATION, MULTIPLY AR4*-1
@AR4=hi(B)
B=AR3
; RELOADS DELAY PARAMETER VALUE
nop
AR3=#VALUE
; RESETS STEP COUNTER TO 10
RESUME
*AR5=A
; STORING CURRENT INPUT IN MEMORY
AR0=B
; LOADS AR0 WITH DELAY PARAMTER
*AR1+%=A
; STORES CURRENT INPUT IN BUFFER AND
INCREMENTS POINTER
NOP
NOP
A=*AR1-0%
; MOVES POINTER BACK BY DELAY PARAMTER
A=*AR5 >>1
; RELOADING CURRENT INPUT
A = A + *AR1+0% >>1
; ADDING DELAYED VALUED AND MOVES POINTER TO
ORIGINAL LOCATION
A = #0FFFCh & A
; clearing 2 LSBs
tdxr = a
; send A to TDM transmit register
return_enable
; Return and Enable interrupts
NOCHANGE
;
GOTO RESUME

Potrebbero piacerti anche