Notes From James
Home | About | Download
Coverville - Violent Femmes album   James - Wednesday, March 7, 2012, 12:19 am

On to the next project: a cover album of Violent Femmes. My song: Promise. Just need to get started now...

RPM Challenge - Completed!   James - Tuesday, February 28, 2012, 4:40 am

Check here to listen:

isny's player:

February Album Writing Month / RPM Challenge   James - Friday, February 10, 2012, 5:06 pm

It's February, so I'm writing and recording an album for FAWM and the RPM Challenge. When I'm done, I'll have to post it to Bandcamp or some site like that. For this challenge, I'm using the same drum beat for each of the songs. So far, so good...none of the songs really sounds like the others.

BicycleErie   James - Sunday, January 15, 2012, 7:25 pm

Working on my latest project, BicycleErie. This will have maps of bicycle friendly routes, bike racks, and other such things. Let's hope this one takes off!

Arduino music   James - Friday, December 30, 2011, 8:11 pm

Here is a nice code sample that I put together that plays music on the Arduino. Just hook up a speaker to pin 8, add a resistor if necessary, and it will play a few songs, one with multiple voices (polyphonic music).

// Arduino Music Demo
// James S. Ghofulpo
//
// Plays multi voice music.  Documentation for writing your own music is below.

#define TS         ( 130 ) // Time for a 1/16th note, in ms
#define STACATTO   ( 80 )  // Time for a stacatto note, in ms
#define OUTPUT_PIN ( 8 )   // Which pin on the Arduino are we modulating
#define NUM_VOICES ( 2 )   // Number of voices supported
#define MAX_CYCLES ( 10 )  // On and off cycles before switch

// Data structure for each voice

typedef struct {
     float f; // Frequency
     long  t; // Time left to play this note
     long  decay_time; // Time left to decay (turn off) note
     long  on_pt;  // On phase time
     long  off_pt; // Off phase time
     int   synchronizing; // Set to 1 if we are waiting to synchronize
     int   current_voice; // which voice is being analyzed in the muisc
     const char * music;
     const char * start_of_music;
     const char * return_pos;
} voice_info_t;

// Function to play a song
//
// Tone Commands:
// a-g - Select low octave note
// A-G - Select high octave note
// +   - This note, up one octave
// -   - This note, down one octave
// #   - Sharp
// &   - Flat
// t   - Note is a triplet (1/3 of timing)
// .   - Note is dotted (timing * 1.5)
// ,   - Note is stacatto
// r   - Rest
// s, e, q, h, w - Timing (1/16, 1/8, 1/4, 1/2, 1) of note.  Note plays when time is selected!
//
// Voice / flow commands:
//
// V  - This is part of the next voice
// >X - Call part X
// [X yyyyy] - Define part x to be yyyyy
// |  - End of measure.  Allows for synchronization, in case of misprogrammed music.
// k  - The previously mentioned note selects the key signature (i.e. fk selects F major).

void play_song( const char * this_song )
{
   int inx = 0;
   int iny;
   int duration = 0;
   int note_offset = -1;
   voice_info_t info[NUM_VOICES]; // Each voices' info
   int triplet = 0;
   int key[12];
   long shortest_time = 999999;
   int current_phase = 0;
   long current_time;
   int in_combo;
   long time_in_micros;
   float on_duty_cycle = 0.1;
   int duty_cycle_direction = 0;
   int current_voice = 0;
   int cycle_count = 0;
   int dotted = 0;
   int stacatto = 0;
   char search_target;
   int everybody_is_done = 0;
   int accidental = 0;
      
   for ( inx = 0; inx < NUM_VOICES; inx++ )
   {
       info[inx].music = this_song;
       info[inx].start_of_music = this_song;
       info[inx].return_pos = this_song;
       info[inx].f = 0;
       info[inx].t = 0;
       info[inx].decay_time = 0;
       info[inx].on_pt = 0; // Frequency of this voice
       info[inx].off_pt = 0;
       info[inx].synchronizing = 0;
       info[inx].current_voice = 0;
   }
   
   // Initialize key to C major
   
   for ( inx = 0; inx < 12; inx++ )
   {
       key[inx] = 0;
   }
   
   //Serial.println( "Starting loop" );
   
   while ( !everybody_is_done )
   {       
       int everybody_is_synchronizing = 1;
       everybody_is_done = 1; // Assume we are all done
       
       for ( inx = 0; inx < NUM_VOICES; inx++ ) 
       {
           if ( *info[inx].music != 0 )
           {
               everybody_is_done = 0;
          
               if ( !info[inx].synchronizing ) // Somebody is still running...
               {
                   everybody_is_synchronizing = 0;
                   break;
               }
           }           
       }
       
       // If everybody is synchronizing, then we can continue.
       
       if ( everybody_is_synchronizing )
       {
           for ( inx = 0; inx < NUM_VOICES; inx++ ) 
           {
               info[inx].synchronizing = 0;
           }
       }
       
       // Code to check for the next note/sets of notes
       
       for ( inx = 0; inx < NUM_VOICES; inx++ ) // Check all voices
       {
           while (  ( info[inx].t <= 0 ) // out of time, get next note
                 && ( *info[inx].music != 0 ) // Still music left to play
                 && ( !info[inx].synchronizing ) ) // And not waiting for everybody to be ready
           {
               // Serial.print( *info[inx].music );
               
               switch( *info[inx].music )
               {
                   case '[': // Skip section  [ music ]                   
                       while ( ( *info[inx].music != 0 ) && ( *info[inx].music != ']' ) )
                       { 
                           info[inx].music++;
                       }
                   break;
                   case ']':
                       info[inx].synchronizing = 1; // Wait for everybody to get done
                       info[inx].music = info[inx].return_pos; 
                       info[inx].current_voice = 0;
                   break;
                   case 'V': // End of this part
                       info[inx].current_voice++;
                       break; // Do nothing: End marker
                   case '>': // Call a subroutine
                       info[inx].music++; // Get the marker
                       search_target = *info[inx].music;
                       info[inx].return_pos = info[inx].music; // The return position will be +1
                       info[inx].music = info[inx].start_of_music; // Rewind
                       while ( ( *info[inx].music != '[' ) || ( *(info[inx].music+1) != search_target ) )
                       {
                           info[inx].music++;
                       }
                       info[inx].music++; // Skip the bracket
                       info[inx].music++; // Skip the marker      
                       info[inx].current_voice = 0; // Starting with voice 0    
                       info[inx].synchronizing = 1; // Wait for everybody to get done
                       break;
                   case '|': // Force synchronize between voices             
                       if ( info[inx].current_voice == inx )
                       { 
                           info[inx].synchronizing = 1; // Wait for everybody to get done
                       }
                   break;
                   case 'c': note_offset = 15; break;
                   case 'd': note_offset = 17; break;
                   case 'e': if ( note_offset == -1 )
                             note_offset = 19;
                         else
                             duration = TS * 2; // Eighth
                   break;
                   case 'f': note_offset = 20; break;
                   case 'g': note_offset = 22; break;
                   case 'a': note_offset = 24; break;
                   case 'b': note_offset = 26; break;
                   case 'C': note_offset = 27; break;
                   case 'D': note_offset = 29; break;
                   case 'E': note_offset = 31; break;
                   case 'F': note_offset = 32; break;
                   case 'G': note_offset = 34; break;   
                   case 'A': note_offset = 36; break;
                   case 'B': note_offset = 38; break;        
                   case '+': note_offset += 12; break; // Up an octave
                   case '-': note_offset -= 12; break; // Down an octave
                   case '#': accidental = 1; break; // Up a half step
                   case '&': accidental = -1; break; // Down a half step
                   case 's': duration = TS; break;     // Sixteenth
                   case 'q': duration = TS * 4; break; // Quarter
                   case 'h': duration = TS * 8; break; // Half
                   case 'w': duration = TS * 16; break; // Whole
                   case 'r': note_offset = -2; break;  // Rest, not really necessary, except for eighth notes
                   case 't': triplet = 1; break; // Duration is a triplet
                   case '.': dotted = 1; break; // Dotted value
                   case ',': stacatto = 1; break; // Stacatto
                   // default: break; // Unhandled command
               }
       
               if ( *info[inx].music == 'k' ) // Handle keys
               {
                   int base = note_offset % 12;
            
                   for ( iny = 0; iny < 12; iny++ )
                   {
                        key[iny] = 0;
                   }
                   
                   int num_sharps = 0;
                   int num_flats = 0;
            
                   switch ( base )
                   {
                       case 0: key[3] = key[8] = key[10] = 1; break; // A
                       case 1: key[2] = key[7] = -1; break;
                       case 2: key[0] = key[3] = key[5] = key[8] = key[10] = 1; break; // B
                       case 3: break; // C
                       case 4: key[0] = key[2] = key[5] = key[7] = key[10] = -1; break;
                       case 5: key[3] = key[8] = 1; break; // D
                       case 6: key[0] = key[2] = key[7] = -1; break;
                       case 7: key[3] = key[5] = key[8] = key[10] = 1; break; // E
                       case 8: key[2] = -1; break; // F
                       case 9: key[0] = key[2] = key[3] = key[5] = key[7] = key[10] = -1; break;
                       case 10: key[8] = 1; break; // G
                       case 11: key[0] = key[2] = key[5] = key[7] = -1; break;                
                   }      
         
                   note_offset = -1;
               }
               
               if ( duration != 0 ) // Note is complete
               {
                   if ( triplet )
                   {
                       duration /= 3;
                   }
                   
                   if ( dotted )
                   {
                       duration = ((float)duration * 1.5);
                   }
                
                   if ( info[inx].current_voice == inx ) // This note is for this voice
                   {   
                       info[inx].t = millis() + duration;
                       info[inx].decay_time = info[inx].t - ( stacatto ? duration - STACATTO : 0 );
                       int base = note_offset % 12;               
                   
                       // Sample code to add phasing effects to music
                   /*
                   if ( duty_cycle_direction == 0 )
                   {
                       on_duty_cycle += 0.1;
                       
                       if ( on_duty_cycle > 0.8 )
                       {
                            duty_cycle_direction = 1;
                       }
                   }
                   else
                   {
                       on_duty_cycle -= 0.1;
                       
                       if ( on_duty_cycle < 0.2 )
                       {
                            duty_cycle_direction = 0;
                       }
                   }                   
                   */                     
               
                       if ( note_offset >= 0 )
                       {
                           info[inx].f = pow( 1.059460646483, note_offset + key[base] + accidental ) * 220.0;
                           float pt = 1000000 / ( info[inx].f );
                           
                           // The on phase time can be set here to add 'phasing' type effects
                       /*
                       on_pt[inx] = (long)( pt * on_duty_cycle );    
                       if ( on_pt[inx] < 50 )
                       {
                          on_pt[inx] = 50;
                       }   
                       on_pt[inx] = (long)( pt * on_duty_cycle );     */
                           info[inx].on_pt  = 50;   
                           info[inx].off_pt =(long)(  pt - info[inx].on_pt );
                       }
                       else // Rest
                       {
                           info[inx].f = 0;
                       }                   
                   } // Else, this note is not for us
                   
                   // Reset parser
                   note_offset = -1;
                   duration = 0;
                   triplet = 0;
                   dotted = 0;
                   stacatto = 0;
                   accidental = 0;
               }
               
               info[inx].music++; // Next character
           }
       } // Checked all voices

       // Play the note / set of tones, until end of somebody's note
       
       in_combo = 1;
    
       while ( in_combo )
       {               
           time_in_micros = micros();
           
           current_phase = !current_phase;
           
           if ( info[current_voice].f == 0 ) // Rest all voices
           {
               digitalWrite( OUTPUT_PIN, LOW );
           }
           else
           {          
               digitalWrite( OUTPUT_PIN, current_phase ? HIGH : LOW ); 
           }
           
           if ( cycle_count++ > MAX_CYCLES ) // Check if we need to change voices
           {
               cycle_count = 0;
               current_time = millis();
               int start_voice = current_voice;
               
               do
               {
                   current_voice = ( current_voice + 1 ) % NUM_VOICES;
               }
               while ( ( info[current_voice].f == 0 ) && ( current_voice != start_voice ) );
               
               for ( inx = 0; inx < NUM_VOICES; inx++ )
               {
                   if ( current_time > info[inx].t ) // If this note has expired
                   {
                       info[inx].t = 0; // Request the next note
                       info[inx].f = 0; // Turn off the note
                       in_combo = 0; // Get next note                       
                   }
                   else if ( current_time > info[inx].decay_time ) // stop this note
                   {
                       info[inx].f = 0;
                   }
               } 
           }           
           
           if ( current_phase )
           {
               shortest_time = info[current_voice].on_pt;
           }
           else
           {
               shortest_time = info[current_voice].off_pt;
           }      
           
           time_in_micros = micros() - time_in_micros;
           
           delayMicroseconds( shortest_time - time_in_micros ); // Sleep the time minus time to process this loop           
       }
   } // While looping
}

// Here are some sample pieces of music.  All songs, except for 'bourree', are single voice

  // Super Mario Bros.
  char super_mario_bros[] =
          "[A EsEsrsEsrsCsEsrsG,ererq]" // Intro
          "[B C,ersg,ers,e,ersa,eb,ea#sasrs gtqEtqGtqA,eFsGsrsE,eCsDsbsre]" // Main music
          "[C reGsF#sFsD#srsEsrsg#sasCsrsasCsDs]" // Falling theme
          "[D reGsF#sFsD#srsEsrsC+srsC+sC+srsre]" // Falling end 1
          "[E reD#sreDsreCersrerq]" // Falling end 2
          "[F CsCsrsCsrsCsDsrsEsCsrsasgsrsre CsCsrsCsrsCsDsEsrh CsCsrsCsrsCsDsrsEsCsrsasgsrsre EsEsrsEsrsCsEsrsGsrsrerq]" // Finish
          "[G g-tqctqetqCtqEtqGqEq g-#tqctqe&tqg#gCtqE&tqG#qE&q a-#tqdtqftqa#tqDtqFtqA#qA#tqA#tqA#tq C+qqh]" // Finale
          "[H EsCsrsg,ersg#,easFsrsFsasrsre btqAtqAtqAtqGtqFtqEsCsrsasgsrsre EsCsrsg,ersg#,easFsrsFsasrsre bsFsrsFsFtqEtqDtqC,ererq]"
          ">A >B >B >C >D >C >E >F" // Play the intro and the main tune
          "   >B >B >C >D >C >E >F" // Play the main tune again
          ">H >H >G";               // Play the second theme, followed by the finale
  
  // char air[] = "ek eegefebegefses febegeCqbqa#e bi"; // Key of E
  
  // Bourree by G.F. Handel, adapted from 'Music' by Software Technology Corp.
  char bourree[] = "[A"
                   "gk Dq | D,qb,qCebea,eg,e | EqGhFeEe | DqC,e,beaebec,ea,e |" // M 1-4
                   "   bqghaq | beC#ed,eb,eC#eDeE,eC#,e | DeEeF,eD,eE,eFeG,eE,e |" // M 5-7
                   "   FeGeA+ereC#e | D.h"                            // M 8-9
                   "V  bq | a,qg,qfeb-q | gqEqDqgere | fqrqgqfq |" // M1-4
                   "   gqdhfq | gqaqgqeq | aqaqaqC#q | dhaqeq | f.h]" // m5-9
                   "[B"
                   "gk A+q | AqFqGeFeEeDe | GqBhEq | D#qEqFqGeAe |" // M17-20
                   "   GqEhDq | DqCebeCqCq | CqbeaebqDq | EeFeGeEeFeGeA+eFe |" // M21-24
                   "   GeAeBeGeAeBeC+eAe | BqAeGeFeGeAeFe | GeAeBeAqCq | bqaegefegeaege |" // M25-28
                   "   geaebegeaebeceae | beCeDqbqaege | g.h" // M29-31
                   "V  Fq | FqDqDererq | dqb-ecedqeq | fqgqEqDq |" // M17-20
                   "   bqEhDq | eqeheq | dqdhgq | ghah |" // M21-24
                   "   DhDh | DqCebeaqDq | DqDqDqCq | dqrqrh |" // M25-28
                   "   derereredererq | dererqdqcq | b-.h]" // M29-31
                   ">A >A >B >B"; // Play the two parts

  char deck_the_halls[] = "[A g.qfeeqdq cqdqeqcq] " // Deck the halls with boughs of holly
                          "[B deeefedee.qde cqb-qch] " // Fa la la la la la la la la
                          "[C aeaeaeaeg.q fe eqdqch ]" // Last fa la la la
                          ">A >B >A >B "
                          "d.qeefqdq e.qfegqdq eefegqaebeCq bqaqgh "
                          ">A >C";
                          
  char nyan_cat[] = 
      "bk " // Key of B
      "[A D+sE+sF+eB+eD+sE+sF+sB+sC++sD++sC++sA+sB+e |"
      "   F+ed+se+sF+eB+eC++sA+sB+sC++sE++sD++sE++sC++s]" // Intro music
      "[B FeGeDsDsrsbsD&sCsbsrsbeCe | D&eD&sCsbsCsDsFsGsdsfscsdsbscsbs " // Main theme
      "   DeFeGsDsFsCsDsbsD&sDsD&sCsbscs | D&ebsCsDsFsCsDsCsbsCebece ]"
      "[C befsgsbefsgsbsCsDsbsesDsEsFs | bebefsgsbsfsEsDsCsbsfsdsesfs |" // Chorus
      "   befsgsbefsgsbsbsCsDsbsfsgsfs ]"
      "[D bebsasbsfsgsbsEsDsEsFsbeae ]" // Chorus end 1
      "[E bebsasbsfsgsbsEsDsEsFsbeCe ]" // Chorus end 2
      "[F bebsasbsfsgsbsEsDsEsFsbe ]" // Chorus end 2, without last note
      ">A >B >B >C >D >C >E "
      "   >B >B >C >D >C >F";     

  //char chord0[] = "cw";
  //char chord1[] = "rwCwCwCwCwCwCw V cwdwewfwgwAwBwCwDwEwFwGw";  
  //char chord[] = "CwCwCw V gwgwgw V cedeeefegeAeBeCeDeEeFeGe";
  char silence[] = "rwrwrw";
 
 void setup() {
   pinMode( OUTPUT_PIN, OUTPUT );
   //Serial.begin( 115200 );
       
   play_song( super_mario_bros );
   play_song( silence );
   
   play_song( nyan_cat );
   play_song( silence );
   
   play_song( deck_the_halls );
   play_song( silence );
   
   play_song( bourree );
   play_song( silence );
}

void loop() {
  // no need to repeat the melody.
}

Important Stuff
Ghofulpo.com
Bike to Work Week

Friends
Peter PoP
Sneakatron

Latest Posts

Find Stuff
By Date, tags, etc.

Commands
Home
RSS
Index
Login