Project tutorial
Arduino - Making Music Using Step Motors

Arduino - Making Music Using Step Motors © GPL3+

A step motor itself can generate sound when it is controlled at at proper speeds. Let's see two motors play the "Marble Machine" song.

  • 4,089 views
  • 2 comments
  • 21 respects

Components and supplies

About this project

Demonstration

In the demonstration video, I used the step motor to play the "Marble Machine" song. VOLUME UP!

  • Step motors connect with paper plate.
  • Step motors connect with XY plotter.

Why Can Step Motors Create Music?

When a step motor moves with a specific speed value, it creates the vibration with a specific frequency, the vibration make the surrounding environment oscillate. The oscillation creates a mechanical wave. Frequency value is depended on the speed. When frequency value is between about 20 Hz and 20 kHz, it becomes sound wave and our ear can hear it.By adjusting the speed, we can create the different frequency of sound. Therefore, we can create a different note of music.By mapping music notes of a song to speed, moving step motor with the speed values in sequence, step motor can create melody of that song. We can use more than one motor to play a complex song.

Different material connected with motor will create the different timbre. In this project, I use two kind of material that connect with step motors:

  • Step motors connect with paper plate. Actually, paper plate is just for decoration. It does not make big effect on timbre.
  • Step motors connect with XY plotter.

You can connect steps motor with any thing or machine.

Wiring

  • Stack PHPoC Shield or PHPoC WiFi Shield on Arduino.
  • Stack two PES-2604 stepper motor controllers on the PHPoC Shield or PHPoC WiFi Shield.
  • Connect two stepper motors to terminal block of two PES-2605 stepper motor controllers .
  • Bipolar stepper motor.
  • Unipolar stepper motor: there are two ways to connect a unipolar stepper motor to terminal block of PES-2605. User can choose one of them.
  • Set expansion ID for each step motor controllers are 13 and 14 via DIP switch on expansion board.You can refer to below table to set expansion ID.

Code

StepMusic.inoArduino
#include <math.h>
#include <Phpoc.h>
#include <PhpocExpansion.h>


ExpansionStepper step1(13);
ExpansionStepper step2(14);

ExpansionStepper steps[2] = {step1, step2};

void stepPlaySetup(int play_id, int vref = 8, int mode = 2, int accel = 10000);

void setup() {
    Serial.begin(9600);
    while(!Serial)
        ;

    Phpoc.begin(PF_LOG_SPI | PF_LOG_NET);
    Expansion.begin();

    stepPlaySetup(0);
    stepPlaySetup(1);
    stepPlayTempo(38);

    play_marble_machine_song();
}

void loop() {

}

const char melody1a[] PROGMEM = "5E2.67 4B2 4A8 4G8 4A4 4B4 4G8 4A8 5D8 R2.67 4B2 4A8 4G8 4A4 4F#4 4G8 4A8 5D8";
const char melody1b[] PROGMEM = "R2.67 4B2 5D8 5C8 4B4 4A4 4G8 4A8 4E8 R8 4C8 4E8 4B8 3B8 4C8 4D8 5D8 5C8 4B4 4A4 4G8 4A8 5E8";
const char melody1c[] PROGMEM = "R2.67 4B2 4A8 4G8 4A4 4B4 4G8 4A8 5D8 R2.67 4B2 5D8 5C8 4B4 4A4 4G8 4A8 5D8";
const char melody1d[] PROGMEM = "R2.67 4B2.67 4A8 5E8 R8 4B4 4A4 4G8 4F#8 4E8 R8 3B8 4C8 4F#8 4C8 4E8 4G8 4D8 4F#8 4A8 3B8 4B8 4D8 4G8 4A8 5E8";

const char chord1a[] PROGMEM = "3E4 4E2.67 3E8 4E4 3E4 4E2.67 3E8 4E4 3G4 4G2.67 3G8 4G4 3G4 4G2.67 3G8 4G4";
const char chord1b[] PROGMEM = "3D4 4D2.67 3D8 4D4 3D4 4D2.67 3D8 4D4 3C4 4C2.67 3C8 4C4 3D4 4D2.67 3D8 4D4";
const char chord1c[] PROGMEM = "3E4 4E2.67 3E8 4E4 3E4 4E2.67 3E8 4E4 3G4 4G2.67 3G8 4G4 3G4 4G2.67 3G8 4G4";
const char chord1d[] PROGMEM = "3D4 4D2.67 3D8 4D4 3D4 4D2.67 3D8 4D8 3C4 4C2.67 3C8 4C4 3D4 4D2.67 3D8 4D4";

const char* const melody_table[] PROGMEM = { melody1a, melody1b, melody1c, melody1d };
const char* const chord_table[] PROGMEM = { chord1a, chord1b, chord1c, chord1d };

char buffer[110];

int melody[55];
int chord[55];
byte melody_len, chord_len;

void play_marble_machine_song() {
    for (byte i = 0; i < 4; i++) {
        strcpy_P(buffer, (char*)pgm_read_word(&(melody_table[i])));
        melody_len = stepPlayEncode(buffer, melody);
        strcpy_P(buffer, (char*)pgm_read_word(&(chord_table[i])));
        chord_len = stepPlayEncode(buffer, chord);

        stepPlayChangeDir();
        stepPlayHarmony(melody, chord, melody_len, chord_len);
        //stepPlayMelody(melody, melody_len);
    }

    Serial.println("End!");
}

/* Library */
int stepPlaySpeed = 1000; // ms per bar
int stepPlayDirection = +1;

void stepPlaySetup(int play_id, int vref = 8, int mode = 2, int accel = 10000) {
    steps[play_id].setVrefStop(2);
    steps[play_id].setVrefDrive(vref);
    steps[play_id].setMode(mode);
    steps[play_id].setAccel(accel);
}

void stepPlayTempo(int tempo) {
    stepPlaySpeed = (int)(1000.0 / (tempo / 60.0));
}

void stepPlayChangeDir() {
        stepPlayDirection *= -1;
}

int stepPlayEncode(char *score, int *score_encoded) {
    char note[10];
    int score_len = 0;
    int score_encoded_id = 0;
    int blankPos = -1;
    int blankPosNext = 0;

    while(blankPosNext != -1) {
        float dur_fp;
        long dur_ms;
        long freq;

        blankPosNext = blankPos + 1;

        while(score[blankPosNext] != ' ') {
            blankPosNext++;
            if(score[blankPosNext]  == 0) {
                score_len = blankPosNext;
                blankPosNext = -1;
                break;
            }
        }

        if(blankPosNext >= 0) {
            int i;
            for(i = blankPos + 1; i < blankPosNext; i++)
                note[i - (blankPos + 1)] = score[i];

            note[i - (blankPos + 1)] = 0;
            blankPos = blankPosNext;

            if(note[0] == ' ')
                continue;
        } else {
            int i;
            for(i = blankPos + 1; i < score_len; i++)
                note[i - (blankPos + 1)] = score[i];

            note[i - (blankPos + 1)] = 0;
        }

        if(note[0] == 'R') { /* rest */
            note[0] = '0';
            dur_fp =  atof(note);
            dur_ms = (long)(stepPlaySpeed / dur_fp);

            freq = 0;
        } else { /* tone */
            int tone = (note[0] - 48)  * 12; // octave * 12

            // C  C# D  D# E  F  F# G  G# A A# B
            // 0  1  2  3  4  5  6  7  8  9 10 11

            switch(note[1]) {
                case 'C':
                    tone += 0;
                    break;
                case 'D':
                    tone += 2;
                    break;
                case 'E':
                    tone += 4;
                    break;
                case 'F':
                    tone += 5;
                    break;
                case 'G':
                    tone += 7;
                    break;
                case 'A':
                    tone += 9;
                    break;
                case 'B':
                    tone += 11;
                    break;
                default:
                    Serial.print("encode_score: unknown tone: ");
                    Serial.println(note);
                    return 0;
            }

            if(note[2] == '#') {
                tone++;
                note[0] = '0';
                note[1] = '0';
                note[2] = '0';
            } else if(note[2] == 'b') {
                tone--;
                note[0] = '0';
                note[1] = '0';
                note[2] = '0';
            } else {
                note[0] = '0';
                note[1] = '0';
            }

            dur_fp = atof(note);
            dur_ms = (long)(stepPlaySpeed / dur_fp);

            int octave = tone / 12;
            tone = tone % 12;

            long freqA = 440.0 * pow(2, (octave - 4));
            freq = (int)(freqA * pow(2, (tone - 9) / 12.0));
        }

        score_encoded[score_encoded_id++] = freq;
        score_encoded[score_encoded_id++] = dur_ms;
    }

    return score_encoded_id;
}

void stepPlayMelody(int *melody, int melody_len) {
    int melody_count = 0;

    while(melody_count < melody_len) {
        int freq = melody[melody_count++];
        int dur_ms = melody[melody_count++];

        if(freq) {
            steps[0].setSpeed(freq);
            steps[0].stepGoto(stepPlayDirection * 1000000);

            delay(dur_ms);
            steps[0].stop(0);
        } else // zero frequency is 'rest'
            delay(dur_ms);
    }
}

void stepPlayHarmony(int *melody1, int *melody2, int melody1_len, int melody2_len) {
    int *melody[2] = {melody1, melody2};
    unsigned long melody_start_ms = millis();
    unsigned long melody_next_ms[2] = { 0, 0 };
    int melody_count[2] = { 0, 0 };
    int melody_len[2] = { melody1_len, melody2_len };

    while((melody_count[0] < melody_len[0] ) || (melody_count[1] < melody_len[1] ) || melody_next_ms[0] || melody_next_ms[1]) {
        for(int i = 0; i < 2; i++) {
            if(melody_next_ms[i]) {
                if(melody_next_ms[i] <= millis()) {
                    steps[i].stop(0);
                    melody_next_ms[i] = 0;
                }
            } else {
                if(melody_count[i] < melody_len[i] ) {
                    int freq = melody[i][melody_count[i]];
                    int dur_ms = melody[i][melody_count[i] + 1];

                    melody_count[i] += 2;

                    if(freq) {
                        steps[i].stop(0);
                        steps[i].setSpeed(freq);
                        steps[i].stepGoto(stepPlayDirection * 1000000);

                        Serial.print("freq: ");
                        Serial.print(freq);
                        Serial.print(", dur_ms: ");
                        Serial.println(dur_ms);
                    }

                    melody_next_ms[i] = millis() + dur_ms;
                }
            }
        }
    }
}

Comments

Similar projects you might like

Electronic Music

Project showcase by Glauber Santiago

  • 1,275 views
  • 1 comment
  • 0 respects

Translightion Board (Controllable Music Visualizer)

Project tutorial by Joshua and Miranda Hansen

  • 2,453 views
  • 1 comment
  • 12 respects

Control Music Volume and Ledbar Using Slider of 1Sheeld

Project tutorial by ahmed ismail

  • 1,950 views
  • 2 comments
  • 14 respects

Fingerscan: Music at Your Fingertips

Project showcase by touchmysound

  • 10,839 views
  • 6 comments
  • 31 respects

Arduino - Drawing via Web Using Step Motor Controller

Project tutorial by IoT_lover

  • 9,142 views
  • 7 comments
  • 80 respects

How to make music with an Arduino

Project tutorial by Code_and_Make

  • 7,476 views
  • 0 comments
  • 16 respects
Add projectSign up / Login