サウンドを再生するだけのプログラムです。どうしても長くなってしまう・・・。
本当はすべてinoファイルに書こうと思たんだけどどうしても
void TC5_Handler(void) __attribute__ ((weak, alias("SoundStreamCallback")));~
の行でエラーになってしまったのでcppファイルに分割しました。TC5_Handlerはinoファイル内では書けないのかな?
とにかくわかる範囲で説明。
TCは多分タイムカウンタの事。このカウンタ使って周期的に割り込み処理を起こしてその中で10bitDACにデータを書き込み音を再生している。
このプログラムでは1秒間に11025回の割り込み処理を起こしその度にstream_buffer内の1バイトを10bitDACに送っている。
10bitDACに送るデータ形式は符号なし10bitデータなので符号なし8bitデータを用意して割り込み処理内でデータを<<2して送っている。
stream_bufferはリングバッファになっていて800バイト確保して前半400バイトを再生している場合は後半400バイトをデータ更新、後半400バイトを再生している場合は前半400バイトをデータ更新している。
UpdateSoundStream()はloopで毎回呼び出す必要があり、GetSoundStreamWritableSize()でサウンドバッファに書き込みするバイト数を取得して0以外ならWriteSoundStream()でwaveデータを書き込む。
このプログラムはwaveの終端になったらwaveの先頭に戻ってループ再生している。
またTinyArcadeは1チャンネル分しかサウンドを再生することができないためBGM,SEなどたくさん同時に再生したい場合は自前でwaveを合成する必要がある。
#include <TinyScreen.h>
#include "SoundStream.hpp"
#include "TwinkleBeep01.h"
TinyScreen tiny_screen = TinyScreen(TinyScreenPlus);
int wave_sample;
void setup()
{
	tiny_screen.begin();
	tiny_screen.setBitDepth(TSBitDepth8);
	tiny_screen.setBrightness(8);
	tiny_screen.setFont(liberationSansNarrow_12ptFontInfo);
	tiny_screen.fontColor(TS_8b_White, TS_8b_Black);
	InitializeSoundStream();
	wave_sample = 0;
}
void loop()
{
	tiny_screen.setCursor(0,0);
	tiny_screen.print("Now playing!");
	UpdateSoundStream();
	int writable_size = GetSoundStreamWritableSize();
	int wave_size = static_cast<int>(sizeof(TwinkleBeep01_wave));
	if(writable_size > 0)
	{
		size_t write_size = writable_size;
		size_t left_size = wave_size - wave_sample;
		if(left_size < writable_size)
		{
			write_size = left_size;
		}
		if(write_size > 0)
		{
			unsigned char* write_wave_buffer = new unsigned char[writable_size];
			memcpy(write_wave_buffer, &TwinkleBeep01_wave[wave_sample], write_size);
			wave_sample += write_size;
			if(writable_size > left_size)
			{
				int left_write_size = writable_size - left_size;
				if(left_write_size > 0)
				{
					wave_sample = 0;
					memcpy(&write_wave_buffer[write_size], &TwinkleBeep01_wave[wave_sample], left_write_size);
					wave_sample += left_write_size;
				}
			}
			WriteSoundStream(write_wave_buffer);
			delete [] write_wave_buffer;
		}
		if(wave_sample >= wave_size)
		{
			wave_sample = 0;
		}
	}
}#ifndef SOUNDSTREAM_HPP #define SOUNDSTREAM_HPP static const int SOUND_BUFFER_SIZE = 800; static const int SOUND_BUFFER_SIZE_HALF = SOUND_BUFFER_SIZE / 2; static const int SOUND_FREQUENCY = 11025; void InitializeSoundStream(); void FinalizeSoundStream(void); void UpdateSoundStream(void); int GetSoundStreamWritableSize(void); bool WriteSoundStream(const unsigned char* buffer); #endif
#include <TinyScreen.h>
#include "SoundStream.hpp"
unsigned char stream_buffer[SOUND_BUFFER_SIZE];
int sample_index;
int write_buffer;
bool request;
bool tcIsSyncing(void)
{
	return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
}
void tcReset(void)
{
	// Reset TCx
	TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
	while(tcIsSyncing());
	while(TC5->COUNT16.CTRLA.bit.SWRST);
}
void InitializeSoundStream(void)
{
	memset(stream_buffer, 0x80, SOUND_BUFFER_SIZE);
	sample_index = 0;
	write_buffer = 0;
	request = false;
	analogWrite(A0, 0);
	// Enable GCLK for TCC2 and TC5 (timer counter input clock)
	GCLK->CLKCTRL.reg = static_cast<unsigned short>((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)));
	while(GCLK->STATUS.bit.SYNCBUSY);
	tcReset();
	// Set Timer counter Mode to 16 bits
	TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
	// Set TC5 mode as match frequency
	TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
	TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1;
	TC5->COUNT16.CC[0].reg = static_cast<unsigned short>((SystemCoreClock / SOUND_FREQUENCY - 1));
	while(tcIsSyncing());
	// Configure interrupt request
	NVIC_DisableIRQ(TC5_IRQn);
	NVIC_ClearPendingIRQ(TC5_IRQn);
	NVIC_SetPriority(TC5_IRQn, 0);
	NVIC_EnableIRQ(TC5_IRQn);
	// Enable the TC5 interrupt request
	TC5->COUNT16.INTENSET.bit.MC0 = 1;
	while(tcIsSyncing());
	// Enable TC
	TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
	while(tcIsSyncing());
}
void FinalizeSoundStream(void)
{
	// Disable TC5
	TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
	while(tcIsSyncing());
	// Reset TCx
	TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
	while(tcIsSyncing());
	while(TC5->COUNT16.CTRLA.bit.SWRST);
}
void UpdateSoundStream(void)
{
	int play_buffer = 0;
	if(sample_index >= SOUND_BUFFER_SIZE_HALF)
	{
		play_buffer = 1;
	}
	if(write_buffer == play_buffer)
	{
		request = true;
	}
}
int GetSoundStreamWritableSize(void)
{
	if(request == false)
	{
		return 0;
	}
	return SOUND_BUFFER_SIZE_HALF;
}
bool WriteSoundStream(const unsigned char* buffer)
{
	int play_buffer = 0;
	if(sample_index >= SOUND_BUFFER_SIZE_HALF)
	{
		play_buffer = 1;
	}
	write_buffer = 1 - play_buffer;
	memcpy(&stream_buffer[SOUND_BUFFER_SIZE_HALF * write_buffer], buffer, SOUND_BUFFER_SIZE_HALF);
	request = false;
	return true;
}
#ifdef __cplusplus
extern "C"
{
#endif
	void SoundStreamCallback(void)
	{
		while(DAC->STATUS.bit.SYNCBUSY == 1);
		DAC->DATA.reg = static_cast<unsigned short>(stream_buffer[sample_index] << 2); // 8bit->10bit
		while(DAC->STATUS.bit.SYNCBUSY == 1);
		++ sample_index;
		if(sample_index >= SOUND_BUFFER_SIZE)
		{
			sample_index = 0;
		}
		TC5->COUNT16.INTFLAG.bit.MC0 = 1;
	}
	void TC5_Handler(void) __attribute__ ((weak, alias("SoundStreamCallback")));
#ifdef __cplusplus
}
#endif// 11025Hz 8bit mono wavedata
const unsigned char TwinkleBeep01_wave[40045] =
{
	128, 128, 122, 116, 113, 119, 139, 150, 152, 141, 105, 83, 79, 91, 138, 176,
	178, 174, 128, 79, 76, 84, 132, 186, 196, 190, 151, 92, 76, 81, 112, 172,
	197, 194, 159, 95, 64, 63, 80, 135, 178, 179, 168, 117, 67, 60, 68, 111,
:
:
:
続くTwinkleBeep01_waveがループ再生されます。