Skip to main content

Tagged “arduino”

  1. Arduino music

    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. } `

  2. Arduino Bike Computer

    I'm currently working on an Arduino based bike computer / data logger, based on a Arduino Uno and an SD shield. It seems to work quite well, and I use it for recording my progress on my bike trainer. I'm going to replace it with a RBBB and a micro-SD adapter I found online to make it portable.

See all tags.