Both sides previous revisionPrevious revisionNext revision | Previous revision |
resources:tools-software:sharc-audio-module:baremetal:simple-midi-synth [15 Nov 2018 14:37] – Chad Wentworth | resources:tools-software:sharc-audio-module:baremetal:simple-midi-synth [26 Feb 2019 19:56] (current) – [Setting up the MIDI Control] Chad Wentworth |
---|
| |
The synthesizer will support a handful of oscillators (sine, square, triangle, etc.) as well as ADSR (Attack-Decay-Sustain-Release) envelope control. Here's a nice [[https://www.wikiaudio.org/adsr-envelope/|tutorial on ADSR]]. In this tutorial, we'll trigger the synthesizer from the MIDI interface. | The synthesizer will support a handful of oscillators (sine, square, triangle, etc.) as well as ADSR (Attack-Decay-Sustain-Release) envelope control. Here's a nice [[https://www.wikiaudio.org/adsr-envelope/|tutorial on ADSR]]. In this tutorial, we'll trigger the synthesizer from the MIDI interface. |
| |
==== Project Structure ==== | |
This time, we'll create a folder under /src on SHARC Core 1 called ''audio_synthesis''. The following zip file contains ''simple_synth.c'' and ''simple_synth.h'' which implement a basic synth engine. Unzip these two files into the new ''/src/audio_synthesis'' folder. | |
| |
{{ :resources:tools-software:sharc-audio-module:baremetal:simple_synth.zip |simple_synth.zip}} | |
| |
==== Ensuring MIDI is Set Up Properly ==== | ==== Ensuring MIDI is Set Up Properly ==== |
Up until now, we've been working in ''callback_audio_processing.cpp''. In this tutorial, we'll also be working on ''Callback_MIDI_Message.cpp''. | Up until now, we've been working in ''callback_audio_processing.cpp''. In this tutorial, we'll also be working on ''Callback_MIDI_Message.cpp''. |
| |
To begin, let's get the audio processing in place. At the top of ''callback_audio_processing.cpp'' include our synth with the other include files like so: | To begin, let's get the audio processing in place. At the top of ''callback_audio_processing.cpp'' include our synth audio element and our audio utilities with the other include files like so: |
| |
<code c> | <code c> |
// Simple Synth Engine | // Simple Synth Engine |
#include "audio_synthesis/simple_synth.h" | #include "audio_processing/audio_elements/audio_elements_common.h" |
| #include "audio_processing/audio_elements/audio_utilities.h" |
| #include "audio_processing/audio_elements/simple_synth.h" |
</code> | </code> |
| |
<code c> | <code c> |
// Create a synth with up to 16 voices | // Create a synth with up to 16 voices |
cSynth synth_voices[16]; | SIMPLE_SYNTH synth_voices[16]; |
</code> | </code> |
| |
And in ''processaudio_setup()'', we'll initialize each "voice" of our synthesizer. The first parameter we pass is a pointer to the struct instance. The next four parameters are the attack, decay, sustain and release parameters in //samples//. So if want to create an instrument with an attach that is 1 second long, and our sample rate is 48KHz, we'd use a value of 48000. The next argument is the type of oscillator we want to use in our synth. If you look at ''simple_synth.h'', you'll find a few options include sine wave, square wave, triangle wave and a pulse train. Lastly, we'll pass along a few parameters related to our audio system setup. | And in ''processaudio_setup()'', we'll initialize each "voice" of our synthesizer. The first parameter we pass is a pointer to the struct instance. The next four parameters are the attack, decay, sustain and release parameters in //samples//. So if want to create an instrument with an attach that is 1 second long, and our sample rate is 48KHz, we'd use a value of 48000. The next argument is the type of oscillator we want to use in our synth. If you look at ''audio_processing/audio_elements/simple_synth.h'', you'll find a few options include sine wave, square wave, triangle wave and a pulse train. Lastly, we'll pass along a few parameters related to our audio system setup. |
| |
<code c> | <code c> |
20000, | 20000, |
SYNTH_TRIANGLE, | SYNTH_TRIANGLE, |
AUDIO_BLOCK_SIZE, | |
(float) AUDIO_SAMPLE_RATE ); | (float) AUDIO_SAMPLE_RATE ); |
} | } |
float temp_audio[AUDIO_BLOCK_SIZE], temp_audio_accum[AUDIO_BLOCK_SIZE]; | float temp_audio[AUDIO_BLOCK_SIZE], temp_audio_accum[AUDIO_BLOCK_SIZE]; |
| |
// Quick way to initialize audiochannel_0_left_out | // Quick way to zero audiochannel_0_left_out |
for (int j=0;j<AUDIO_BLOCK_SIZE;j++) { | clear_buffer(temp_audio_accum, AUDIO_BLOCK_SIZE); |
temp_audio_accum[j] = 0.0; | |
} | |
| |
// Scan remaining channels and synthesize when playing | // Scan remaining channels and synthesize when playing |
for (int i=0;i<16;i++) { | for (int i=0;i<16;i++) { |
synth_read(&synth_voices[i], temp_audio ); | synth_read(&synth_voices[i], temp_audio, AUDIO_BLOCK_SIZE ); |
| |
for (int j=0;j<AUDIO_BLOCK_SIZE;j++) { | // Mix this synth voice with our accumulated audio |
temp_audio_accum[j] += temp_audio[j]; | mix_2x1(temp_audio, temp_audio_accum, temp_audio_accum, AUDIO_BLOCK_SIZE); |
} | |
} | } |
| |
// Scale and copy the synthesized audio to our output buffers | // Scale and copy the synthesized audio to our output buffers |
for (int j=0;j<AUDIO_BLOCK_SIZE;j++) { | gain_buffer(audiochannel_0_left_out, 0.25, AUDIO_BLOCK_SIZE); |
audiochannel_0_left_out[j] = 0.25 * temp_audio_accum[j]; | gain_buffer(audiochannel_0_right_out, 0.25, AUDIO_BLOCK_SIZE); |
audiochannel_0_right_out[j] = 0.25 * temp_audio_accum[j]; | |
} | |
} | } |
</code> | </code> |
| |
<code c> | <code c> |
#include "audio_synthesis/simple_synth.h" | #include "audio_processing/audio_elements/simple_synth.h" |
extern cSynth synth_voices[]; | extern SIMPLE_SYNTH synth_voices[]; |
</code> | </code> |
| |
| |
---- | ---- |
{{navigation SHARC Audio Module#reverb-tutorial|Building a Reverb Effect#.|Bare Metal Framework#class-d-2-1-amp|Building a 2.1 Amplifier}} | {{navigation SHARC Audio Module#class-d-2-1-amp|Building a 2.1 Amp#.|Bare Metal Framework#..hardware|Hardware Reference}} |