PSG音源で音を鳴らす

カウントダウン音を鳴らし、終わると一定の間隔をおいて再度鳴らすことを繰り返します。

2022-06-12
公開

コード

main.c

  1. #include <genesis.h>
  2.  
  3. /**
  4. * PSGの停止/再生を制御するための定数
  5. */
  6. typedef enum {
  7. MUSIC_STOP, // 停止
  8. MUSIC_PLAY, // 再生
  9. } MusicState;
  10.  
  11. int main(u16 hard) {
  12. // 曲(トーン値と発音時間の組)
  13. u16 musicalScore[8][2] = {
  14. {273, 10},
  15. {0, 50},
  16. {273, 10},
  17. {0, 50},
  18. {273, 10},
  19. {0, 50},
  20. {52, 10}
  21. };
  22. // 曲の再生位置
  23. u16 index = 0;
  24. // 曲の状態(停止/再生)
  25. u16 state = MUSIC_PLAY;
  26. // PSGを再生するチャンネル番号
  27. u8 channel = 0;
  28. // 次の曲再生までの待ち時間
  29. u16 interval = 120;
  30. // 時間判定用の減算カウンタ
  31. u8 counter = 0;
  32.  
  33. // エンベロープレベルの設定
  34. PSG_setEnvelope(channel, PSG_ENVELOPE_MAX);
  35.  
  36. VDP_drawText("SOUND ONLY", 15, 13);
  37.  
  38. // メインループ
  39. while (TRUE) {
  40. SYS_doVBlankProcess();
  41.  
  42. // 曲が停止状態
  43. if (state != MUSIC_PLAY) {
  44. // 曲の状態を初期化
  45. state = MUSIC_PLAY;
  46. index = 0;
  47. // カウンタに再生待ち時間を設定
  48. counter = interval;
  49. }
  50.  
  51. // 再生/停止の残り時間を減らす
  52. if (counter) {
  53. counter--;
  54. }
  55. // 残り時間カウンタが0
  56. else {
  57. // 曲の最後まで来ていれば曲を停止する
  58. if (index >= sizeof(musicalScore) / sizeof(musicalScore[0])) {
  59. state = MUSIC_STOP;
  60. PSG_setTone(channel, 0);
  61. continue;
  62. }
  63.  
  64. // 指定のトーン値を鳴らし、発音時間をカウンタに設定する
  65. u16 tone = musicalScore[index][0];
  66. counter = musicalScore[index][1];
  67. PSG_setTone(channel, tone);
  68.  
  69. // 曲の再生位置を進める
  70. index++;
  71. }
  72. }
  73.  
  74. return 0;
  75. }

実行結果

上記コードをSGDK1.70でコンパイルし
Gens v2.14 Souvenirで実行したスクリーンショット

解説

PSG_setToneの音(第2引数)に0以外を設定すると、0を設定するまで音が鳴り続けます。
同じ数値を連続して設定した場合も音の切れ目などは発生しないため、同じ音を連続して出したい場合は数フレーム0を設定する必要があります。

この音を実際に使っているCRAZYBUSは、当該画面ではキー操作などの必要がないため、sleep命令により処理を止めることで音の長さを制御しています。
この方法はあまり良いやり方とは言えないため、当コードではカウンタを使って音の長さを制御しています。

数値だけでは分かりにくいPSG音に関して、周波数との変換表があるBasiEgaXorzドキュメントページのリンクを載せています。ただし値がSGDKと反転しているため、使う際に設定する値は1024から掲載された値を引いたものになります。

ダウンロード