3

MP3 から PCM を抽出するために FMOD ライブラリを使用しています。2 チャンネル全体 - 16 ビットのものを取得し、44100hz のサンプル レートは 1 秒間に 44,100 サンプルの「サウンド」であることも取得します。私が得られないのは、16ビット値が正確に何を表しているのかということです。xy 軸に座標をプロットする方法は知っていますが、何をプロットしているのでしょうか? Y 軸は時間を表し、X 軸は何を表しますか? 騒音レベル?振幅と同じですか?この値を構成するさまざまなサウンドを特定するにはどうすればよいですか。つまり、16 ビットの数値からスペクトルを取得するにはどうすればよいでしょうか。

これは別の質問かもしれませんが、実際に私が本当に答える必要があるのは、25 ミリ秒ごとに振幅を取得するにはどうすればよいかということです。44,100 個の値を取り、40 (40 * 0.025 秒 = 1 秒) で割りますか? これにより、1102.5 サンプルが得られます。では、1102 の値をブラックボックスに入力して、その瞬間の振幅を取得しますか?

元の投稿を編集して、すぐにテストする予定のコードを追加しました: (注: フレームレートを 25 ミリ秒から 40 ミリ秒に変更しました)

// 44100 / 25 frames = 1764 samples per frame -> 1764 * 2 channels * 2 bytes [16 bit sample] = 7056 bytes
private const int CHUNKSIZE = 7056;
uint    bytesread = 0;
var squares = new double[CHUNKSIZE / 4];
const double scale = 1.0d / 32768.0d;

do
{
    result = sound.readData(data, CHUNKSIZE, ref read);

    Marshal.Copy(data, buffer, 0, CHUNKSIZE);

    //PCM samples are 16 bit little endian
    Array.Reverse(buffer);

    for (var i = 0; i < buffer.Length; i += 4)
    {
        var avg = scale * (Math.Abs((double)BitConverter.ToInt16(buffer, i)) + Math.Abs((double)BitConverter.ToInt16(buffer, i + 2))) / 2.0d;
        squares[i >> 2] = avg * avg;
    }

    var rmsAmplitude = ((int)(Math.Floor(Math.Sqrt(squares.Average()) * 32768.0d))).ToString("X2");

    fs.Write(buffer, 0, (int) read);

    bytesread += read;

    statusBar.Text = "writing " + bytesread + " bytes of " + length + " to output.raw";
} while (result == FMOD.RESULT.OK && read == CHUNKSIZE);

mp3 をロードした後、私の rmsAmplitude は 3C00 から 4900 の範囲にあるようです。広がりを期待していました。

4

3 に答える 3

2

はい、サンプルは(その時点での)振幅を表します。

スペクトルを取得するには、通常、時間領域から周波数領域に変換します。

最後の質問: 複数のアプローチが使用されています - RMSが必要になる場合があります。

于 2012-04-30T17:26:07.443 に答える
0

一般に、x 軸は時間値で、y 軸は振幅です。周波数を取得するには、データをフーリエ変換する必要があります (ほとんどの場合、高速フーリエ変換 [fft] アルゴリズムを使用します)。

最も単純な「音」の 1 つを使用するために、周波数 f の単一周波数ノイズがあると仮定しましょう。これは (振幅/時間領域で) y = sin(2 * pi * x / f) として表されます。これを周波数領域に変換すると、周波数 = f になります。

于 2012-04-30T17:32:26.983 に答える