Correctly calculate and draw waveform based on the sample rate
-
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
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()); }
-
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); } }
-
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.
-
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.
@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
-
@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
@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 which44100
divides by? -
@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 which44100
divides by?@JonB Well just assumed it's closer to
44100 / 40 = 1102.5
and I hoped it will get a close number of samples to44800 / 40 = 1200
.Well it didn't worked and the waveform was still malformed.
-
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){
-
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); } }
-
@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