Platform SDK: DirectX

ステップ 4 : ProcessPMsg メソッドの定義

[Visual Basic]

ここでは、C++ でのアプリケーション開発について説明する。Visual Basic については、「DirectMusic Visual Basic チュートリアル」を参照すること。

[C++]

このツールの実際の動作は、IDirectMusicTool::ProcessPMsg から派生したメソッド内で実行される。IDirectMusicTool::GetMediaTypes が返す配列内に列挙されたタイプのあらゆるメッセージは、このメソッドを要求する。

CEchoTool::ProcessPMsg メソッドは、最初にローカル変数の何らかの初期化を行う。

HRESULT STDMETHODCALLTYPE CEchoTool::ProcessPMsg(
  IDirectMusicPerformance* pPerf, 
  DMUS_PMSG* pMsg)
{
  DMUS_NOTE_PMSG* pNote;
  DWORD dwCount;
  DWORD dwEchoNum;
  MUSIC_TIME mtDelay;
 
// SetEchoNum()と SetDelay()はこれらのメンバ変数を使うので、
// クリティカルセクションを利用してこれらをスレッドセーフにする。
  EnterCriticalSection(&m_CrSec);
  dwEchoNum = m_dwEchoNum;
  mtDelay = m_mtDelay;
  LeaveCriticalSection(&m_CrSec);
 

次にこのメソッドは、メッセージに対して IDirectMusicGraph::StampPMsg メソッドを呼び出す。処理が終わった後でこのメッセージを他のツールに転送しなければならない場合、StampPMsg は成功する (DirectMusic が最終出力ツールを用意しているため、メッセージの転送先となるアプリケーション固有のツールが存在しない場合でも、StampPMsg は成功するはずである)。失敗した場合、メソッドは S_FREE を返し、メッセージは自動的に無視される。

  if ((NULL == pMsg->pGraph) ||
    FAILED(pMsg->pGraph->StampPMsg(pMsg)))
  {
    return DMUS_S_FREE;
  }
 

ここでは CEchoTool がメッセージを処理する。DMUS_PMSGT_NOTE、DMUS_PMSGT_MIDI、または DMUS_PMSGT_PATCH のタイプのメッセージのみを受け取るよう設定されている点に注意すること (これらのタイプは DMUS_PMSGT_TYPES 列挙型の一部である)。

連続するエコーを作成するたびに、ツールは以下のことを行う。

MIDI の音符を扱うサンプルコードを示す。

  if( pPMsg->dwType == DMUS_PMSGT_MIDI )
  {
    // MIDI メッセージをエコー チャンネルにコピーする。
    for( dwCount = 1; dwCount <= dwEchoNum; dwCount++ )
    {
      DMUS_MIDI_PMSG* pMidi;
      if( SUCCEEDED( pPerf->AllocPMsg( sizeof(DMUS_MIDI_PMSG),
        (DMUS_PMSG**)&pMidi )))
      {
        // オリジナル メッセージをこのメッセージにコピーする。
        memcpy( pMidi, pPMsg, sizeof(DMUS_MIDI_PMSG) );
 
        // オブジェクトへのポインタを保持または保持している
        // 可能性のあるフィールドの Addref か消去を実行する。
        if( pMidi->pTool ) pMidi->pTool->AddRef();
        if( pMidi->pGraph ) pMidi->pGraph->AddRef();
        pMidi->punkUser = NULL;
 
        // メッセージが次の上位グループへ移動するよう、
        // P チャンネルを設定する。
        pMidi->dwPChannel = pMidi->dwPChannel + 
                (16*dwCount);
 
        // エコーされるメッセージの時間への追加を行う。
        pMidi->mtTime += (dwCount * mtDelay);
 
        // メッセージを追加するので、MUSIC_TIME だけが有効になる。
        // REFERENCE_TIME は、SendPMsg()の内部で
        // 再計算される。
        pMidi->dwFlags = DMUS_PMSGF_MUSICTIME;
 
        // メッセージを送信する。
        pPerf->SendPMsg( (DMUS_PMSG*)pMidi );
      }
    }
  }
 

パッチ チェンジもコピーされ、現在使われていないものも含め他のすべてのエコー チャンネルに送信される。そのため、後でエコーを追加した場合でも、正しい音色による演奏が行われる。サンプルの EchoTool アプリケーションでは、Echotool.h で MAX_ECHOES が定義されている点に注意すること。

  else if( pPMsg->dwType == DMUS_PMSGT_PATCH )
  {
    for( dwCount = 1; dwCount <= MAX_ECHOES; dwCount++ )
    {
      DMUS_PATCH_PMSG* pPatch;
      if( SUCCEEDED( pPerf->AllocPMsg( sizeof(DMUS_PATCH_PMSG),
        (DMUS_PMSG**)&pPatch )))
      {
        // オリジナルメッセージをこのメッセージにコピーする。
        memcpy( pPatch, pPMsg, sizeof(DMUS_PATCH_PMSG) );
 
        // オブジェクトへのポインタを保持または保持している
        // 可能性のあるフィールドの Addref か消去を実行する。
        if( pPatch->pTool ) pPatch->pTool->AddRef();
        if( pPatch->pGraph ) pPatch->pGraph->AddRef();
        pPatch->punkUser = NULL;
 
        // メッセージが次の上位グループへ移動するよう、
        // P チャンネルを設定する。
        pPatch->dwPChannel = pPatch->dwPChannel + 
          (16*dwCount);
 
        // エコーされるメッセージの時間への追加を行う。
        pPatch->mtTime += (dwCount * mtDelay);
 
        // メッセージを追加するので、MUSIC_TIME だけが有効になる。
        // REFERENCE_TIME は、SendPMsg()の内部で
        // 再計算される。
        pPatch->dwFlags = DMUS_PMSGF_MUSICTIME;
 
        // メッセージを送信する。
        pPerf->SendPMsg( (DMUS_PMSG*)pPatch );
      }
    }
  }
 

このメソッドは、MIDI の音符と同様の方法で音符を扱うが、ボリュームを下げるためのステップを追加する。

  else if( pPMsg->dwType == DMUS_PMSGT_NOTE )
  {
    // 次の音符のベロシティを追跡するための変数を作成する。
    BYTE bVelocity;
    pNote = (DMUS_NOTE_PMSG*)pPMsg;
    bVelocity = pNote->bVelocity;
 
    for( dwCount = 1; dwCount <= dwEchoNum; dwCount++ )
    {
      if( SUCCEEDED( pPerf->AllocPMsg( sizeof(DMUS_NOTE_PMSG),
              (DMUS_PMSG**)&pNote )))
      {
        // オリジナルの音符をこのメッセージにコピーする。
        memcpy( pNote, pPMsg, sizeof(DMUS_NOTE_PMSG) );
 
        // オブジェクトへのポインタを保持または保持している
        // 可能性のあるフィールドの Addref か消去を実行する。
        if( pNote->pTool ) pNote->pTool->AddRef();
        if( pNote->pGraph ) pNote->pGraph->AddRef();
        pNote->punkUser = NULL;
 
        // エコーされるメッセージの時間への追加を行う。
        pNote->mtTime += (dwCount * mtDelay);
 
        // エコーされた音符のボリュームを下げる。
        bVelocity = (BYTE) (bVelocity - 
                ((bVelocity * (dwCount * 15))/100));
        pNote->bVelocity = bVelocity;
 
        // メッセージを追加するので、MUSIC_TIME だけが有効になる。
        // REFERENCE_TIME は、SendPMsg()の内部で
        // 再計算される。
        pNote->dwFlags = DMUS_PMSGF_MUSICTIME;
        pNote->dwPChannel = pNote->dwPChannel + 
          (16*dwCount);
 
        // メッセージを送信する。
        pPerf->SendPMsg( (DMUS_PMSG*)pNote );
      }
    }
  }
 

最後に、ProcessPMsg メソッドは DMUS_S_REQUEUE を返し、オリジナル メッセージはパイプラインへ戻される。

return DMUS_S_REQUEUE;
} // CEchoTool::ProcessPMsg()の終わり

次項 : ステップ 5 : クラス メソッドの定義