電子工作初心者が電子楽器作ってみた
こちらは「Applibot Advent Calendar 2023」7日目の記事になります。前回の記事はコチラです。
目次(クリックすると展開されます)
なんで電子楽器?
好きなアーティストのかたが特殊な電子楽器を使っており、自分でも弾いてみたいと思いなんとか作れないかと考えたのがきっかけでした。
普段業務でプログラムを書いており、プログラミングスキルを活かしてなんとかできるではないかと考え作ることを決意しました。
Arduinoを用いて音を鳴らす
楽器にするには大きさなども考えるとマイコンが最適だと考えをArduino使って音を出せるようにしようと考えました。
マイコンを触ること自体が初めてだったため、まずはArduinoを用いて音を鳴らすプログラムと回路をブレッドボードで組むことにしました。
こちらが1秒間音を鳴らすプログラムです。
void setup()
{
tone(8, 440); // 8番ピンから440Hzの音を鳴らす
delay(1000); // 1秒間スリープ
noTone(8); // 8番ピンの音を停止
}
void loop()
{
}
次にこちらがブレッドボード上で作成した回路です。
(実際には物理のブレッドボードを使用しましたが本記事ではわかりやすくするためにFritzingの図を使用しています)
Arduinoはコスパも良く初心者がまず触れるのにはちょうど良かったです。
また、Arduinoは有名なこともありネット上に情報がたくさんあったため初心者でも問題なくプログラムを組むことができました。
抵抗値の変化をArduinoで取得
音を出すことができたので、次はセンサーを使って音を変化させる仕組みづくりをしました。
センサーにはCdSセルという光の明るさによって抵抗の変わるパーツを使用しました。
センサーを通した電圧を読み取ってON/OFFを判定し、一定周期内のON/OFF回数によって音を変えるプログラムを作りました。
void setup()
{
Serial.begin(9600);
}
int beforeReadValue = 0; // 光センサーの読み取り値
int switchingCount = 0; // ON/OFF回数のカウント
unsigned long elapsedTime; // 経過時間(ミリ秒)
long samplingTime = 1000; // サンプリングする時間(ミリ秒)
void loop()
{
// アナログポート0番ピンから光センサーの値を読み取る
int readValue = analogRead(A0);
// 前回との差が50以上なら切り替わったと判定
if (abs(readValue - beforeReadValue) > 50) {
beforeReadValue = readValue;
switchingCount++;
}
// 起動からの経過時間取得
unsigned long now = millis();
// ON/OFF回数の結果をtoneにセット
if (now - elapsedTime > samplingTime) {
if (switchingCount == 0) {
noTone(8); // 切り替え回数が0の場合は音を停止
} else {
tone(8, switchingCount);
}
// リセット
elapsedTime = now;
switchingCount = 0;
}
}
回路は以下のようにA0から電圧をインプットとして受け取るようにしました。
その電圧を計測する回路にCdSセルという光センサーを取り付けました。
音を調整する
toneでは音が寂しいため、音の波形をsin波で作成し倍音を加えることで厚みのある音が出るようにしました。
#include <MozziGuts.h>
#include <mozzi_midi.h>
#include <Oscil.h>
#include <tables/sin2048_int8.h>
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin1(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin3(SIN2048_DATA);
void setup()
{
Serial.begin(9600);
startMozzi(CONTROL_RATE);
}
int beforeReadValue = 0; // 光センサーの読み取り値
int switchingCount = 0; // ON/OFF回数のカウント
unsigned long elapsedTime; // 経過時間(ミリ秒)
long samplingTime = 1000; // サンプリングする時間(ミリ秒)
void loop()
{
// アナログポート0番ピンから光センサーの値を読み取る
int readValue = analogRead(A0);
// 前回との差が50以上なら切り替わったと判定
if (abs(readValue - beforeReadValue) > 20) {
beforeReadValue = readValue;
switchingCount++;
}
// 起動からの経過時間取得
unsigned long now = millis();
if (now - elapsedTime > samplingTime) {
// リセット
elapsedTime = now;
switchingCount = 0;
}
audioHook();
}
// 音の調整
void updateControl() {
// 出力する音の決定
float val = switchingCount;
float base = mtof(val);
// 倍音の生成
float overtone1 = mtof(val+12*1); // 2倍
float overtone2 = mtof(val+12*2); // 3倍
aSin1.setFreq(base);
aSin2.setFreq(overtone1);
aSin3.setFreq(overtone2);
}
// オーディオの繰り返し出力処理
int updateAudio() {
long waveSum = aSin1.next() + aSin2.next() + aSin3.next();
return waveSum >> 4;
}
ここで問題が発覚します。
楽器にするには抵抗値の変化を(ほぼ)リアルタイムでサンプリングして音に変換したいのですが、Arduinoのループの処理速度では理想的な音の変化を出すことができませんでした。
また、あまり音が安定せず狙った音を狙ったタイミングで出すことが困難でした。
素人なりに色々調べてはみたものの、Arduinoでサンプリングし音に変換するには限界があるなと感じました。
マイコンを使わずアナログに変更
プログラムではなくなってしまいますが、本当にリアルタイムで音の変化を出したいならいっそセンサーを介した電圧の変化をそのままスピーカーに伝えてはどうか?と考えました。
ここでは詳細は記載しませんがスピーカーの原理についても調べ、うまくすれば音を鳴らせそうだったのでとりあえず回路を組んで検証してみることに。
こちらもブレッドボード上で作成して検証。
電源をCdSセルを通し、そのままスピーカーに繋ぐだけの簡単な回路です。
ブレッドボード上で回路の動作確認ができたので、実際に基盤に半田づけをしていきました。
完成した回路がこちら。
実際に楽器として使用するには、ある程度大きな音を出せる必要があるため増幅機として小型アンプを用いました。
電源は乾電池、type-Cのどちらからでも共有できるようにしました。CdSセルは裏側に取り付けています。
出力はRCAジャック(ブラウン管テレビ等への入力で使用する赤白のやつ)にし、RCA→6.3mmモノラルプラグオーディオ変換ケーブルを使うことでエフェクターに接続できるようにしました。
ケースは3DCADでモデリングしたものを3Dプリンターで印刷しました。
楽器完成
完成した楽器がこちらです。
プログラム等には関係なかったので、光の明滅機構の仕組みは省略させていただきました。
切り出した円盤と電球を扇風機に取り付けています。
扇風機の回転速度が音程決めるため、スピードコントローラーを取り付けています。
まとめ
今回は結果的に断念しましたが、うまく使えばArduinoはできることが多いなと感じました。
波形を見つつ調整していけばもっとスムーズに作業を進められた思うのでオシロスコープは買っておけば良かったです。
また、本職がエンジニアなのでPCで処理することを考えがちになってしまいますが、今回でアナログの良さを感じることができ良い経験になりました。
「以上、Applibot Advent Calendar 2023 7日目の記事でした。」
Discussion