3

我使用以下代码成功地从 Wasapi 捕获了声音:

IWaveIn waveIn = new WasapiLoopbackCapture();
waveIn.DataAvailable += OnDataReceivedFromWaveOut;

我现在需要做的是,以pcm8000 的采样率和每个单声道采样 16 位重新采样内存中的数据。

我不能ACMStream用来重新采样示例,因为录制的音频是每秒 32 位。

我试过这段代码将字节从 32 位转换为 16 位,但我每次得到的只是空白音频。

byte[] newArray16Bit = new byte[e.BytesRecorded / 2];
short two;
float value;
for (int i = 0, j = 0; i < e.BytesRecorded; i += 4, j += 2)
{
    value = (BitConverter.ToSingle(e.Buffer, i));
    two = (short)(value * short.MaxValue);

    newArray16Bit[j] = (byte)(two & 0xFF);
    newArray16Bit[j + 1] = (byte)((two >> 8) & 0xFF);
}

source = newArray16Bit;
4

1 回答 1

2

我使用此例程从 WASAPI IeeeFloat 动态重新采样到我的应用程序中需要的格式,即 16kHz、16 位、1 通道。我的格式是固定的,所以我对我需要的转换进行了硬编码,但可以根据需要进行调整。

private void ResampleWasapi(object sender, WaveInEventArgs e)
{
    //the result of downsampling
    var resampled = new byte[e.BytesRecorded / 12];
    var indexResampled = 0;

    //a variable to flag the mod 3-ness of the current sample
    var arity = -1;

    var runningSamples = new short[3];
    for(var offset = 0; offset < e.BytesRecorded; offset += 8)
    {
        var float1 = BitConverter.ToSingle(e.Buffer, offset);
        var float2 = BitConverter.ToSingle(e.Buffer, offset + 4);

        //simple average to collapse 2 channels into 1
        float mono = (float)((double)float1 + (double)float2) / 2;

        //convert (-1, 1) range int to short
        short sixteenbit = (short)(mono * 32767);

        //the input is 48000Hz and the output is 16000Hz, so we need 1/3rd of the data points
        //so save up 3 running samples and then mix and write to the file
        arity = (arity + 1) % 3;

        //record the value
        runningSamples[arity] = sixteenbit;

        //if we've hit the third one
        if (arity == 2)
        {
            //simple average of the 3 and put in the 0th position
            runningSamples[0] = (short)(((int)runningSamples[0] + (int)runningSamples[1] + (int)runningSamples[2]) / 3);

            //copy that short (2 bytes) into the result array at the current location
            Buffer.BlockCopy(runningSamples, 0, resampled, indexResampled, 2);

            //for next pass
            indexResampled += 2;
        }
    }

    //and tell listeners that we've got data
    RaiseDataEvent(resampled, resampled.Length);
}
于 2020-04-10T17:49:00.787 回答