Introduction

前回から大分間が開きましたが、音声処理の仕事は継続中です。
といっても、毎日の作業全部が音声処理のタスクというわけではないのですが。

音声処理のタスクのうち、複数のチャネルを持つWAVファイルを分割する機能の実装があります。
5.1chの分割を行うようですが、5.1chの .1 って何?と思って調べてみたら、小数の0.1という訳ではないのね。事実上の6chということの模様。
今回はこの機能を実装してみました。
ソースは下記になります

Explanation

今回はコンソールアプリでデモを作りました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using (var wav = new WaveFileReader(path))
{
var channels = wav.WaveFormat.Channels;
var bitsPerSample = wav.WaveFormat.BitsPerSample;
var sampleRate = wav.WaveFormat.SampleRate;
var length = (int)(wav.Length / channels);
var bitLength = bitsPerSample / 8;
if (channels <= 1)
{
Console.WriteLine("Input file does not contain multiple channels.");
return;
}

int bytesRead;
var buffer = new byte[bitLength * sampleRate * channels];

var buffers = new List<MemoryStream>();
for (var index = 0; index < channels; index++)
buffers.Add(new MemoryStream(length));

while ((bytesRead = wav.Read(buffer, 0, buffer.Length)) > 0)
{
var offset = 0;
while (offset < bytesRead)
{
for (var n = 0; n < channels; n++)
{
buffers[n].Write(buffer, offset, bitLength);
offset += bitLength;
}
}
}

for (var index = 0; index < channels; index++)
{
using (var writer = new WaveFileWriter($"{index + 1}.wav", new WaveFormat(sampleRate, bitsPerSample, 1)))
{
var buf = buffers[index].GetBuffer();
writer.Write(buf, 0, buf.Length);
buffers[index].Dispose();
}
}
}

wavファイルのパスを指定し、WaveFileReader で読み込み、分割を行った後に、チャネル毎に分割して書き出しを行っているだけです。
wavファイルで複数のチャネルは、16bitの4チャネルの場合、先頭から順番に

  • ch1(2byte=16bit)
  • ch2(2byte)
  • ch3(2byte)
  • ch4(2byte)
  • ch1(2byte)
  • ch2(2byte)
  • ch3(2byte)
  • ch4(2byte)
    ..

と繰り返しで格納されています。
なので、それを順番にバッファに書き出しするだけです。
bitsPerSampleを8で除算しているのは、byteに変換しているからですね。

テスト

手元に複数チャネルの音声ファイルが無かったので、ネットから探しました。
そこで見つけたのが下記。

不幸にも5.1chがリンク切れなのですが、8chとか普通じゃお目にかかりそうもないものを見つけたので試しに分割してみました。
8_Channel_ID.wavをダウンロードして、デモアプリに渡します。
するとデモアプリと同じフォルダに1.wav,2.wav….8.wavの8つのwavファイルが生成されます。
分割されたファイルにはそれぞれ、

  • 1.wav: 1st: Front Left
  • 2.wav: 2nd: Front Right
  • 3.wav: 3rd: Centre
  • 4.wav: 6th: tone
  • 5.wav: 4th: Back Left
  • 6.wav: 5th: Back Right
  • 7.wav: 7th: Auxiliary Left
  • 8.wav: 8th: Auxiliary Right

という、単語を発声する男性の声またはトーンだけが含まれています。
元々のファイルにもそれらが時間差で出力されていましたが、これらが綺麗に分離されているのがわかります。

Conclusion

複数チャネルの音声データの分割など、普通は用途がありませんが、そんな要求が来てもこれで大丈夫です。

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/AudioSignalProcessing/NAudio/NAudio3