サンプルレート変換を組み込んでみた。

公開:2011-09-14 19:17
更新:2020-02-15 04:36
カテゴリ:wasapi,c++,dawもどきの作成,windows,audio,windows api

初期化処理にサンプルレート変換を組み込んでみた。


// WASAPIの初期化処理

// IMMDeviceEnumeratorの取得
THROW_IF_ERR(
  CoCreateInstance(
  __uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
  IID_PPV_ARGS(&device_enumerator_)));

// デフォルトのオーディオデバイスを取得する
THROW_IF_ERR(
  device_enumerator_
  ->GetDefaultAudioEndpoint(eRender,eMultimedia,&current_device_)
  );

// オーディオクライアントを取得
THROW_IF_ERR(
  current_device_
  ->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER,
  NULL, reinterpret_cast<void **>(&audio_client_))
  );

// 代替フォーマット定義
sf::co_task_memory<WAVEFORMATEX>  alt_format;

// 読みこもうとしているWAVファイルのフォーマットをサポートしているか?
HRESULT hr = audio_client_->IsFormatSupported(
  AUDCLNT_SHAREMODE_SHARED ,&wfx.Format,&alt_format);
bool sample_rate_convert = false;
float sample_rate_backup = 0.0f;
if(hr != S_OK) //  S_FALSEならそのフォーマットをサポートしていないらしい..
{
  // サンプルレートのコンバート
  if(alt_format->nSamplesPerSec != wfx.Format.nSamplesPerSec)
  {
    // 本来のサンプルレートをバックアップする
    sample_rate_backup = wfx.Format.nSamplesPerSec;
    // 代替フォーマットのサンプルレートをセットする
    wfx.Format.nSamplesPerSec = alt_format->nSamplesPerSec;
    // 再計算する
    wfx.Format.nAvgBytesPerSec = alt_format->nSamplesPerSec * wfx.Format.nBlockAlign;
    // もう一回チェックする。
    // サンプルレート以外でサポートしていない点があれば例外が発生する。
    THROW_IF_ERR(audio_client_->IsFormatSupported(
AUDCLNT_SHAREMODE_SHARED ,&wfx.Format,&alt_format));
    // フラグをセットする
    sample_rate_convert = true;
  } else {
    // サンプルレート以外であれば例外を出す。
    throw win32_error_exception(hr);
  }
}

// 再生クライアントの初期化

REFERENCE_TIME buffer_period =  latency_ms_ /* ms */ * 10000 ;

REFERENCE_TIME buffer_duration = buffer_period * periods_per_buffer_;

THROW_IF_ERR(audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED  , 
  AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_RATEADJUST, 
  buffer_duration, 
  buffer_period,
  &(wfx.Format), 
  NULL));

// バッファサイズの取得
THROW_IF_ERR(audio_client_->GetBufferSize(&buffer_size_));

// 再生クライアントの取得
THROW_IF_ERR(audio_client_->GetService(IID_PPV_ARGS(&audio_render_client_)));

// サンプルレートコンバータ
if(sample_rate_convert)
{
  THROW_IF_ERR(audio_client_->GetService(IID_PPV_ARGS(&audio_clock_adjustment_)));
  // 本来のサンプルレートをセットする
  audio_clock_adjustment_->SetSampleRate(sample_rate_backup);
}

audio clientをAUDCLNT_STREAMFLAGS_RATEADJUSTフラグをつけて初期化し、GetService()でIAudioClockAdjustmentインターフェースを取得し、SetSampleRate()で変換したいサンプルレートをセットするのである。これでサンプルレートを変換することができる。でも性能は良くないらしい

コードは上記のように適当だ。モノラルのサポートなどはまだだったりする。

変更部分のソースコード