ArduinoでMIDI音源を作ってみた

2014/12/07追記 情報が古くなったので、書き直しました→ArduinoでMIDI音源を作ってみた(改)
MIDIの楽器を作ることを目標に、ArduinoでMIDI音源を作ってみました。
MIDIから入力した信号を音程にして、スピーカーから出力します。
[nicolink vmode=”2″ videoid=”sm14662804″]
プログラム概要
MIDI信号のデコードには、MIDI Libraryを使います。v3.0で動作を確認しています。
このライブラリを使うと、データの受け取り&解析をしてくれ、MIDI信号を深く知らなくても必要な信号だけを抽出できます。
音の出力には、標準でtone関数がありますが同時出力音が1音とちょっとさびしいので、Arduino Tone Libraryを使い、3音まで同時出力できるようにします。
ただし、1ポートから一音しか出すことが出来ず、1つのスピーカーから3音を出すには3ポートから出た信号を無理やり1つのスピーカーに突っ込んでます。
LCDの上段には、音を出すチャンネルを表示、下段には出力している音の周波数を表示しました。
チャンネルはA0のボリュームで選択します。
注意
必要なMIDI信号しか使っていないので、多くあるMIDI信号の機能の内、このプログラムでは一部しか使用していません。
・NoteOn・NoteOff・・・指定の音階の音を出すことは出来ますが、ボリュームを変えることはできません。
・PitchBend・・・ピッチを微妙にずらす時に使用します。対応しています。
また、処理速度が追いつかないのか、たまに再生されない音があるようです。
Arduino 1.0でverify時の注意(2012/3/9追記)
Arduino 1.0だとそのままでは動きません。Toneライブラリでエラーが出るようです。
引用:
Arduino-1.0 でスケッチをコンパイルしようとするもエラー発生。色々調べて、 「Arduino Tone Library」の Tone.cpp にある
#include <wiring.h>
を
#include <wiring_private.h>
と書き直してスケッチをアップロードできた。
リンク先に感謝
プログラム
外部ライブラリである、MIDI LibraryとArduino Tone Libraryをインストールする必要があります。インストールは、Arduinoをインストールしたフォルダのlibrariesフォルダにコピーして、ソフトを再起動すると使用できます。
#include <LiquidCrystal.h> #include <Tone.h> #include <MIDI.h> //LCD接続ピン #define D7 4 #define D6 5 #define D5 6 #define D4 7 #define Enb 8 #define RW 9 #define RS 10 //スピーカー接続ピン #define Speaker1 13 #define Speaker2 12 #define Speaker3 11 //再生チャンネル選択ボリューム #define analogPin 0 // MIDIからToneに変換------------------------------------- int m2t[127] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 11, 19, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, 107, 115, 123, //NOTE_B2 131, //NOTE_C3 139, //NOTE_CS3 147, //NOTE_D3 156, //NOTE_DS3 165, //NOTE_E3 175, //NOTE_F3 185, //NOTE_FS3 196, //NOTE_G3 208, //NOTE_GS3 220, //NOTE_A3 233, //NOTE_AS3 247, //NOTE_B3 262, //NOTE_C4 277, //NOTE_CS4 294, //NOTE_D4 311, //NOTE_DS4 330, //NOTE_E4 349, //NOTE_F4 370, //NOTE_FS4 392, //NOTE_G4 415, //NOTE_GS4 440, //NOTE_A4 466, //NOTE_AS4 494, //NOTE_B4 523, //NOTE_C5 554, //NOTE_CS5 587, //NOTE_D5 622, //NOTE_DS5 659, //NOTE_E5 698, //NOTE_F5 740, //NOTE_FS5 784, //NOTE_G5 831, //NOTE_GS5 880, //NOTE_A5 932, //NOTE_AS5 988, //NOTE_B5 1047, //NOTE_C6 1109, //NOTE_CS6 1175, //NOTE_D6 1245, //NOTE_DS6 1319, //NOTE_E6 1397, //NOTE_F6 1480, //NOTE_FS6 1568, //NOTE_G6 1661, //NOTE_GS6 1760, //NOTE_A6 1865, //NOTE_AS6 1976, //NOTE_B6 2093, //NOTE_C7 2217, //NOTE_CS7 2349, //NOTE_D7 2489, //NOTE_DS7 2637, //NOTE_E7 2794, //NOTE_F7 2960, //NOTE_FS7 3136, //NOTE_G7 3322, //NOTE_GS7 3520, //NOTE_A7 3729, //NOTE_AS7 3951, //NOTE_B7 4186, //NOTE_C8 4435, //NOTE_CS8 4699, //NOTE_D8 4978 //NOTE_DS8 }; //変数初期化=========================================================== int vol = 0; int tone1Interval = 0; int tone2Interval = 0; int tone3Interval = 0; //クラス初期化=========================================================== //LCD LiquidCrystal lcd(RS,RW,Enb,D4,D5,D6,D7); //tone Tone tone1; Tone tone2; Tone tone3; void setup() { tone1.begin(Speaker1); tone2.begin(Speaker2); tone3.begin(Speaker3); MIDI.begin(); //LCD lcd.clear(); lcd.begin(16, 2); } void loop() { //音出力---------------------------------------------------------- uint8_t code; uint8_t ch,data1,data2,Channel; if (MIDI.read()) { MIDI.setInputChannel(vol); // Channel switch(MIDI.getType()) { case NoteOn: data1 = MIDI.getData1(); // note no data2 = MIDI.getData2(); // velocity if(data2 == 0){ lcd.print(data2, BIN); lcd.print(" "); } else { if(tone1Interval == 0){ tone1Interval = data1; tone1.play(m2t[data1]); lcd.setCursor(0,1); lcd.print(m2t[data1]); lcd.print(" "); }else{ if(tone2Interval == 0){ tone2Interval = data1; tone2.play(m2t[data1]); lcd.setCursor(5,1); lcd.print(m2t[data1]); lcd.print(" "); }else{ if(tone3Interval == 0){ tone3Interval = data1; tone3.play(m2t[data1]); lcd.setCursor(10,1); lcd.print(m2t[data1]); lcd.print(" "); } } } } break; case NoteOff: data1 = MIDI.getData1(); // note no if(tone1Interval == data1){ tone1Interval = 0; tone1.stop(); lcd.setCursor(0,1); lcd.print(" "); } if(tone2Interval == data1){ tone2Interval = 0; tone2.stop(); lcd.setCursor(5,1); lcd.print(" "); } if(tone3Interval == data1){ tone3Interval = 0; tone3.stop(); lcd.setCursor(10,1); lcd.print(" "); } break; case PitchBend: data2 = MIDI.getData2(); if(tone1Interval != 0){ int tmp = tone1Interval + 19 + data2; tone1.play(tmp); lcd.setCursor(0,1); lcd.print(tmp); lcd.print(" "); } if(tone2Interval != 0){ int tmp = tone2Interval + 19 + data2; tone2.play(tmp); lcd.setCursor(5,1); lcd.print(tmp); lcd.print(" "); } if(tone3Interval != 0){ int tmp = tone3Interval + 19 + data2; tone3.play(tmp); lcd.setCursor(10,1); lcd.print(tmp); lcd.print(" "); } lcd.setCursor(5,0); lcd.print(data2,HEX ); lcd.print(" "); break; default: break; } } //MIDIチャンネル選択---------------------------------------------------------- int beforvol = vol; vol = analogRead(analogPin); vol = vol / 64; vol = vol + 1; if(beforvol != vol){ tone1.stop(); tone2.stop(); tone3.stop(); tone1Interval = 0; tone2Interval = 0; tone3Interval = 0; lcd.setCursor(0,0); lcd.print(vol); lcd.print(" "); } }
verify
み、Midiだとぅ!? [ArduinoでMIDI音源を作ってみた] http://t.co/KhcTnXd8 @ichirowoさんから
[…] ArduinoのスケッチはイチロヲさんのサイトのArduinoでMIDI音源を作ってみたを参考にさせてもらいました。 […]
[…] 参考サイト ArduinoでMIDI音源を作ってみた | メモとか倉庫とか(仮) 2012-03-07 – 熊工房 ohgumaの腹凹ませたい日記 ↑こちらのサイトによると、Aruidno IDE 1.0以降ではTone.cppの #include <wir […]