Our ECE 4760 final project was to create a virtual saxophone that uses Direct Digitial Synthesis (DDS) to synthesize the output notes. Pushbuttons are connected to a PVC pipe to mimic the saxophone’s mechanical structure, and a microphone that detects noise is used to determine whether or not the user is blowing into the device.
We decided to do this project because we enjoyed the ECE 4760 Lab on DDS and wanted to explore it further. In addition, we were intrigued by some of the previous ECE 4760 projects that created virtual instruments, and decided to create a saxophone because we have previous experience playing this instrument. This project was very enjoyable because it combined the knowledge gained in previous labs with our musical interests.
High Level Design
The rationale for this project design is to facilitate an easy, user-friendly mechanism for users to learn or practice playing the saxophone on this virtual device. The desire to learn to play a musical instrument is common for people of all ages, but the significant cost of purchasing an instrument can be a deterrent for doing so. The cost of a new alto saxophone can range from five hundred dollars to thousands of dollars, in addition to the cost of maintenance and any necessary repairs. This device provides a fun alternative, allowing interested musicians to learn a new instrument at a fraction of the cost. This idea was inspired by a previous final project, “Recorder Hero”, in which buttons were used to form the key fingerings and a microphone was used to detect input. Although our project is similar in spirit, the virtual saxophone involved new Direct Digital Synthesis (DDS) to create a saxophone voice, a more complex input system that allows the user to accent each note rather than just control the volume, and a unique hardware system to resemble an alto saxophone in both look and feel.
The saxophone voice was created using additive synthesis with ten harmonics, where the amplitude, rise, and fall time were individually tuned to create the appropriate voice. Nineteen different buttons were glued on to our device to allow the user to control the frequency of the note. Although a standard alto saxophone usually has twenty buttons, the button we excluded is used as an alternate fingering for some notes, so it does not affect the frequency range of the device. The saxophone is a member of the woodwind family of instruments, which means sound is created when the player blows air through a wooden reed. In order to simulate this process, a microphone was used to detect whether or not the user is blowing into the instrument. By allowing the user to blow into a microphone, the noise in the microphone is detected to adjust the volume of the output. In addition to simply blowing into the instrument, a saxophonist is able to modify the articulation of each note through a process called tonguing. Tonguing refers to modifying the syllables used when blowing into the instrument. During this process, the tongue momentarily comes into contact with the wooden reed, blocking airflow into the instrument. When the tongue loses contact with the reed, a constant airflow enters the instrument into a continuous stream. In order to simulate this process, anytime the user’s tongue momentarily blocks the flow of air, the reduction in noise across the microphone is detected, allowing the sound to naturally decay. Once the tongue loses contact and air flow is resumed, the air flow across the microphone increases, causing the notes to be reset to maximum amplitude. This produces a similar sound output as the alto saxophone, allowing the user to put an accent on each note if desired.
The logic structure of the overall design was relatively straightforward. The Analog-to-Digital Converter (ADC) is used to read in noise from the microphone. If the noise level is above a specified threshold, the current button configuration is polled to output the correct frequency. Once the noise level goes below the specified threshold, the note naturally decays. The output is filtered and sent to portable speakers to play the synthesized note. The DDS process is described in much greater detail in the software design section, and the hardware involved, including the buttons, microphone, amplifiers, and filters are described in the hardware design section.
Although there are no relevant patents to this project, the process of instrument synthesis is a complex technique, and some methods used are not shared with the public. The DDS used in this project is based off Wind Instruments Synthesis Toolbox, included in the references section. This is a Matlab / GNU Octave toolkit that uses a complex additive synthesis technique to read music score files and synthesize the output using ten different possible instruments. The synthesis used to create a saxophone voice was greatly simplified and was modified to work on the microcontroller by replacing any built-in Matlab functions with corresponding C code, and replacing computationally expensive operations such as divides with faster operations such as shifts. While the provided toolbox uses over thirty harmonics for some notes, our DDS was reduced to ten terms without sacrificing the voice quality. The amplitudes in the Matlab toolbox were used as a basis for choosing the amplitude of each term in our synthesis process.
The hardware portion of this project can be broken down into two main subcomponents: the physical design of the saxophone and the analog circuitry. The physical design of the saxophone involved obtaining a PVC pipe that resembled the shape and size of a saxophone. Careful measures were taken to attach buttons onto the PVC pipe to represent the different keys of the saxophone. The spacing and location of the buttons were approximated to be as close to a real alto saxophone as possible so that an experienced player could pick it up and start playing immediately. The mouthpiece was built by extending the microphone wires through the PVC pipe and attaching the microphone to a kazoo. A bottle cap was added below the octave pushbutton on the back of the saxophone as a thumb rest. A hook was also added to attach a neckstrap to the device. A pouch was used to store away the white board, the microcontroller, and the rest of the analog circuitry. The speaker was attached to the side of the PVC by easily inserting it on the open end of the pipe.
The analog circuitry of this lab consisted of the microphone input, the PWM output, and the pushbutton circuit. The microphone input first needed to be passed through an amplifier circuit to amplify the signal from millivolts to volts so that the signal was easier to work with. This amplifier circuit was built by passing the microphone input through the positive input terminal of the LM358 and building a feedback loop through the output and negative terminal.
The output of the amplified microphone signal was then passed through an op-amp comparator to generate fast, logic-level output swings. This basically pushed the microphone signal to the VCC and ground rails whenever noise that passed a certain threshold was detected on the microphone.
The square-wave signal produced by the op-amp comparator, however, needed to be modified since it featured very fast high-low transitions whenever an input on the microphone was detected. Instead, a consistent high-signal was desired so that the device would be “ON” when the microphone was blown into. To do this, the circuit was extended to pass the signal through a diode and then a resistor and capacitor in parallel. This allowed the signal to be maintained as high whenever fast high-low transitions were detected. This filtered signal was then finally sent to pin A0 of the Mega644 for an analog to digital conversion. To protect A0 (the analog input), a 1k resistor and two 1N914 diodes were connected, as shown below, to constrain the voltage between 0 and 5V.
Pin B.3 was used as the pulse width modulation (PWM) output from the Mega644. This needed to be connected to the 3.5mm audio input to the speakers. The PWM was passed through a low-pass filter before sending the signal to the speakers in order to reduce/eliminate any noise. The low-pass filter was built using a simple RC circuit. Since the PWM’s sampling frequency would be about 8kHz, the cutoff frequency should be no higher than 2kHz. If the frequency was greater than 4kHz, there would be aliasing. The resistor value had to be greater than the Thevenin resistance of port B.3 but smaller than the input impedance of the sound amplifier and so a good choice was 10kOhms. Using the desired frequency constraints given above and choosing the resistor to be 10kOhms, the following equation was used to determine the capacitance: 1/(2*pi*τ) < 2000 = 1/(2*pi*R*C) < 2000. A .1uF capacitance satisfied this equation since 1/(2*pi*10000*.1E-6) = 159Hz. A picture of the PWM connection to the 3.5mm socket via the low-pass filter is given below.
The pushbutton circuit was pretty simple. One end of the pushbutton was connected to ground while the other was connected to a pull-up 10k resistor. The output of the pushbutton was detected at the resistor-pushbutton terminal. This formed an active-low switch as the output was high when the button was not pressed (open circuit to VCC) and low when the button was pressed (direct connection to ground).
Direct Digital Synthesis Outline
The core of the software design involves synthesizing each note using additive synthesis. The sample code provided for additive synthesis for Lab 3 was used as a starting point, and the code slowly evolved into our final design. Timer 0 runs at the full rate without interrupts in fast PWM mode, causing the timer to count from 0 to 255 by incrementing by one every cycle. Thus, this is essentially allowing Timer 1 to run at 16,000,000 / 256 = 62,500 Hz PWM mode. Timer 1 was set to run at 8000 Hz, and the clear-on-match interrupt was enabled. During the ISR for Timer 1, the amplitude for each exponential and sine term are updated to slowly decay each note. In order to speed up the execution time of the ISR, the discrete differential equation was used to approximate the exponentials. Likewise, a lookup table for the sine values was created in the initialize code to avoid another lengthily calculation. Once the final value for the output was produced, it was assigned to OCR0A, which corresponds to output pin B.3 that produces that sound.
In the provided sample code, a button push sets a variable pluck, which resets the exponentials to their original (maximum) value in the ISR. This essentially causes a new note to be played. To modify the existing framework, we keep track of two variables: pluck and play_note. The variable pluck functions in a similar manner to the provided code, resetting the amplitude of each note to their maximum value. The value of play_note is equal to one if a note is currently being played and zero otherwise. Keeping track of this prevents pluck from getting constantly reset while the user is blowing a constant stream of air, as this would create a drumming noise.
Once the switches were wired up to the PVC, a basic test was performed to ensure each key was working. The challenging part was to determine which pin each button was connected to since we had over twenty wires coming off of our device. Rather than attempt to follow each wire back to the source button, we used the UART to print which pin was activated when each button was pressed, and used this information to map the buttons to their pin number in software. This test allowed us to catch a few wiring mistakes, such as a missing ground connection on one button.
After the buttons were configured to the appropriate microcontroller pins, every possible note frequency and the corresponding button configuration was encoded. The thirty-two notes supported by this device range from A#2 to F5, the same frequency range as a typical alto saxophone. A mapping from each note to the corresponding frequency is shown below. Some notes have duplicate fingerings, so there were actually thirty-six total fingerings to detect. Since each button has two states (either pushed or not pushed) and there are nineteen total buttons, there are a total of 524,288 possible states of the system to detect. Checking every possible state is unreasonable, so we used a binary encoding to check for the thirty-six key configurations corresponding to the notes supported by the virtual saxophone. This was done by setting three char variables to an eight digit binary number, where each binary digit corresponds to whether or not a particular key is pressed. This allowed us to quickly check three char variables in a conditional statement to determine which frequency to output, rather than have to explicitly check every pin value in every conditional statement.
|9V Battery||Wilson Farms||$5.00||1||$5.00|
|Custom PC Board||Lab||$4.00||1||$4.00|
|Two-pack Belt Hooks||Dollar Tree||$1.00||1||$1.00|
|PVC Pipe||Previously Owned||$0.00||Several pieces||$0.00|
|3M Hook||Previously Owned||$0.00||1||$0.00|
|1k Ohm Resistor||Lab||$0.00||3||$0.00|
|10k Ohm Resistor||Lab||$0.00||23||$0.00|
|100k Ohm Resistor||Lab||$0.00||1||$0.00|
|1M Ohm Resistor||Lab||$0.00||1||$0.00|
|Sam Adams bottle cap||Previously Owned||$0.00||1||$0.00|
|Flat Wire||Lab||$0.00||6 ft||$0.00|
For more detail: Virtual Saxophone Using Atmega644