NAudio ライブラリでオーディオを再生する(4)


さて、まだまだ解決すべき問題は多いのですが、今回はNAudioライブラリを使ってWASPAIのオーディオ入力を扱ってみたいと思います。

WASAPIのオーディオ入力

WASAPI には、オーディオ出力(render)、オーディオ入力(capture)、オーディオ出力のモニター(loopback)の3つの機能があります。出力はすでに試してきたので、今回はプログラムが入力として扱うcaptureとloopbackを試してみようというわけです。入力(capture)又は出力モニター(loopback)の音を別の出力からモニターする入力モニターのようなものを作ってみましょう。Windows の「このデバイスを聴く」みたいな機能ですね。

NAudio-monitor流れ説明図

NAudio では、WasapiCapture という入力を扱うクラスと、WasapiLoopbackCapture という出力モニターを扱うクラスがあるので、これらを使ってみましょう。プログラムの肝心なところは次のように動きます。

  1. 指定したオーディオ入力を WasapiCapture で開く
  2. 必要ならフォーマットを変換する
  3. ボリューム、メーターの機能を追加する
  4. 指定したオーディオ出力を WasapiOut で開く
  5. 入出力を動かして、入力を出力に流し込む

これができれば、サウンドファイルの再生音とマイクなどの入力をミックスすることがでるはずなので、漠然と実現したいミキサーに少し近づきます。では、肝心のところだけ、コードをお見せしましょう。

private void buttonStart_Click(object sender, EventArgs e)
{
	DisposeAll();
	textBoxStatus.Text = "";
	output = CreateOutputDevice();

	WaveInProvider waveInProvider;

	if (radioButtonInput.Checked)
	{
		input = CreateCaptureDevice();
		waveInProvider = new WaveInProvider(input);
	}
	else
	{
		loopback= CreateLoopbackDevice();
		waveInProvider = new WaveInProvider(loopback);
	}

	// SampleChannel は音量調整用
	SampleChannel sampleChannel = WaveInToSample(waveInProvider);

	// Volume delegate 定義して、動的に音量を変える
	// setVolumeDelegateflot value) を呼び出すと音量が変わる
	setVolumeDelegate = (float vol) => sampleChannel.Volume = vol;

	// n 回ごとに最大値を調べてお知らせする MeteringSampleProvider に流し込む
	MeteringSampleProvider postVolumeMeter = new MeteringSampleProvider(sampleChannel);

	postVolumeMeter.SamplesPerNotification = postVolumeMeter.WaveFormat.SampleRate / 10; // 0.1秒
	postVolumeMeter.StreamVolume += OnPostVolumeMeter;

	// 出力に流し込んで初期化
	output.Init(new SampleToWaveProvider(postVolumeMeter as ISampleProvider));
	trackBarVolume_ValueChanged(trackBarVolume, new EventArgs());
	// 動作開始
	output.Play();
	if (input != null)
	{
		try
		{
			input.StartRecording();
		}
		catch (Exception ex)
		{
			MessageBox.Show("input " + ex.Message + "\r\n" + input.WaveFormat);
			DisposeAll();
		}
	}
	else if (loopback != null)
	{
		try
		{
			loopback.StartRecording();
		}
		catch (Exception ex)
		{
			MessageBox.Show("loopback " + ex.Message + "\r\n" + loopback.WaveFormat);
			DisposeAll();
		}
	}

}

何度か書いてきた NAudio のコードとさほど変わりませんが、入出力を同時に扱っています。途中で出てくる WaveInToSample メソッドは、入力のフォーマットに合わせて音量調整用の SampleChannel を生成するために書いた関数です。SampleChannel にいきなり PCM 32ビットを入力しようとすると、「サポートしていない」というエラーがでるので、付け加えました。元々は1行でこう書いてありました。ちょっと回りくどい事をしている気もします。

sampleChannel = new SampleChannel(waveInProvider);

後半はすこしエラー処理を増やしたけど、普通に音を再生するときと同じです。input.StartRecording() で入力の処理をしているところだけがすこしだけ違っています。

入力モニターは動くけど…

さて、細かいところはソースを見ていただくことにして、動かしてみます。入力モニターはそこそこ動きます。Start ボタンを押すと、出力に指定した入力の音が聞こえ、ボリュームも調整できるし、レベルメーターも動きます。

NAudio-moniter

でも、出力モニター(loopback)のほうは全然動きません。ここが動くのを期待していたので残念です。

それから、サンプリング周波数、ビット数、チャンネル数を変えると動いたり動かなかったりします。どうも、サウンドドライバによって条件が違うように見えます。今回のプログラムはややデバッグ用みたいなものになってしまいました。もう少し解明できてからにしても良かったのですが、途中経過としてコードもアップしておきます。WASAPI の仕様をもう少し理解できたら、さらにきれいなコードがかける気がしてきました。ただ、出力モニター(loopback)は NAudio 1.6 で実装されたらしいので、まだライブラリのコードが洗練されていないのかもしれません。

もうひと頑張りです。

load_downloadNAudioWaveinMonitorTest

参考

  • NAudio
    http://naudio.codeplex.com/

You can skip to the end and leave a response. Pinging is currently not allowed.
Subscribe to RSS Feed Twitter は Ume108 だよ