locked
Combining contents of two DirectSound buffers RRS feed

  • Question

  • Not sure if this is the right forum, but it's the closest I could find.  I've got a program that takes in two capture inputs through DirectSound and outputs a WAV file to the file system and sound to the speakers/headphones.  At this point, I'm using data from one of the capture buffers for the playback buffer, but I'd like to combine both buffers together into one sound.  I've tried just adding the two buffers together, but that's giving me the occasional overflow error (and setting that array position to byte.MaxValue gives me some strange playback results).  Do you have any other ideas?

    Here's <roughly> what I have, with a few function calls taken out for brevity:

    Common.notificationEvent.WaitOne(Timeout.Infinite, true);
    
    byte[] fBuf = (byte[])frontBuf.Read(offset, typeof(byte), LockFlag.None, Common.notifySize);
    byte[] rBuf = (byte[])rearBuf.Read(offset, typeof(byte), LockFlag.None, Common.notifySize);
    double[] dblFront = new double[fBuf.Length];
    double[] dblRear = new double[rBuf.Length];
    double[] procData = new double[dblFront.Length];
    for (int i = 0; i < fBuf.Length; i++)
    {
      dblFront[i] = System.Convert.ToDouble(fBuf[i]);
      dblRear[i] = System.Convert.ToDouble(rBuf[i]);
      procData[i] = dblFront[i] + dblRear[i];
    }
    byte[] fprocData = new byte[procData.Length];
    for (int i = 0; i < procData.Length; i++)
    {
      if (Double.IsNaN(procData[i]))
        fprocData[i] = (byte)0;
      else
        try
        {
          fprocData[i] = System.Convert.ToByte(procData[i]);
        }
        catch (OverflowException e)
        {
          fprocData[i] = byte.MaxValue;
        }
    }
    //write contents of capture buffer to playback buffer
    Common.ampBuffer.Write(offset, fprocData, LockFlag.None); // temporarily using combined data for playback
    //move capture offset
    offset = (offset + Common.notifySize) % (Common.bufferPositions * Common.notifySize);
    //write captured sound to wav file and update length of wave file
    Writer.Write(fBuf, 0, fBuf.Length); //temporarily using front data for playback
    length += fBuf.Length;
    

     


    Michael L.
    Wednesday, August 4, 2010 6:50 AM

Answers

  • Are you using 8-bit audio?  If so I highly suggest you switch to 16-bit audio for better quality.  For 16-bit audio the data type is a signed short.

    Generally speaking when adding to signals together there will be a little overflow, the overflow is typically dealt with by clipping the values to the maximum allowed for the output data type.  If the signals are both loud or have a lot of correlation then you can add some negative gain into the sum operation. e.g. 

    output[i] = (sig1[i] * 0.73) + (sig2[i] * 0.73);
    // clip output
    if (output[i] > MAX_SIG)
    output[i] = MAX_SIG;
    else if (output[i] < MIN_SIG)
    output[i] = MIN_SIG;

    for 8-bit audio min = 0, max = 255, nom = 128
    for 16-bit audio min = -32678, max = 32767, nom = 0

    Note that the sum operation doesn't work correctly for 8-bit audio unless you normalize the values to be signed first, i.e. subtract 128 during the conversion.


    www.chrisnet.net
    • Proposed as answer by Ralf G Thursday, August 5, 2010 3:45 PM
    • Marked as answer by The March Hare Thursday, August 12, 2010 1:28 PM
    Wednesday, August 4, 2010 2:24 PM

All replies

  • Are you using 8-bit audio?  If so I highly suggest you switch to 16-bit audio for better quality.  For 16-bit audio the data type is a signed short.

    Generally speaking when adding to signals together there will be a little overflow, the overflow is typically dealt with by clipping the values to the maximum allowed for the output data type.  If the signals are both loud or have a lot of correlation then you can add some negative gain into the sum operation. e.g. 

    output[i] = (sig1[i] * 0.73) + (sig2[i] * 0.73);
    // clip output
    if (output[i] > MAX_SIG)
    output[i] = MAX_SIG;
    else if (output[i] < MIN_SIG)
    output[i] = MIN_SIG;

    for 8-bit audio min = 0, max = 255, nom = 128
    for 16-bit audio min = -32678, max = 32767, nom = 0

    Note that the sum operation doesn't work correctly for 8-bit audio unless you normalize the values to be signed first, i.e. subtract 128 during the conversion.


    www.chrisnet.net
    • Proposed as answer by Ralf G Thursday, August 5, 2010 3:45 PM
    • Marked as answer by The March Hare Thursday, August 12, 2010 1:28 PM
    Wednesday, August 4, 2010 2:24 PM
  • Thanks for the help.  I was using 16-bit audio, but I was getting some weird stuttering issues (I think it's just that my computer's a bit slow), so I moved to 8-bit audio just to make sure the thing worked smoothly.  Using the negative gain was the trick.
    Michael L.
    Thursday, August 5, 2010 3:07 PM