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だけに」とかオヤジギャグが浮かぶ。
  • 仕方なく抵抗を増やして暗くする。それでも動画上ではハレーション出てるが、実物は割と暗めで地味だったりする。動画のために生を地味にするって悲しい。

みっかぼの無料Androidアプリはこちら。