Audio Workshop 12
Oscillators and Envelope
Synthesis is the process of creating sounds. In this tutorial, we’ll listen to some of the fundamental synthesis building blocks available.
Oscillator is an object that generates one tone or frequency at a time though in some cases it may be modulated by an external control signal. The output can be one of several different wave shapes such as sine or square wave.
Envelope relates to how the amplitude of sound changes over time, described as the attack, sustain and decay of a sound.
Design the Audio System
In this system, waveform1 is the “control waveform”. It is (usually) a relatively low frequency which controls (modulates) another signal.
The sine_fm1 generates a sine wave that can be frequency modulated using the waveform1 while sine1 generates a regular sine wave
The pink1 object generates a constant background / ambient type noise
Like in the previous tutorial, the mixers are used as switches to allow us to hear one of the 4 synthesized sounds and to hear it directly or modified by the envelope1 object.
Draw the audio system below in the Design Tool.
Turn the Design into Code and Use it in a Program
Copy and paste the code below into the IDE window. Compared to the original Part_2_08_Oscillators example in the IDE, we have just updated the pin numbers.
// Advanced Microcontroller-based Audio Workshop // // http://www.pjrc.com/store/audio_tutorial_kit.html // https://hackaday.io/project/8292-microcontroller-audio-workshop-had-supercon-2015 // // Part 2-8: Oscillators // ProtoSupplies.com Changes and Additions // Change pin #'s to match tutorial adapter #include <Bounce.h> Bounce button0 = Bounce(3, 15); Bounce button1 = Bounce(4, 15); // 15 = 15 ms debounce time Bounce button2 = Bounce(5, 15); /////////////////////////////////// // copy the Design Tool code here /////////////////////////////////// //=============================================================================== // Initialization //=============================================================================== void setup() { Serial.begin(9600); AudioMemory(20); sgtl5000_1.enable(); sgtl5000_1.volume(0.32); pinMode(3, INPUT_PULLUP); pinMode(4, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); mixer1.gain(0, 0.75); mixer1.gain(1, 0.0); mixer1.gain(2, 0.0); mixer1.gain(3, 0.0); mixer2.gain(0, 0.15); mixer2.gain(1, 0.0); mixer2.gain(2, 0.0); mixer2.gain(3, 0.0); waveform1.begin(WAVEFORM_SAWTOOTH); waveform1.amplitude(0.75); waveform1.frequency(50); waveform1.pulseWidth(0.15); sine_fm1.frequency(440); sine_fm1.amplitude(0.75); sine1.frequency(200); sine1.amplitude(0.75); pink1.amplitude(0.75); envelope1.attack(10); envelope1.hold(10); envelope1.decay(25); envelope1.sustain(0.4); envelope1.release(70); } int waveform_type = WAVEFORM_SAWTOOTH; int mixer1_setting = 0; int mixer2_setting = 0; elapsedMillis timeout = 0; bool mixer2_envelope = false; //=============================================================================== // Main //============================================================================== void loop() { button0.update(); button1.update(); button2.update(); // Left changes the type of control waveform if (button0.fallingEdge()) { Serial.print("Control waveform: "); if (waveform_type == WAVEFORM_SAWTOOTH) { waveform_type = WAVEFORM_SINE; Serial.println("Sine"); } else if (waveform_type == WAVEFORM_SINE) { waveform_type = WAVEFORM_SQUARE; Serial.println("Square"); } else if (waveform_type == WAVEFORM_SQUARE) { waveform_type = WAVEFORM_TRIANGLE; Serial.println("Triangle"); } else if (waveform_type == WAVEFORM_TRIANGLE) { waveform_type = WAVEFORM_PULSE; Serial.println("Pulse"); } else if (waveform_type == WAVEFORM_PULSE) { waveform_type = WAVEFORM_SAWTOOTH; Serial.println("Sawtooth"); } waveform1.begin(waveform_type); } // middle button switch which source we hear from mixer1 if (button1.fallingEdge()) { if (mixer1_setting == 0) { mixer1.gain(0, 0.75); mixer1.gain(1, 0.0); mixer1.gain(2, 0.0); mixer1.gain(3, 0.0); Serial.println("Mixer1: Control oscillator"); mixer1_setting = 1; } else if (mixer1_setting == 1) { mixer1.gain(0, 0.0); mixer1.gain(1, 0.75); mixer1.gain(2, 0.0); mixer1.gain(3, 0.0); Serial.println("Mixer1: Frequency Modulated Oscillator"); mixer1_setting = 2; } else if (mixer1_setting == 2) { mixer1.gain(0, 0.0); mixer1.gain(1, 0.0); mixer1.gain(2, 0.75); mixer1.gain(3, 0.0); Serial.println("Mixer1: Regular Sine Wave Oscillator"); mixer1_setting = 3; } else if (mixer1_setting == 3) { mixer1.gain(0, 0.0); mixer1.gain(1, 0.0); mixer1.gain(2, 0.0); mixer1.gain(3, 0.75); Serial.println("Mixer1: Pink Noise"); mixer1_setting = 0; } } // Right button activates the envelope if (button2.fallingEdge()) { mixer2.gain(0, 0.0); mixer2.gain(1, 1.0); mixer2_envelope = true; timeout = 0; envelope1.noteOn(); } if (button2.risingEdge()) { envelope1.noteOff(); timeout = 0; } // after 4 seconds of inactivity, go back to // steady listening intead of the envelope if (mixer2_envelope == true && timeout > 4000) { mixer2.gain(0, 0.15); mixer2.gain(1, 0.0); mixer2_envelope = false; } // use the knobs to adjust parameters //float knob1 = (float)analogRead(A1) / 1023.0; float knob2 = (float)analogRead(A2) / 1023.0; float knob3 = (float)analogRead(A3) / 1023.0; waveform1.frequency(360 * knob2 + 0.25); sine_fm1.frequency(knob3 * 1500 + 50); sine1.frequency(knob3 * 1500 + 50); }
Now Export and copy and paste the Design Tool code into the program to complete it and verify and upload the program to the Teensy.
When this program runs, the buttons and knobs have the following functions:
- BTN0 (left): Cycles through the 5 control waveform types
- Sawtooth
- Sine
- Square
- Triangle
- Pulse
- BTN1 (middle): Cycles through the 4 mixer1 signals
- Control Waveform
- Frequency Modulated Sine
- Pure Sine
- Pink Noise
- BTN3 (right): Activate the envelope
- Press = Note Begin
- Release = Note End
- (after 4 seconds) = Revert to steady tone from mixer1
- Knob VR1/A2 (left): Varies control waveform frequency
- Knob VR2/A3 (right): Varies sign_fm1 & sign1 frequency
Open the Serial Monitor window so you can see what settings you are selecting.
Listen to the Five Control Waveform Types
Press BTN1 until mixer1 is passing the control oscillator. Then turn knob VR1/A2 clockwise until the control oscillator is a recognizable tone.
Now press BTN0 and listen to each control waveform. The serial monitor will tell you which one is playing. Each will have a distinctive sound.
Listen to the Modulated Waveform with Each Control Type
Turn the VR1/A2 knob fully counterclockwise. this will configure the control oscillator to a very low frequency, far below human hearing. If sawtooth, square or pulse are selected, you may hear occasional clicking due to the sharp waveform edges, but the tone of the waveform itself is inaudible.
Press BTN1 to configure mixer1 to pass the modulated sine wave (Frequency Modulated Oscillator). Adjust VR2/A3 for a comfortable tone range.
Listen to the modulated sine with each control waveform (BTN0). You should be able to hear the effect of the control waveform shape. Sawtooth causes a gradual rise in tone, then sudden drop back down. Sine varies the tone back and forth. Square will alternate between 2 tones. Triangle should be similar to sine, but the tone changes less smoothly. Pulse should be similar to square, except you will hear one tone nearly all the time and the other only briefly.
Experiment with Faster Control Waveforms
While listening to the modulated waveforms, increase the control waveform (knob VR1/A2). You should hear funny sounds. With sawtooth or triangle control, you should hear strange tones, perhaps “metallic” sounding as the control frequency rises much higher.
Listen to Envelope Effect
Envelope describes how the amplitude of sound changes over time.
Adjust the settings for a distinctive sound and then repeatedly tap the right BTN2 button to activate the envelope. Tap it in a simple rhythm.
Envelope tries to transform a tone into the intensity profile of a musical note. it rapidly changes the signal level in several phases.
Consider a flute. The attack phase is similar to initially blowing into the tube, causing pressure to build before any substantial sound to hear. The decay phase emulates the equalizing of pressure between the instrument and musician. The sustain phase is the steady sound heard as the musician continues blowing in the tube. The final release phase emulates the gradual decrease in pressure & sound after the musician stops applying air pressure.
These oscillators and envelopes are some of the basic building blocks for music synthesis.
Next up, we’ll look at audio analysis and more sophisticated ways for the program to interact with the audio system.