戻る

サウンド再生

サウンドを再生するだけのプログラムです。どうしても長くなってしまう・・・。
本当はすべて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を合成する必要がある。

要するにこのプログラムはBGM再生中にSEが再生できないためこのままゲームプログラムに使えない…。

サンプルプログラム

  • SoundSample1.ino
    #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;
    		}
    	}
    }
  • SoundStream.hpp
    #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
  • SoundStream.cpp
    #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
  • TwinkleBeep01.h
    // 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,
    :
    :
    :
    続く

実行結果

SoundSample1.jpg

TwinkleBeep01_waveがループ再生されます。

サンプルプログラムのダウンロード


添付ファイル: fileSoundSample1.jpg 88件 [詳細] fileSoundSample1.zip 82件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-01-30 (月) 01:57:19 (482d)