Binary Beethoven: Coding a Musical Idea

Beethoven Title

Beethoven Two Measures

The first four ominous notes of the Fifth Symphony are well known:  da-da-da-dum!   That musical idea seems so obvious now, but think just for a moment about how radical it was and is.  First, this is a symphony that doesn’t begin with a note.  It begins with a rest, an eighth note rest.  It begins with a moment of silence.  Second, the motif is only four notes, but the first three notes are the same note, the G, repeated three times.  The fourth note, the Eb, is held until the conductor motions to continue.  The orchestra is barely two bars into the music when the conductor stops the performance.  Finally, if you have the entire score, you can see that every instrument plays those exact same notes (G, G, G, Eb) and does so at ff.

So, Beethoven notated a very loud repetitive group of notes to be played by an orchestra in unison – and, based on the tempo, to play it very fast.  He started with silence and, two bars into the symphony, stopped the entire orchestra.  And that’s why Beethoven was a genius.  That’s why we’re starting with Beethoven.  Because… Beethoven.

MUSICAL SPECIFICATIONS

Although we are living in the age of machine learning algorithms in which smart electronic devices adapt and evolve, every “computer” starts as just a box of silicon chips, plastic, and a bit of metal.  To get the Arduino to play a few notes of Beethoven, we need to provide it explicit instructions.  We need to program the Arduino to incorporate everything we just described that makes this motif unique:

  • Which notes to play?  (G, G, G, and Eb)
  • How long to play each?  (1/8, 1/8, 1/8, half-note)
  • What tempo to play the notes?  (108 half-notes per minute)
  • How loud to play the notes?  (ff)
  • When not to play?  (at the start, for an eighth-note length)

Each of these parameters must be programmed into the Arduino.  Below is a program that does all of this and, with the push of a button, will play the opening motif.

In this program, the musical notes are translated into MIDI note values (G=67, Eb=63).  Midi allows for a velocity of 0 to 127.  We have assigned ff to a value of 120, almost the highest velocity, but leaving some room for a potential fff in the future.

The tempo is specified as “108” for a half note.  That translates into approximately 555ms using the following math:

  • Marked tempo = 108 half notes per minute
  • Minute = 60 seconds
  • 60 seconds / 108 per second = .55555 of a second for a half note
  • .55555 of a second = ~556 milliseconds

An eighth note is one fourth of a half note, so an eighth note would be:

556 milliseconds / 4 = 139 milliseconds

Thus, each of the first four events (eighth rest plus three eighth notes) should each play for 139ms each.  The half note should play for at least 556ms and more, depending on the fermata.

But there is a problem using those exact values for timing notes.  Those precise values assume absolutely no time between notes, a perfect legato, one note blending directly into the next.  But the score is not marked legato.  So, we have to provide a bit of an offset.  In this case, we are using 10 milliseconds.   But instead of just adding that time in between the notes, we are subtracting it from the playing time of the note and adding the 10 milliseconds in as silence.

In this program, all of the parameters described are spelled out in detail:  individual notes, time each notes is played, time between notes, and dynamics.  In terms of MIDI, this is set up to use the Hairless MIDI option using MIDI over serial, but you could make a slight change to send MIDI over a traditional MIDI cable (see here for more on that).

 

SPECIFICATIONS IN CODE

/*
  Binary_Beethoven

  This program does only one thing: Play the 
  opening motif to Beethoven's Fifth Symphony.
  It demonstrates how to define variables and
  use them to trigger the notes.  LOOP checks
  for a button press and, if pressed, plays
  the motif.

  All of the variables (note, note length, etc.)
  are fixed -- coded as exact values that will
  never change.  This is a rigid approach to
  coding a musical idea, but demonstrates which
  variables are necessary to represent everything
  in Beethoven's first two bars.

  For more on this circuit and programs, see:
  www.amateurmusicology.com
  Elliot Inman Spring 2016

*/

// Create variables to use throughout the program

//  One digital switch connected to pin D2
//  We will use this to trigger the motif
int switch1;

// Opening Motif notes:  67=G, 63=Eb
int note_to_play1 = 67;
int note_to_play2 = 67;
int note_to_play3 = 67;
int note_to_play4 = 63;

// Opening Motif note durations
//  139 = eighth note
//  556 = half note  (108 half notes a minute)
//  Values are reduced by 10ms to allow some time
//  between the sounding of each note
int time_to_play1 = 139 - 10;
int time_to_play2 = 139 - 10;
int time_to_play3 = 139  - 10;
int time_to_play4 = 556  - 10;

// variable to provide the 10ms delay between notes
int time_between_notes = 10;

// Variable to define the eighth note rest
int rest = 139;

// Variable to define the sustain on Eb
int firmata = 556 * 2;

// Variable to define the dynamic (scale of 0 to 127)
int ff = 120;


//  SETUP the Arduino with a baud rate and tell
//  it what to do with various pins

void setup() {
  //  Set MIDI baud rate for HAIRLESS MIDI:
  Serial.begin(115000);  // for standard MIDI use 31250
  pinMode(2, INPUT_PULLUP);  // breadboard button input
  pinMode(12, INPUT);  // On-Off Switch input

}


//  LOOP that will cycle endlessly.

void loop() {
  // Check to see if the ON/OFF switch is on.
  // If so, proceed.  Otherwise, keep checking.
  while (digitalRead(12) == HIGH)
  {
    //  Check switches
    //  Because these are INPUT_PULLUP switches,
    //  Pressed = LOW or 0 and Not Pressed = HIGH or 1
    switch1 = digitalRead(2);

    // If switch1 is pressed, do this:
    if (switch1 == LOW)
    {
      delay(rest);  // play the eighth note rest

      // play the 1st g eighth note at ff
      noteOn(0x90, note_to_play1, ff);
      delay(time_to_play1);
      noteOn(0x90, note_to_play1, 0); // stop playing
      delay(time_between_notes);

      // play the 2ndt g eighth note at ff
      noteOn(0x90, note_to_play2, ff);
      delay(time_to_play2);
      noteOn(0x90, note_to_play2, 0);  // stop playing
      delay(time_between_notes);

      // play the 3rd g eighth note at ff
      noteOn(0x90, note_to_play3, ff);
      delay(time_to_play3);
      noteOn(0x90, note_to_play3, 0);  // stop playing
      delay(time_between_notes);

      // play the Eb half note at ff
      noteOn(0x90, note_to_play4, ff);
      delay(firmata);   // hold for specified duration
      noteOn(0x90, note_to_play4, 0);  // stop playing
      delay(time_between_notes);

    }
  }
}

/*  noteOn function to play a MIDI note
    COMMAND 0x90 sends NOTE ON on Channel 1.
    PITCH is the note from 0 to 127 with 60 as middle C.
    Keep in mind that some MIDI instruments may not sound
    outside of their normal real acoustic range.
    VELOCITY is how hard the note is struck (from 0 to 127),
    but is often perceived as volume.
    Using 0 for velocity is the same as turning a note OFF,
    so that is often used instead of a note OFF command.
*/

void noteOn(int command, int pitch, int velocity) {
  Serial.write(command);
  Serial.write(pitch);
  Serial.write(velocity);
}

 

BUGS and FEATURES

This program works, but it isn’t very interesting for very long.  All of the variables are set to values that can never change.  The program will flawlessly execute the same exact pattern of sounds over and over and over… like a machine.  It is precisely rendered, but minimally musical.  There are many ways to make the program more musical:  using a potentiometer to change the speed; using a photocell to control the dynamics; or using an array of sensors to control individual notes – until Beethoven’s original idea is no longer recognizable.

Likewise, there are many ways to make the program more computationally efficient:  using a for loop to repeat the repeated notes; rewriting the entire note structure into an array; and creating a more abstract timed event that can be executed as a sound or a silence depending on the requirements of the score.

But this is Beethoven, pure and simple.  Because… Beethoven.

 

Apologies to Max Mathews who explained all of this and more in The Technology of Computer Music in 1969.  Everything you need to know in two pages, give or take a couple of lines:

Mathews TOCM 1969

~ WEI 2016

 

 

This entry was posted in Arduino, CODE. Bookmark the permalink.