11

(Marcin) #1
FORGE

pitch += envMod();

The above operator is adding the value returned
from the envMod() function we’re about to write to
the current value of pitch.


int envMod() {
unsigned long current_dur = millis() - note_
time;
if (current_dur <= pitchEnv[0]) { // Attack
return ((pitchMax * (100 * current_dur) /
pitchEnv[0]) / 100);
} else if (current_dur <= (pitchEnv[0] +
pitchEnv[1])) { //Decay
pitchEnv[1]) / 100);
return (pitchMax - (pitchMax - pitchEnv[2])
* (100 * (current_dur - pitchEnv[0]) /
pitchEnv[1]) / 100);
} else { // Sustain
return (pitchEnv[2]);
}}

The above code is complicated, so we’ll break
it down into parts. It starts off by taking another
timestamp for when the function is being run. By
subtracting the note’s start time, which we saved
earlier, and by using the time values in the envelope
array, we can calculate which stage of the envelope
we should be in. This is what the if and else
statements are doing, with the first simply checking
to see whether the time is less than the time of


the attack stage, and the second whether the time
frame is between the attack and the end of the
decay. If it is, we have a long calculation that does
the following:


  1. Calculates current time frame as a percentage of
    the whole stage

  2. Returns a percentage of changing value


We both multiply by 100 and divide by 100 in the
expressions to keep the end values as integers
and avoid floating point mathematics, which is a lot
slower and resource hungry on an Arduino. With
the attack stage finished, the next if deals with the
release stage. Finally, if we’re in the sustain stage,
we simply return the sustain value from the array.
With that function written, you can now re-upload
the project to your Arduino. When you press the
button, the pitch of the sound will now change
according to the durations and sustain level of the
envelope, making the sound much more dynamic
and interesting. You could even build this into a
synthesizer, adding potentiometers to control the
values for each stage of the envelope, or adding
more modulation envelopes to control amplitude,
or even pulse-width modulation. But that’s
another story.
The code for this project can be downloaded
from hsmag.cc/sEgZSN.

Arduino interrupts work at the
hardware level and can respond to
detected changes on specific pins,
such as the rising or falling signal you
get by pressing a button, but which
pins you can use is restricted, and
different Arduinos support different
numbers of pins. On our Uno (and other
328-based Arduinos), pins 2 and 3 are
the only two capable of generating
interrupts, and we’ve settled on pin 3
for the button connection. But to get
pin 3 to generate interrupts requires
an extra step we wouldn’t ordinarily
take, and that’s to convert this pin
number into an ‘interrupt number’. This
is because most Arduinos support a
restricted number of interrupts, just
two on the Uno, and the number for
each interrupt won’t necessarily align
with the pin being used to generate
the input. If your project needs more
interrupts, the best thing to do is
upgrade your Arduino.

HARDWARE INTERRUPTS

ARDUINO INTERRUPT PINS

328-based, Uno, Nano, Mini 2, 3

32u4-based, Micro, Leonardo 0, 1, 2, 3, 7

Due all digital inputs

Uno WiFi v2 all digital inputs

Zero all digital inputs except 4

Mega, Mega2560, MegaADK 2, 3, 18, 19, 20, 21

MKR boards 0, 1, 4, 5, 6, 7, 8, 9, A1, A2

Just like writing
English, the simple
approach should
always be taken
when writing code,
even if you know it
can be compacted.
This makes it much
easier for other
programmers, and
your future self,
to understand.

QUICK TIP

Free download pdf