Skip to main content
 首页 » 编程设计

c#之重新采样环回捕获

2024年02月27日1752php

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

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

我现在需要做的是将内存中的数据重新采样为 pcm,采样率为 8000,每个样本单声道 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; 

请您参考如下方法:

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

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); 
}