RGB 32バンド オーディオスペクトラムビジュアライザー - Arduino LEDマトリックスプロジェクト
必要な部品と材料
| 部品 | 数量 |
|---|---|
| Arduino Nano R3 | 1 |
| WS2812B 8×32 RGB LEDマトリックス | 1 |
| 抵抗 4.75kΩ | 3 |
| 抵抗 100kΩ | 2 |
| 抵抗 10kΩ | 1 |
| スルーホール抵抗 390Ω | 1 |
| コンデンサ 100nF | 2 |
| コンデンサ 1000µF | 1 |
| SparkFun プッシュボタンスイッチ 12mm | 1 |
| 4×6cm マルチホール試作基板 | 1 |
必要な工具と機械
- はんだごて(汎用)
- 3.5mmジャック分岐ケーブル
プロジェクト概要
このプロジェクトについて
Arduino Nanoと8×32 WS2812B RGB LEDマトリックスを使用して、32バンドのオーディオ(音楽)周波数スペクトラムをRGBで可視化するプロジェクトです。
元になったオリジナルプロジェクト
Shajeeb氏による、MAX72xx LEDマトリックスベースのオリジナルプロジェクト「32-Band Audio Spectrum Visualizer Analyzer」に感謝します。私はLEDマトリックス駆動部分のみを修正し、RGB WS2812B LEDマトリックスに対応させました。
WS2812B RGB LEDマトリックスについて
5050 SMD高輝度LEDベースのRGB LEDマトリックスを使用する場合、外部電源が必要です。1LEDあたり10mA以上消費するため、全LEDを最大輝度で点灯させると2.5A以上を消費する可能性があります。
このため、+5Vラインにダイオードを直列挿入し、USBケーブル未接続時にArduinoをスタンドアロンで動作させられるようにし、ArduinoがRGBマトリックスの電源にならないよう保護しています(供給不能な大電流から内部回路を守るため)。
オリジナルプロジェクトに加え、LEDマトリックス入力を電圧スパイクから保護するため、ArduinoピンD6とデータ入力の間に390Ω抵抗を直列挿入し、Arduino電源電圧の安定化のため1000µF 12Vコンデンサを追加しました。
ハードウェア組み立て
メイン写真の通り、最初のプロトタイプは4×6cmのマルチホール基板上に構築しました。2つのRCAオーディオソケットを基板に直接はんだ付け(3.5mmメスジャックソケットに置き換え可能)。ハムノイズを防ぐため、音源とボードの音声入力間はシールドケーブルで接続することが重要です。また、ArduinoとLEDマトリックス間の接続はできるだけ短く保つことを推奨します。
コードについて
ソフトウェア全体は、FFTライブラリを用いたサンプリング手順の作者と、それを完成させたShajeeb氏の素晴らしい仕事に基づいています。
私は以下の2つの関数を追加しました:
- GetLedFromMatrix(...): マトリックスを行と列にマッピングし、256個のLEDを行・列座標でアドレッシング可能にする関数
- SetColumn(...): オーディオデジタイズで得られたピーク値(0〜7)と、2次元配列でプリセットされた色に基づき、各列のLEDを点灯させる関数。色の値を変更して好みの配色にカスタマイズ可能です。Adafruit NeoPixelライブラリのデモから採用した
Wheel()サブルーチン(0〜255の値から32bitカラー値を生成)を使用し、setPixelColorに直接渡せるようにしています。メモリ制約を考慮し、32bit変数でRGB値を保持するのは避けるべきです。
オーディオイコライゼーション
PCマザーボード内蔵サウンドカードからの音声でテストしたところ、低域が強く高域が弱いため、32要素のバイト配列 eq[32] でイコライゼーションカーブを定義し、低域を減衰・高域を強調するようにしました。不要な場合は EQ_ON を false に設定するか、eq[32] の32値を変更して調整可能です。値100で変化なし、100未満で減衰、100超で強調されます。
LED輝度
マトリックス輝度はコード内で32(BRIGHTNESS定数)にプリセットされています。WS2812Bの理論上の最大輝度は255ですが、100を超えると白色が薄黄色になってしまいます。これはマトリックスへの給電が右側コネクタのみのためと思われ、中央の赤黒ワイヤーからも給電すれば改善する可能性があります。現在検証中です。
輝度64なら1A電源で十分ですが、それ以上なら2A電源が必須です。
今後のアップデート予定
現在は OpenMusicLabs FHT ライブラリを使用した新バージョンを開発中です。Arduino FFTより何倍も高速に動作します。お楽しみに!
※拙い英語で恐縮です。Google翻訳を使用しました。
コード: Spectrum_Analyzer_WS2812B.ino
/* Copyright (c) 2019 Shajeeb TM
* MIT License
* WS2812B LED Matrix version by Janux
*/
#include <arduinoFFT.h>
#include <SPI.h>
#include <Adafruit_NeoPixel.h>
#define SAMPLES 64 // 2の累乗であること
#define xres 32 // 表示列数(SAMPLES/2以下)
#define yres 8 // 表示行数
#define ledPIN 6 // LEDマトリックス制御ピン
#define NUM_LEDS (xres * yres) // 総LED数 = 256
#define BRIGHTNESS 32 // 輝度(0-255)
#define buttonPin 5 // 表示色切替ボタンピン
byte yvalue, displaycolumn, displayvalue;
int peaks[xres];
byte state = HIGH, previousState = LOW;
byte displaycolor = 0;
double vReal[SAMPLES];
double vImag[SAMPLES];
byte data_avgs[xres];
arduinoFFT FFT = arduinoFFT();
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 100;
Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUM_LEDS, ledPIN, NEO_GRB + NEO_KHZ800);
// イコライザーフィルター:低域減衰・高域強調(PC内蔵サウンドカード対策)
bool EQ_ON = true; // falseで無効化
byte eq[32] = {50, 55, 60, 70, 75, 80, 85, 95, 100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 100, 100, 100, 100, 115, 125, 140, 160, 185, 200, 225, 255 };
// 表示色プリセット(Wheel関数で変換、0はカスタム色用)
byte colors[][8] = {
{170, 160, 150, 140, 130, 120, 1, 1},
{1, 5, 10, 15, 20, 25, 90, 90},
{90, 85, 80, 75, 70, 65, 1, 1},
{90, 90, 90, 30, 30, 30, 1, 1},
{170, 160, 150, 140, 130, 120, 0, 0},
{170, 160, 150, 140, 130, 120, 1, 1},
{170, 160, 150, 140, 130, 120, 1, 1}
};
void setup() {
pixel.begin();
pixel.setBrightness(BRIGHTNESS);
// ADCフリーランニングモード、プリスケーラ32設定
ADCSRA = 0b11100101; // 0xE5
ADMUX = 0b00000000; // A0ピン使用、外部基準電圧
}
void loop() {
// サンプリング
for (int i = 0; i < SAMPLES; i++) {
while (!(ADCSRA & 0x10)); // ADC変換完了待ち(ADIFビット)
ADCSRA = 0b11110101; // ADIFクリア(0xF5)
int value = ADC - 512; // DCオフセット除去
vReal[i] = value / 8; // 圧縮して格納
vImag[i] = 0;
}
// FFT処理
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
// FFT結果を表示列数(xres)に再配列
int step = (SAMPLES / 2) / xres;
int c = 0;
for (int i = 0; i < (SAMPLES / 2); i += step) {
data_avgs[c] = 0;
for (int k = 0; k < step; k++) {
data_avgs[c] += vReal[i + k];
}
data_avgs[c] /= step;
c++;
}
// 表示処理
for (int i = 0; i < xres; i++) {
if (EQ_ON) data_avgs[i] = data_avgs[i] * (float)(eq[i]) / 100; // EQ適用
data_avgs[i] = constrain(data_avgs[i], 0, 80);
data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres); // 0-8行にマッピング
yvalue = data_avgs[i];
peaks[i]--; // ピーク減衰
if (yvalue > peaks[i]) peaks[i] = yvalue; // ピーク保持
yvalue = peaks[i];
displaycolumn = i;
displayvalue = yvalue;
setColumn(displaycolumn, displayvalue);
}
pixel.show();
displaycolorChange(); // ボタンチェックで色モード切替
}
// 指定列(x)のLEDを値(y)に応じて点灯
void setColumn(byte x, byte y) {
byte led, i;
for (i = 0; i < yres; i++) {
led = GetLedFromMatrix(x, i);
if (peaks[x] > i) {
switch (displaycolor) {
case 4: // 配列値0でピーク色カスタマイズ
if (colors[displaycolor][i] > 0) {
pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
} else {
pixel.setPixelColor(led, 255, 255, 255); // 白色でピーク表示
}
break;
case 5: // 列ごとに色変更
pixel.setPixelColor(led, Wheel(x * 16));
break;
case 6: // 行ごとに色変更
pixel.setPixelColor(led, Wheel(i * 36));
break;
default: // displaycolor 0-3: 配列定義色
pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
}
} else {
pixel.setPixelColor(led, 0); // 消灯
}
}
}
// 座標(x,y)からLED番号を計算(蛇行配置、入力コネクタ右側、右下が0番)
byte GetLedFromMatrix(byte x, byte y) {
x = xres - x - 1;
if (x & 0x01) { // 奇数列は逆順
return ((x + 1) * yres - y - 1);
} else { // 偶数列は正順
return ((x + 1) * yres - yres + y);
}
}
// ボタンで表示色モード切替(デバウンス付き)
void displaycolorChange() {
int reading = digitalRead(buttonPin);
if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) {
displaycolor++;
if (displaycolor > 6) displaycolor = 0;
lastDebounceTime = millis();
}
previousState = reading;
}
// Adafruit NeoPixelデモからのユーティリティ: 0-255からカラー値生成(R→G→B→R遷移)
unsigned long Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return pixel.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return pixel.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return pixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
カスタムパーツとエンクロージャ
3Dプリント用ファイルと設計データ: arduino_rgb_audio_analyzer_lX4Dv4Pta2.zip
回路図
回路図はプロジェクトページに掲載されています。
製造プロセス
- 32バンドArduinoオーディオスペクトラムアナライザー:リニア&疑似ログ表示対応
- スマート渇きアラート植物アラーム – 最適な水やりタイミングを知らせるDIYセンサー
- イタリア語ワードクロック自作:Arduino Nano、NeoPixel、LCD、RTCで時刻を文字で表示
- Arduino MKR Fox 1200で作る信頼性の高いSigfox kWhメーター
- Bluetooth対応温度モニター:Arduino NanoとHC-06でスマホ監視
- 非接触ジェスチャー錠: APDS-9960とArduinoでセキュアアクセス
- Arduino Nanoコンパニオンキット – 電子工作に必須の部品とツールを搭載した多機能IC型デバイス
- Arduino Micro/Leonardo用 USB-MIDIアダプタキット – 完全パーツリストと実装ガイド
- Arduino用絶縁アナログ入力回路の設計:LM331 V-F変換+フォトカプラでノイズ耐性を確保
- 抵抗2本だけで作るArduino UNO用TV出力ケーブル (RCA/コンポジット)
- Arduino UNOで作る精密反応速度テスター