Standard MIDI file player for the eVY1 shield and analog joy stick
Dependencies: DirectoryList SDFileSystem mbed
Fork of eVY1_SMF_player by
MicroSDカードからSMF(スタンダードMIDIファイル)を読み込み、データをシリアルでeVY1シールドに転送して再生します。 MIDIファイル形式は、Format 0のみ対応しています。アナログジョイスティックを使用してテンポとピッチの変更が出来るようにしました。
動作確認は、mbed FRDM-K64Fで行っています。
eVY1シールドをそのまま刺して使用できます(オンボードのMicroSDスロットを使います)。
eVY1を使用した場合、MIDIデータのCH.1は強制的にeVocalodによる歌声として使用されてしまうため(プログラムチェンジも不可)、強制的にCH.16に割り当てています。そのため、CH.16を使用しているMIDIファイルはデータ通りに再生する事が出来ません。
アナログジョイスティックの X Y データは、それぞれアナログ入力の A0, A1 に接続しています。
main.cpp
- Committer:
- MACRUM
- Date:
- 2017-01-07
- Revision:
- 4:4dcc1464c89e
- Parent:
- 3:2a58b7f4b0cb
File content as of revision 4:4dcc1464c89e:
/** * Standard MIDI file player for the eVY1 shield * * @author Toyomasa Watarai * @version 0.1 * @date July-2015 * * This program parse MIDI format 0 files on SDCard * and plays the data using eVY1 shield * * Ported by Arduino example code of the SWITCHSCIENCE, Thanks! * https://github.com/SWITCHSCIENCE/eVY1_Shield * */ #include "mbed.h" #include "SDFileSystem.h" #include "DirectoryList.h" #define _DEBUG #define _NO_eVocaloid_ #if defined(TARGET_K64F) #define USE_DIRECTORY_LIST SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS RawSerial midi(D1, NC); InterruptIn btn(PTA4); AnalogIn ax(A0); AnalogIn ay(A1); Ticker click; float x, y; #elif defined(TARGET_LPC1114) SDFileSystem sd(dp2, dp1, dp6, dp4, "sd"); // MOSI, MISO, SCK, CS RawSerial midi(dp16, NC); InterruptIn btn(dp9); #if defined(_DEBUG) #undef _DEBUG #endif #elif defined(TARGET_WIZWIKI_W7500P) SDFileSystem sd(PB_3, PB_2, PB_1, PB_0, "sd"); // MOSI, MISO, SCK, CS RawSerial midi(D1, NC); InterruptIn btn(PC_6); #if defined(_DEBUG) #undef _DEBUG #endif #endif #ifdef _DEBUG Serial pc(USBTX, USBRX); #define DEBUG_PRINT(...) { pc.printf(__VA_ARGS__);} #else #define DEBUG_PRINT(...) void error(const char* format, ...) {} #endif FILE *fp; Timer timer; uint32_t tempo, org_tempo; uint32_t delta_time; uint32_t TIMER; uint32_t STATE; uint32_t pitch_update = 0; #define midi_read() (fgetc(fp)) void get_val(void) { x = ax.read(); y = ay.read(); tempo = org_tempo + ((ax - 0.5f) * 400); pitch_update = 1; } void disable_timer(void) { timer.stop(); } uint32_t delta_time_read(void) { uint32_t r_buf; uint32_t ret = 0; while(1) { r_buf = midi_read(); ret = (ret <<7) | (r_buf & 0x7f); if ((r_buf & 0x80) == 0) break; } TIMER += ((ret * tempo) / delta_time); return ret; } void midi_play(void) { int32_t buf[256]; uint32_t cnt; uint32_t cmd; if (pitch_update) { uint32_t pitch; pitch = 0x4000 + ((y - 0.5f) * 2000); for(uint32_t i=0; i<16; i++) { midi.putc(0xE0 | i); midi.putc(pitch & 0x7F); midi.putc((pitch >> 8) & 0x7F); } pitch_update = 0; } buf[0] = midi_read(); buf[1] = midi_read(); cmd = (buf[0] & 0xf0); if ((cmd == 0x80) || (cmd == 0x90) || (cmd == 0xA0) || (cmd == 0xB0) || (cmd == 0xE0)) { buf[2] = midi_read(); #if defined(_NO_eVocaloid_) if ((buf[0] & 0x0f) == 0x0f) { // CH.16 return; } if ((buf[0] & 0x0f) == 0x00) { // CH.1 buf[0] = (buf[0] | 0x0f); // Force change to CH.16 } #endif midi.putc(buf[0]); midi.putc(buf[1]); midi.putc(buf[2]); } else if (cmd == 0xC0) { #if defined(_NO_eVocaloid_) if ((buf[0] & 0x0f) == 0x00) { // CH.1 buf[0] = (buf[0] | 0x0f); // Force change to CH.16 } #endif midi.putc(buf[0]); midi.putc(buf[1]); } else if (cmd == 0xD0) { midi.putc(buf[0]); midi.putc(buf[1]); } else if (cmd == 0xF0) { switch( buf[0] & 0x0F ) { case 0x00 : // SysEx case 0x07 : // SysEx2 cnt = buf[1]; midi.putc(buf[0]); for(uint32_t i=1; i<cnt+1; i++) { midi.putc(midi_read()); } break; case 0x0f : // Meta event switch ( buf[1] ) { case 0x00: // Sequence number midi_read(); break; case 0x51: // Set tempo midi_read(); // len (== 3) tempo = midi_read(); tempo = (tempo << 8 ) | midi_read(); tempo = (tempo << 8 ) | midi_read(); tempo = tempo / 1000; org_tempo = tempo; //tempo += (ax * 10); DEBUG_PRINT("Set tempo = %d\n", tempo); break; case 0x2f: // End of Track midi_read(); // Read zero disable_timer(); STATE = 2; break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: cnt = midi_read(); // len for(uint32_t i=0; i<cnt; i++) DEBUG_PRINT("%c", midi_read()); DEBUG_PRINT("\n"); break; default: cnt = midi_read(); // len for(uint32_t i=0; i<cnt; i++) midi_read(); break; } break; } } } void smf_main_loop(void) { if(STATE == 1) { if (TIMER < timer.read_ms()) { midi_play(); if (STATE != 2) delta_time_read(); } } } void smf_init(void) { TIMER = 0; tempo = 500; // default value uint32_t ch; for (ch=0; ch<16; ch++) { midi.putc(0xB0|ch); midi.putc(0x78); midi.putc(0x00); midi.putc(0xB0|ch); midi.putc(0x79); midi.putc(0x00); } // Skip MIDI header for (uint32_t i=0; i<8; i++) { midi_read(); } uint32_t format; format = (midi_read() << 8); format |= midi_read(); if ( format > 1) { DEBUG_PRINT("This is not a MIDI format 0 file!\n", format); STATE = 2; return; } uint32_t track; track = (midi_read() << 8); track |= midi_read(); DEBUG_PRINT("Number of tracks : %d\n", track); // timebase delta_time = (midi_read() << 8); delta_time |= midi_read(); DEBUG_PRINT("tempo = %d, delta_time = %d\n", tempo, delta_time); // skip track chunk header for (uint32_t i=0; i<0x8; i++) midi_read(); TIMER = (delta_time_read() * tempo) / delta_time ; DEBUG_PRINT("TIMER = %d\n", TIMER); STATE = 1; } void skip() { STATE = 2; } int main() { DEBUG_PRINT("Initializing...\n"); btn.mode(PullUp); btn.fall(&skip); midi.baud(31250); click.attach(&get_val, 0.2); wait(3.5); // Wait few seconds for booting eVY1-Shleld. #if !defined(_NO_eVocaloid_) const uint8_t aMsg[] = "\xF0\x43\x79\x09\x00\x50\x10" "4 a\0" "\xF7"; for (uint32_t i = 0; i < sizeof(aMsg)-1; midi.putc(aMsg[i++])); #endif DEBUG_PRINT("Initialized.\n"); char buf[50]; #if defined(USE_DIRECTORY_LIST) DirectoryList dir("/sd"); if ( dir.error_check() ) { DEBUG_PRINT("directory could not be opened\r\n"); return -1; } for ( int i = 0; i < dir.size(); i++ ) { sprintf(buf, "/sd/%s", dir[ i ].c_str() ); #else for ( uint32_t i = 0; i < 10; i++ ) { sprintf(buf, "/sd/%d.mid", i); #endif fp = fopen(buf, "r"); if (fp == NULL) { DEBUG_PRINT("Unable to read the file \n"); } else { timer.reset(); timer.start(); smf_init(); if ( STATE == 2 ) { fclose(fp); #if defined(__MICROLIB) && defined(__ARMCC_VERSION) // with microlib and ARM compiler free(fp); #endif continue; } DEBUG_PRINT("Now, playing (%s)... \n", buf); while (1) { smf_main_loop(); if (STATE == 2) { break; } } fclose(fp); #if defined(__MICROLIB) && defined(__ARMCC_VERSION) // with microlib and ARM compiler free(fp); #endif DEBUG_PRINT("End.\n"); } } }