1

I'm trying to create a program, using Qt (c++), which can record audio from my microphone using QAudioinput and QIODevice. I made a research and I came up with an example located on the this page. This example does what I need.

Now, I am trying to create an audio waveform of the recorded sound. I want to extract audio amplitudes and save them on a QList. To do that I use the following code:

//Check the number of samples in input buffer
qint64 len = m_audioInput->bytesReady();

//Limit sample size
if(len > 4096)
    len = 4096;
//Read sound samples from input device to buffer
qint64 l = m_input->read(m_buffer.data(), len);
if(l > 0)
{

    //Assign sound samples to short array
    short* resultingData = (short*)m_buffer.data();

     for ( i=0; i < len; i++ )
     {
         btlist.append( resultingData[ i ]);
     }

}

m_audioInput is QAudioinput | m_buffer is QBytearray | m_input is QIODevice | btlist is QList

I use the following QAudioFormat:

m_format.setFrequency(44100); //set frequency to 44100
m_format.setSampleRate(44100); //set sample rate to 44100
m_format.setChannels(1); //set channels to mono
m_format.setSampleSize(16); //set sample sze to 16 bit
m_format.setSampleType(QAudioFormat::SignedInt ); //signed integer sample
m_format.setByteOrder(QAudioFormat::LittleEndian); //Byte order
m_format.setCodec("audio/pcm"); //set codec as simple audio/pcm

When I print my QList, using qWarning() << btlist.at(int), I get some positive and negative numbers which represents my audio amplitudes. I used Microsoft Excel to plot the data and compare it with the actual sound waveform.

(EDIT BASED ON THE OP COMMENT) I am drawing the waveform using QPainter in Qt like this

  for(int i = 1; i < btlist.size(); i++){ 
       double x1 = (i-(i/1.25))-0.2;
       double y1 = btlist.at(i-1);
       double x2 = i-(i/1.25);
       double y2 = btlist.at(i);
       painter.drawLine(x1,y1,x2, y2); 
  }

The problem is that I also get lots of zeros (0) in my QList between the amplitude data like this, which if I draw as a waveform they are a straight line, which is not normal because it causes corruption to my waveform. My question is why is that happening? What these zeros (0) represent? Am I doing something wrong? Also, is there a better way to extract audio amplitudes from QBytearray?

Thank you.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
DaReDeViL
  • 43
  • 2
  • 8
  • how do you draw your waveform?? – UmNyobe Dec 20 '12 at 08:58
  • Hello UmNyobe, am drawing the waveform using QPainter in Qt like this: for(int i = 1; i < btlist.size(); i++){ painter.drawLine(((i-(i/1.25))-0.2),btlist.at(i-1),(i-(i/1.25)),btlist.at(i)); } – DaReDeViL Dec 20 '12 at 09:02
  • can you show your waveform too, and what do you mean by corruption?? – UmNyobe Dec 20 '12 at 09:33
  • 1
    You use len when filling the data, but the actually read bytes is l, not len. So if l < len, you're filling the list with invalid data from the buffer. – Frank Osterfeld Dec 20 '12 at 09:40
  • Here is what I get [link](http://s7.postimage.org/fxmo85pnf/waveform.png) when I record to this sound [link](http://www.youtube.com/watch?v=5TGCFGsQIx0). By corruption I mean amplitude with zero value. – DaReDeViL Dec 20 '12 at 09:43
  • Hello Frank Osterfeld, I changed "len" with "l" as you suggested but I still get the same thing. – DaReDeViL Dec 20 '12 at 09:52
  • @DaReDeViL see the end of my edit – UmNyobe Dec 20 '12 at 09:54

1 Answers1

0

The drawline method you are using take integer values. Which means most of the time both of your x indexes will be the same. By simplifiyng your formula the x value at a given i is (i/5.0). By itself it is not an issue because the lines will be superposed, and it is a perfect way of drawing (just to make sure that's what you want to do).

The zero you see can be perfectly valid. They represent silence.

The real issue is that the range of your 16 bits PCM values is [-32767 , 32768]. I doubt that the paint device you are using cover this range. You need to normalize your y-axis. Moreover, it seems taht the qt coordinated system doesn't have negative values (edit: Nevermind the negatives, its says logical coordinates are converted).

For instance, convert your pcm values using :

  ((btlist.at(i) / MAX_AMPLITUDE + 1.0) / 2) * paintDevice.height();

Edit:

Btw, you are not using l, which is the real amount of data you read. If it is inferior to len, you will read invalid values at the end of your buffer, possibly read garbage\ read zeros\crash.

And your buffer is a byte buffer. And you iterate using a short pointer. So whether you use l or len the maximum size need to be divided by two. This is probably the cause of the ling line of zero in your picture.

 for ( i=0; i < l/2; i++ )
 {
     btlist.append( resultingData[ i ]);
 }
UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • Thanks for your reply. I did notice that mistake you and Frank Osterfeld mentioned. Thank you. I changed it to "l" but I still get the same issue. The plot is the same as [link](http://s7.postimage.org/fxmo85pnf/waveform.png). I also tried to plot the data using Excel and I get the same thing. – DaReDeViL Dec 20 '12 at 09:56
  • 1
    I did now. Oh my god! I did not noticed that mistake. Thank you very much sir. I appreciate yours and Frank Osterfeld help. Thank you! :) – DaReDeViL Dec 20 '12 at 10:06
  • typical mistakes. I make tons of them :) – UmNyobe Dec 20 '12 at 10:08