Skip to content

Instantly share code, notes, and snippets.

@user890104
Created February 13, 2019 00:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save user890104/a251ce0ce9837c85ac5ba72c9e6ec35f to your computer and use it in GitHub Desktop.
Save user890104/a251ce0ce9837c85ac5ba72c9e6ec35f to your computer and use it in GitHub Desktop.
Arduino MIDI nodejs stepper motor
<?php
if (
empty($_SERVER['argc']) || empty($_SERVER['argv']) ||
!is_int($_SERVER['argc']) || !is_array($_SERVER['argv']) ||
3 !== $_SERVER['argc'] || 3 !== count($_SERVER['argv'])
)
{
echo 'usage: ', $_SERVER['argv'][0], ' <input> <output>', "\n";
exit;
}
$start_oct = 0;
$end_oct = 9;
$notes = array();
for ($oct = $start_oct; $oct < $end_oct; ++$oct)
{
$notes[$oct] = array();
$notes[$oct][-1] = 0;
for ($note = 0; $note < 12; ++$note)
{
$freq = pow(2, ($oct * 12 + $note - 45) / 12) * 440;
$notes[$oct][$note] = $freq;
}
}
$note_names = array(
'X' => -2,
'P' => -1,
'C' => 0,
'C#' => 1,
'D' => 2,
'D#' => 3,
'E' => 4,
'F' => 5,
'F#' => 6,
'G' => 7,
'G#' => 8,
'A' => 9,
'A#' => 10,
'B' => 11,
);
// ----------------------
$beat_len = 0;
$note_lengths = array(
'1+1+1/4' => 9,
'1+1' => 8,
'1' => 4,
'2.5' => 3,
'2+1/4' => 2.5,
'2' => 2,
'4.5' => 1.5,
'4+1/2' => 1.5,
'4' => 1,
'8' => .5,
'8.5' => .75,
'8+1/2+1/4' => .3 + 5/4,
'16' => .25,
'32' => .125,
);
file_put_contents($_SERVER['argv'][2], '');
$file = file($_SERVER['argv'][1]);
$file = array_map('trim', $file);
$file = array_map('strtoupper', $file);
$result = [];
foreach ($file as $line)
{
if (strlen($line) < 1 || '#' === $line[0])
{
continue;
}
elseif ('T' == $line[0])
{
$beat_len = 60 / trim(substr($line, 1));
continue;
}
if (empty($beat_len))
{
continue;
}
$line = preg_replace('/\s+/', ' ', $line);
@list($note, $oct, $len) = explode(' ', $line);
$note = $note_names[$note];
if (-2 === $note)
{
exit;
}
$len = $note_lengths[$len] * $beat_len;
//file_put_contents($_SERVER['argv'][2], pack('VV', round($notes[$oct][$note] ? 91225 / $notes[$oct][$note] : 0), round($len * 1000000)), FILE_APPEND);
$result[] = [
round($notes[$oct][$note], 2),
round($len * 1000),
];
}
file_put_contents($_SERVER['argv'][2], json_encode($result));
'use strict';
const fs = require('fs');
const midi = require('midi');
const SerialPort = require('serialport');
const Ready = require('@serialport/parser-ready');
const magic = Math.pow(2, 1 / 12);
console.log('[ARDUINO] Opening serial port');
const port = new SerialPort('COM20', {
baudRate: 9600
});
port.on('error', function(err) {
console.log('[ARDUINO] Error: ', err.message)
});
port.on('open', function(err) {
console.log('[ARDUINO] Serial port opened, waiting for Arduino');
});
const parser = port.pipe(new Ready({
delimiter: 'READY'
}));
function sendFreq(freq, callback) {
port.write(freq.toFixed(2) + '\n', callback);
}
// play fixed song
const seq = JSON.parse(fs.readFileSync('notes.txt'));
let idx = 0;
function playSeq() {
if (idx >= seq.length) {
sendFreq(0, function() {
port.close();
});
return;
}
console.log(seq[idx]);
sendFreq(seq[idx][0]);
setTimeout(playSeq, seq[idx][1]);
idx++;
}
/*
parser.on('ready', function() {
console.log('[ARDUINO] Ready for input');
playSeq();
});
*/
// play live stream
let relayMessages = false;
const input = new midi.input();
const inputPortsCount = input.getPortCount();
console.log('[MIDI] Input ports count:', inputPortsCount);
if (inputPortsCount === 0) {
process.exit();
}
console.log('[MIDI] First port name:', input.getPortName(0));
function numberToFreq(number) {
number += 12 * 2;
return 440 * Math.pow(magic, number - 81);
}
let activeNote = 0;
let activeNotes = [];
function noteChange(number, isOn) {
let pos = activeNotes.indexOf(number);
if (pos > -1) {
activeNotes.splice(pos, 1);
}
if (isOn) {
activeNotes.push(number);
}
if (activeNotes.length === 0) {
activeNote = 0;
sendFreq(0);
return;
}
let newNote = activeNotes[activeNotes.length - 1];
if (newNote !== activeNote) {
activeNote = newNote;
sendFreq(numberToFreq(newNote));
}
}
input.on('message', function(deltaTime, message) {
console.log('[MIDI]', message);
if (relayMessages) {
const cmd = message[0];
const num = message[1];
const velocity = message[2];
if (cmd === 0x90) {
if (velocity === 0) {
noteChange(num, 0);
}
else {
noteChange(num, 1);
}
}
if (cmd === 0x80) {
noteChange(num, 0);
}
}
});
input.openPort(0);
parser.on('ready', function() {
console.log('[ARDUINO] Ready for input');
relayMessages = true;
});
# Super Mario theme song
# source: http://gprime.net/images/mariopiano/
# col1 = note, col2 = octave, col3 = duration (1 / x)
# t = tempo (bpm), p = pause
# http://gprime.net/images/mariopiano/smb1maintheme1_4.png
t 216
e 5 8
e 5 8
p 0 8
e 5 8
p 0 8
c 5 8
e 5 8
p 0 8
g 5 4
p 0 4
g 4 4
p 0 4
c 5 4
p 0 8
g 4 4
p 0 8
e 4 4
p 0 8
a 4 8
p 0 8
b 4 8
p 0 8
a# 4 8
a 4 8
p 0 8
g 4 8
e 5 8
p 0 8
g 5 8
a 5 8
p 0 8
f 5 8
g 5 8
p 0 8
e 5 8
p 0 8
c 5 8
d 5 8
b 4 8
p 0 4
c 5 4
p 0 8
g 4 4
p 0 8
e 4 4
p 0 8
a 4 8
p 0 8
b 4 8
p 0 8
a# 4 8
a 4 8
p 0 8
g 4 8
e 5 8
p 0 8
g 5 8
a 5 8
p 0 8
f 5 8
g 5 8
p 0 8
e 5 8
p 0 8
c 5 8
d 5 8
b 4 8
p 0 4
p 0 4
g 5 8
f# 5 8
f 5 8
d# 5 8
p 0 8
e 5 8
p 0 8
g# 4 8
a 4 8
c 5 8
p 0 8
a 4 8
c 5 8
d 5 8
p 0 4
g 5 8
f# 5 8
f 5 8
d# 5 8
p 0 8
e 5 8
p 0 8
c 6 8
p 0 8
c 6 8
c 6 4
p 0 4
p 0 4
g 5 8
f# 5 8
f 5 8
d# 5 8
p 0 8
e 5 8
p 0 8
g# 4 8
a 4 8
c 5 8
p 0 8
a 4 8
c 5 8
d 5 8
p 0 4
d# 5 4
p 0 8
d 5 4
p 0 8
c 5 2
p 0 2
p 0 4
g 5 8
f# 5 8
f 5 8
d# 5 8
p 0 8
e 5 8
p 0 8
g# 4 8
a 4 8
c 5 8
p 0 8
a 4 8
c 5 8
d 5 8
p 0 4
g 5 8
f# 5 8
f 5 8
d# 5 8
p 0 8
e 5 8
# http://gprime.net/images/mariopiano/smb1maintheme2_4.png
p 0 8
c 6 8
p 0 8
c 6 8
c 6 4
p 0 4
p 0 4
g 5 8
f# 5 8
f 5 8
d# 5 8
p 0 8
e 5 8
p 0 8
g# 4 8
a 4 8
c 5 8
p 0 8
a 4 8
c 5 8
d 5 8
p 0 4
d# 5 4
p 0 8
d 5 4
p 0 8
c 5 2
p 0 2
c 5 8
c 5 8
p 0 8
c 5 8
p 0 8
c 5 8
d 5 8
p 0 8
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
c 5 8
c 5 8
p 0 8
c 5 8
p 0 8
c 5 8
d 5 8
e 5 8
p 0 1
c 5 8
c 5 8
p 0 8
c 5 8
p 0 8
c 5 8
d 5 8
p 0 8
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
e 5 8
e 5 8
p 0 8
e 5 8
p 0 8
c 5 8
e 5 8
p 0 8
g 5 4
p 0 4
g 4 4
p 0 4
c 5 4
p 0 8
g 4 4
p 0 8
e 4 4
p 0 8
a 4 8
p 0 8
b 4 8
p 0 8
a# 4 8
a 4 8
p 0 8
g 4 8
e 5 8
p 0 8
g 5 8
a 5 8
p 0 8
f 5 8
g 5 8
p 0 8
e 5 8
p 0 8
c 5 8
d 5 8
b 4 8
p 0 4
c 5 4
p 0 8
g 4 4
p 0 8
e 4 4
p 0 8
a 4 8
p 0 8
b 4 8
p 0 8
a# 4 8
a 4 8
p 0 8
g 4 8
e 5 8
p 0 8
g 5 8
a 5 8
p 0 8
f 5 8
g 5 8
p 0 8
e 5 8
p 0 8
c 5 8
d 5 8
b 4 8
p 0 4
e 5 8
c 5 8
p 0 8
g 4 8
p 0 4
g# 4 8
p 0 8
# http://gprime.net/images/mariopiano/smb1maintheme3_4.png
a 4 8
f 5 8
p 0 8
f 5 8
a 4 4
p 0 4
b 4 8
a 5 8
p 0 8
a 5 8
a 5 8
g 5 8
p 0 8
f 5 8
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
e 5 8
c 5 8
p 0 8
g 4 8
p 0 4
g# 4 8
p 0 8
a 4 8
f 5 8
p 0 8
f 5 8
a 4 4
p 0 4
b 4 8
f 5 8
p 0 8
f 5 8
f 5 8
e 5 8
p 0 8
d 5 8
c 5 2
p 0 2
e 5 8
c 5 8
p 0 8
g 4 8
p 0 4
g# 4 8
p 0 8
a 4 8
f 5 8
p 0 8
f 5 8
a 4 4
p 0 4
b 4 8
a 5 8
p 0 8
a 5 8
a 5 8
g 5 8
p 0 8
f 5 8
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
e 5 8
c 5 8
p 0 8
g 4 8
p 0 4
g# 4 8
p 0 8
a 4 8
f 5 8
p 0 8
f 5 8
a 4 4
p 0 4
b 4 8
f 5 8
p 0 8
f 5 8
f 5 8
e 5 8
p 0 8
d 5 8
c 5 2
p 0 2
c 5 8
c 5 8
p 0 8
c 5 8
p 0 8
c 5 8
d 5 8
p 0 8
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
c 5 8
c 5 8
p 0 8
c 5 8
p 0 8
c 5 8
d 5 8
e 5 8
p 0 1
c 5 8
c 5 8
p 0 8
c 5 8
p 0 8
c 5 8
d 5 8
p 0 8
# http://gprime.net/images/mariopiano/smb1maintheme4_4.png
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
e 5 8
e 5 8
p 0 8
e 5 8
p 0 8
c 5 8
e 5 8
p 0 8
g 5 4
p 0 4
g 4 4
p 0 4
e 5 8
c 5 8
p 0 8
g 4 8
p 0 4
g# 4 8
p 0 8
a 4 8
f 5 8
p 0 8
f 5 8
a 4 4
p 0 4
b 4 8
a 5 8
p 0 8
a 5 8
a 5 8
g 5 8
p 0 8
f 5 8
e 5 8
c 5 8
p 0 8
a 4 8
g 4 4
p 0 4
e 5 8
c 5 8
p 0 8
g 4 8
p 0 4
g# 4 8
p 0 8
a 4 8
f 5 8
p 0 8
f 5 8
a 4 4
p 0 4
b 4 8
f 5 8
p 0 8
f 5 8
f 5 8
e 5 8
p 0 8
d 5 8
c 5 2
p 0 2
c 5 4.5
g 4 4.5
e 4 4
a 4 4
b 4 4
a 4 4
g# 4 4
a# 4 4
a 4 4
g 4 1
[[1318.51,139],[1318.51,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1318.51,139],[0,139],[1567.98,278],[0,278],[783.99,278],[0,278],[1046.5,278],[0,139],[783.99,278],[0,139],[659.26,278],[0,139],[880,139],[0,139],[987.77,139],[0,139],[932.33,139],[880,139],[0,139],[783.99,139],[1318.51,139],[0,139],[1567.98,139],[1760,139],[0,139],[1396.91,139],[1567.98,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1174.66,139],[987.77,139],[0,278],[1046.5,278],[0,139],[783.99,278],[0,139],[659.26,278],[0,139],[880,139],[0,139],[987.77,139],[0,139],[932.33,139],[880,139],[0,139],[783.99,139],[1318.51,139],[0,139],[1567.98,139],[1760,139],[0,139],[1396.91,139],[1567.98,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1174.66,139],[987.77,139],[0,278],[0,278],[1567.98,139],[1479.98,139],[1396.91,139],[1244.51,139],[0,139],[1318.51,139],[0,139],[830.61,139],[880,139],[1046.5,139],[0,139],[880,139],[1046.5,139],[1174.66,139],[0,278],[1567.98,139],[1479.98,139],[1396.91,139],[1244.51,139],[0,139],[1318.51,139],[0,139],[2093,139],[0,139],[2093,139],[2093,278],[0,278],[0,278],[1567.98,139],[1479.98,139],[1396.91,139],[1244.51,139],[0,139],[1318.51,139],[0,139],[830.61,139],[880,139],[1046.5,139],[0,139],[880,139],[1046.5,139],[1174.66,139],[0,278],[1244.51,278],[0,139],[1174.66,278],[0,139],[1046.5,556],[0,556],[0,278],[1567.98,139],[1479.98,139],[1396.91,139],[1244.51,139],[0,139],[1318.51,139],[0,139],[830.61,139],[880,139],[1046.5,139],[0,139],[880,139],[1046.5,139],[1174.66,139],[0,278],[1567.98,139],[1479.98,139],[1396.91,139],[1244.51,139],[0,139],[1318.51,139],[0,139],[2093,139],[0,139],[2093,139],[2093,278],[0,278],[0,278],[1567.98,139],[1479.98,139],[1396.91,139],[1244.51,139],[0,139],[1318.51,139],[0,139],[830.61,139],[880,139],[1046.5,139],[0,139],[880,139],[1046.5,139],[1174.66,139],[0,278],[1244.51,278],[0,139],[1174.66,278],[0,139],[1046.5,556],[0,556],[1046.5,139],[1046.5,139],[0,139],[1046.5,139],[0,139],[1046.5,139],[1174.66,139],[0,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1046.5,139],[1046.5,139],[0,139],[1046.5,139],[0,139],[1046.5,139],[1174.66,139],[1318.51,139],[0,1111],[1046.5,139],[1046.5,139],[0,139],[1046.5,139],[0,139],[1046.5,139],[1174.66,139],[0,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1318.51,139],[1318.51,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1318.51,139],[0,139],[1567.98,278],[0,278],[783.99,278],[0,278],[1046.5,278],[0,139],[783.99,278],[0,139],[659.26,278],[0,139],[880,139],[0,139],[987.77,139],[0,139],[932.33,139],[880,139],[0,139],[783.99,139],[1318.51,139],[0,139],[1567.98,139],[1760,139],[0,139],[1396.91,139],[1567.98,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1174.66,139],[987.77,139],[0,278],[1046.5,278],[0,139],[783.99,278],[0,139],[659.26,278],[0,139],[880,139],[0,139],[987.77,139],[0,139],[932.33,139],[880,139],[0,139],[783.99,139],[1318.51,139],[0,139],[1567.98,139],[1760,139],[0,139],[1396.91,139],[1567.98,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1174.66,139],[987.77,139],[0,278],[1318.51,139],[1046.5,139],[0,139],[783.99,139],[0,278],[830.61,139],[0,139],[880,139],[1396.91,139],[0,139],[1396.91,139],[880,278],[0,278],[987.77,139],[1760,139],[0,139],[1760,139],[1760,139],[1567.98,139],[0,139],[1396.91,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1318.51,139],[1046.5,139],[0,139],[783.99,139],[0,278],[830.61,139],[0,139],[880,139],[1396.91,139],[0,139],[1396.91,139],[880,278],[0,278],[987.77,139],[1396.91,139],[0,139],[1396.91,139],[1396.91,139],[1318.51,139],[0,139],[1174.66,139],[1046.5,556],[0,556],[1318.51,139],[1046.5,139],[0,139],[783.99,139],[0,278],[830.61,139],[0,139],[880,139],[1396.91,139],[0,139],[1396.91,139],[880,278],[0,278],[987.77,139],[1760,139],[0,139],[1760,139],[1760,139],[1567.98,139],[0,139],[1396.91,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1318.51,139],[1046.5,139],[0,139],[783.99,139],[0,278],[830.61,139],[0,139],[880,139],[1396.91,139],[0,139],[1396.91,139],[880,278],[0,278],[987.77,139],[1396.91,139],[0,139],[1396.91,139],[1396.91,139],[1318.51,139],[0,139],[1174.66,139],[1046.5,556],[0,556],[1046.5,139],[1046.5,139],[0,139],[1046.5,139],[0,139],[1046.5,139],[1174.66,139],[0,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1046.5,139],[1046.5,139],[0,139],[1046.5,139],[0,139],[1046.5,139],[1174.66,139],[1318.51,139],[0,1111],[1046.5,139],[1046.5,139],[0,139],[1046.5,139],[0,139],[1046.5,139],[1174.66,139],[0,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1318.51,139],[1318.51,139],[0,139],[1318.51,139],[0,139],[1046.5,139],[1318.51,139],[0,139],[1567.98,278],[0,278],[783.99,278],[0,278],[1318.51,139],[1046.5,139],[0,139],[783.99,139],[0,278],[830.61,139],[0,139],[880,139],[1396.91,139],[0,139],[1396.91,139],[880,278],[0,278],[987.77,139],[1760,139],[0,139],[1760,139],[1760,139],[1567.98,139],[0,139],[1396.91,139],[1318.51,139],[1046.5,139],[0,139],[880,139],[783.99,278],[0,278],[1318.51,139],[1046.5,139],[0,139],[783.99,139],[0,278],[830.61,139],[0,139],[880,139],[1396.91,139],[0,139],[1396.91,139],[880,278],[0,278],[987.77,139],[1396.91,139],[0,139],[1396.91,139],[1396.91,139],[1318.51,139],[0,139],[1174.66,139],[1046.5,556],[0,556],[1046.5,417],[783.99,417],[659.26,278],[880,278],[987.77,278],[880,278],[830.61,278],[932.33,278],[880,278],[783.99,1111]]
{
"name": "music",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"midi": "^0.9.5",
"serialport": "^7.1.4"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
#include <Stepper.h>
const float degreesOfStep = 1.875;
const int stepsPerRevolution = 360 / degreesOfStep; // change this to fit the number of steps per revolution for your motor
float revsPerMinute = 0;
// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);
void setup() {
Serial.begin(9600);
Serial.println("READY");
}
void loop() {
if (Serial.available()) {
String line = Serial.readStringUntil(10);
Serial.println("ECHO: " + line);
float freq = line.toFloat();
float revsPerSecond = freq / stepsPerRevolution;
revsPerMinute = revsPerSecond * 60;
// set the motor speed:
myStepper.setSpeed(revsPerMinute);
if (revsPerMinute == 0) {
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
}
}
// step 1/100 of a revolution:
if (revsPerMinute > 0) {
myStepper.step(1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment