EMo

.

.

.

Abstract

Once upon a time there were these two engineers. One day they went up to RATT and decided to have a debate on which was more important, becoming an ASIC Design Engineer or a Rock'n'Roll star. Of course the only logical conclusion was to do both and EMo was born on the back of a napkin.

EMo is a digital signal processor which performs digital distortion for an electric guitar. With traditional analog distortion, the distortion level is not proportional to the level of the guitar signal. When the guitarist plays soft, there is no distortion and when he rocks out, there is extreme distortion. With EMo, the distortion level is set with a switch and the amount of rockin' the guitarist does will only effect the volume of the output not the fidelity, or lack thereof.

Because we designed it in a modular fashion, it will be easy to add other features. We began by adding a guitar tuner and a noise gate and designed for other features to come, such as Digital Delay and Reverb.

1. Overview

EMo is the rock and roll version of turning the wimp on the beach into the rippling muscle head who gets all the girls (in the music biz we call them groupies). Old school analog distortion is just that, old school. EMo is the saviour of Rock'n'Roll. Look at the guitar signals below.

If you can't see the difference, hear the difference.

The first signal is a clean signal, no distortion at all. The second signal is old school analog distortion. Notice how much information is lost. The only part which is preserved is the frequency. Guitarists who use this are nothing more than glorified clock-pulse generators. Now look at the EMo wave. Notice how the basic envelope of the signal is maintained and how all the nuances are preserved. Witness the power of EMo.

Because EMo was designed in a modular fashion, it is very easy to expand upon the original design. Eight separate modules interact with each other through two top level entities encompassing two chips and the external circuit. These modules perform all the basic digital processing functions required such as finding the amplitude of a signal, determining the period of a signal, processing a signal and I/O to lights, ADC/DAC and SRAM. Any new modules can easily be added and will be able to take advantage of these features. A guitar tuner, noise gate and of course EMo are three options which have already been implemented.

2. Design Details

There are eight separate entities that work as the pillars of a two level hierarchy and two entities that combine them and provide glue logic. In this section we'll describe the specific function of each entity and how it works.

2.1 The System Poem

Data is acquired, processed, and output.

So EMo, too,

2.2 The System

In essence this system implements an algorithm. The algorithm is simple, but implies a complex system because it requires foreknowledge of characteristics of the data stream. We have to store an amount of data and process it after the data arrives. The data is assumed (correctly, as shown in computer simulation) to be well behaved, it arrives at random intervals but always before the fixed length of memory used to store the data. With this assumption in hand (high pass filter in our holster), we see that we can process the data at the last possible moment without worry of being premature. The data required is guaranteed to have arrived. To simplify the design we have to separate memory controllers (keepers) that are the pride and joy of there creators. One takes care of the predictable, that is the actual samples, while the other takes care of the less orderly peaks. Together they work in harmony in one single simple system.

2.3 Components

2.3.1 Controller

The controller is the central nervous system of our design, it is a finite state machine that has direct connections to every other entity except for the tuner. True to it's name it controls most everything from a high level of abstraction, that is, it tells other modules what to do and when to do it, but it doesn't have an inkling of an idea of the inner workings of other entities.

The controller communicates to different entities in different manners. For instance the processor takes 3 clock cycles to complete it's task, the controller is happily unaware of this and simply waits for a process done command. Other tasks like transition detection are done while passing through states, they are simple and assumed (correctly) to be finished within one clock cycle, the controller will use the returned data in the next state. The controller might have been a fiercesome beast with all the different entities we used, but with this handshaking used for anything one clock cycle long everything is quite simple.

The controller is kept in synch using a clock signal divided down to the sample frequency.

2.3.2 Sample_keeper and Peak_keeper

These entities are responsible for communicating with SRAM. Much of the code and hardware of the keepers is identical, but their functional ity is very different. I'll describe the common functionality first, and then get into why and how they are different.

2.3.2.1 Similarities

Neither of the keepers handles the data directly. The entities simply load whatever is on the super_tune_bus (the system bus) to a particular address, making sure that the address is valid throughout the read or write operation and that the appropriate lines are triggered. That is to say the keepers don't have any data lines and to save space have only the address and control lines they need. Both entities are implemented as finite state machines that handshake with the main controller. They receive a read or write command and reply when they're finished, this makes for a sweet controller module. Control of the physical address lines is arbitrated by the top entity, one level above in the hierarchy, the controller tells top which address lines to connect (multiplex) to the SRAM address lines.

2.3.2.2 Differences

Sample_keeper has 10 address lines as it needs to write to 1024 memory spaces (the logistics of this are discussed under Latency and Timing Parameters). The number 1024 was chosen to fit our timing specs and because it was easily implemented with a ten bit counter that didn't need any logic to reset itself (it just wraps around). The SRAM we worked with used 15 address lines, to interface we simply concatena ted this local address value with a 5 bit static vector. Peak_keeper only has to address 256 values and so uses 8 address lines, thus the top entity concatenates a 7 bit static vector with the local address to appropriately manipulate the SRAM. The first five bits are different from those of the sample_keeper and so we introduce the concept of memory partitioning (Sadly we bow our heads in memory of less versatile operating systems). The keeper of the peaks, unlike its brother sample_keeper has two counters that increment separately. In each cycle one sample needs reading, and one sample needs writing however peaks come at random (or should we say rock) intervals. We manage peaks by writing one everytime we see a zero crossing at the input and by reading the appropriate one when it comes time to process it. To implement this we need two counters for the peak_keeper. The counter in charge of reading is incremented by the controller while the write counter increments itself.

Sample_keeper uses ALL of its memory in a cool way, that is, it writes to the current memory location, later in the cycle when it's time to read it increments the counter before it reads. When this value is read the memory location is free to be written to again, and so this keeper manages both reads and writes with a single counter.

2.3.2.3 These Keepers Rock

These keepers are well defined! They are incredibly modular and easy to use I implemented a digital delay test circuit using sample_keeper almost exactly as it was originally written. Perhaps we'll be able to use these modules as blocks for future designs.

2.2.3 Zero_cross

This entity really represents the heart and soul of EMo. Zero crossings allow us to manage the data, to group samples and extract information from them. We need two of these modules because there are two times we need to be aware of a new half wave, the first time when we're keeping track of the incoming sample. We constantly search for the peakiest data value, when we see that we're finished with this half wave, we must record the peak and begin anew. The second time we need to be aware when a new half wave is at the output, our processor needs to know the peak that is associated with the current sample. When we see a transition in the 'about to be processed data,' we know again that it's time to move to the new peak. Zero_cross works by polling the sign bit of the sample in question, it has the last sign bit stored in memory, if the sign bit has changed, it signals to the controller that there has been a transition. This entity is really small and simple to use, so we can justify having two of them, rather than having a more complex system with more than one output. At first the zero crossing detector seemed to be just a means to and end, but it became a lot more than that. You'll see when brought into the context of the noise gate that separating this anonymous data stream into half waves allowed us to make a cool abstractio n. We've got a lot out of half waves, frequency and peak information, when used wisely we can more intelligently control the data stream. The tuner, and a really smart noise gate are dividends that pay off nicely. This is a lot of neat stuff for an entity that only takes up 4. 5 modules.

2.2.4 Noise_gate

Here worlds collide when we realize how far we've come. The noise gate is a finite state machine that makes EMo a little bit smarter. We know that there's a little bit of junk that's picked up by the guitar when the guitarist isn't playing, we can get rid of this without disturbing small waves that naturally occur in an 'active' signal We only turn the the output to zero if the output has been low for the last few peaks, and only let the output pass if we've seen a few high peaks. In a sense half waves become an abstraction that we build on to sense 'context'. Future extensions of this concept could include building on the abstraction of context into something greater, perhaps to set an attack level or control decay, and who knows after that! Our initial design for the noise gate was time based, and very intricate, however we found we'd already built a rock solid foundation and could easily build on it. What a great feeling.

2.3.5 Peak_finder

The peak_finder, is an essential, true to its name, it finds peaks. It's entire function is to find the maximum value in a stream of data and be able to write it to the bus. It contains a finite state machine that allows it to write to the bus in a really predictable, orderly fashion. The peaks are stored unsigned in order to aid processing.

2.3.6 Processor

This is the entity that performs the magic, it computes EMo. Essentially the algorithm is to multiply the current sample by a given EMo factor (a power of two), if the result is greater than the current peak then the peak is output, otherwise the multiplied value is output. This is implemented as skinnily as possible, rather than multiply the value and check for an overflow, we shift the peak down by the EMo factor and compare it to the absolute value of the sample. If the sample is greater than the down shifted peak, we realize that shifted up it would exceed the peak. If this is the case we invert the unshifted peak if needed, and write it to the bus, otherwise, we write the leftshifted sample to the bus. A finite state machine helps us load the sample and then the peak from memory. The calculations are done in two states, it works pretty smoothly.

2.3.7 Tuner

The tuner is capable of computing which note the signal is closest to, and whether it is higher, lower or just right. It accomplishes this by counting the number of clock pulses between successive zero crossings. After every half wave, the counter is compared to stored values and the tuner calculates which note the signal is closest to. The tuner then uses this information to determine how many waves will have to be read in until an accurate assessment of the frequency can be made. If an E5 is played for instance, the tuner will determine this after only one halfwave, with very poor accuracy. Because the frequency of E5 is so high, 32 waves will need to be added together to give the desired accuracy. Each note requires a different number of waves to be added together to achieve the same accuracy, just as they all have different frequencies, but the total time is always near 2. 9 us. Once 32 halfwaves which are all reasonably close to E5 have been sampled, the 'total' counter is compared with stored values and the tuner can now determine if the signal is higher, lower or an exact E5. The tuner will light the appropriate lights to indicate this and will then start all over again. There are exactly 267. 57 11kHz clock pulses in a perfect 659. 25Hz E5. After rounding to 268 and requiring exactly that many clock pulses to trigger the perfect E5 light, the final accuracy is 2.28Hz.

A table showing the number of waves required and the accuracies of each note, E5, B4, G4, D4, A3 and E3 is given in below. See a complete flowchart in the appendix.

Frequency of perfect note (Hz) Accuracy of Tuner (Hz) Number of halfwaves required

E5

659.26

2.28 (0.35%)

32

B4

493.88

1.30 (0.26%)

24

G4

392.00

1.05 (0.27%)

20

D4

293.66

0.83 (0.28%)

16

A3

220.00

0.87 (0.40%)

12

E3

164.81

0.56 (0.34%)

8

2.3.8 Top

This is the top level of the hierarchy (go figure). Basically it binds the controller, keepers, zero_cross, noise_gate, peak_finder together. This entity lives in the first FPGA and contains output lines to communicate to the second FPGA. Top shares a bus with SRAM and has output lines to control and address the memory. There is a little bit of logic to arbitrate to control the address line bus.

2.3.9 Top2

This is the top level file for our second FPGA, it connects up the processor and the tuner. Top2 contains no logic, it merely connects appropriate lines in tuner and processor to their counter parts in the first FPGA. The output comes from the second FPGA, out the B proto connector.

3. Latency and Timing Parameters

Our system has an inherent delay. Let's face it. The fact is that to process the data we need to keep it within the system for about 25 ms. Clay and I found that the lowest frequency that could possibly emit from my bass guitar was 40 Hz. Because we work in terms of half waves this implies zero crossings at a maximum of 12. 5 ms, but we realize the simplications of missing zerocrossings, so we give ourselves a factor of two leeway. At the initial sampling frequency, 44. 1kHz this meant about 1000 samples to be stored in memory. The latency is rather obese, but I believe guitarists will be able to learn to play with the delay, as Clay succinctly put it,"When da' drumma' bang the bass pedal, he don hear nuttin fo' until da tang hit da drum anyway, a guita' man could do dat".

4. Conclusion

As the final day approached, EMo had still not seen completion but certainly not for lack of trying. The EMo algorithm is involved, it involves communicating with fairly complex external circuitry and communications with sram. However, EMo makes no apologies for being ambitious, rather all the better to fail with a space ship than pass with a doorbell. EMo justifies itself even if it is a complete failure (which of course, it is not) because it's a cool creative vision, bred of passion, fed on labour.

A lot of the territories were unchartered, and perhaps EMo has made a few inroads with its few working and realized pieces. Certainly, we've learned a lot, but we most definitely plan to get EMo working in the next few days (Christmas holidays if necessary and legal), not for our own benefit, but for the good of all mankind.

EMo out.





The body of the report is for the show but its the appendix thats for all the dough.


Appendix Table of Contents