ArduinoでMIDI音源を作ってみた



2014/12/07追記 情報が古くなったので、書き直しました→ArduinoでMIDI音源を作ってみた(改)


 

MIDIの楽器を作ることを目標に、ArduinoでMIDI音源を作ってみました。
MIDIから入力した信号を音程にして、スピーカーから出力します。

プログラム概要

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ライブラリでエラーが出るようです。

熊工房 ohgumaの腹凹ませたい日記

引用:

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

3 コメント
  1. み、Midiだとぅ!? [ArduinoでMIDI音源を作ってみた] http://t.co/KhcTnXd8 @ichirowoさんから

  2. […] ArduinoのスケッチはイチロヲさんのサイトのArduinoでMIDI音源を作ってみたを参考にさせてもらいました。 […]

  3. […] 参考サイト ArduinoでMIDI音源を作ってみた | メモとか倉庫とか(仮) 2012-03-07 – 熊工房 ohgumaの腹凹ませたい日記 ↑こちらのサイトによると、Aruidno IDE 1.0以降ではTone.cppの #include <wir […]

コメントをどうぞ

*