简体   繁体   中英

C# How do I set the volume of sound bytes[]

Im trying to change the volume of sound bytes[] in C#. Im reading a sound file with FFMPEG and and wanna change the volume on the fly. I found some examples and but I didnt understand them.

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!");

Your question not very well phrased. Imagine you were talking about an image and asked "how do I decrease the amount of Red in image bytes[]?". The answer would be that you have to decode byte[] into and RGB tuple of the appropriate bit depth, modify the R value and then convert back to a byte[]. Same thing here. You convert the byte[] into samples of the appropriate bit-depth, rescale, and then convert back to a byte[].

In your case there are 16 bits per sample so you need to join each pair of consecutive bytes into a short, scale it, and then split back apart.

Starting from where you read the byte[]:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM