コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

サウンドの拡張(1)

ndslibのサウンドライブラリですが、長い曲が再生できないのを修正した後、いろいろと使っていて欲しい機能がいろいろ出てきたので、独自拡張しました。

ARM9側からサウンドチャネルの制御

従来のサウンドコマンドは、ARM7側空ききチャネルを探してサウンドを鳴らす仕組みになっています。そこで、ARM9側からチャネルを指定して鳴らすこともできるように、message構造体を拡張しました。

 struct {
  //playchanel is my Original Extension.
  //8bit  7  6  5  4   3        2         1  0
  //    | Chanel-Id | |x| |Set/Non-Set| | mode |
  // mode 0: Only Setting & Free Chanel ...return( used chanel )
  // mode 1: Play         & Free Chanel ...return( used chanel )
  // mode 2: Only Setting & Appointed Chanel ...return( used chanel )
  // mode 3: Play         & Appointed Chanel ...return( used chanel )
  //  Bit2 : SoundData Setting Flag
  u8	playchanel;
  u16 type; 
  const void* data;
  u32 loopPoint;
  u32 dataSize;
  u16 freq;
  u8 volume;
  u8 pan;
  bool loop;
  u8 format;
} SoundPlay;

playchanelという変数を1つ追加しました。これは上位4ビットにチャネルを持ち、下位4ビットが制御系のビットになります。

  • Bit 0 データセット時にサウンドを鳴らすフラグ
  • Bit 1 上位4ビットにセットしたチャネルにデータをセットするか、空きチャネルを使うかのフラグ(現在未使用)
  • Bit 2 データがセットされているか否かのフラグ(ARM9側で管理する)
  • Bit 3 No Use
  • Bit4-5 チャネル番号

こんな感じでセットします。Bit2はARM7では使いません。ARM9側で保持するようにプログラミングしています。また、Bit0でサウンドを鳴らすかどうかをセットできるので、ARM9側にsoundPlayWave()、soundSetWave()の2つの関数を追加しました。

ARM9側からplay制御

int soundPlayWave(int chanel,const void* data,SoundFormat format,u32 dataSize,u16 freq,u8 volume,u8 pan,bool loop,u32 loopPoint){ 
	
 FifoMessage msg;
 msg.type = SOUND_PLAY_MESSAGE;
 msg.SoundPlay.playchanel = (chanel<<4) | 1;
 msg.SoundPlay.data = data;
 msg.SoundPlay.freq = freq;
 msg.SoundPlay.volume = volume;
 msg.SoundPlay.pan = pan;
 msg.SoundPlay.loop = loop;
 msg.SoundPlay.format = format;
 msg.SoundPlay.loopPoint = loopPoint;
 msg.SoundPlay.dataSize = dataSize >> 2;

 fifoSendDatamsg(FIFO_USER_05, sizeof(msg), (u8*)&msg);

 while(!fifoCheckValue32(FIFO_USER_05));

 return (int)fifoGetValue32(FIFO_USER_05);
}

int soundSetWave(int chanel,const void* data,SoundFormat format,u32 dataSize,u16 freq,u8 volume,u8 pan,bool loop,u32 loopPoint){
	
 FifoMessage msg;
 msg.type = SOUND_PLAY_MESSAGE;
 msg.SoundPlay.playchanel = (chanel<<4);
 msg.SoundPlay.data = data;
 msg.SoundPlay.freq = freq;
 msg.SoundPlay.volume = volume;
 msg.SoundPlay.pan = pan;
 msg.SoundPlay.loop = loop;
 msg.SoundPlay.format = format;
 msg.SoundPlay.loopPoint = loopPoint;
 msg.SoundPlay.dataSize = dataSize >> 2;

 fifoSendDatamsg(FIFO_USER_05, sizeof(msg), (u8*)&msg);

 while(!fifoCheckValue32(FIFO_USER_05));

 return (int)fifoGetValue32(FIFO_USER_05);
}

この2つの関数ですが、playchanelの設定以外は同じ処理です。鳴らすかどうかの判断はARM7側(下記)です。

//---------------------------------------------------------------------------------
void soundDataHandler2(int bytes, void *user_data) {
//---------------------------------------------------------------------------------
 int channel = -1;

 FifoMessage msg;

 fifoGetDatamsg(FIFO_USER_05, bytes, (u8*)&msg);

 if(msg.type == SOUND_PLAY_MESSAGE) {

   channel = ((int)msg.SoundPlay.playchanel)>>4;

   if(channel >= 0) {
     SCHANNEL_SOURCE(channel) = (u32)msg.SoundPlay.data;
     SCHANNEL_REPEAT_POINT(channel) = (u32)msg.SoundPlay.loopPoint;
     SCHANNEL_LENGTH(channel) = msg.SoundPlay.dataSize;
     SCHANNEL_TIMER(channel) = SOUND_FREQ( msg.SoundPlay.freq );
     if( msg.SoundPlay.playchanel&1 ){
       SCHANNEL_CR(channel) = SCHANNEL_ENABLE | SOUND_VOL(msg.SoundPlay.volume) | SOUND_PAN(msg.SoundPlay.pan) | (msg.SoundPlay.format << 29) | (msg.SoundPlay.loop ? SOUND_REPEAT : SOUND_ONE_SHOT);
     }
     else{
       SCHANNEL_CR(channel) = ~SCHANNEL_ENABLE &( SCHANNEL_ENABLE | SOUND_VOL(msg.SoundPlay.volume) | SOUND_PAN(msg.SoundPlay.pan) | (msg.SoundPlay.format << 29) | (msg.SoundPlay.loop ? SOUND_REPEAT : SOUND_ONE_SHOT));
     }
   }
 } else if(msg.type == SOUND_PSG_MESSAGE) {

  以下省略。

また、ARM9側から空きチャネルの取得とチャネルが再生中か否かを取得したかったので、そのための関数も追加しました。

FifoSoundCommandの追加

typedef enum {
  SOUND_SET_PAN        = 0 << 20,
  SOUND_SET_VOLUME     = 1 << 20,
  SOUND_SET_FREQ       = 2 << 20,
  SOUND_SET_WAVEDUTY   = 3 << 20,
  SOUND_MASTER_ENABLE  = 4 << 20,
  SOUND_MASTER_DISABLE = 5 << 20,
  SOUND_PAUSE          = 6 << 20,
  SOUND_RESUME         = 7 << 20,
  SOUND_KILL           = 8 << 20,
  SOUND_SET_MASTER_VOL = 9 << 20,
  MIC_STOP             = 10 << 20,
  SOUND_GET_ID_STATUS  = 11 << 20, //新規拡張
  SOUND_GET_FREE_ID    = 12 << 20 //新規拡張
} FifoSoundCommand;

SOUND_GET_ID_STATUS と SOUND_GET_FREE_ID が追加分です。

チャネルの状態を取得

チャネルが再生中かどうかを調べます。再生中だと1が返ってきます。

int soundIdStatus(int soundId){
  fifoSendValue32(FIFO_USER_05, SOUND_GET_ID_STATUS | (soundId << 16) );

  while(!fifoCheckValue32(FIFO_USER_05));

  return (int)fifoGetValue32(FIFO_USER_05);
}

ARM7側では、SOUND_GET_ID_STATUSコマンドを見て処理します。soundCommandHandler2()から抜粋。

   case SOUND_GET_ID_STATUS:
      fifoSendValue32(FIFO_USER_05, (u32)getChannelStatus(channel) );
      break;

   case SOUND_GET_FREE_ID:
      fifoSendValue32(FIFO_USER_05, (u32)getFreeChannel2() );
      break;

下記も追加しています。

//---------------------------------------------------------------------------------
int getChannelStatus( int ch ) {	//新規拡張
//---------------------------------------------------------------------------------
  if(SCHANNEL_CR(ch) & SCHANNEL_ENABLE)	return 1;

  return 0;
}

空きチャネル取得

サウンドの空いているチャネルを取得します。

int soundFreeId(void){
 fifoSendValue32(FIFO_USER_05, SOUND_GET_FREE_ID );

 while(!fifoCheckValue32(FIFO_USER_05));

 return (int)fifoGetValue32(FIFO_USER_05);
}

ARM7側は上に書いた case SOUND_GET_FREE_ID: で処理されます。
これでまた、いろいろと使い勝手がよくなった感じです。

本当にやりたいことリスト

(ブログの終わりにやりたいことを書いておきたいと思います)

  • 求職活動・・・このブログで興味を持った人一声かけてください。m(_ _)m
  • Androidプログラム
  • Web系のプログラム