Manipulating PCM data and recording question

Hi guys,

I'm working on a project that implements LMS algorithm with direct sound.
LMS basicaly creates an adaptive filter using data from a playing wav file and data comming from a mic recording. I've created a full duplex object and playing a wav file (streaming) while recording what is being played using a mic.

My problem is as follows :
I need to calculate an error (=original sound - norm_factor*recorded sound)
the need for norm_factor comes from the difference in the volume of the original sound and the recorded sound (the mic is placed about 1.5m from the speaker. When I try to calculate that factor I always get a value that is close to 1 which looks to me not normal.

I am calculating this factor by selecting going over one buffer of the played sound and the equivalent buffer of the recorded sound :

for i=0;i<end of buffer;i++
{ sum_of_played+=(*(play_buffer+i));
  sum_of_recorded+=(*(capture_buffer+i));
}
norm_factor=(sum_or_played/length_of_buffer)/(sum_of_recorded/length_of_buffer)

When I've tryed to debug the process and watch the value of *(play_buffer+i)
and *(capture_buffer+i) I see that they are the same and the value (which supposed to be of type double) looks some thing like this : 128 "ε"

What are these values and how does the capture buffer store its data (I understand that it's PCM data, but does it pass some kind of normalization )


Sorry for the long post
Thanks
Gena



Answer this question

Manipulating PCM data and recording question

  • Kvltv

    The interpretation of the sound buffer depend on the frequency and format of the PCM, for high quality 44Mhz it's not signed value for low 22 Mhz it's a ''Signed'' number...

    I think, the data are in Little Endian...basicly They store the low byte first, then the high byte
    So you will need to do a binary shift of 8  something like this MyByte>>8 < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

    RealValue=(FirstByte<<8)+(SecondByte>>8);

    So you need to convert your buffer in order to use it...

    When you will get this RealValue you will have to test whether it's signed or not...
    Signed number goes from -127 to 128... for a range of 255 bits
    the value of FF is 255 in unsigned value, it's -127 in signed value...
    Check if the type BYTE is signed or not, I think it's an unsigned int

    If it's in Little endian (not little indian ;-) )...but low byte first...the value 0F and F0 are not the same at all
    because the FO will have a 1 in the most left bit this will give a negative number...

    another problem is saturation, you cannot just Add two buffer because they will saturate and double the volume...you need to bring down both buffer before you add their value....(or substract I imagine)

    I don't see why you would sum up all the buffer value...and then substract to find this average
    You cannot really sum up a wave that goes in negative value to get a correction factor....
    even more so if the buffer don't really stand for the exact same wave...
    But maybe it's ok...

    Another think is that PCM seems to be a 0 value then a real value...to make pulse (not sure)

    This link will explain better then me :-)
    http://www.codeguru.com/cpp/g-m/multimedia/audio/article.php/c8935/

  • lorifajose

    any comments
  • Srefae

    Hi ,

     

    Thanks for the great answer.  

    But there is still one thing I do not understand , durring my work I did the following:

    I've took some double value (0.5 for example) , then I did something like this

     

    for (i=0;i<length_of_buffer;i++)

    {  (*playbuffer)=(*playbuffer)/dev  //dev is the double value (0.5)

    playbuffer++}

     

    and what this did was lowering the volume of the wav by 2 .

    If directx works with the wav samples as is , i.e with little endian (I am not a programmer so I have a very slight idea of what this is) , so how could this code work as it did

     

    Could you propose some way of calculating the error vector between a recorded buffer and the played one I work in 22KHz , and using MATLAB it's very easy , but with C  I have problems. ( error(n)= played(n) - recorded(n) )

     

    Once again , many thanks for your help


  • bkannappan

    Hi ,

    Of caurse you are right , and dividing by 0.5 should have double the volume  I meant

    multyply .

    But the strange thing was that it worked as I wrote it. What I don't understand is how did it work if the samples are stored in little endian (or does the system knows by itself how to translate this into a real value )

    About the calculation of the error i will definately try it. I do not have to worry about the sync between the two waves since the LMS algorithm also compensates for phase difference (what you reffered to as sync) . I just have to see how the fact that the error is calculated only for possitive values will influence the LMS.

    So I think something like this should do :

     

    for(i=0;i<length_of_buffer;i++)

    { if (played(i)>0 && recorded(i)>0)

    error=played(i)-recorded(i)

    else

    error=played(i)-recorded(i-1) }      //the phase difference does not matter

    avg_error=error/(length_of_buffer / 2)   //  /2 because checking only positive values   

     

    Your proposition about calculating the average is also very good in my case - although it's correct only for a small buffer (as you said you can get a big bump) but since I need it only for calculating the ratio between the volume of the played sound and of the recorded sound , if I get a bump in one of them I should get it in the other as well and the ration should stay constant (more or less) .

    I used the sum as I did for this since I thought that the data is unsigned and then the DC is basically the volume .

    One thing I did not understand is about the char arrays. How can you cast PCM data to be a char I understand that the PCM data  in directX is only integer And why do you need to cast buffer2 into char if it's already a buffer of chars "char buffer2[40000];"

    I am a litle thick in all of this since I'm not a programmer . I really apretiate your help and patience with me. Thank you .

     


  • IainMc

    The best way to understand your value is to plot them on a graph

    I use a small GDI render, that basicaly draw from point to point the pulse

    (With a Pen resource  and simple Goto from one value to the other)

    That way you will see the buffer has it is...

    that's the way I saw the saturation when I added the value

    I guess you can try to plot the wave buffer with matlab too

    and place both buffer sample one on top of the other

    < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

    As for the divided by 0.5 it should have double all the value... 100/0.5 is like 100*2

    The sound should have increase...strange :-)
    What you should do is cast your type to force the value to a Signed Byte or a char

    char buffer1[40000];
    char buffer2[40000];

    loop this line:

    buffer1Idea=(char)buffer2Idea/2;

    You allways work in Integer value (there is no need to use Float or Double its never a fraction)

    Their is no strange modulation, the DX buffer play the buffer he get if the DX buffer

    is set to the same parameter of the Wave Buffer

     

    As for the Error between the 2 wave file,

    Sound are like Sin wave,

     

    x = Ampli*Sin(Frequency) + C

     

    We know frequency stay the same so only Amplitude vary to produce the sound

    Ampli is the volume, frequency the sound, and C is the value if the sin goes to 0

     

    If you do the average of a Sin Wave you are going to get 0,

    because half the time it goes up the other half it goes in the negative...

    Ampli is from 0 to the top positive value

    If you get a value it's because there is a constant C in the wave (like a DC voltage in an AC wave)

    But they don't have that in Wave buffer PCM

     

    You could keep only the positive value of the buffer (the negative are symetrical)

    And then do the average of only the positive value

    But this will get you the average of all the wave

    Maybe it's very acurate at the start and of poor acuracy at the end...

    Even worst you could register a bump at the end of one buffer that let your average meaningless

     

    PCM are digital value of a wave their positive value will have an enveloppe that look like a wave

    You can draw this enveloppe by plotting a line from their positive value from one to the other

    And then draw the enveloppe of the second sound the same way

    The difference between those two ''wave'' line would be your error

    You should calculate all those little difference between the wave and plot that too

    You should get a little wave of ''error'' at the bottom of your graph

    If it's not in sync that error wave is going to be big,

    the more in sync you are the lower the error wave will be

    You will have to slide one wave to put it in sync with the other

     

    One problem will be to match both enveloppe to one another,

    When you plot them you will see if they are in sync or not

     

    If you calculate the envelope difference when not in sync you will get the wrong error

    It's not going to be an error but the sound difference at that time because the wave are not in sync

     

    So, you should plot the value, keep only the positive value, trace a line on top of them

    And compare the ''enveloppe'' error between both wave and plot that too

    Error(t)=ValueSin2(t)-ValueSin1(t)

     

    You will see if they are in sync or not

    The more in sync, the smaller the error wave will be

    (you slide one buffer to match the sound and put them in sync)


  • Manipulating PCM data and recording question