All pastes #2109095 Raw Edit

Stuff

public text v1 · immutable
#2109095 ·published 2012-02-02 18:06 UTC
rendered paste body
//Melody - Will play a melody 
//    Sort-of-MIDI

// Alter the variable string 'melody' in setup() to change the melody played.
// notes are defined with 4 characters
//    Xa01
// X is the note letter, [A-F], capitals only.
// a is the accidental, or modifier. s for sharp [+1 semitone], n for natural[+0 semitone] b for flat [-1 semitone]. lowercase only.
// 0 is the octave modifier, [0-9]. C4 is middle C. Octave -1 was not implemented because fuck you.
// 1 is the length number of the note, [0-9]. Common range [3-7]
//  9:  longa
//  8:  double whole note/breve
//  7:  whole note/semibreve
//  6:  half note/minim
//  5:  quarter note/crotchet
//  4:  eighth note/quaver
//  3:  sixteenth note/semiquaver
//  2:  thirty-second note/demisemiquaver
//  1:  sixty-fourth note/hemidemisemiquaver
//  0:  hundred twenty-eighth note/Quasihemidemisemiquaver/Semihemidemisemiquaver
//
// The melody string can be however long a char array is allowed to be, I couldn't find it in the reference but I didn't look very hard.
// It must consist of only a series of note definitions, Xa01Xa01Xa01
// E.G. "Cn44Gn43En43An34Bn45As45An35Gn46En44Gn45An34Fn43Gn46En43Cn45Dn45Bn44"


//Constants
#define speakerPin 12 //Pin the speaker is connected to
#define quavLength 600 //How long a quaver lasts. 600 should give 100BPM, I think.
#define midA 440 //Frequency of middle A in Hz all not frequencies are derived from here.
#define errorLED 13 //Pin that the error LED is connected to. Built in LED on Mega is 13.
float* globF; // Global for the frequencies
int* globL; // Global for the lengths
int numNotes; //how many notes there are in the melody. Also needs to be passed from setup() to loop()

//Functions:

void error(String message) { // What to do in case of error
  digitalWrite(errorLED, HIGH); // Turn the error light on
  Serial.println(message); // Print an error message
  delay(10000); // Wait 10 seconds
}
  
float switchNote(char X, char a, int o) { //  Convert note to frequency  
  //Based on the modifier, convert note to a step number using maths with the ASCII values
  
  int noteStep;
  if (a=='s') {
    noteStep = X - 63;
  }
  else if (a=='n') {
    noteStep = X - 64;
  }
  else if (a=='b') {
    noteStep = X - 65;
  }
  else {
    error("Invalid Modifier");
  }

  int steps = o-4;
  steps = steps * 12;
  
  if(steps>=0) {
    steps = steps + noteStep;
  }
  else if(steps<0) {
    steps = steps - noteStep;    
  }
  else {
    error("This error should be impossible");
  }
  
  float exponent = steps/12;
  float tempow = pow(2, exponent);
  float frequency = tempow * midA; // Calculated using the midi equation from http://en.wikipedia.org/wiki/Note
  
  return frequency;
}

float findLength(int y) { // Turn the length value into a number of milliseconds
  float temp = 0.625; // How many quavers in a Semihemidemisemiquaver
  for(int i = 0;i<y;i++) { // Convert the note length int into a factor to multiply the quaver length by
    temp = temp + temp;
  }
  
  return temp;
}

//The standard functions
void setup() {  

  pinMode(speakerPin, OUTPUT);
  Serial.begin(9600);

  //The melody to play goes here
  char melody[] = "Cn64Gn63En63An64Bn65As65An65Gn66En64Gn65An64Fn63Gn66En63Cn65Dn65Bn64"; //  Must be nothing but a series of 4 note strings.

  //How many notes long is the melody?
  numNotes = strlen(melody) / 4; //I don't know why the leading * is needed, but apparently it is.
  //Arrays to hold the frequencies and lengths of the notes.
  float* freqs = (float*) malloc(numNotes*sizeof(float)); //because float freqs[numNotes]; would be too simple
  int* lengths = (int*) malloc(numNotes*sizeof(int));
  
  for(int i=0; i<numNotes; i++) { //separate the melody out into notes etc
    char currNote[5];
    currNote[0] = melody[4*i];
    currNote[1] = melody[(4*i)+1];
    currNote[2] = melody[(4*i)+2];
    currNote[3] = melody[(4*i)+3];
    currNote[4] = char(0); //Make the last character a NULL/terminator
    
    int hurr = int(currNote[2]) - 48; //fucking char - int conversions
    int durr = int(currNote[3]) - 48;
    
    freqs[i] = switchNote(currNote[0], currNote[1], hurr); //convert the note to a frequency and store it in freqs
    lengths[i] = findLength(durr); //Convert the timing 
  }
  globF = freqs; //Put the array of frequencies into the global so loop() can read it
  globL = lengths; //Do the same for the lengths
  
  Serial.print(freqs);
  Serial.println("<--freqs (setup)");
  Serial.print(String(lengths));
  Serial.println("<--lengths (setup)");
  
}

void loop() {
  
  Serial.print(String(globF));
  Serial.println("<--freqs (loop)");
  Serial.print(String(globL));
  Serial.println("<--lengths (loop)");
  
  int gapLength = 150; //How long the speaker is silent for before it plays the next note
  for(int i=0; i<numNotes; i++) { // Not sure if this will use the right value for numNotes, should be tested with Serial.print.
    int playLength = globL[i] - gapLength;
    tone(speakerPin, globF[i], playLength);
    delay(globL[i]); // Not entirely sure if this should be gapLength, globL[i], or something else
  }
  delay(5000); //Pause for 5 seconds before repeating the melody
}