MIDI Synthesizer, Hardware Interface - Senior Design Project Lab | ECE 445, Study Guides, Projects, Research of Electrical and Electronics Engineering

Material Type: Project; Class: Senior Design Project Lab; Subject: Electrical and Computer Engr; University: University of Illinois - Urbana-Champaign; Term: Spring 2000;

Typology: Study Guides, Projects, Research

Pre 2010

Uploaded on 03/16/2009

koofers-user-8xt
koofers-user-8xt 🇺🇸

4.7

(3)

10 documents

1 / 25

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
MIDI Synthesizer
by
Peter Shargo and Greg Bishop
ECE345 Course Section H
Lawrence Ronk (T.A.)
2 May 2000
Project #56
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19

Partial preview of the text

Download MIDI Synthesizer, Hardware Interface - Senior Design Project Lab | ECE 445 and more Study Guides, Projects, Research Electrical and Electronics Engineering in PDF only on Docsity!

MIDI Synthesizer by Peter Shargo and Greg Bishop ECE345 Course Section H Lawrence Ronk (T.A.) 2 May 2000 Project #

ABSTRACT

A MIDI synthesizer was implemented on a DSP evaluation board. A hardware box was developed to interface a MIDI device such as a keyboard to the serial port of the evaluation board. The synthesizer uses wavetable synthesis to generate tones at different frequencies, as specified by the keyboard. The code is made up of generic oscillators that operate on the wavetables that are stored in memory. Thus, any set of wavetables may be stored in memory to produce different types of sounds, with only minimal changes necessary in the actual code. The entire system works extremely well, despite a small difference in the data transmission rate of the keyboard and the clocking rate of the serial port on the evaluation board. ii

1. INTRODUCTION

1.1 Overview of Project

The project is a complete musical performance system. Using any device capable of transmitting MIDI messages, the DSP code can be driven to generate different types of sounds. A block diagram of the entire project appears in Fig. 1. The interface was built to be able to connect the MIDI device to the DSP, since the two have different standards for data transfer. The DSP program generates tones based on messages it receives from the MIDI device. The musical waveforms are created using a technique known as wavetable synthesis.

1.2 Overview of Wavetable Synthesis

There are many different types of synthesis in use today, and they have been implemented both digitally and in analog format. Different techniques have evolved over the years, and certain methods have proven to be excellent at synthesizing certain types of instruments, while other methods have excelled at others. Also, the type of synthesis used usually depends on the application; a cheap device needs to use a synthesis technique that, while it may not create the most impressive sounds, can be implemented inexpensively, while a top-of-the-line product needs to have very convincing sounds. The

DSP Board

Running Synthesizer Code

Hardware

Interface

MIDI Device

Fig. 1. General Block Diagram of Project

technique that we have chosen to implement, multiple wavetable synthesis, has proven to be very effective at generating musical sounds. Wavetable synthesis is an efficient technique for the generation of a particular periodic waveform; in this case, a musical tone. Prior to synthesis, one cycle of the waveform is stored in a table. To generate samples during synthesis, table lookup is performed for the desired number of samples. To “play” the table at a higher frequency, you simply move through the table with a larger increment. If one were to move through the table with an increment of 2, he would reach the end of the table twice as fast as someone moving through the table with an increment of 1. Therefore, the first person’s frequency would be twice that of the second person, or one octave higher. A method of generating more complicated periodic signals is called multiple wavetable synthesis. As the name suggests, it is similar to wavetable synthesis, except with more tables. The output of the synthesizer is based on a sum of fixed waveforms with time-varying weights, which allows for the generation of very convincing time-varying timbres. While almost exact representations of instruments can be created by using a set of tables which form a basis for the spectrum of the instrument, adequate representations can be achieved using only a few of the basis spectra. In our case, we used three wavetables to generate our sounds.

1.3 Overview of MIDI

The MIDI (Musical Instrument Digital Interface) standard is a popular and widely used method for the coding of musical performance data. As McQueer [2] and Heckroth [1] note, the standard specifies a 31.25 kHz data transmission rate between devices. The information is sent asynchronously, 8 bits at a time with one start bit and one stop bit. The standard interface between MIDI devices is a 5-pin DIN connector with a 5 mA current loop between pins 4 and 5. The standard specifies the format for many types of messages of interest in musical performance. For the purposes of this project, however,

2. DESIGN PROCEDURE

2.1 Hardware Interface

Due to the differences in interconnect standards for the output of the keyboard and the input serial port of the DSP, it was necessary to construct a hardware interface allowing the MIDI messages from the keyboard to be sent to the DSP serial port. A basic circuit diagram is given in Fig. 2. The optoisolator keeps the input from the keyboard electrically isolated from the rest of the circuit, preventing any spikes in the current loop to cause huge voltage rises in the rest of the circuit. Since the optoisolator outputs standard logic levels of 0V for logic low and 5V for logic high, the line driver is needed to convert to the serial port standard of 9V for a logic low and –9V for a logic high. The output then goes to the DSP board.

2.2 Oscillator Design

The fundamental sound generator for wavetable synthesis, as well as all other types of synthesis, is the oscillator. Since our synthesizer was being implemented on a digital signal processor, we had to be able to implement a digital oscillator. A digital oscillator takes amplitude and frequency as inputs, and performs table lookup on the wavetables. The first thing the oscillator does is take the desired frequency to determine the sample increment needed for the table, using the following formula from Roads [4]:

increment = frequency * table length / sample rate (1)

Each wavetable will have the same increment; after being multiplied by the correct amplitudes (discussed shortly), the total output will consist of the sum of the outputs of each wavetable oscillator. From Keyboard (^) To DSP Optoisolator Line Driver Fig. 2. General Block Diagram of Interface Circuit

As mentioned previously, the sample increment is used to ‘resample’ the waveform in order to generate the desired frequency. The instantaneous table index is determined by the sample increment and the previous index, using the following formula, also from Roads [4]:

index = modtable length(previous index + increment) (2)

The sample output is determined by the amplitude and the value of the wavetable at the current index, using the following formula from Roads [4]:

output = amplitude * wavetable[index] (3)

The amplitude that is used is determined by the duration of the desired sound and the length of the amplitude envelope table, according to Roads [4]:

amplitude_increment = (table length) / (duration * sampling rate) (4)

This brings us to the question of what happens when we end up with non-integer indices for our wavetables or amplitude envelopes. There are three common options: truncation, rounding, and linear interpolation. Truncation cuts off the entire fractional part, rounding gives the nearest integer, and linear interpolation gives a value in between. For example, given an index of 42.57 leads to the following: Truncation: value = table[42] Rounding: value = table[43] Linear Interpolation: value = .57 * table[42 + 1] + (1 - .57) * table[42] Truncation introduces the largest approximation error, but takes the least computation time. Rounding gives slightly better approximations, but takes slightly more computation time. Linear interpolation has the least approximation error of the three methods, but uses the most computation time. Several points must be made regarding approximation error. First, the approximation error for all three methods decreases with increased table length. Second, the difference between results yielded by truncation and rounding affects only the phase of the resulting waveform, which is not detectable by human ears, so the audible error will be the same for both methods. For this reason, as well as the value of computation

3. DESIGN DETAILS

1.1 Serial Routine

As the MIDI data enters the DSP board though the serial port, the software must correctly interpret the messages and handle them accordingly. Once the messages arrive at the DSP, the information needs to be directed to the oscillator portion of the code for processing. This is done using a routine called serial_loop. The flow diagram for this procedure is given in Appendix 1, and is explained in detail here. At the start of the code, the program is directed to serial_loop. Since this is a real time system, the serial port must be continually checked for new data, and this is done after every 16 output samples. At the beginning of serial_loop, one byte of data is read from the serial input buffer. If nothing is received, program control is returned to the oscillator bank. If something is received, it is up to the code to determine what the incoming byte represents in the MIDI message, or if it is something to be ignored. The MIDI standard species that a keyboard may optionally send the byte 0FEh periodically while the device is plugged in. A device at the other end of the cable can use this information to verify that the keyboard is still connected. In this case, the byte is ignored since it does not play a relevant role in the messages of interest to this project. When a new NOTE ON message is received by serial_loop, the first byte received is the NOTE ON status byte, or 090h. Upon receiving this byte, a flag is set indicating that the status byte has been received. Program control is then assigned back to the oscillator bank. The next time a byte is received by serial_loop, the flag indicates that the NOTE ON status byte has previously been received. The new byte is therefore expected to be the note number. This number is recorded and a new flag is set, indicating that the note number has been received. Again, control returns to the oscillator bank. The reason the program returns to the oscillator bank after each received byte is in case of a delay in the transmission of the MIDI data. If the message does not come all at once for any reason, no samples will

be skipped in other oscillators that are currently playing. Upon receiving the third byte, the flag indicates that the status byte and note number have both been received, and we should now be expecting the attack velocity. This byte is recorded as such, and we are now ready to process all of the information from the message. Although the MIDI standard specifies that a NOTE OFF message should have a status byte of 080h, it is acceptable practice to use another NOTE ON message with all zeros for the attack velocity, as mentioned in the introduction. Therefore, upon receiving all the information from a new message, the first thing to do is compare the note number against all the oscillators that are currently playing a note. If a match is found, then the message is indeed a NOTE OFF, and the note should be stopped. A flag is set to inform the oscillator bank that the NOTE OFF has been received for the particular note, so that the oscillator may begin the decay of the note. If the note is not found anywhere in the list of oscillators, then a new NOTE ON message has been received. The first thing to check is the variable called full. Each time a new note comes in, full is incremented. Therefore, full must also be checked each time to be sure that the maximum number of notes is not already playing. If this is the case, then the new NOTE ON message should be ignored. This synthesizer is capable of playing eight notes at a time. If there are less than eight notes playing, the new message is valid, and an available oscillator must be located. Each oscillator is checked to see if it is occupied with a note, and if it is empty, the note is placed there. The oscillator bank uses these same variables to determine if a specific oscillator has a note to play. After the note and its corresponding velocity are stored in an oscillator, program control is once again returned to the oscillators. An important consideration is the running status mode of the MIDI keyboard. In this mode, when a succession of notes are played together, the status byte is only sent for the first note. It is then assumed that this status byte corresponds to all notes sent after it, and is thus omitted from future notes. Therefore, if a message is received without a status byte, it is to be assumed that the last status byte

duration as several hundredths of a second to as long as he or she wishes. The solution to this problem is to break the amplitude envelopes into several pieces. We have chosen to divide these envelopes into three parts: the attack region, the hold point, and the release region. The hold point is perhaps the most important of these, because it determines the other two regions. This point is determined through visual analysis of the envelopes themselves; therefore, different instruments can have different hold points, and they are verified through aural tests. The general idea is to look at the most dominant amplitude envelope for the particular sound (it will usually have a much greater amplitude) and visually locate the point at which the graph has leveled off somewhat right before a fast decay to the end. A good visual example is Fig. 3: The increments for the attack and release regions are determined through aural trial-and-error. The attack region increment is extremely important for the effectiveness of the synthesized sound; a synthesized instrument with an attack increment that is too fast or too slow will often sound ridiculous and implausible. On the other hand, the increment for the release region doesn’t seem to have much of an effect on the plausibility of the sound, because it should be relatively large. When a note key is released, the expectation is that the note will stop playing almost immediately; this corresponds to a Fig. 3. Regions of Amplitude Envelope

large release increment. It is extremely important to note that finding good values for the hold point and the attack region increment are essential for effective and plausible synthesis. The algorithm for traversing the amplitude envelope is relatively simple. When a NOTE ON message is received by the DSP, the oscillator begins to move through the attack region of the amplitude envelope with the ‘attack’ increment. If the hold point is reached before a NOTE OFF message is received, it stays at the hold point (i.e., it uses an increment of 0) until that message is received, at which point it moves through the release region with its associated increment. On the other hand, if a NOTE OFF message is received before the hold point is reached, it continues to move throughout the entire envelope; however, it immediately moves to the fast, large increment associated with the release region. The release region increment is large enough that the entire envelope can be traversed in a small fraction of a second. When the end of the envelope is reached, the note is done playing, and the registers are updated accordingly. At this point, the increments for both the wavetables and the amplitude envelopes are known. Table lookups are performed on all of the tables; the wavetable values are determined through truncation of the indices, while the amplitudes are determined by linear interpolation. These values are multiplied together and summed over the three sets of tables. Finally, a table lookup is performed using the velocity value sent by the keyboard; these values are supposed to represent a logarithmic scale. This is used to determine the overall volume of the output samples. Each of the eight oscillators calculates its output samples in the same manner.

1.3 Hardware Interface

The design used for the interface circuit is based off a schematic recommended by the MIDI specification. The actual schematic appears in Fig 4. The main components are the optoisolator and the line driver. It is important that the current loop be electrically isolated from the rest of the circuit, so that small spikes in the current will not cause huge voltage rises in the rest of the circuit. The line driver is

4. DESIGN VERIFICATION

1.4 Software Testing

For the purposes of testing the serial routine and subsequently the oscillator bank, a Matlab graphical user interface was created. With the interface, the user specifies a MIDI note number in the range of 0 to 127 in a text edit box. There are a series of pushbuttons that may be used to simulate MIDI messages based on the specified note number. The first two buttons simulate simple NOTE ON and NOTE OFF messages. Each sends the status byte, note number and constant attack velocity through the serial port. The next two buttons are labeled CHORD ON and CHORD OFF. These simulate several notes being played at the same time. Coinciding with the observed behavior of the keyboard, the first NOTE ON message is sent with the status byte, but each of the others sends only the note number and velocity. The CHORD OFF sends the same thing as the chord on, but with zero for all the velocities. There is also a button labeled Garbage, which sends a random few bytes to insure that the serial code is able to ignore messages that it is not expecting. By using this interface, the code was tested as if it were receiving messages directly from the keyboard. It was first tested for serial routine functionality. We were able to step through the code as the messages were received from Matlab, and check to see that serial_loop was handling the messages properly. The code was checked for the proper storage of the note numbers and velocities in the correct locations, as well as the handling of special situations, such as the running status byte and the case where all eight oscillators are full. After the serial routine was verified to be operating properly, the oscillator code was activated to see if it could respond to the Matlab MIDI messages correctly. This included checking that each oscillator began playing a note when serial_loop placed a note number in its variable location, and that the note was stopped when serial_loop set the flag indicating that the NOTE OFF message had been received.

bit, the cumulative error at the end of the entire byte must not exceed 50% for every bit to be sampled correctly. Thus, with 8 data bits, 1 start bit, 1 stop bit, and no parity, the percent error must not exceed 50% / 10 bits = 5%. However, in our case, the stop bits were not integral to our data, so even if it were sampled incorrectly, we could ignore it. Therefore, ignoring any possible ‘frame errors’ that would result, we were left with 9 bits (8 data bits plus 1 start bit) that were important. This corresponds to a higher maximum permissible percent error between the data rate and the expected data rate: 50% / 9 bits = 5.556%. Fig. 5. UART Clocking Analysis

4.3. 2 Clock Cycle Analysis

The factor that determines the maximum polyphony (that is, the number of notes that can be played at the same time) is the amount of clock cycles available for calculations for each sample. Our DSP EVM has a processor clock of 80MHz, and a sample rate of 44.1KHz. This means that only

8010^6 / 44.110^3 = 1814 clock cycles can be used for calculations between each sample. We have determined a rough estimate (‘rough’ due to the fact that not all code is executed each time) of how many clock cycles each oscillator uses to calculate its output samples. Our best estimate of the worst- case, maximum cycle use is approximately 175 cycles per oscillator. This means that the maximum number of oscillators, and therefore the maximum polyphony achievable, is 1814 / 175 = 10.37. Therefore, using our synthesis scheme, and our DSP and its associated hardware, no more than 10 notes can be played at any one time.