C#如何设置声音字节的音量[]

时间:2016-07-22 17:24:00

标签: c# audio ffmpeg

我试图在C#中改变声音字节[]的音量。我正在用FFMPEG读取声音文件,并且想要动态改变音量。我找到了一些例子,但我不理解它们。

public void SendAudio(string pathOrUrl)
{
    cancelVid = false;
    isPlaying = true;

    mProcess = Process.Start(new ProcessStartInfo
    { // FFmpeg requireqs us to spawn a process and hook into its stdout, so we will create a Process
        FileName = "ffmpeg",
        Arguments = "-i " + (char)34 + pathOrUrl + (char)34 + // Here we provide a list of arguments to feed into FFmpeg. -i means the location of the file/URL it will read from
        " -f s16le -ar 48000 -ac 2 pipe:1", // Next, we tell it to output 16-bit 48000Hz PCM, over 2 channels, to stdout.
        UseShellExecute = false,
        RedirectStandardOutput = true, // Capture the stdout of the process
        Verb = "runas"
    });

    while (!isRunning(mProcess)) { Task.Delay(1000); }

    int blockSize = 3840; // The size of bytes to read per frame; 1920 for mono
    byte[] buffer = new byte[blockSize];
    byte[] gainBuffer = new byte[blockSize];
    int byteCount; 

    while (true && !cancelVid) // Loop forever, so data will always be read
    {
        byteCount = mProcess.StandardOutput.BaseStream // Access the underlying MemoryStream from the stdout of FFmpeg
        .Read(buffer, 0, blockSize); // Read stdout into the buffer

        if (byteCount == 0) // FFmpeg did not output anything
            break; // Break out of the while(true) loop, since there was nothing to read.

        if (cancelVid)
            break;

        disAudioClient.Send(buffer, 0, byteCount); // Send our data to Discord
    }
    disAudioClient.Wait(); // Wait for the Voice Client to finish sending data, as ffMPEG may have already finished buffering out a song, and it is unsafe to return now.
    isPlaying = false;
    Console.Clear();
    Console.WriteLine("Done Playing!");

1 个答案:

答案 0 :(得分:0)

你的问题不是很好。想象一下,你正在谈论一个图像并询问"如何减少图像字节中的红色数量[]?"。答案是你必须解码相应位深度的byte []和RGB元组,修改R值然后转换回byte []。这里也是一样的。您将byte []转换为适当位深度的样本,重新缩放,然后转换回byte []。

在你的情况下,每个样本有16位,所以你需要将每对连续的字节连接成一个短的,缩放它,然后再分开。

从您读取字节[]的位置开始:

for (int i = 0 ; i < blockSize/2 ; ++i)
{

    // convert to 16-bit
    short sample = (short)((buffer[i*2+1] << 8) | buffer[i*2])

    // scale
    const double gain = 0.5; // value between 0 and 1.0
    sample = (short)(sample * gain + 0.5);

    // back to byte[]
    buffer[i*2+1] = (byte)(sample >> 8);
    buffer[i*2] = (byte)(sample & 0xff);
}