ラズベリーパイにつなげた圧電スピーカを使って涼宮ハルヒの憂鬱のエンディング曲『ハレ晴レユカイ』をレトロな感じで鳴らしてみます。(写真、ホコリっぽいラズパイですいません!)
こんな感じ。
まえおき
個人的に圧電スピーカの音が好きです。
昔の任天堂ゲームウォッチを思い出します。(知ってる人いないかな?)
ラズベリーパイにWiringPiというC言語ライブラリをインストールすると圧電スピーカを制御できます。
圧電スピーカはこんなやつです。モノタロウなどで1個250円くらいで売っています。
作った環境
ラズベリーパイは最初からC言語環境(gccコンパイラ)が使えるので、今回必要なソフトウエアは、WiringPiというC言語のライブラリだけです。まだWiringPiをインストールされていない方は以下を参考にしてください。
配線自体は特にすることがありません。
ブレッドボードを使って圧電スピーカをラズパイのGPIO25ポートにつなげてください。アースのGNDポートはどこでもかまいません。
こんな感じになります。
プログラム作成にあたってやったこと
プログラム作成にあたって必要になったのは、ドレミの音を圧電スピーカで鳴らす際の周波数値です。
これには以下のサイトを参考にしました。
周波数値が分かったら、定数にしてプログラムで利用しやすくします。(実際は小数点以下もありますが適度に丸めています)
CDEFGABがドレミファソラシに対応しています。C1とD1は1つ上の音階のドとレです。
#define C 262 // ド
#define Cs 277 // ド#
#define Df 277 // レ♭
#define D 294 // レ
#define Ds 311 // レ#
#define Ef 311 // ミ♭
#define E 330 // ミ
#define F 349 // ファ
#define Fs 370 // ファ#
#define Gf 370 // ソ#
#define G 392 // ソ
#define Gs 415 // ソ#
#define Af 415 // ラ♭
#define A 440 // ラ
#define As 466 // ラ#
#define Bf 466 // シ♭
#define B 494 // シ
#define C1 523 // ド(音階+1)
#define D1 587 // レ(音階+1)
#define M 0 // 無音
#define END -1 // 楽譜終了
ちなみに上記は『ハレ晴レユカイ』で必要な部分のみの音階です。最後の方の定数Mの無音ですが、『ハレ晴レユカイ』の最後の「大きな、夢、夢、好きでしょ?」のところで使っています。歌の流れからすると「夢」の後にちょっと間があくためです。
わたしは音楽センスと知識がゼロだったので、妻と娘に手伝ってもらいました。
音符には長さがあることを分かっていませんでした。最初に作ったものは『ハレ晴レ不愉快』となってしまいました。
音符の長さも定数化しています。
#define x1 200 // 1拍
#define x2 400 // 2拍
#define x3 600 // 3拍
#define x4 800 // 4拍
#define x5 1000 // 5拍
#define x9 1800 // 9拍
#define x9_5 1900 // 9.5拍
#define x10 2000 // 10拍
数値の200は、200ミリ秒の意味です。一応1拍を200ミリ秒としているだけです。調整する際は、適当に変えてください。
この定数を使って、例えばドレミを各1拍ずつ鳴らすには、
const int score[] =
{
C, x1, D, x1, E, x1, END
}
などとします。定数の最後にENDを入れて曲の終わりとしています。
ハレ晴レユカイの楽譜などわたしに読めるわけもないので、以下のドレミで書かれているサイトを参考にしました。
和歌山 まとめ ハレ晴レユカイ 楽譜 | https://w.atwiki.jp/esetyaku/pages/11.html
ありがとうございます。
で、出来上がったのが以下の配列データです。(サビの部分だけですが、いい感じに仕上がったと思います)
const int score[MAX] =
{
// ある晴れた日の事
A, x1, A, x2, A, x1, A, x2, A, x1, G, x2, F, x1, G, x1, A, x5,
// 魔法以上の愉快が
A, x1, A, x2, A, x1, A, x2, A, x1, As, x2, A, x1, As, x1, C1, x3,
// 限りなく降り注ぐ
C1, x1, C1, x1, As, x2, A, x1, F, x3, C1, x1, C1, x1, As, x2, A, x1, F, x3,
// 不可能じゃないわ
C1, x1, C1, x1, As, x2, A, x1, G, x2, F, x2, G, x9,
// 明日また会う時
A, x1, A, x2, A, x1, A, x2, A, x1, G, x2, F, x1, G, x1, A, x5,
// 笑いながらハミング
A, x1, A, x2, A, x1, A, x2, A, x1, As, x2, A, x1, As, x1, C1, x3,
// うれしさを集めよう
C1, x1, C1, x1, As, x2, A, x1, F, x3, C1, x2, D1, x2, A, x1, G, x2, F, x3,
// 簡単なんだよこんなの
As, x2, As, x2, As, x2, As, x1, C1, x1, A, x2, A, x1, G, x3,
// 追いかけてね
F, x1, G, x1, Af, x2, Af, x1, G, x2, F, x9_5,
// つかまえてみて
F, x1, G, x1, Af, x2, Af, x1, G, x2, F, x5,
// 大きな夢、夢、好きでしょ?
C, x2, C, x1, F, x2, E, x2, F, x1, E, x1, M, x2, F, x1, E, x1, M, x2, F, x1, E, x1, F, x1, E, x1, M, x3,
// 終了
END
};
実際に圧電スピーカから音を鳴らすには、WiringPiのSofttoneというライブラリを使います。
プログラムのメイン部分を示します。
何をやっているのかは、コメント文を参考にしてください。
int main(void){
int i; // カウント用
// WiringPi初期化
if (wiringPiSetupGpio() < 0){
printf("gpio error.\n");
return EXIT_FAILURE;
}
// Software Toneの初期化
if ( softToneCreate(SPK) != 0){
printf("softToneCreate error.\n");
return EXIT_FAILURE;
}
// ハレ晴レユカイを演奏する
for (i = 0 ; score[i]!=-1; i+=2) {
printf("%03d %3d\n", score[i], score[i+1]); // コンソールに現在の再生周波数値を表示
softToneWrite(SPK, score[i]); // 音の出力(ここで圧電スピーカに音が出る)
delay(score[i+1]); // 同じ音を鳴らすために処理を遅延(ずっと音を鳴らした状態にする)
softToneWrite(SPK, 0); // 音と音の間に切れ目を入れるために無音を20ミリ秒入れる
delay(20);
}
return EXIT_SUCCESS;
}
実際に鳴らしてみて気づいたのですが、音と音の間に無音部分を入れないと曲っぽく聞こえないということです。
この部分。
softToneWrite(SPK, 0); // 音と音の間に切れ目を入れるために無音を20ミリ秒入れる
delay(20);
まだまだ改良の余地は沢山ありそうですが、ソースコード全体を示します。
ソースコード全体
以上、ラズベリーパイでC言語+WiringPi+圧電スピーカを使って『ハレ晴レユカイ』を鳴らす、でした。
簡単じゃないよ~こんなの!(笑)
コメント
ソースコードをありがとうございます。
自作で作ったuefi flashback 更新用 のraspi-zeroに プログラムに組み込みました。
自分で使うだけなので 音を入れる必要もないのですが、つまらないので音楽をと
思い、ここに辿りつきました。
自分用に 少し 修正してバックグランドで鳴らすようにしました。
C だと軽いので zeroでも音をならしても最大2.5%位しか食ってないので、常用できそうです。
(#^.^#)
raspi-luchyさん、こんにちは!
ソースコード、少しは役に立ったようで良かったです。
flashback更新用、色々とラズパイも用途があるんですね。
わたしもraspi-zero使ってみたいのですが、最近手に入りにくいのであきらめています(・´ω`・)