ノクターンでLチカ

投稿日:

 いやもう、「オッサンとバイエル、ピアノ等」って銘打ってて、長らくなかったこのネタ。ええ、ピアノですよ、ピアノ。

「Arduinoをピアノにつなぎたいッ!」

……すなわちコレである。Arduinoをピアノにつなぎ、LEDをピアノ演奏に合わせて明滅させようというものだ。

 いまや遅しとやってみた。

ノクターンでLチカ

 一つ覚えみたいにノクターンで申し訳ないですが(笑)、すんませんレパートリーがあんまりないもんで。

IMG_3276

 アナログピンからピアノの音声出力を読み、それに合わせてTLC5940NTに接続されたLEDを適宜明滅させるわけである。いかにもピアノ風味に明滅させるにあたっては、乱数によるLED選択と、先日会得した「PWMを十分に使い、余韻をもって各LEDを徐々に消す」という技を遺憾なく使用した。

 これをやるには、アナログピンに上手に音声を入れる必要がある。

 こういう時、電圧レベルを知るのにオシロスコープなどが使えればいいのだが、残念ながら持っていない。そこで、あらかじめテスターのACでテレビ、ラジオ、自分のピアノなどの音声出力端子からだいたいのレベルを推定し、次に十分な抵抗を入れて、Arduinoのアナログピンに入力して読み取った。その結果、だいたい200mVの振幅程度であることがわかった。これならばArduinoに直接入れてもどうということはなさそうだ。ただし、レベルが小さいから、ソフトウェアのほうでうまくやる必要がある。

 次に、音声はアナログ信号だから、プラス・マイナスに振れる。一方、Arduinoのアナログ入力は0~5Vの間を1024分割で読むのだから、ここをうまく工夫しなければならない。

 まず、2.5Vを中心に電圧が振れるよう、2.5Vを生成して合成する。ちょうどTLC5940NTを動かすために5Vの3端子レギュレータを使っているので、ここから抵抗分圧で2.5Vを作り、それを合成する。合成するとき、出力側の音声端子に電流が流れ込んではまずいから、コンデンサを0.1μFばかりつける。周波数は見当がつくが、電圧の見当がつきにくいので、とりあえず0.1μFにして、出来が悪いようなら取り換えることにする。

 まず、大して疑問もない簡素な付加回路。たしか、パルス技術ではこういうの、「クランパ」って言ったっけな……。

音声入力のためのクランパ
「voice2tlc」の回路図

 それで、TLCなどと一緒にLEDを植え込む。

IMG_3273

 ミニジャックを接続するために、秋月電子の「ステレオミニジャックDIP化キット」を取り付けた。

ミニジャックの部分
IMG_3274

 で、スケッチはこうなった。

//
//  voice2tlc.ino
//    アナログピンに音声を入れ、TLC5940NTを使ってLEDを光らせる。
//    27.08.13(木)1000~
//    佐藤俊夫
//
#include "Tlc5940.h"
#include <stdio.h>
//
const int
  AUDIO = 0, //  アナログ0ピン
  THRESH = 8;  //  8単位以上のレベルならLEDを点灯
//
void setup() {
  Tlc.init();
  Tlc.clear();
  Tlc.update();
}

void loop() {
  int v = 0, l = 0;
  static long int prevtime = 0.0;
  static int prevv = 0;
  v = abs(analogRead(AUDIO) - 512);
  l = constrain(fmap(v, 0, 15, 0, 4095), 0, 4095);
  if(millis() >= prevtime + 10){
    prevtime = millis();
    for(int i = 0; i <= 15; i++){
      Tlc.set(i, Tlc.get(i) * 0.9);
    }
  }
  for(int i = 0; i <= 15; i++){
    if(random(0, 16) == 1 && prevv != v && v >= THRESH){
      Tlc.set(i, l);
    }
  }
  Tlc.update();
  prevv = v;
}
//
float fmap(float x, float in_min, float in_max, float out_min, float out_max) {
  //  もともとの「map()」がlong int型でこの用途に合わないので、float型を定義
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください