Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Correctly calculate and draw waveform based on the sample rate
Forum Updated to NodeBB v4.3 + New Features

Correctly calculate and draw waveform based on the sample rate

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 692 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    marcelnitan
    wrote on last edited by marcelnitan
    #1

    I'm working on a waveform for my player and so far everything went well, until I changed the sample rate from 48000 to 441000 and the waveform doesn't draw correctly. I'm stuck at calculating the correct number of samples to get to make it work correctly for (int i = 0; i < count; i += 1200){ // This works fine for 48000Hz but not for 441000Hz and I can't figure out how to do calculate it correctly

    8b761060-a9b8-449e-a54b-db117f9f3813-image.png

    Here's my code (full source code can be found at https://github.com/nitanmarcel/vpsplayer/tree/waveform_new:

    #include "waveformwidget.h"
    
    WaveformWidget::WaveformWidget()
    {
        waveformReady = false;
        m_pixLabel = new QLabel(this);
        m_pixLabel->show();
        this->m_paintTimer = new QTimer(this);
        connect(this->m_paintTimer, &QTimer::timeout, this, &WaveformWidget::drawWave);
        m_paintTimer->setInterval(100);
        m_paintTimer->start();
    }
    
    WaveformWidget::~WaveformWidget()
    {
    
    }
    
    // targetFormat = QAudioFormat(QAudioDeviceInfo::defaultOutputDevice().preferredFormat());
    // targetFormat.setCodec(QStringLiteral("audio/pcm"));
    // targetFormat.setSampleType(QAudioFormat::SignedInt);
    // targetFormat.setSampleSize(16);
    // if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
    //   targetFormat.setByteOrder(QAudioFormat::BigEndian);
    // else
    //   targetFormat.setByteOrder(QAudioFormat::LittleEndian);
    // qDebug() << "Sample rate:" << targetFormat.sampleRate();
    // qDebug() << "Channel count:" << targetFormat.channelCount();
    
    // QAudioFormat decodeFormat(targetFormat);
    // decodeFormat.setSampleType(QAudioFormat::Float);
    // decodeFormat.setSampleSize(32);
    
    void WaveformWidget::setFormat(QAudioFormat format)
    {
        audioFormat = format; // target_format from above
    }
    
    void WaveformWidget::setReady(bool ready)
    {
        waveformReady = ready;
    }
    
    void WaveformWidget::appendSamples(QAudioBuffer buffer)
    {
        qreal peak = getPeakValue(buffer.format());
        const qint16 *data = buffer.constData<qint16>();
        int count = buffer.sampleCount() / 2;
        for (int i = 0; i < count; i += 1200){ // This works fine for 48000Hz but not for 441000Hz and I can't figure out how to do calculate it correctly
            double val = data[i]/peak;
            samples.append(val);
        }
    }
    
    void WaveformWidget::clearSamples()
    {
        samples.clear();
    }
    
    qreal WaveformWidget::getPeakValue(const QAudioFormat& format)
    {
        // Note: Only the most common sample formats are supported
        if (!format.isValid())
            return qreal(0);
    
        if (format.codec() != "audio/pcm")
            return qreal(0);
    
        switch (format.sampleType()) {
        case QAudioFormat::Unknown:
            break;
        case QAudioFormat::Float:
            if (format.sampleSize() != 32) // other sample formats are not supported
                return qreal(0);
            return qreal(1.00003);
        case QAudioFormat::SignedInt:
            if (format.sampleSize() == 32)
    #ifdef Q_OS_WIN
                return qreal(INT_MAX);
    #endif
    #ifdef Q_OS_UNIX
                return qreal(SHRT_MAX);
    #endif
            if (format.sampleSize() == 16)
                return qreal(SHRT_MAX);
            if (format.sampleSize() == 8)
                return qreal(CHAR_MAX);
            break;
        case QAudioFormat::UnSignedInt:
            if (format.sampleSize() == 32)
                return qreal(UINT_MAX);
            if (format.sampleSize() == 16)
                return qreal(USHRT_MAX);
            if (format.sampleSize() == 8)
                return qreal(UCHAR_MAX);
            break;
        }
    
        return qreal(0);
    }
    
    void WaveformWidget::drawWave()
        {
            if (!waveformReady)
                return;
            int numberOfSamples = samples.size();
            int count = numberOfSamples / 2;
            float xScale = (float)width() / count;
            float center = (float)height() / 2;
            m_pixMap = QPixmap(size());
            m_pixMap.scaled(size());
            m_pixMap.fill(Qt::black);
            QPainter painter(&m_pixMap);
            painter.setPen(Qt::red);
            int currIndex = m_pixMap.rect().x();
            for(int i = 0; i < numberOfSamples; ++i){
                painter.drawRect(i * xScale, center - (samples[i] * center), 2, (samples[i] * center) * 2);
                currIndex++;
            }
    
            m_pixMap.scaled(width(), height());
            m_pixLabel->setPixmap(m_pixMap);
            m_pixLabel->resize(width(), height());
        }
    
    1 Reply Last reply
    0
    • M Offline
      M Offline
      marcelnitan
      wrote on last edited by
      #7

      Solved. Found my answer in a qt spectrum analyzer repository

      https://github.com/danielholanda/Qt-Audio-Spectrum-Analyzer/blob/master/Qt_code/mainwindow.cpp#L229

      The only change is in the append samples function:

      void WaveformWidget::appendSamples(QAudioBuffer buffer)
      {
          QAudioBuffer::S32F *data = buffer.data<QAudioBuffer::S32F>();
          qreal peakValue = qreal(1.00003); // sample type is always float as defined by the Audio_player.cpp source
          int count = buffer.sampleCount() / 2;
          for (int i = 0; i < count; i += 1050){
              double val = data[i].left/peakValue;
              samples.append(val);
          }
      }
      

      This was the old code

      void WaveformWidget::appendSamples(QAudioBuffer buffer)
      {
          qreal peak = getPeakValue(buffer.format());
          const qint16 *data = buffer.constData<qint16>();
          int count = buffer.sampleCount() / 2;
          for (int i = 0; i < count; i += 1200){
              double val = data[i]/peak;
              samples.append(val);
          }
      }
      
      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi,

        Your hardcoded 1200 step in that loop is the issue. 48000 / 1200 is an int value but 441000 / 1200 is not hence you are not working on the full sample.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        M 1 Reply Last reply
        0
        • SGaistS SGaist

          Hi,

          Your hardcoded 1200 step in that loop is the issue. 48000 / 1200 is an int value but 441000 / 1200 is not hence you are not working on the full sample.

          M Offline
          M Offline
          marcelnitan
          wrote on last edited by marcelnitan
          #3

          @SGaist I tried with 1102 and it's the same thing. Other numbers that 44100 divides by and that still didn't worked.

          I've tried messing up with the getPeakValue return and I got a smaller waveform. Still not the right one but it did something. So I'm guessing I have to find the correct value to normalize the data (which is what the getPeakValue function does

          JonBJ 1 Reply Last reply
          0
          • M marcelnitan

            @SGaist I tried with 1102 and it's the same thing. Other numbers that 44100 divides by and that still didn't worked.

            I've tried messing up with the getPeakValue return and I got a smaller waveform. Still not the right one but it did something. So I'm guessing I have to find the correct value to normalize the data (which is what the getPeakValue function does

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #4

            @marcelnitan said in Correctly calculate and draw waveform based on the sample rate:

            @SGaist I tried with 1102 and it's the same thing. Other numbers that 44100 divides by and that still didn't worked.

            Could you explain how 1102 is one of the numbers which 44100 divides by?

            M 1 Reply Last reply
            1
            • JonBJ JonB

              @marcelnitan said in Correctly calculate and draw waveform based on the sample rate:

              @SGaist I tried with 1102 and it's the same thing. Other numbers that 44100 divides by and that still didn't worked.

              Could you explain how 1102 is one of the numbers which 44100 divides by?

              M Offline
              M Offline
              marcelnitan
              wrote on last edited by
              #5

              @JonB Well just assumed it's closer to 44100 / 40 = 1102.5 and I hoped it will get a close number of samples to 44800 / 40 = 1200.

              Well it didn't worked and the waveform was still malformed.

              1 Reply Last reply
              0
              • M Offline
                M Offline
                marcelnitan
                wrote on last edited by
                #6

                Now I'm working with 42 samples and seems that the weight stays the same as before, and there's just a small silence at the begining of the waveform.

                for (int i = 0; i < count; i += 1050){

                516c79cb-7564-477b-abee-20c845938bfd-image.png

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  marcelnitan
                  wrote on last edited by
                  #7

                  Solved. Found my answer in a qt spectrum analyzer repository

                  https://github.com/danielholanda/Qt-Audio-Spectrum-Analyzer/blob/master/Qt_code/mainwindow.cpp#L229

                  The only change is in the append samples function:

                  void WaveformWidget::appendSamples(QAudioBuffer buffer)
                  {
                      QAudioBuffer::S32F *data = buffer.data<QAudioBuffer::S32F>();
                      qreal peakValue = qreal(1.00003); // sample type is always float as defined by the Audio_player.cpp source
                      int count = buffer.sampleCount() / 2;
                      for (int i = 0; i < count; i += 1050){
                          double val = data[i].left/peakValue;
                          samples.append(val);
                      }
                  }
                  

                  This was the old code

                  void WaveformWidget::appendSamples(QAudioBuffer buffer)
                  {
                      qreal peak = getPeakValue(buffer.format());
                      const qint16 *data = buffer.constData<qint16>();
                      int count = buffer.sampleCount() / 2;
                      for (int i = 0; i < count; i += 1200){
                          double val = data[i]/peak;
                          samples.append(val);
                      }
                  }
                  
                  1 Reply Last reply
                  0
                  • SalemSabrehagenS Offline
                    SalemSabrehagenS Offline
                    SalemSabrehagen
                    wrote on last edited by
                    #8

                    @marcelnitan said in Correctly calculate and draw waveform based on the sample rate:

                    for (int i = 0; i < count; i += 1200){ // This works fine for 48000Hz but not for 441000Hz and I can't figure out how to do calculate it correctly

                    441000Hz doesn't devide by 1200, im not sure, might be a hint for your bad drawing

                    /Ralf

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved