至らぬ所や、未実装の箇所もいくらかありますが
気分転換を図りたいのが正直なところでして。
これを最初のバージョンとしたいと思います。
ドレミ音のみ、実機周波数に併せてます。
単音再生を前提として作成してます。
libnds 関数のみでPSGチャンネル・ノイズチャンネルの
複数再生を作るのは大変だと言うことは分かりました。
そのレベルのサウンドドライバを構築するのなら
むしろARM7コードで制御するのが賢い選択でしょうと。
データを垂れ流すだけのWAV再生ならまだ
libnds 関数の手軽さに優位性が見えますが。
CAL_SUND, CAL_SHTS, CAL_LONSはドレミ音を使ったサウンド再生なので
実機に近しい音となってます。
CAL_ENDS, CAL_ERRS はタイミング合わせのみの状態、
キー入力音、内蔵プログラムのタイマーカウント音、の
ユーザがプログラムで鳴らすことができない音もまだ未実装です。
main.c
/*--------------------------------------------------------------------------------- Amp module test version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #include <nds.h> #include <stdio.h> #include "Amp.h" //--------------------------------------------------------------------------------- int main(void) { //--------------------------------------------------------------------------------- u32 kdr = 0; u8 note_val = 0; //initMain lcdSwap(); consoleDemoInit(); keysSetRepeat(20, 10); //initAmp Amp_Init(); //drawTitle printf("Amp module test\n\nversion 0.01\nOct 22, 2009\n\n(C)2009 REGEKATSU\n\n\n"); while(1) { swiWaitForVBlank(); Amp_Exec(); printf("\x01b[8;0HNOTE VAL = %01X", note_val); scanKeys(); kdr = keysDownRepeat(); //--- inSequenceExec --- //playSound if(keysDown() & (KEY_A | KEY_X)){ Amp_CallSound(note_val); } //stopSound if(keysDown() & (KEY_B | KEY_Y)){ Amp_StopSound(); } //nextNote if(kdr & KEY_UP){ if(note_val < 15){ note_val++; } } //prevNote if(kdr & KEY_DOWN){ if(note_val > 0){ note_val--; } } //CAL_ENDS timing check if(keysDown() & KEY_RIGHT){ Amp_CallEndSound(); } //CAL_ERRS timing check if(keysDown() & KEY_LEFT){ Amp_CallErrorSound(); } //volumeUp if(kdr & KEY_R){ Amp_VolumeUp(); } //volumeDown if(kdr & KEY_L){ Amp_VolumeDown(); } //panLeft if(kdr & KEY_SELECT){ Amp_PanLeft(); } //panRight if(kdr & KEY_START){ Amp_PanRight(); } } } //---------------------------------------------------------------------------------
Amp.h
/*--------------------------------------------------------------------------------- Amp module header version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #ifndef _AMP_H_ #define _AMP_H_ #include <nds/ndstypes.h> typedef enum{ NOTE_NULL = 0x00, NOTE_A_DOWN = 0x01, NOTE_B_DOWN = 0x02, NOTE_C = 0x03, NOTE_D = 0x04, NOTE_E = 0x05, NOTE_F = 0x06, NOTE_G = 0x07, NOTE_A = 0x08, NOTE_B = 0x09, NOTE_C_UP = 0x0A, NOTE_D_UP = 0x0B, NOTE_E_UP = 0x0C, NOTE_F_UP = 0x0D, NOTE_G_UP = 0x0E, NOTE_REST = 0x0F }NOTE_VAL; #ifdef __cplusplus extern "C" { #endif //基本実行関数 void Amp_Init(void); void Amp_Clear(void); u32 Amp_Exec(void); //基本再生/停止関数 void Amp_PlaySound(u8 note_val, u32 play_time); void Amp_StopSound(void); void Amp_SetScoreSound(u32 *score_val, int score_size); void Amp_ScoreSound(void); //キータッチ音 void Amp_BeepSound(void); //タイマーチクタク音 void Amp_ClockSound(void); //プリセットサウンド関数 void Amp_CallEndSound(void); void Amp_CallErrorSound(void); void Amp_CallShortSound(void); void Amp_CallLongSound(void); void Amp_CallSound(u8 note_val); //オプション設定関数 void Amp_VolumeUp(void); void Amp_VolumeDown(void); void Amp_PanLeft(void); void Amp_PanRight(void); #ifdef __cplusplus } #endif #endif //_AMP_H_
AmpPrivate.h
/*--------------------------------------------------------------------------------- Amp module private header version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #ifndef _AMP_PRIVATE_H_ #define _AMP_PRIVATE_H_ #include <nds/ndstypes.h> #include <nds/arm9/sound.h> #include "Amp.h" #include "AmpPSG.h" #include "AmpScore.h" #include "AmpState.h" #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif //_AMP_PRIVATE_H_
Amp.c
/*--------------------------------------------------------------------------------- Amp module routine version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #include "AmpPrivate.h" // 0.1 sec to vblank cycle convert #define SET_TIME(x) (((x)*6)+1) // 1/60 sec to vblank cycle convert #define SET_FRAME(x) ((x)+1) //--------------------------------------------------------------------------------- void Amp_Init(void){ //--------------------------------------------------------------------------------- Amp_Clear(); soundEnable(); } //--------------------------------------------------------------------------------- void Amp_Clear(void){ //--------------------------------------------------------------------------------- Amp_StopSound(); AmpScore_ClearScore(); AmpPSG_ClearPSG(); AmpState_ClearTime(); } //--------------------------------------------------------------------------------- u32 Amp_Exec(void){ //--------------------------------------------------------------------------------- //現在カウンタ値を前回カウンタ値として保存する。 AmpState_SetPlayOld(AmpState_GetPlayTime()); //前回カウンタ値が0でない限り、現在カウンタ値を 1 減算する。 if(AmpState_GetPlayOld()){ AmpState_SetPlayTime(AmpState_GetPlayTime() - 1); } //現在カウンタ値が0になったら(なった瞬間のみ)、サウンド再生を停止する。 if((AmpState_GetPlayTime() == 0) && (AmpState_GetPlayOld() == 1)){ Amp_StopSound(); //スコア再生モード中だった場合、次のスコアデータを処理する。 if(AmpScore_GetScoreMode()){ Amp_ScoreSound(); } } //現在カウンタ値を返値として返す。 return AmpState_GetPlayTime(); } //--------------------------------------------------------------------------------- void Amp_PlaySound(u8 note_val, u32 play_time){ //--------------------------------------------------------------------------------- /*一般的周波数 const static u16 note_table[] = { 980, 1100, 1235, 1308, 1468, 1648, 1746, 1960, 2200, 2469, 2616, 2937, 3296, 3492, 3920, 4400 }; */ //gmc-4 周波数 const static u16 note_table[] = { 980, 1142, 1292, 1354, 1508, 1688, 1784, 2032, 2261, 2560, 2692, 3015, 3449, 3550, 3982, 4400 }; //プレイタイムが 0 の時に実行可能とする。 if(!AmpState_GetPlayTime()){ //ノート指定が 1〜E 以外なら、時間セットのみ有効とし、無音再生とする。 if( !( (note_val >= NOTE_A_DOWN) && (note_val <= NOTE_G_UP) ) ){ AmpState_SetPlayTime(play_time); //ノート指定が 1〜E なら再生を実行する。 }else{ AmpState_SetPlayTime(play_time); AmpPSG_SetFreq(note_table[note_val] * 8 / 10); AmpPSG_PlayPSG(); } } } //--------------------------------------------------------------------------------- void Amp_StopSound(void){ //--------------------------------------------------------------------------------- AmpState_ClearPlayTime(); soundPause(AmpPSG_GetSoundId()); } //--------------------------------------------------------------------------------- void Amp_SetScoreSound(u32 *score_val, int score_size){ //--------------------------------------------------------------------------------- //*score_val : 再生させたいサウンドデータ配列の先頭アドレスを渡す //score_size : サウンドデータ配列長を渡す // //サウンドデータのフォーマット //データ型 : u32 //偶数番地 : 周波数(小数点第一位までを整数として数える。 // 周波数 440.0 Hz なら実際の値は 4400 と指定する) //奇数番地 : 再生時間( 1/60 秒単位) // ※ライブラリ関数の性質上、1フレームの遅れがあるので // 指定には再生させたいフレーム数 + 1 とすること。 // //サウンドデータ例) 「ドレミ」と再生させる場合。 //u32 score_val[6]; //score_val[0] = 654, score_val[1] = SET_FRAME(2); //score_val[2] = 734, score_val[3] = SET_FRAME(2); //score_val[4] = 824, score_val[5] = SET_FRAME(2); AmpScore_SetScoreMode(true); AmpScore_SetScorePValue(score_val); AmpScore_SetScoreSize(score_size); Amp_ScoreSound(); } //--------------------------------------------------------------------------------- void Amp_ScoreSound(void){ //--------------------------------------------------------------------------------- static int idx = 0; //プレイタイムが 0 の時に実行可能とする。 if(!AmpState_GetPlayTime()){ //配列サイズチェック。奇数指定の場合 //書式誤りなので、モードをキャンセルする。 if(AmpScore_GetScoreSize() % 2){ AmpScore_SetScoreMode(false); //スコアデータ終端でないうちは再生を続ける。 }else if(idx != AmpScore_GetScoreSize()){ AmpState_SetPlayTime(AmpScore_GetScorePValue()[idx + 1]); AmpPSG_SetFreq( ( AmpScore_GetScorePValue()[idx] ) * 8 / 10); AmpPSG_PlayPSG(); idx += 2; //スコアデータ終端であれば //スコアモードを終了し、デストラクタを行う。 }else{ AmpScore_SetScoreMode(false); idx = 0; } } } //--------------------------------------------------------------------------------- void Amp_BeepSound(void){ //--------------------------------------------------------------------------------- } //--------------------------------------------------------------------------------- void Amp_ClockSound(void){ //--------------------------------------------------------------------------------- } //--------------------------------------------------------------------------------- void Amp_CallEndSound(void){ //--------------------------------------------------------------------------------- const static u32 score_val[] = { /* freq, play_frame */ 2616, SET_FRAME(3), 2937, SET_FRAME(3), 3296, SET_FRAME(3), 2616, SET_FRAME(3), 2937, SET_FRAME(3), 3296, SET_FRAME(3), 2616, SET_FRAME(3), 2937, SET_FRAME(3) }; Amp_SetScoreSound((u32 *)&score_val[0], 16); } //--------------------------------------------------------------------------------- void Amp_CallErrorSound(void){ //--------------------------------------------------------------------------------- const static u32 score_val[] = { /* freq, play_frame */ 2616, SET_FRAME(3), 2937, SET_FRAME(3), 3296, SET_FRAME(3), 2616, SET_FRAME(3), 2937, SET_FRAME(3), 3296, SET_FRAME(3), 2616, SET_FRAME(3), 2937, SET_FRAME(3), 3296, SET_FRAME(3) }; Amp_SetScoreSound((u32 *)&score_val[0], 18); } //--------------------------------------------------------------------------------- void Amp_CallShortSound(void){ //--------------------------------------------------------------------------------- Amp_PlaySound(NOTE_E_UP, SET_TIME(3)); } //--------------------------------------------------------------------------------- void Amp_CallLongSound(void){ //--------------------------------------------------------------------------------- Amp_PlaySound(NOTE_E_UP, SET_TIME(1)); } //--------------------------------------------------------------------------------- void Amp_CallSound(u8 note_val){ //--------------------------------------------------------------------------------- //ノート指定が 1〜E なら再生を実行し、 //ノート指定が 1〜E 以外なら、再生は行わない //(ノート指定を 0, F としても無音再生とはならない)。 if( (note_val >= NOTE_A_DOWN) && (note_val <= NOTE_G_UP) ){ Amp_PlaySound(note_val, SET_TIME(4)); } } //--------------------------------------------------------------------------------- void Amp_VolumeUp(void){ //--------------------------------------------------------------------------------- AmpPSG_VolumeUp(); } //--------------------------------------------------------------------------------- void Amp_VolumeDown(void){ //--------------------------------------------------------------------------------- AmpPSG_VolumeDown(); } //--------------------------------------------------------------------------------- void Amp_PanLeft(void){ //--------------------------------------------------------------------------------- AmpPSG_PanLeft(); } //--------------------------------------------------------------------------------- void Amp_PanRight(void){ //--------------------------------------------------------------------------------- AmpPSG_PanRight(); } //---------------------------------------------------------------------------------
AmpPSG.h
/*--------------------------------------------------------------------------------- AmpPSG module header version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #ifndef _AMP_PSG_H_ #define _AMP_PSG_H_ #include <nds/ndstypes.h> #include <nds/arm9/sound.h> #ifdef __cplusplus extern "C" { #endif int AmpPSG_GetSoundId(void); void AmpPSG_SetSoundId(int sound_id); void AmpPSG_ClearSoundId(void); DutyCycle AmpPSG_GetDutyCycle(void); void AmpPSG_SetDutyCycle(DutyCycle duty_cycle); void AmpPSG_ClearDutyCycle(void); u16 AmpPSG_GetFreq(void); void AmpPSG_SetFreq(u16 freq); void AmpPSG_ClearFreq(void); u8 AmpPSG_GetVolume(void); void AmpPSG_SetVolume(u8 volume); void AmpPSG_ClearVolume(void); u8 AmpPSG_GetPan(void); void AmpPSG_SetPan(u8 pan); void AmpPSG_ClearPan(void); void AmpPSG_ClearPSG(void); void AmpPSG_PlayPSG(void); void AmpPSG_VolumeUp(void); void AmpPSG_VolumeDown(void); void AmpPSG_PanLeft(void); void AmpPSG_PanRight(void); #ifdef __cplusplus } #endif #endif //_AMP_PSG_H_
AmpPSG.c
/*--------------------------------------------------------------------------------- AmpPSG module routine version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #include "AmpPSG.h" typedef enum{ PSG_VOL_DEF = 63, PSG_VOL_MIN = 0, PSG_VOL_MAX = 127, PSG_PAN_DEF = 63, PSG_PAN_MIN = 0, PSG_PAN_MAX = 127 }PSG_STAT; typedef struct{ int sound_id; DutyCycle duty_cycle; u16 freq; u8 volume; u8 pan; }PsgStatus; static PsgStatus st_psg = {0, DutyCycle_50, 0000, PSG_VOL_DEF, PSG_PAN_DEF}; //--------------------------------------------------------------------------------- // sound_id Getter / Setter / Clear //--------------------------------------------------------------------------------- int AmpPSG_GetSoundId(void){ //--------------------------------------------------------------------------------- return st_psg.sound_id; } //--------------------------------------------------------------------------------- void AmpPSG_SetSoundId(int sound_id){ //--------------------------------------------------------------------------------- st_psg.sound_id = sound_id; } //--------------------------------------------------------------------------------- void AmpPSG_ClearSoundId(void){ //--------------------------------------------------------------------------------- AmpPSG_SetSoundId(0); } //--------------------------------------------------------------------------------- // duty_cycle Getter / Setter / Clear //--------------------------------------------------------------------------------- DutyCycle AmpPSG_GetDutyCycle(void){ //--------------------------------------------------------------------------------- return st_psg.duty_cycle; } //--------------------------------------------------------------------------------- void AmpPSG_SetDutyCycle(DutyCycle duty_cycle){ //--------------------------------------------------------------------------------- st_psg.duty_cycle = duty_cycle; } //--------------------------------------------------------------------------------- void AmpPSG_ClearDutyCycle(void){ //--------------------------------------------------------------------------------- AmpPSG_SetDutyCycle(DutyCycle_50); } //--------------------------------------------------------------------------------- // freq Getter / Setter / Clear //--------------------------------------------------------------------------------- u16 AmpPSG_GetFreq(void){ //--------------------------------------------------------------------------------- return st_psg.freq; } //--------------------------------------------------------------------------------- void AmpPSG_SetFreq(u16 freq){ //--------------------------------------------------------------------------------- st_psg.freq = freq; } //--------------------------------------------------------------------------------- void AmpPSG_ClearFreq(void){ //--------------------------------------------------------------------------------- AmpPSG_SetFreq(0000); } //--------------------------------------------------------------------------------- // volume Getter / Setter / Clear //--------------------------------------------------------------------------------- u8 AmpPSG_GetVolume(void){ //--------------------------------------------------------------------------------- return st_psg.volume; } //--------------------------------------------------------------------------------- void AmpPSG_SetVolume(u8 volume){ //--------------------------------------------------------------------------------- st_psg.volume = volume & 0x7F; } //--------------------------------------------------------------------------------- void AmpPSG_ClearVolume(void){ //--------------------------------------------------------------------------------- AmpPSG_SetVolume(PSG_VOL_DEF); } //--------------------------------------------------------------------------------- // pan Getter / Setter / Clear //--------------------------------------------------------------------------------- u8 AmpPSG_GetPan(void){ //--------------------------------------------------------------------------------- return st_psg.pan; } //--------------------------------------------------------------------------------- void AmpPSG_SetPan(u8 pan){ //--------------------------------------------------------------------------------- st_psg.pan = pan & 0x7F; } //--------------------------------------------------------------------------------- void AmpPSG_ClearPan(void){ //--------------------------------------------------------------------------------- AmpPSG_SetPan(PSG_PAN_DEF); } //--------------------------------------------------------------------------------- // sound_id Getter / Setter / Clear //--------------------------------------------------------------------------------- void AmpPSG_ClearPSG(void){ //--------------------------------------------------------------------------------- AmpPSG_ClearSoundId(); AmpPSG_ClearDutyCycle(); AmpPSG_ClearFreq(); AmpPSG_ClearVolume(); AmpPSG_ClearPan(); } //--------------------------------------------------------------------------------- void AmpPSG_PlayPSG(void){ //--------------------------------------------------------------------------------- st_psg.sound_id = soundPlayPSG(st_psg.duty_cycle, st_psg.freq, st_psg.volume, st_psg.pan); } //--------------------------------------------------------------------------------- void AmpPSG_VolumeUp(void){ //--------------------------------------------------------------------------------- if(st_psg.volume < PSG_VOL_MAX){ st_psg.volume++; soundSetVolume(st_psg.sound_id, st_psg.volume); } } //--------------------------------------------------------------------------------- void AmpPSG_VolumeDown(void){ //--------------------------------------------------------------------------------- if(st_psg.volume > PSG_VOL_MIN){ st_psg.volume--; soundSetVolume(st_psg.sound_id, st_psg.volume); } } //--------------------------------------------------------------------------------- void AmpPSG_PanLeft(void){ //--------------------------------------------------------------------------------- if(st_psg.pan > PSG_PAN_MIN){ st_psg.pan--; soundSetPan(st_psg.sound_id, st_psg.pan); } } //--------------------------------------------------------------------------------- void AmpPSG_PanRight(void){ //--------------------------------------------------------------------------------- if(st_psg.pan < PSG_PAN_MAX){ st_psg.pan++; soundSetPan(st_psg.sound_id, st_psg.pan); } } //---------------------------------------------------------------------------------
AmpScore.h
/*--------------------------------------------------------------------------------- AmpScore module header version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #ifndef _AMP_SCORE_H_ #define _AMP_SCORE_H_ #include <nds/ndstypes.h> #ifdef __cplusplus extern "C" { #endif void AmpScore_SetScoreMode(bool is_score_mode); bool AmpScore_GetScoreMode(void); void AmpScore_ClearScoreMode(void); void AmpScore_SetScorePValue(u32 *p_val); u32* AmpScore_GetScorePValue(void); void AmpScore_ClearScorePValue(void); void AmpScore_SetScoreSize(int size); int AmpScore_GetScoreSize(void); void AmpScore_ClearScoreSize(void); void AmpScore_ClearScore(void); #ifdef __cplusplus } #endif #endif //_AMP_SCORE_H_
AmpScore.c
/*--------------------------------------------------------------------------------- AmpScore module routine version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #include "AmpScore.h" typedef struct{ bool mode; u32 *p_val; int size; }ScoreStatus; static ScoreStatus st_score = {0, 0, 0}; //--------------------------------------------------------------------------------- bool AmpScore_GetScoreMode(void){ //--------------------------------------------------------------------------------- return st_score.mode; } //--------------------------------------------------------------------------------- void AmpScore_SetScoreMode(bool is_score_mode){ //--------------------------------------------------------------------------------- st_score.mode = is_score_mode; } //--------------------------------------------------------------------------------- void AmpScore_ClearScoreMode(void){ //--------------------------------------------------------------------------------- AmpScore_SetScoreMode(false); } //--------------------------------------------------------------------------------- u32* AmpScore_GetScorePValue(void){ //--------------------------------------------------------------------------------- return st_score.p_val; } //--------------------------------------------------------------------------------- void AmpScore_SetScorePValue(u32 *p_val){ //--------------------------------------------------------------------------------- st_score.p_val = p_val; } //--------------------------------------------------------------------------------- void AmpScore_ClearScorePValue(void){ //--------------------------------------------------------------------------------- AmpScore_SetScorePValue(0); } //--------------------------------------------------------------------------------- int AmpScore_GetScoreSize(void){ //--------------------------------------------------------------------------------- return st_score.size; } //--------------------------------------------------------------------------------- void AmpScore_SetScoreSize(int size){ //--------------------------------------------------------------------------------- st_score.size = size; } //--------------------------------------------------------------------------------- void AmpScore_ClearScoreSize(void){ //--------------------------------------------------------------------------------- AmpScore_SetScoreSize(0); } //--------------------------------------------------------------------------------- void AmpScore_ClearScore(void){ //--------------------------------------------------------------------------------- AmpScore_ClearScoreMode(); AmpScore_ClearScorePValue(); AmpScore_ClearScoreSize(); } //---------------------------------------------------------------------------------
AmpState.h
/*--------------------------------------------------------------------------------- AmpState module header version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #ifndef _AMP_STATE_H_ #define _AMP_STATE_H_ #include <nds/ndstypes.h> #ifdef __cplusplus extern "C" { #endif void AmpState_SetPlayTime(u32 play_time); u32 AmpState_GetPlayTime(void); void AmpState_ClearPlayTime(void); void AmpState_SetPlayOld(u32 play_old); u32 AmpState_GetPlayOld(void); void AmpState_ClearPlayOld(void); void AmpState_ClearTime(void); #ifdef __cplusplus } #endif #endif //_AMP_STATE_H_
AmpState.c
/*--------------------------------------------------------------------------------- AmpState module routine version 0.01 Oct 22, 2009 (C)2009 REGEKATSU ---------------------------------------------------------------------------------*/ #include "AmpState.h" //vblank cycle counter static u32 st_play_time = 0; static u32 st_play_old = 0; //--------------------------------------------------------------------------------- void AmpState_SetPlayTime(u32 play_time){ //--------------------------------------------------------------------------------- st_play_time = play_time; } //--------------------------------------------------------------------------------- u32 AmpState_GetPlayTime(void){ //--------------------------------------------------------------------------------- return st_play_time; } //--------------------------------------------------------------------------------- void AmpState_ClearPlayTime(void){ //--------------------------------------------------------------------------------- AmpState_SetPlayTime(0); } //--------------------------------------------------------------------------------- void AmpState_SetPlayOld(u32 play_old){ //--------------------------------------------------------------------------------- st_play_old = play_old; } //--------------------------------------------------------------------------------- u32 AmpState_GetPlayOld(void){ //--------------------------------------------------------------------------------- return st_play_old; } //--------------------------------------------------------------------------------- void AmpState_ClearPlayOld(void){ //--------------------------------------------------------------------------------- AmpState_SetPlayOld(0); } //--------------------------------------------------------------------------------- void AmpState_ClearTime(void){ //--------------------------------------------------------------------------------- AmpState_ClearPlayTime(); AmpState_ClearPlayOld(); } //---------------------------------------------------------------------------------