最近音声データを触ることが多かったので、基本的な用語の説明だけしていく。
sampleRate
単位 : Hz
1秒間のデータを分割する数。
6000Hzだと、0.01秒ごとに分割。
この分割した1つ1つのデータをサンプリングと呼ぶ。
CDは44.1KHz。ChromeのStreamingも44.1KHz。
bitDepth
単位 : bit
デフォルト : 16bit
サンプリングに対して与える情報量。
何bit与えるかを示す。
channels
音をどの程度分けるか。多いほど立体感のある音が作れる。
1 なら モノラル, 2 なら ステレオ。
基本的には、音声なら 1, 音楽なら 2 以上。
sampleRateを修正するJavaScript
48KHzを16KHz(LINEAR16)で保存するには、 downSampleBuffer(buff, 48000, 16000)
で呼び出す。
export const downsampleBuffer = (buffer, sampleRate, outSampleRate) => {
if (outSampleRate > sampleRate) {
console.error('downsampling rate show be smaller than original sample rate');
}
const sampleRateRatio = sampleRate / outSampleRate;
const newLength = Math.round(buffer.length / sampleRateRatio);
const result = new Int16Array(newLength);
let offsetResult = 0;
let offsetBuffer = 0;
// bpsを縮める処理 (n byte分のデータを合算して、n byteで割る)
while (offsetResult < result.length) {
const nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
// 次のoffsetまでの合計を保存
let accum = 0;
let count = 0;
for (let i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i += 1) {
accum += buffer[i];
count += 1;
}
// 16進数で保存 (LINEAR16でストリーミングするため)
result[offsetResult] = Math.min(1, accum / count) * 0x7FFF;
offsetResult += 1;
offsetBuffer = nextOffsetBuffer;
}
return result.buffer;
};
PCM (pulse code modulation)
圧縮していない生データのこと。
拡張子 raw はPCMである。
rawデータに sampleRate, bitDepth, channelsなどのメタ情報をヘッダに加えたものがwavファイル。 と思っていたが、wavファイルはrawデータ以外も使えるらしい。
WAVファイルのヘッダ情報
Int16Array (16bitのデータをwavに変換するJavaScript)
export const createWavHeader = (view, config) => {
const {
sampleRate, bitDepth, channel, dataLength,
} = config;
writeUTFBytes(view, 0, 'RIFF');
// file length
view.setUint32(4, dataLength + 32, true);
// set file size at the end
writeUTFBytes(view, 8, 'WAVE');
// FMT sub-chunk
writeUTFBytes(view, 12, 'fmt ');
// chunk size
view.setUint32(16, 16, true);
// format code
view.setUint16(20, 1, true);
// channels : (current use monoral : 1)
view.setUint16(22, channel, true);
// sampling rate
view.setUint32(24, sampleRate, true);
// data rate
view.setUint32(28, sampleRate * 2 * channel, true);
// data block size
view.setUint16(32, channel * 2, true);
// bits per sample (bitDepth)
view.setUint16(34, bitDepth, true);
// data sub-chunk
writeUTFBytes(view, 36, 'data');
// DUMMY data chunk length (set real value on export)
view.setUint32(40, dataLength, true);
};
export const exportWAV = (
channel, buffers /* Int16Array */, wavConf = { sampleRate: AUDIO_SAMPLE_RATE, bitDepth: AUDIO_BIT_DEPTH }
) => {
const dataLength = buffers.length * channel * 2;
const buffer = new ArrayBuffer(44 + dataLength);
const view = new DataView(buffer);
// copy WAV header data into the array buffer
createWavHeader(view, { ...wavConf, channel, dataLength });
// write audio data
writeFromInputBuffers(view, channel, 44, buffers);
return new Blob([view], { type: 'audio/wav' });
};
音声認識系でよく利用される形で録音
$ brew install sox
音声認識サービスの自動認証は、wavファイルのヘッダ形式を見て、データが違うとエラーになる。
- LINEAR16(16bit)
- 16kHz
- モノラル
rec --rate 16k --bits 16 --channels 1 test.wav
30秒だけ録音
rec --rate 16k --bits 16 --channels 3 test.wav trim 0 30
ハイレゾ( High-Resolution Audio)
ビットレートがめちゃくちゃ高いぜということ。
凄さ | sampleRate(KHz) | bitDepth(bit) | channels | bitRate(kbps) |
---|---|---|---|---|
通常 | 44.1 | 16 | 1 | 705.6 |
通常 | 44.1 | 16 | 1 | 705.6 |
ハイレゾ1 | 96 | 24 | 2 | 4608 |
ハイレゾ2 | 192 | 24 | 2 | 9216 |