ラベル MIDI の投稿を表示しています。 すべての投稿を表示
ラベル MIDI の投稿を表示しています。 すべての投稿を表示

2012年10月30日

Arduinoでピアノ階段 with GarageBand

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前々から予告していた、ピアノ階段(a.k.a. GarageBand階段)プロジェクトが完成・一般公開できたので、その報告と技術的な詳細について。

まずは実際の動作映像から。



仕組みは以前書いた記事(これこれ)から殆ど変わっていませんが、踏み板スイッチの大型化と素材の特性に応じて若干の調整を加えています。

各段の横幅が1800mm奥行きが350mm程度と大きいこと、滑りにくいことなどを条件に素材を選び、最終的には厚さ2mm〜3mm程度のベニヤ板を使用。

1800x900mmサイズのベニヤ板から1800x250mmの板を3枚切り出し、これの片面にアルミ箔テープ(0.1mm厚)、厚手両面テープ(0.5mm厚)を貼る。

貼り付けたアルミ箔テープの片隅に、リード線の先端を扇状に広げたものを乗せ、上から短く切ったアルミ箔テープをしっかりと貼り付ける。


リード線、アルミ箔テープと貼った場所の上にガムテープを貼る。(リード線で盛り上がった部分同士が接触しないように)



これを2枚用意し、2枚のうち1枚のアルミ箔テープの上に「たこ糸」を渡す。(ベニヤ板の自重で常に接触することを防止する)

ここまで出来たら、アルミ箔を貼った面を向かい合わせにして慎重に貼り合わせる。


これを各段に設置、配線していきます。
タクトスイッチをArduinoで使う要領で、各段のスイッチをプルダウンで接続します。


プログラムはこんな感じ。
相変わらずの「動けば良い」コードなので、改良の余地は十分にあるはず。

#include <Bounce.h>

int pinDo = 13;
int pinRe = 12;
int pinMi = 11;
int pinFa = 10;
int pinSo = 9;
int pinLa = 8;
int pinTi = 7;
int pinDo2 = 6;
int pinRe2 = 5;
int state[9];

Bounce Do = Bounce( pinDo,20 );
Bounce Re = Bounce( pinRe,20 );
Bounce Mi = Bounce( pinMi,20 );
Bounce Fa = Bounce( pinFa,20 );
Bounce So = Bounce( pinSo,20 );
Bounce La = Bounce( pinLa,20 );
Bounce Ti = Bounce( pinTi,20 );
Bounce Do2 = Bounce( pinDo2,20 );
Bounce Re2 = Bounce( pinRe2,20 );

void setup() {
  pinMode(pinDo, INPUT);
  pinMode(pinRe, INPUT);
  pinMode(pinMi, INPUT);
  pinMode(pinFa, INPUT);
  pinMode(pinSo, INPUT);
  pinMode(pinLa, INPUT);
  pinMode(pinTi, INPUT);
  pinMode(pinDo2, INPUT);
  pinMode(pinRe2, INPUT);

  Serial.begin(31250); 
}

void loop(){

  Do.update ();
  if ((Do.read() == HIGH)&&(state[0] == 0)) {
    noteOn(144,60,127);
    state[0] = 1;
  }
  if ((Do.read() == HIGH)&&(state[0] == 1)) {
  }
  if ((Do.read() == LOW)&&(state[0] == 1)) {
    noteOn(128,60,127);
    state[0] = 0;
  }
  if ((Do.read() == LOW)&&(state[0] == 0)) {
  }

  Re.update ();
  if ((Re.read() == HIGH)&&(state[1] == 0)) {
    noteOn(144,62,127);
    state[1] = 1;
  }
  if ((Re.read() == HIGH)&&(state[1] == 1)) {
  }
  if ((Re.read() == LOW)&&(state[1] == 1)) {
    noteOn(128,62,127);
    state[1] = 0;
  }
  if ((Re.read() == LOW)&&(state[1] == 0)) {
  }

  Mi.update ();
  if ((Mi.read() == HIGH)&&(state[2] == 0)) {
    noteOn(144,64,127);
    state[2] = 1;
  }
  if ((Mi.read() == HIGH)&&(state[2] == 1)) {
  }
  if ((Mi.read() == LOW)&&(state[2] == 1)) {
    noteOn(128,64,127);
    state[2] = 0;
  }
  if ((Mi.read() == LOW)&&(state[2] == 0)) {
  }

  Fa.update ();
  if ((Fa.read() == HIGH)&&(state[3] == 0)) {
    noteOn(144,65,127);
    state[3] = 1;
  }
  if ((Fa.read() == HIGH)&&(state[3] == 1)) {
  }
  if ((Fa.read() == LOW)&&(state[3] == 1)) {
    noteOn(128,65,127);
    state[3] = 0;
  }
  if ((Fa.read() == LOW)&&(state[3] == 0)) {
  }

  So.update ();
  if ((So.read() == HIGH)&&(state[4] == 0)) {
    noteOn(144,67,127);
    state[4] = 1;
  }
  if ((So.read() == HIGH)&&(state[4] == 1)) {
  }
  if ((So.read() == LOW)&&(state[4] == 1)) {
    noteOn(128,67,127);
    state[4] = 0;
  }
  if ((So.read() == LOW)&&(state[4] == 0)) {
  }

  La.update ();
  if ((La.read() == HIGH)&&(state[5] == 0)) {
    noteOn(144,69,127);
    state[5] = 1;
  }
  if ((La.read() == HIGH)&&(state[5] == 1)) {
  }
  if ((La.read() == LOW)&&(state[5] == 1)) {
    noteOn(128,69,127);
    state[5] = 0;
  }
  if ((La.read() == LOW)&&(state[5] == 0)) {
  }

  Ti.update ();
  if ((Ti.read() == HIGH)&&(state[6] == 0)) {
    noteOn(144,71,127);
    state[6] = 1;
  }
  if ((Ti.read() == HIGH)&&(state[6] == 1)) {
  }
  if ((Ti.read() == LOW)&&(state[6] == 1)) {
    noteOn(128,71,127);
    state[6] = 0;
  }
  if ((Ti.read() == LOW)&&(state[6] == 0)) {
  }

  Do2.update ();
  if ((Do2.read() == HIGH)&&(state[7] == 0)) {
    noteOn(144,72,127);
    state[7] = 1;
  }
  if ((Do2.read() == HIGH)&&(state[7] == 1)) {
  }
  if ((Do2.read() == LOW)&&(state[7] == 1)) {
    noteOn(128,72,127);
    state[7] = 0;
  }
  if ((Do2.read() == LOW)&&(state[7] == 0)) {
  }

  Re2.update ();
  if ((Re2.read() == HIGH)&&(state[8] == 0)) {
    noteOn(144,74,127);
    state[8] = 1;
  }
  if ((Re2.read() == HIGH)&&(state[8] == 1)) {
  }
  if ((Re2.read() == LOW)&&(state[8] == 1)) {
    noteOn(128,74,127);
    state[8] = 0;
  }
  if ((Re2.read() == LOW)&&(state[8] == 0)) {
  }
}

void noteOn(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

本来は、Serial MIDI ConverterでMIDI信号をMacに入力する予定でしたが、何故か鳴ってくれない(おそらくjavaのバージョンアップが原因)ので、ArduinoからMIDI-OUTを出し、それをUSB-MIDIケーブルでMacに入力。

あとはGarageBandを起動すれば、各段に応じた音が鳴ります。

2012年5月6日

お手製パネルスイッチ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回のピアノ階段(GarageBand階段)計画の続き。
ハンズマンでアルミテープと厚手両面テープを、HIヒロセで下敷き2枚を購入。

アルミテープ:厚さ0.1mm、幅50mm、長さ20m
厚手両面テープ:厚さ0.5mm、幅30mm、長さ15m
下敷き:厚さ0.7mm、B5サイズ


下敷きの長辺外側に厚手両面テープを、中央にアルミテープを貼ったものを2枚作る。
両面テープを剥がして向かい合わせに貼り合わせると完成。

単純計算だと厚手両面テープ*2で1mm、アルミテープ*2で0.2mmなので、向かい合わせになったアルミテープの間には0.8mmの隙間ができることになる。


前回と同様、プルダウン、1kΩの抵抗を使用、デジタル13ピンに接続。
スケッチも前回のまま使うので「ド(C3)」の音が割り当てられています。


実際に実行してみました。


課題としては両面テープの部分は押しても反応しない(当然)こと。
細くすると板(今回は下敷きを使用)のたわみで何もしなくても引っ付いてしまう可能性も。

実際に階段に設置する際は、踏まれることを考慮して接点の位置や素材を工夫する必要があるかも。

2012年4月22日

Arduino + GarageBand (MIDIキーボードもどき)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

久しぶりの投稿にして久しぶりのArduinoネタ。

ボタンを押すとドレミファソラシドが鳴るというもので、やっていることは至って簡単。
どのタクトスイッチが押されてるか判定してSerial.printで吐き出し、Mac側でSerial MIDI Converterなるソフトを使ってIAC DriverにMIDI信号を渡し、GarageBandで読み取る。
Arduino → Serial MIDI Converter → IAC Driver → GarageBandというフロー。

ブレッドボード上のタクトスイッチはプルダウン、抵抗は1KΩを入れてある。
チャタリング除去はソフトウェア側にお任せ。(Bounceライブラリを使用)
#include <Bounce.h>

byte pins[8] = {13,12,11,10,9,8,7,6};
byte pitch[8] = {60,62,64,65,67,69,71,72};
int status[8] = {0};

Bounce button[] = {Bounce(pins[0],20),
                   Bounce(pins[1],20),
                   Bounce(pins[2],20),
                   Bounce(pins[3],20),
                   Bounce(pins[4],20),
                   Bounce(pins[5],20),
                   Bounce(pins[6],20),
                   Bounce(pins[7],20)};

void setup() {
  for (int i=0; i< 8; i++) {
    pinMode(pins[i], INPUT);
  }
  Serial.begin(57600); 
}

void loop(){
  for (int i=0; i< 8; i++) {
    button[i].update ();
    
    if ((button[i].read() == HIGH)&&(status[i] == 0)) {
      MIDI_TX(144,pitch[i],127);
      status[i] = 1;
    }if ((button[i].read() == LOW)&&(status[i] == 1)) {
      MIDI_TX(128,pitch[i],127);
      status[i] = 0;
    }if ((button[i].read() == HIGH)&&(status[i] == 1)) {

    }if ((button[i].read() == LOW)&&(status[i] == 0)) {
    
    }
  }
}

void MIDI_TX(unsigned char MESSAGE, unsigned char PITCH, unsigned char VELOCITY) 
{
  Serial.print(MESSAGE);
  Serial.print(PITCH);
  Serial.print(VELOCITY);
}
という感じ。
#相変わらずエレガントさに欠けるなぁ...

MIDIのメッセージについては、144がCh1のNote ONで128がCh1のNote OFFである。
144-128=16で分かるとおり、16チャンネル扱えることが分かる。
ピッチは鍵盤中央のドを60として半音ごとに1増減という仕様。

実際に音を鳴らしてみたり。(黒鍵はブレッドボード上に未実装なので白鍵だけ)

※画面録画です。(手元は上の写真を見てご想像ください)

あとは、このタクトスイッチを踏んでも大丈夫な別の素子に変えて階段に仕掛ける予定。
元ネタはフォルクスワーゲンのピアノ階段という動画。
前々から真似してみたかったので、今年の学園祭で学校に同様の物を仕掛けようかと画策中。

問題はArduino UNO(328)だと入力が足りないこと。
アナログをデジタルに回しても20本しかないので、1オクターブとちょっとしか対応出来ない。
Mega(2560)を使う or UNO(328)を多段にするなど考え中...
追記
シフトレジスタ(PISO)の74HC165を使って入力を増やす方法を教えてもらいました。
時間がある時に試してみます。
本家(ピアノ階段)で使ってる踏んだ時に感知する方法が気になる...
フィルムタイプの圧力センサは高いので代替できる手段を調査中。

追記
階段用スイッチの仕組みを考えました。 → お手製パネルスイッチ

追記2
GarageBand階段、完成しました。 → Arduinoでピアノ階段 with GarageBand