diff --git a/Midi/arduino-midi-player-master/.gitignore b/Midi/arduino-midi-player-master/.gitignore new file mode 100644 index 0000000..dcc58d2 --- /dev/null +++ b/Midi/arduino-midi-player-master/.gitignore @@ -0,0 +1,5 @@ +*.mid +.DS_Store +sequence.h +*.json + diff --git a/Midi/arduino-midi-player-master/LICENSE b/Midi/arduino-midi-player-master/LICENSE new file mode 100644 index 0000000..856ce47 --- /dev/null +++ b/Midi/arduino-midi-player-master/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2016 ilufang + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Midi/arduino-midi-player-master/README.md b/Midi/arduino-midi-player-master/README.md new file mode 100644 index 0000000..118fe78 --- /dev/null +++ b/Midi/arduino-midi-player-master/README.md @@ -0,0 +1,45 @@ +Arduino MIDI Player +=================== + +This program plays MIDI music on Arduino by generating analog/PWM waves on a port connected to a speaker/buzzer. We use timer 2 to do direct digital synthesis (DDS). + +Features +-------- + +- **Chords/multiple notes!** The DDS can add multiple waves together on a single timer and single port. Unlike `tone()` which you can only run one frequency at any time. +- **Sine waves!** You can define any arbitrary function/wave sample to use as the instrument in `smf2seq.js`. No more square waves of the built-in `tone()` function. +- **Tested on UNO!** Though it might not work directly on other models, after some modification the concept should work on any Arduino. (since UNO is the crappiest model) + + +How to use +---------- + +**Hardware** + +1. Connect buzzer/speaker to PWM port 11. Use a proper resister. +2. A variable-resistance resister is recommended to adjust the volume. +3. (Optional) Connect LEDs to port 2-7. +4. Ground everything. + +**Software** + +1. Place your `.mid` file under the main directory +2. Run `node smf2seq.js ` to generate `sequence.h` (You will need to install node.js if you don't have one) +3. Open `arduino-midi-player.ino` in Arduino IDE +4. Compile & Upload + +Limitations +----------- + +Due to the hardware of Arduino, your MIDI might not work perfectly. (Apparently an Arduino UNO will NEVER be able to handle a black MIDI) + +- **Large files.** The max internal storage is 32KB and `smf2seq.js` use 6 bytes for each note. +- **Short time intervals/High BPM.** 1/2048 notes will not likely to play because of the internal clock +- **High/Low pitches.** The clock might not be fast enough to generate a desired wave of the specified frequency +- **Complex chords.** The clock interrupt cannot only process a limit number (4-6) of notes within the clock interval. Lower notes that exceed the limit of `KEYBUF_SIZE` will be discarded +- **Instruments.** MIDI instruments will be disregarded and everything will be sine waves + +Notes +----- + +- macros like `sbi`, `cbi`, `OCR2A` are used instead of API functions like `digitalWrite` to improve performance. Google them for more details diff --git a/Midi/arduino-midi-player-master/arduino-midi-player.ino b/Midi/arduino-midi-player-master/arduino-midi-player.ino new file mode 100644 index 0000000..6680095 --- /dev/null +++ b/Midi/arduino-midi-player-master/arduino-midi-player.ino @@ -0,0 +1,135 @@ +/* + * Arduino MIDI Player + * + * Setup Arduino and use timer2 to synthesize and output sine wave + * + * 2016 by ilufang + */ + +/* + * Part of this file contains code modified/referenced from + * http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-dds-sinewave-generator/ + * + * DDS Sine Generator mit ATMEGS 168 + * Timer2 generates the 31250 KHz Clock Interrupt + * + * KHM 2009 / Martin Nawrath + * Kunsthochschule fuer Medien Koeln + * Academy of Media Arts Cologne + */ + +#include "avr/pgmspace.h" + +#include "midi2wave.h" + +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) + +#define POW2_32 4294967296 +#define refclk 31376.6 // Reference clock + +// variables in interrupt service +volatile int timer_tick = 0; // seeking position in wave +volatile unsigned char timer_micro = 0; // timing counter in microseconds +volatile unsigned short timer_milli = 0; // timing counter in milliseconds +volatile unsigned long phaccu_1, phaccu_2, phaccu_3, phaccu_4, phaccu_5, phaccu_6, phaccu_7, phaccu_8; // phase accumulator +volatile unsigned long tword_m_1, tword_m_2, tword_m_3, tword_m_4, tword_m_5, tword_m_6, tword_m_7, tword_m_8; // DDS tuning word m +unsigned long phaccu_all; + +void setup() +{ + Serial.begin(9600); + Serial.println("Hello"); + for (int i = 2; i <= 8; ++i) + pinMode(i,OUTPUT); // LED output + + pinMode(11,OUTPUT); // PWM Wave output + setupMidi(); + setupTimer2(); +} + +void loop() +{ + while(true) { + if (timer_milli > event_length) { // wait for the next midi event + cbi (TIMSK2,TOIE2); + loadNextEvent(); + // calculate new DDS tuning word + tword_m_1=POW2_32*PIANO(active_keys[0])/refclk; + tword_m_2=POW2_32*PIANO(active_keys[1])/refclk; + tword_m_3=POW2_32*PIANO(active_keys[2])/refclk; + tword_m_4=POW2_32*PIANO(active_keys[3])/refclk; + if (!tword_m_1) phaccu_1 = 0; + if (!tword_m_2) phaccu_2 = 0; + if (!tword_m_3) phaccu_3 = 0; + if (!tword_m_4) phaccu_4 = 0; + timer_milli=0; + sbi (TIMSK2,TOIE2); + } + } +} + +/* + * timer2 setup + * + * set pre-scaler to 1, PWM mode to phase correct PWM, 16000000/510 = 31372.55 Hz clock + */ +void setupTimer2() { + // Timer2 Clock Pre-scaler to : 1 + sbi (TCCR2B, CS20); + cbi (TCCR2B, CS21); + cbi (TCCR2B, CS22); + + // Timer2 PWM Mode set to Phase Correct PWM + cbi (TCCR2A, COM2A0); // clear Compare Match + sbi (TCCR2A, COM2A1); + + sbi (TCCR2A, WGM20); // Mode 1 / Phase Correct PWM + cbi (TCCR2A, WGM21); + cbi (TCCR2B, WGM22); + + // initialize DDS tuning word + tword_m_1=0; + tword_m_2=0; + tword_m_3=0; + tword_m_4=0; + + // disable Timer0 interrupts to avoid timing distortion + cbi (TIMSK0,TOIE0); + // start Timer2! + sbi (TIMSK2,TOIE2); + +} + +/* + * Timer2 Interrupt Service + * + * Running at 31372,550 KHz = 32uSec + * this is the timebase REFCLOCK for the DDS generator + * FOUT = (M (REFCLK)) / (2 exp 32) + * runtime : 8 microseconds ( inclusive push and pop) + */ +ISR(TIMER2_OVF_vect) { + // soft DDS, phase accumulator with 32 bits + phaccu_1 += tword_m_1; + phaccu_2 += tword_m_2; + phaccu_3 += tword_m_3; + phaccu_4 += tword_m_4; + phaccu_5 += tword_m_5; + + // use upper 8 bits for phase accumulator as frequency information + int phaccu_all = sine[phaccu_1>>24]; + phaccu_all += sine[phaccu_2>>24]; + phaccu_all += sine[phaccu_3>>24]; + phaccu_all += sine[phaccu_4>>24]; + phaccu_all += sine[phaccu_5>>24]; + + // Write to PWM port 11 + OCR2A = phaccu_all/KEYBUF_SIZE; + + // Increment timing counter + if(++timer_micro == 31) { + ++timer_milli; + timer_micro=0; + } +} diff --git a/Midi/arduino-midi-player-master/jasmid/LICENSE b/Midi/arduino-midi-player-master/jasmid/LICENSE new file mode 100644 index 0000000..407a442 --- /dev/null +++ b/Midi/arduino-midi-player-master/jasmid/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2010, Matt Westcott & Ben Firshman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The names of its contributors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Midi/arduino-midi-player-master/jasmid/README b/Midi/arduino-midi-player-master/jasmid/README new file mode 100644 index 0000000..e877b12 --- /dev/null +++ b/Midi/arduino-midi-player-master/jasmid/README @@ -0,0 +1,51 @@ +# Midifile.js + +This module parses the Standard Midi File. + +The code was modified to adapt to the 'require' way of nodejs. Irrelevant code have been removed. + +The SMF parser part of the jasmid project is used. See jasmid's README and LICENSE for more info + +Jasmid's original repository: https://github.com/gasman/jasmid + +# JASMID Original Readme + +``` +jasmid - A Javascript MIDI file reader and synthesiser + +Originally presented at BarCamp London 8, 13-14 November 2010 + +Instructions: +Open index.html in browser. Turn up volume. Click on link. + +Sound output is via one of the following mechanisms, according to what your +browser supports: +* Mozilla Audio Data API +* Web Audio API + +* a Flash fallback originally taken from dynamicaudio.js by Ben Firshman + and hacked around by me. + + +The code: +stream.js - helper library for reading a string as a stream of typed data +midifile.js - parses the MIDI file format into a header and a list of tracks, + each consisting of a list of event objects +replayer.js - steps over the data structure generated by midifile.js and calls + the appropriate operations on the synthesiser +synth.js - audio synthesiser; generates waveforms according to tweakable + parameters +audio.js - passes the generated waveform to either the Audio Data API or the + Flash fallback widget (da.swf) + + +Limitations: +* The only event types supported by replayer.js are note on, note off, tempo + change and program change +* There are currently only two instrument presets defined in synth.js - one for + strings and a 'piano' one for everything else - and neither of them are + particularly good (just a single volume-modulated sine wave). + + +Matt Westcott - @gasmanic - http://matt.west.co.tt/ +``` diff --git a/Midi/arduino-midi-player-master/jasmid/midifile.js b/Midi/arduino-midi-player-master/jasmid/midifile.js new file mode 100644 index 0000000..f239e4c --- /dev/null +++ b/Midi/arduino-midi-player-master/jasmid/midifile.js @@ -0,0 +1,241 @@ +// This file has been converted for node 'require' +/* +class to parse the .mid file format +(depends on stream.js) +*/ +var Stream = require("./stream.js"); + +module.exports = function(data) { + function readChunk(stream) { + var id = stream.read(4); + var length = stream.readInt32(); + return { + 'id': id, + 'length': length, + 'data': stream.read(length) + }; + } + + var lastEventTypeByte; + + function readEvent(stream) { + var event = {}; + event.deltaTime = stream.readVarInt(); + var eventTypeByte = stream.readInt8(); + if ((eventTypeByte & 0xf0) == 0xf0) { + /* system / meta event */ + if (eventTypeByte == 0xff) { + /* meta event */ + event.type = 'meta'; + var subtypeByte = stream.readInt8(); + var length = stream.readVarInt(); + switch(subtypeByte) { + case 0x00: + event.subtype = 'sequenceNumber'; + if (length != 2) throw "Expected length for sequenceNumber event is 2, got " + length; + event.number = stream.readInt16(); + return event; + case 0x01: + event.subtype = 'text'; + event.text = stream.read(length); + return event; + case 0x02: + event.subtype = 'copyrightNotice'; + event.text = stream.read(length); + return event; + case 0x03: + event.subtype = 'trackName'; + event.text = stream.read(length); + return event; + case 0x04: + event.subtype = 'instrumentName'; + event.text = stream.read(length); + return event; + case 0x05: + event.subtype = 'lyrics'; + event.text = stream.read(length); + return event; + case 0x06: + event.subtype = 'marker'; + event.text = stream.read(length); + return event; + case 0x07: + event.subtype = 'cuePoint'; + event.text = stream.read(length); + return event; + case 0x20: + event.subtype = 'midiChannelPrefix'; + if (length != 1) throw "Expected length for midiChannelPrefix event is 1, got " + length; + event.channel = stream.readInt8(); + return event; + case 0x2f: + event.subtype = 'endOfTrack'; + if (length != 0) throw "Expected length for endOfTrack event is 0, got " + length; + return event; + case 0x51: + event.subtype = 'setTempo'; + if (length != 3) throw "Expected length for setTempo event is 3, got " + length; + event.microsecondsPerBeat = ( + (stream.readInt8() << 16) + + (stream.readInt8() << 8) + + stream.readInt8() + ) + return event; + case 0x54: + event.subtype = 'smpteOffset'; + if (length != 5) throw "Expected length for smpteOffset event is 5, got " + length; + var hourByte = stream.readInt8(); + event.frameRate = { + 0x00: 24, 0x20: 25, 0x40: 29, 0x60: 30 + }[hourByte & 0x60]; + event.hour = hourByte & 0x1f; + event.min = stream.readInt8(); + event.sec = stream.readInt8(); + event.frame = stream.readInt8(); + event.subframe = stream.readInt8(); + return event; + case 0x58: + event.subtype = 'timeSignature'; + if (length != 4) throw "Expected length for timeSignature event is 4, got " + length; + event.numerator = stream.readInt8(); + event.denominator = Math.pow(2, stream.readInt8()); + event.metronome = stream.readInt8(); + event.thirtyseconds = stream.readInt8(); + return event; + case 0x59: + event.subtype = 'keySignature'; + if (length != 2) throw "Expected length for keySignature event is 2, got " + length; + event.key = stream.readInt8(true); + event.scale = stream.readInt8(); + return event; + case 0x7f: + event.subtype = 'sequencerSpecific'; + event.data = stream.read(length); + return event; + default: + // console.log("Unrecognised meta event subtype: " + subtypeByte); + event.subtype = 'unknown' + event.data = stream.read(length); + return event; + } + event.data = stream.read(length); + return event; + } else if (eventTypeByte == 0xf0) { + event.type = 'sysEx'; + var length = stream.readVarInt(); + event.data = stream.read(length); + return event; + } else if (eventTypeByte == 0xf7) { + event.type = 'dividedSysEx'; + var length = stream.readVarInt(); + event.data = stream.read(length); + return event; + } else { + throw "Unrecognised MIDI event type byte: " + eventTypeByte; + } + } else { + /* channel event */ + var param1; + if ((eventTypeByte & 0x80) == 0) { + /* running status - reuse lastEventTypeByte as the event type. + eventTypeByte is actually the first parameter + */ + param1 = eventTypeByte; + eventTypeByte = lastEventTypeByte; + } else { + param1 = stream.readInt8(); + lastEventTypeByte = eventTypeByte; + } + var eventType = eventTypeByte >> 4; + event.channel = eventTypeByte & 0x0f; + event.type = 'channel'; + switch (eventType) { + case 0x08: + event.subtype = 'noteOff'; + event.noteNumber = param1; + event.velocity = stream.readInt8(); + return event; + case 0x09: + event.noteNumber = param1; + event.velocity = stream.readInt8(); + if (event.velocity == 0) { + event.subtype = 'noteOff'; + } else { + event.subtype = 'noteOn'; + } + return event; + case 0x0a: + event.subtype = 'noteAftertouch'; + event.noteNumber = param1; + event.amount = stream.readInt8(); + return event; + case 0x0b: + event.subtype = 'controller'; + event.controllerType = param1; + event.value = stream.readInt8(); + return event; + case 0x0c: + event.subtype = 'programChange'; + event.programNumber = param1; + return event; + case 0x0d: + event.subtype = 'channelAftertouch'; + event.amount = param1; + return event; + case 0x0e: + event.subtype = 'pitchBend'; + event.value = param1 + (stream.readInt8() << 7); + return event; + default: + throw "Unrecognised MIDI event type: " + eventType + /* + console.log("Unrecognised MIDI event type: " + eventType); + stream.readInt8(); + event.subtype = 'unknown'; + return event; + */ + } + } + } + + stream = Stream(data); + var headerChunk = readChunk(stream); + if (headerChunk.id != 'MThd' || headerChunk.length != 6) { + throw "Bad .mid file - header not found"; + } + var headerStream = Stream(headerChunk.data); + var formatType = headerStream.readInt16(); + var trackCount = headerStream.readInt16(); + var timeDivision = headerStream.readInt16(); + + if (timeDivision & 0x8000) { + throw "Expressing time division in SMTPE frames is not supported yet" + } else { + ticksPerBeat = timeDivision; + } + + var header = { + 'formatType': formatType, + 'trackCount': trackCount, + 'ticksPerBeat': ticksPerBeat + } + var tracks = []; + for (var i = 0; i < header.trackCount; i++) { + tracks[i] = []; + var trackChunk = readChunk(stream); + if (trackChunk.id != 'MTrk') { + throw "Unexpected chunk - expected MTrk, got "+ trackChunk.id; + } + var trackStream = Stream(trackChunk.data); + while (!trackStream.eof()) { + var event = readEvent(trackStream); + tracks[i].push(event); + //console.log(event); + } + } + + return { + 'header': header, + 'tracks': tracks + } +} diff --git a/Midi/arduino-midi-player-master/jasmid/stream.js b/Midi/arduino-midi-player-master/jasmid/stream.js new file mode 100644 index 0000000..291f134 --- /dev/null +++ b/Midi/arduino-midi-player-master/jasmid/stream.js @@ -0,0 +1,71 @@ +// This file has been converted for node 'require' + +/* Wrapper for accessing strings through sequential reads */ +module.exports = function(str) { + var position = 0; + + function read(length) { + var result = str.substr(position, length); + position += length; + return result; + } + + /* read a big-endian 32-bit integer */ + function readInt32() { + var result = ( + (str.charCodeAt(position) << 24) + + (str.charCodeAt(position + 1) << 16) + + (str.charCodeAt(position + 2) << 8) + + str.charCodeAt(position + 3)); + position += 4; + return result; + } + + /* read a big-endian 16-bit integer */ + function readInt16() { + var result = ( + (str.charCodeAt(position) << 8) + + str.charCodeAt(position + 1)); + position += 2; + return result; + } + + /* read an 8-bit integer */ + function readInt8(signed) { + var result = str.charCodeAt(position); + if (signed && result > 127) result -= 256; + position += 1; + return result; + } + + function eof() { + return position >= str.length; + } + + /* read a MIDI-style variable-length integer + (big-endian value in groups of 7 bits, + with top bit set to signify that another byte follows) + */ + function readVarInt() { + var result = 0; + while (true) { + var b = readInt8(); + if (b & 0x80) { + result += (b & 0x7f); + result <<= 7; + } else { + /* b is the last byte */ + return result + b; + } + } + } + + return { + 'eof': eof, + 'read': read, + 'readInt32': readInt32, + 'readInt16': readInt16, + 'readInt8': readInt8, + 'readVarInt': readVarInt + } +} diff --git a/Midi/arduino-midi-player-master/midi2wave.h b/Midi/arduino-midi-player-master/midi2wave.h new file mode 100644 index 0000000..33662ca --- /dev/null +++ b/Midi/arduino-midi-player-master/midi2wave.h @@ -0,0 +1,58 @@ +/* + * Midi2Wave + * + * Playback controller + * + * Load MIDI events into the global variable + */ + +#ifndef __MIDI2WAVE_H__ +#define __MIDI2WAVE_H__ + +#include "sequence.h" + +#define MAX_NOTE 128 +#define KEYBUF_SIZE 5 +#define SINE_SAMPLE_SIZE 256 + +#define PIANO(key) (key?(pow(1.0594630943592952645618252949463,key+1-32-49+24)*440):0) + +#define NOTE_NUMBER(index) pgm_read_byte_near(notes+index) +#define NOTE_DELAY(index) (pgm_read_word_near(params+index)>>4) +#define NOTE_VEL(index) (pgm_read_word_near(params+index)&15) + +unsigned char volatile active_keys[KEYBUF_SIZE]; +unsigned char volatile key_vels[MAX_NOTE]; + +volatile char note_count = 0; + +// The current length in milliseconds +int event_length = 0; + +// The primary key +char key = 61; + +/* + * Setup + * + * Initialize stuff + */ +void setupMidi(); + +/* + * Render wave buffer + * + * Generate the wave buffer with current notes + */ +void renderWaveBuffer(); + +/* + * Load next event + * + * Load the next midi note/chord + * Updates the next delay variable + * Updates LEDs + */ +void loadNextEvent(); + +#endif diff --git a/Midi/arduino-midi-player-master/midi2wave.ino b/Midi/arduino-midi-player-master/midi2wave.ino new file mode 100644 index 0000000..5d78e2f --- /dev/null +++ b/Midi/arduino-midi-player-master/midi2wave.ino @@ -0,0 +1,84 @@ +/* + * Midi2Wave + * + * Implementation + */ + + +#include "midi2wave.h" + +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) + +short ptr; + +void setupMidi() { + for (int i=0; i=0; --i) // Goes down: make sure the most significant note gets played + if ( key_vels[i] && !(key_vels[i]&32) ) { + for (char j=0; j= SONG_LEN) + { + // Restart in 3s + Serial.println("Ended."); + setupMidi(); + event_length = 3000; + for (int i = 0; i < 7; ++i) + sbi(PORTD, i+2); + return; + } + + int new_length = NOTE_DELAY(ptr)*TEMPO; + key_vels[NOTE_NUMBER(ptr)-1] = NOTE_VEL(ptr); + + ++ptr; + if (new_length == 0) + loadNextEvent(); + else { + renderWaveBuffer(); + event_length = new_length; + } +} diff --git a/Midi/arduino-midi-player-master/smf2seq.js b/Midi/arduino-midi-player-master/smf2seq.js new file mode 100644 index 0000000..018a8de --- /dev/null +++ b/Midi/arduino-midi-player-master/smf2seq.js @@ -0,0 +1,152 @@ +/* + * SMF to SEQ + * + * Convert Standard MIDI file to event array + * Output file as sequence.h: to be compiled with ino files + * + * This program uses part of jasmid to decode and parse .mid files + * Please refer to jasmid/LICENSE for the jasmid license + * + * Run this file with node.js + * $ node smf2seq.js [SMF filename] + * + * 2016 by ilufang + */ + +Midifile = require("./jasmid/midifile.js"); +fs = require("fs"); + +// # Read and parse SMF +var filename = process.argv[2]?process.argv[2]:"song.mid"; +var midi_blob = fs.readFileSync(filename); +var t = ""; +for (var i=0; i 127) + seq[i].velocity = 127; + notes.push(seq[i].noteNumber); + note_params.push((seq[i].deltaTime<<4)+(seq[i].velocity>>3)); + } + } +} + +fs.writeFileSync("midi.json", JSON.stringify(seq, null, '\t')); + +// # Generate sin table +var file = "// MIDI events\n// Generated by smf2seq.js\n"; + +var sine_sample = [], sine_sample_size = 256; +for (var i = 0; i < sine_sample_size; i++) { + sine_sample.push(128+Math.round(128*Math.sin(2*Math.PI*i/sine_sample_size))); +} + +file += "const unsigned char sine[] = {"+sine_sample.join(",")+"};\n"; +file += "#define TEMPO "+tempo+"\n"; +file += "#define SONG_LEN "+notes.length+"\n"; +file += "PROGMEM const unsigned char notes[] = {"+notes.join(",")+"};\n"; +file += "PROGMEM const int params[] = {"+note_params.join(",")+"};\n"; + +console.log("Using memory: "+(notes.length*3)); +console.log("Total memory: 32256"); + +// # Write to file +fs.writeFileSync("sequence.h",file); diff --git a/Midi/mg/AVR.INC b/Midi/mg/AVR.INC new file mode 100644 index 0000000..85a7003 --- /dev/null +++ b/Midi/mg/AVR.INC @@ -0,0 +1,368 @@ +;------------------------------------------------; +; Constants + +.equ RAMTOP = 0x60 ; SRAM top address +.equ RAMTOP100 = 0x100 ; For memory mapped I/O devices + + +.equ bit0 = 0b00000001 +.equ bit1 = 0b00000010 +.equ bit2 = 0b00000100 +.equ bit3 = 0b00001000 +.equ bit4 = 0b00010000 +.equ bit5 = 0b00100000 +.equ bit6 = 0b01000000 +.equ bit7 = 0b10000000 + + +.def T0L = r0 +.def T0H = r1 +.def T2L = r2 +.def T2H = r3 +.def T4L = r4 +.def T4H = r5 +.def T6L = r6 +.def T6H = r7 +.def T8L = r8 +.def T8H = r9 +.def T10L = r10 +.def T10H = r11 +.def T12L = r12 +.def T12H = r13 +.def T14L = r14 +.def T14H = r15 + + +.def AL = r16 +.def AH = r17 +.def BL = r18 +.def BH = r19 +.def CL = r20 +.def CH = r21 +.def DL = r22 +.def DH = r23 +.def EL = r24 +.def EH = r25 + + + +;------------------------------------------------; +; Push/Pop register pair +; +; pushw Z + +.macro pushw + push @0H + push @0L +.endm + +.macro popw + pop @0L + pop @0H +.endm + + +;------------------------------------------------; +; Load/store word from/to direct memory/immediate +; +; ldsw Z,mem +; ldiw Z,imm + +.macro ldiw + ldi @0L,low(@1) + ldi @0H,high(@1) +.endm + +.macro ldsw + lds @0L,@1 + lds @0H,@1+1 +.endm + +.macro stsw + sts @0+1,@1H + sts @0,@1L +.endm + +.macro lddw + ldd @0L,@1 + ldd @0H,@1+1 +.endm + +.macro stdw + std @0+1,@1H + std @0,@1L +.endm + +.macro ldw + ld @0L,@1 + ld @0H,@1 +.endm + +.macro stw + st @0,@1L + st @0,@1H +.endm + +.macro inw + in @0L,@1L + in @0H,@1H +.endm + +.macro outw + out @0H,@1H + out @0L,@1L +.endm + + +;------------------------------------------------; +; Store immediate into indirect memory via r16 +; +; sti Z,imm +; stdi Z+d,imm + +.macro sti + ldi r16,@1 + st @0,r16 +.endm + +.macro stdi + ldi r16,@1 + std @0,r16 +.endm + +.macro muli + ldi r16,@1 + mul @0,r16 +.endm + + +;------------------------------------------------; +; add/sub/subc/cp/cpc/lsl/lsr/rol/ror to register pair +; + +.macro addiw + subi @0L,low(-(@1)) + sbci @0H,high(-(@1)) +.endm + +.macro subiw + subi @0L,low(@1) + sbci @0H,high(@1) +.endm + +.macro addw + add @0L,@1L + adc @0H,@1H +.endm + +.macro adcw + adc @0L,@1L + adc @0H,@1H +.endm + +.macro subw + sub @0L,@1L + sbc @0H,@1H +.endm + +.macro sbcw + sbc @0L,@1L + sbc @0H,@1H +.endm + +.macro cpw + cp @0L,@1L + cpc @0H,@1H +.endm + +.macro cpcw + cpc @0L,@1L + cpc @0H,@1H +.endm + +.macro cpiw + cpi @0L,low(@1) + ldi r16,high(@1) + cpc @0H,r16 +.endm + +.macro andw + and @0L,@1L + and @0H,@1H +.endm + +.macro andiw + andi @0L,low(@1) + andi @0H,high(@1) +.endm + +.macro orw + or @0L,@1L + or @0H,@1H +.endm + +.macro oriw + ori @0L,low(@1) + ori @0H,high(@1) +.endm + +.macro lslw + lsl @0L + rol @0H +.endm + +.macro lsrw + lsr @0H + ror @0L +.endm + +.macro asrw + asr @0H + ror @0L +.endm + +.macro rolw + rol @0L + rol @0H +.endm + +.macro rorw + ror @0H + ror @0L +.endm + +.macro clrw + clr @0L + clr @0H +.endm + +.macro comw + com @0L + com @0H +.endm + +.macro negw + com @0H + neg @0L + brne PC+2 + inc @0H +.endm + +.macro movew + mov @0L, @1L + mov @0H, @1H +.endm + +.macro lpmw + lpm @0L, @1 + lpm @0H, @1 +.endm + + +;------------------------------------------------; +; Store immediate into direct memory via r16 +; +; stsi var,imm + +.macro stsi + ldi r16,@1 + sts @0,r16 +.endm + + +;------------------------------------------------; +; Output port immediate via r16 +; +; outi port,var + +.macro outi + ldi r16,@1 + out @0,r16 +.endm + + +;------------------------------------------------; +; Add immediate to register + +.macro addi + subi @0,-(@1) +.endm + + +;------------------------------------------------; +; Long branch + + +.macro rjne + breq PC+2 + rjmp @0 +.endm + +.macro rjeq + brne PC+2 + rjmp @0 +.endm + +.macro rjcc + brcs PC+2 + rjmp @0 +.endm + +.macro rjcs + brcc PC+2 + rjmp @0 +.endm + +.macro rjtc + brts PC+2 + rjmp @0 +.endm + +.macro rjts + brtc PC+2 + rjmp @0 +.endm + +.macro rjge + brlt PC+2 + rjmp @0 +.endm + +.macro rjlt + brge PC+2 + rjmp @0 +.endm + + +.macro retcc + brcs PC+2 + ret +.endm + +.macro retcs + brcc PC+2 + ret +.endm + +.macro reteq + brne PC+2 + ret +.endm + +.macro retne + breq PC+2 + ret +.endm + + +;------------------------------------------------; +; Move single bit between two registers +; +; bmov dstreg,dstbit,srcreg.srcbit + +.macro movb + bst @2,@3 + bld @0,@1 +.endm + + diff --git a/Midi/mg/mel.txt b/Midi/mg/mel.txt new file mode 100644 index 0000000..fdc6e61 --- /dev/null +++ b/Midi/mg/mel.txt @@ -0,0 +1,499 @@ +;For Elise (3/8, 60bpm) + +;