LPC810メモ:疑似正弦波で音楽を鳴らす(μ's/Snow halation)
前回の続き、電子オルゴールの長めのサンプル。
前回は動きがなくて動画の意味が全く無かったので、音に連動して光るLEDを置いてみた。
動画だと音と画面がずれてるのが残念。生で見るとけっこういい感じだし、音も澄んでるのだが。
曲はμ'sのSnow halation。ラブライブにはまっている娘(2人とも)の関心を買うことを狙った選曲。
参考にした譜面はこれ。買ったのに全然弾けなかったのだが、今回使えてよかった。
なお電子工作と無関係な余談だが、上の本にはアニメ1期の曲までしか載ってない。このサンプルも本当はユメノトビラにしたかったのだが断念・・・と思ったら2期の本も出てたのを今日知った。さすがに買おうとは思わないが。
譜面の話はさておき、本サンプルにおいて前提とする環境はこちら→LPC810メモ 共通の準備
SCTなど基本的なサンプルについてはこちら→LPC810みっかぼ自作サンプル集
サンプルコードは、譜面データが大きくなったことと、LEDを光らせるコードが足された以外は特に変わりなし。
サンプルコード
SctSoundUtil.h,SctSoundUtil.cpp -> こちらのサンプルから持ってくる。
SctTonePart.h,SctTonePart.cpp -> こちらのサンプルから持ってくる。
sample.cpp
#include "LPC8xx.h" #include "SctSoundUtil.h" #include "SctTonePart.h" // 前奏 constexpr uint8_t PRE_p0[] { V(10), O5,R4,E4,B4,Gs2,A(10), R2,A2,Gs2,A2, Gs4,Fs2,E(10), Gs(8),B(8), R1,E1,A(6),R2,A2,Gs2,A2, B1,O6,E(3),O5,A2,Gs4,E(6), Cs1,Fs(5),O6,Cs2,Cs2,O5,A2,Fs2,Cs2, O4,A(16), O6,E(16), EOD }; constexpr uint8_t PRE_p1[] { V(10), R(16), R(16), R(16), O4,B(8),O5,Cs(8), Cs(8),R(8), Gs4,R(12), O4,A(6),R(10), D(16),T(16), EOD }; constexpr uint8_t PRE_p2[] { V(5), O3,A2,O4,E2,B2,O5,Cs(10), O4,Cs2,A2,B2,O5,E(10), Cs(16), O3,E2,B2,O4,E2,Fs2,Gs4,Cs4, O3,Fs2,O4,Cs2,Gs2,A(10), O3,E2,B2,O4,Fs2,Gs(10), O3,D2,A2,O4,Cs2,Fs(10), O3,E(16),T(16), EOD }; // Aメロ constexpr uint8_t A_p0[] { // ふしぎだね O5,R1,E(3),Fs2,E(6),Fs2,E(6), Cs4,O4,B4,A4, B4,O5,Cs2,Cs(10), R(8),E2,D2,Cs2,Cs(6), D2,O4,A4,O5,D4,Cs(6), O4,A2,Gs4,A4,B(10), R2,E2,Gs2,B2, O5,D2,D(6),Cs2,Cs(6), O5,E4,Fs2,E(6),Fs2,E(6), Cs4,O4,B4,A4, B4,O5,E4,Fs4,O4,A(6), O5,A4,Gs4,E(6), O4,A4,A2,A4,O5,D4,E(6), O4,A2,B4,A4,A2, T(16), O5,Cs(6),Cs(6),O4,B4, EOD }; constexpr uint8_t A_p1[] { // ふしぎだね O4,Fs(14), Gs(10), R(8), E(6),E(10), R(8), Gs(8), Fs(14),F(16), E(10), R(8), G2,G(6),G2,G(6), A(16), Gs(16), Gs(12),Cs(6), O5,Cs4,O4,B4,Gs(6), D(14),Fs(8), D(8),D2, T(16), R(16), EOD }; constexpr uint8_t A_p2[] { // ふしぎだね O3,D4,A2,O4,E(10), O3,E4,B2,O4,Fs(10), O3,Fs(6),Fs4,Fs2,A2,O4,Cs(10), O3,B(8), D2,D2,Fs2,A(10), B(6),B2,R2,B(6), O4,Cs(16), O3,E2,E(6),A2,A(6), V(10), O3,D4,D4,D4,D4, E4,E4,E4,E4, Cs4,Cs4,Cs2,Cs2,Fs(8), Fs4,Fs4,Fs4, O3,B4,B4,B4,B4, E4,E4,E4,E4, A4,A4,A4,A4, A4,A4,A4,A4, EOD }; // Bメロ constexpr uint8_t B_p0[] { // はじめて O5,Cs4,D4,Fs4,D2,Gs2, T(16), O4,B4,O5,E4,Gs4,Cs2,B4, A2,Gs2,A(10), Fs4,D4,Fs4,A4, Gs4,A2,Gs(10), Fs4,D4,Fs4,A4, B4,E2,E(10), Fs4,D4,Fs4,A2,A2, R2,Fs4,Gs4,A4,B2, T(16), O6,Cs(6),O5,B(10), EOD }; constexpr uint8_t B_p1[] { // はじめて O4,A(14),B2, T(16), Gs(8),O5,Cs4,Cs2,E(8), Cs(10), O4,A(16), B(16), A(16), Gs(16), A(16), R2,A(14), B4,B4,B4,B4, O5,A(6),Gs(10), EOD }; constexpr uint8_t B_p2[] { // はじめて O4,D(6),D2,D(8), E(6),E2,E(8), Cs(6),Cs2,F(6),F2, Fs(6),Fs2,E(6),E2, O3,B4,B4,B2,B2,B4, O4,Cs4,Cs4,Cs2,Cs2,Cs4, D4,D4,D2,D2,D4, Cs4,Cs4,Cs2,Cs2,Cs4, D4,D4,D2,D2,D4, Ds4,Ds4,Ds2,Ds2,Ds4, E4,E4,E4,E4, E2,E2,R(12), EOD }; // サビ前半 constexpr uint8_t SABI1_p0[] { // とどけて O5,R4,E4,B4,Gs2,A(6), A4,Gs4,A4, Gs4,Fs2,E(10), O4,B(8),O5,Cs(8), R4,E4,B4,Gs2,A(10), R4,A2,B2, O(6),Cs(6),O5,B2,B(6),B2, O(6),D4,Cs2,O5,B4,A(6), EOD }; constexpr uint8_t SABI1_p1[] { // とどけて O5,Cs(14),E2,T(16), Cs(16), O4,Gs(8),Gs(8), O5,Cs(14),Cs(10),R(8), Fs(16), A(6),D4,D(6), EOD }; constexpr uint8_t SABI1_p2[] { // とどけて O3,A4,A4,A2,A2,A4, O4,Cs4,Cs4,Cs2,Cs2,Cs4, D4,D4,D2,D2,D4, E4,E4,F2,F2,F4, Fs4,Fs4,Fs2,Fs2,Fs4, O4,E4,E4,E2,E2,E4, Ds4,Ds4,Ds2,Ds2,Ds4, O3,B2,B(6),O4,E2,E(6), EOD }; // サビ後半 constexpr uint8_t SABI2_p0[] { // おもいが R4,E4,B4,Gs2,A(6), A4,Gs4,A4, Gs4,Fs2,E(10), E4,D4,Cs4,O4,B4, O5,R4,E4,B4,Gs2,A(10), R4,A2,B2, O6,Cs(6),O5,B2,B(6),B2, O6,D4,Cs2,O5,B4,O6,Cs(6), O5,R4,Cs4,Fs4,A4, Gs4,A2,Gs(10), Cs4,E2,E2,Gs4,Cs2,Cs2, Cs2,B2,Gs2,A(10), EOD }; constexpr uint8_t SABI2_p1[] { // おもいが O5,Cs(14),E2,T(16), Cs(16), O4,B(8),Gs(8), O5,Cs(14),Cs(10),R(8), Fs(16), A(6),Gs4,Gs(6), O4,A(16), O5,F(6),F(10), O4,A(16), R(6),O5,Fs(10), EOD }; constexpr uint8_t SABI2_p2[] { // おもいが O3,A4,A4,A2,A2,A4, O4,Cs4,Cs4,Cs2,Cs2,Cs4, D4,D4,D2,D2,D4, E4,E4,F2,F2,F4, Fs4,Fs4,Fs2,Fs2,Fs4, E4,E4,E2,E2,E4, Ds4,Ds4,Ds2,Ds2,Ds4, D(6),Cs4,Ds2,F4, Fs(6),Fs2,Fs(8), F(6),F2,F(8), E(6),E2,E(8), Ds(6),Ds2,Ds(8), EOD }; // 間奏 constexpr uint8_t INT_p0[] { // とびこむ〜間奏〜snow halation D4,E2,E2,A2,O6,D4,Cs(6), O5,A2,Gs4,A4,A2,T(16), O5,D(6),E2,B2,A2,Gs2,A(12),O6,Ds1,E(3),E2, O6,E2,D4,C2,O5,B2,O6,C4,D2, D4,C2,O5,B4,G2,A2,G2,T(16), O5,E4,R2,Ds1,E1,G4,A2,B2, O6,R2,C2,D2,D4,C2,D2,E2, E4,F2,E4,D4,C2,T(16), O5,A(6),E1,G1,O6,D4,C2,O5,B4, G2,A2,G(10), O6,C(6),O5,E1,G1,O6,D4,D2,D2, R2,C2,O5,B2,O6,D1,E(3),E2,D2,C2, O6,D(16),R(6),D4,C2,D2,E2, E(16), E(12),O5,E4, O5,R4,E4,B4,Gs2,A(6), A4,Gs4,A4, Gs4,Fs2,E(10), O4,B(8),O5,Cs(8), O5,R4,E4,B4,Gs2,A(10), R4,A2,B2, O6,Cs(6),O5,B2,B(6),B2, O6,D4,Cs2,O5,B4,A(6), EOD }; constexpr uint8_t INT_p1[] { // とびこむ〜間奏 O4,A(14),O5,E(16), F2, T(16), O4,B(8),O5,D(6),Cs(10),R(8), O5,G(16), E(16), D(8),F(8), O4,B(16), B(16), O5,C(16), C4,D4,E4,B4, O5,C(16), D(16), E(16), F(16), O5,Fs(16), R(16), Gs(16), E(12),O4,B4, O5,Cs(14),E2, T(16), O4, A(16), Gs(8),Gs(8), O5,Cs(14),E(10), R(8), Fs(16), Fs(6),D4,D(6), EOD }; constexpr uint8_t INT_p2[] { // とびこむ〜間奏 O3,B(6),B2,B(8), O4,Cs(6),Cs2,Cs(8), D(16), O4,G(8),E2,E2,R4, O3,F4,O4,C2,E4,A(6), O4,D4,D2,G4,B(6),C4,C2,E4,A(6), D4,D2,G4,B(6), O3,B4,B2,O4,E4,G(6), O4,B(8),G(8), A(8),B(8), O5,C4,O4,B4,A4,E4, O4,C4,C2,E4,A(6), O4,D4,D2,G4,B(6), O4,C4,C2,E4,A(6), O4,D4,D2,G4,B(6), O4,E(6),E4,Fs4,B(6), O5,E4,Fs(8), D(16), O4,E(12),E4, O3,A(10),A2,B2,O4,Cs2, T(16), D(6),D(10), E(8),F(8), O4,Fs(16), E(16), Ds4,Ds2,Ds2,Ds2,Ds2,Ds2,Ds2, O3,B2,B(6),O4,E2,E(6), EOD }; // コーダ constexpr uint8_t CODA_p0[] { // とびこむ〜Coda O5,Cs4,E2,E2,A2,O6,D4,Cs(6), O5,A2,Gs4,A4,A2,T(16), T(6),E2,B2,A2,Gs2,A2, T(16), O5,B(8),O6,Cs(8), E(8),Cs(8), O5,B(8),O6,E(8), Fs2,Cs2,O4,A4,O5,Cs2,O4,A2,Fs4, D(6),E4,Fs2,Gs4, A4,A4,A4,A4, O5,E4,E4,Gs4,Gs4, Gs4,Gs4,A4,A4, Gs4,Fs4,F4,Cs4, Cs4,Cs4,Cs4,Cs4, O4,B4,B4,O5,E4,E4, Fs4,Fs4,Fs4,Fs2,Gs2, A2,A(6),A2,B(6), R4, O6,E(16),T(16), EOD }; constexpr uint8_t CODA_p1[] { // とびこむ〜Coda O4,A(14),O5,D(16), Cs2, T(16), T(6), R(8), Cs2, T(16), O5,Gs(8),Gs(8), Fs(8),Fs(8), E(8),E(8), O4,A(8),Fs(8), O3,A(6),B(10), B4,B4,O4,Cs4,Cs4, Gs4,Gs4,B4,B4, B4,B4,O5,Cs4,Cs4, O4,B4,B4,Gs4,Gs4, E4,E4,E4,E4, Fs4,Fs4,Gs4,Gs4, A4,A4,A(8), O5,D2,D(6),Fs2,Gs(6), R4,O5,A(16),T(16), EOD }; constexpr uint8_t CODA_p2[] { // とびこむ〜Coda O4,D(6),D2,D(8), O4,E2,E(10),E4, O3,A4,A4,A2,A2,A4, O4,Cs4,Cs4,Cs2,Cs2,Cs4, O4,D4,D4,D2,D2,D4, O4,E4,E4,F2,F2,F4, O4,Fs4,Fs4,Fs2,Fs2,Fs4, O4,E4,E4,E2,E2,E4, O4,Ds4,Ds4,Ds2,Ds2,Ds4, O3,B4,B2,O4,E(6),E4, O3,A4,A2,E2,A4,A2,E2, O4,Cs4,Cs2,O3,Gs2,O4,Cs4,Cs2,O3,Gs2, O4,D4,D2,O3,A2,O4,D4,D2,O3,A2, O4,E4,E2,O3,B2,O4,F4,F2,Cs2, Fs4,Fs2,Cs2,Fs4,Fs2,Cs2, O4,E4,E2,O3,B2,O4,E4,E2,O3,B2, O4,Ds4,Ds2,O3,A2,O4,Ds4,Ds2,O3,A2, B2,B(6),O4,E2,E(6), R4,D(16),T(16), EOD }; const uint8_t *part0[] = { PRE_p0, A_p0, B_p0, SABI1_p0, SABI2_p0, INT_p0, SABI2_p0, CODA_p0, nullptr }; const uint8_t *part1[] = { PRE_p1, A_p1, B_p1, SABI1_p1, SABI2_p1, INT_p1, SABI2_p1, CODA_p1, nullptr }; const uint8_t *part2[] = { PRE_p2, A_p2, B_p2, SABI1_p2, SABI2_p2, INT_p2, SABI2_p2, CODA_p2, nullptr }; static SctTonePart sctTonePart[3]; static void handler() { uint8_t duty{0}; bool endFlag{true}; for(uint8_t i = 0; i < 3; i++) { auto &t = sctTonePart[i]; duty += t.proceed(); if(!t.eol()) { endFlag = false; } if(t.getDamper() == 0) { // 音が変わった瞬間にLEDをつける LPC_GPIO_PORT->SET0 |= (1<<(i + 1)); } else if(t.getDamper() == 7){ // 減衰が7になったらLEDを消す LPC_GPIO_PORT->CLR0 |= (1<<(i + 1)); } } if(endFlag) { SctSoundUtil::stop(); } else { SctSoundUtil::setDuty(duty); } } int main(void) { // GPIOに対してclockを有効化 // UM10601 4.6.13 System clock control register LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); // PIO0_1,PIO0_2,PIO0_3 (6,5,4番のpin)をoutputに設定 // UM10601 7.6.3 GPIO port direction registers LPC_GPIO_PORT->DIR0 |= (1<<1) | (1<<2) | (1<<3); LPC_GPIO_PORT->CLR0 |= (1<<1) | (1<<2) | (1<<3); sctTonePart[0].setMml(768, part0); sctTonePart[1].setMml(768, part1); sctTonePart[2].setMml(768, part2); SctSoundUtil::setCallback(handler); SctSoundUtil::init(); SctSoundUtil::start(); return 0; }
接続
基本的には最初のサンプルと同じ、ただし以下が異なる。
- 電池がCR2032だとどうも安定しないので、単3の充電池3本に変更。
- 3,4,5番ピンにLEDをつける。LEDについてる抵抗は10kΩx2で20kΩ。
- 最初は3kΩだったのだが、「補足/雑感」で述べる事情で暗くした。
補足/雑感
- 3000byteジャスト、まだまだ書ける。ボタンでもう一回演奏したり、演奏終わったらsleepしたりとか、いつかやりたい。
- 前回の「おじいさんの古時計」ではじめてYouTubeに動画をアップしてみたのはいいものの、絵が動かない。動いても自分の手ぶれだけ、というのは寂しかったので、無理やり感があるがLEDをつけた。
- やってみると、抵抗3kでピカピカ光って、生でみる限りではとてもいい感じになった。
- しかしスマホで撮影してみると、ハレーションが激しく、極めて不快な映像になり愕然。「Snow halationだけに」とかオヤジギャグが浮かぶ。
- 仕方なく抵抗を増やして暗くする。それでも動画上ではハレーション出てるが、実物は割と暗めで地味だったりする。動画のために生を地味にするって悲しい。