Demonstration




Why can Step Motor Create Music?

When 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.




Things Used In This Project
  • PHPoC Blue or PHPoC Black (P4S-342 / P4S-341)
  • Two Step Motor Smart Expansion Boards (PES-2403)
  • Two step motors
  • XY-Plotter (Optional)


In this project, I use two step motors installed on XY-Plotter. Why I use the motors install on XY-plotter. Because I have already had it and also want to hear timbre of XY-Plotter. You can install two step motors to any material to hear it timbre or even we don’t need to use any material.
With two motor, we can create melody and chord.

In demonstration video, I use the step motor to play "Marble Machine" song.




Assembly
  • Stack two step motor smart expansion boards on the PHPoC board.
    The ID of this expansion board is set to 13 and 14 by adjusting the dip switch position as shown on bellow image

    Click image for larger version  Name:	making_music.jpg Views:	1 Size:	38.2 KB ID:	690
  • Refer to specification of your step motor to see how to connect step motor to step motor smart extension board. In my case, I use 42BYG Stepper Motor.
    The connection as follow:
    • Board ---------- step motor
    • M1+ ----------- black
    • M1- ------------ green
    • M2+ ----------- blue
    • M2- ------------ red
    • GND ----------- DC12V -
    • VM -------------- DC12V +


Source Code

task0.php
PHP Code:
<?php

include_once "/lib/se_step_play.php";

function 
play_marble_machine_song()
{
    global 
$step_play_dir;

    
// test
    
$melody1a step_play_encode("5E2.67 4B2 4A8 4G8 4A4 4B4 4G8 4A8 5D8 R2.67 4B2 4A8 4G8 4A4 4F#4 4G8 4A8 5D8");
    
$melody1b step_play_encode("R2.67 4B2 5D8 5C8 4B4 4A4 4G8 4A8 4E8 R8 4C8 4E8 4B8 3B8 4C8 4D8 5D8 5C8  4B4 4A4 4G8 4A8 5E8");
    
$melody1c step_play_encode("R2.67 4B2 4A8 4G8 4A4 4B4 4G8 4A8 5D8 R2.67 4B2 5D8 5C8 4B4 4A4 4G8 4A8 5D8");
    
$melody1d step_play_encode("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");  

    
$chord1a step_play_encode("3E4 4E2.67 3E8 4E4 3E4 4E2.67 3E8 4E4 3G4 4G2.67 3G8 4G4 3G4 4G2.67 3G8 4G4");
    
$chord1b step_play_encode("3D4 4D2.67 3D8 4D4 3D4 4D2.67 3D8 4D4 3C4 4C2.67 3C8 4C4 3D4 4D2.67 3D8 4D4");
    
$chord1c step_play_encode("3E4 4E2.67 3E8 4E4 3E4 4E2.67 3E8 4E4 3G4 4G2.67 3G8 4G4 3G4 4G2.67 3G8 4G4");
    
$chord1d step_play_encode("3D4 4D2.67 3D8 4D4 3D4 4D2.67 3D8 4D8 3C4 4C2.67 3C8 4C4 3D4 4D2.67 3D8 4D4");  

    
step_play_dir(+1);
    
step_play_harmony($melody1a$chord1a);
    
//step_play_melody($melody1a);
    
step_play_dir(-1);
    
step_play_harmony($melody1b$chord1b);
    
step_play_dir(+1);
    
step_play_harmony($melody1c$chord1c);
    
step_play_dir(-1);
    
step_play_harmony($melody1d$chord1d);

}

spc_reset();
spc_sync_baud(460800);

step_play_setup(013);
step_play_setup(114);
step_play_tempo(38);

play_marble_machine_song();

?>



Library

Two libraries are required for this example. You need the official library sd_spc.php in PHPoC Support Package and the library se_step_play.php for step motor performance.
The library must be located in the /lib folder

se_step_play.php
PHP Code:
<?php

include_once "/lib/sd_spc.php";

$step_play_speed 1000// ms per bar
$step_play_dir = +1;
$step_play_sid = array(0000);

function 
step_play_setup($play_id$sid$vref 8$mode "half"$accel 10000)
{
    global 
$step_play_sid;

    if(
spc_request_sys($sid"get did") != "40002403")
        exit(
"step_play_setup: expansion not found\r\n");

    
spc_request_dev($sid"set vref stop 2");
    
spc_request_dev($sid"set vref goto $vref");
    
spc_request_dev($sid"set mode $mode");
    
spc_request_dev($sid"set accel $accel");

    
$step_play_sid[$play_id] = $sid;
}

function 
step_play_tempo($tempo)
{
    global 
$step_play_speed;

    
$step_play_speed = (int)(1000.0 / ($tempo 60.0));
}

function 
step_play_dir($dir)
{
    global 
$step_play_dir;

    if(
$dir >= 0)
        
$step_play_dir = +1;
    else
        
$step_play_dir = -1;
}

function 
step_play_encode($score)
{
    global 
$step_play_speed;

    
$score_array explode(" "$score);
    
$score_count count($score_array);

    
$score_encoded "";

    for(
$i 0$i $score_count$i++)
    {
        if(!(
$note $score_array[$i]))
            continue;

        if(
strtoupper($note[0]) == "R")
        { 
/* rest */
            
$dur_fp = (float)substr($note1);
            
$dur_ms = (int)round($step_play_speed $dur_fp);

            
$score_encoded .= int2bin(02);
            
$score_encoded .= int2bin($dur_ms2);
        }
        else
        { 
/* tone */
            
$tone = (int)$note[0] * 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(strtoupper($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:
                    exit(
"encode_score: unknown tone '" $note[1] . "'\r\n");
                    break;
            }

            if(
$note[2] == "#")
            {
                
$tone++;
                
$dur_fp = (float)substr($note3);
            }
            else
            if(
$note[2] == "b")
            {
                
$tone--;
                
$dur_fp = (float)substr($note3);
            }
            else
                
$dur_fp = (float)substr($note2);

            
$dur_ms = (int)($step_play_speed $dur_fp);

            
$octave $tone 12;
            
$tone $tone 12;

            
$freqA 440.0 pow(2, ($octave 4));
            
$freq = (int)round($freqA pow(2, ($tone 9) / 12.0));

            
$score_encoded .= int2bin($freq2);
            
$score_encoded .= int2bin($dur_ms2);
        }
    }

    return 
$score_encoded;
}

function 
step_play_melody($melody)
{
    global 
$step_play_dir;
    global 
$step_play_sid;

    while(
$melody)
    {
        
$freq bin2int($melody02);
        
$dur_ms bin2int($melody22);

        if(
$freq)
        {
            if(
$step_play_dir 0)
                
spc_request_dev($step_play_sid[0], "goto +1000000 $freq");
            else
                
spc_request_dev($step_play_sid[0], "goto -1000000 $freq");
            
usleep($dur_ms 1000);
            
spc_request_dev($step_play_sid[0], "stop 0");
        }
        else 
// zero frequency is 'rest'
            
usleep($dur_ms 1000);

        
$melody substr($melody4);
    }
}

function 
step_play_harmony($melody1$melody2)
{
    global 
$step_play_dir;
    global 
$step_play_sid;

    
$pid_st0 pid_open("/mmap/st0");
    
pid_ioctl($pid_st0"start");

    
$melody = array($melody1$melody2);
    
$melody_next_ms = array(00);

    while(
$melody[0] || $melody[1] || $melody_next_ms[0] || $melody_next_ms[1])
    {
        for(
$i 0$i 2$i++)
        {
            if(
$melody_next_ms[$i])
            {
                if(
$melody_next_ms[$i] <= pid_ioctl($pid_st0"get count"))
                {
                    
spc_request_dev($step_play_sid[$i], "stop 0");
                    
$melody_next_ms[$i] = 0;
                }
            }
            else
            {
                if(
$melody[$i])
                {
                    
$freq bin2int($melody[$i], 02);
                    
$dur_ms bin2int($melody[$i], 22);

                    
$melody[$i] = substr($melody[$i], 4);

                    if(
$freq)
                    {
                        if(
$step_play_dir 0)
                            
spc_request_dev($step_play_sid[$i], "goto +1000000 $freq");
                        else
                            
spc_request_dev($step_play_sid[$i], "goto -1000000 $freq");
                    }

                    
$melody_next_ms[$i] = pid_ioctl($pid_st0"get count") + $dur_ms;
                }
            }
        }
    }

    
pid_close($pid_st0);
}

?>