qt audio output divide 100000 generate sinus wav
-
i work with example qt audio output and I do not understand the 2 lines, why we set duration * 1000000
m_generator = new Generator(m_format, DurationSeconds*1000000, ToneSampleRateHz, this);
and then divide by 100000
qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8)) * durationUs / 100000;????????????????????????
code:
#include <QAudioDeviceInfo>
#include <QAudioOutput>
#include <QDebug>
#include <QVBoxLayout>
#include <qmath.h>
#include <qendian.h>#include "audiooutput.h"
#define PUSH_MODE_LABEL "Enable push mode"
#define PULL_MODE_LABEL "Enable pull mode"
#define SUSPEND_LABEL "Suspend playback"
#define RESUME_LABEL "Resume playback"
#define VOLUME_LABEL "Volume:"const int DurationSeconds = 1;
const int ToneSampleRateHz = 600; // default = 600;
const int DataSampleRateHz = 44100;
const int BufferSize = 32768;Generator::Generator(const QAudioFormat &format,
qint64 durationUs,
int sampleRate,
QObject *parent)
: QIODevice(parent)
, m_pos(0)
{
if (format.isValid())
generateData(format, durationUs, sampleRate);
}Generator::~Generator()
{}
void Generator::start()
{
open(QIODevice::ReadOnly);
}void Generator::stop()
{
m_pos = 0;
close();
}void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate)
{
const int channelBytes = format.sampleSize() / 8;
const int sampleBytes = format.channelCount() * channelBytes;qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8)) * durationUs / 100000; Q_ASSERT(length % sampleBytes == 0); Q_UNUSED(sampleBytes) // suppress warning in release builds
//QMessageBox::warning(this, "sd", "sd", QMessageBox::Ok)
m_buffer.resize(length);
unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
int sampleIndex = 0;while (length) { const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex % format.sampleRate()) / format.sampleRate()); for (int i=0; i<format.channelCount(); ++i) { if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) { const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255); *reinterpret_cast<quint8*>(ptr) = value; } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) { const qint8 value = static_cast<qint8>(x * 127); *reinterpret_cast<quint8*>(ptr) = value; } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) { quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535); if (format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian<quint16>(value, ptr); else qToBigEndian<quint16>(value, ptr); } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) { qint16 value = static_cast<qint16>(x * 32767); if (format.byteOrder() == QAudioFormat::LittleEndian) qToLittleEndian<qint16>(value, ptr); else qToBigEndian<qint16>(value, ptr); } ptr += channelBytes; length -= channelBytes; } ++sampleIndex; }
}
qint64 Generator::readData(char *data, qint64 len)
{
qint64 total = 0;
if (!m_buffer.isEmpty()) {
while (len - total > 0) {
const qint64 chunk = qMin((m_buffer.size() - m_pos), len - total);
memcpy(data + total, m_buffer.constData() + m_pos, chunk);
m_pos = (m_pos + chunk) % m_buffer.size();
total += chunk;
}
}
return total;
}qint64 Generator::writeData(const char *data, qint64 len)
{
Q_UNUSED(data);
Q_UNUSED(len);return 0;
}
qint64 Generator::bytesAvailable() const
{
return m_buffer.size() + QIODevice::bytesAvailable();
}AudioTest::AudioTest()
: m_pushTimer(new QTimer(this))
, m_modeButton(0)
, m_suspendResumeButton(0)
, m_deviceBox(0)
, m_device(QAudioDeviceInfo::defaultOutputDevice())
, m_generator(0)
, m_audioOutput(0)
, m_output(0)
, m_buffer(BufferSize, 0)
{
initializeWindow();
initializeAudio();
}void AudioTest::initializeWindow()
{
QScopedPointer<QWidget> window(new QWidget);
QScopedPointer<QVBoxLayout> layout(new QVBoxLayout);m_deviceBox = new QComboBox(this); const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultOutputDevice(); m_deviceBox->addItem(defaultDeviceInfo.deviceName(), qVariantFromValue(defaultDeviceInfo)); foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) { if (deviceInfo != defaultDeviceInfo) m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo)); } connect(m_deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); layout->addWidget(m_deviceBox); m_modeButton = new QPushButton(this); m_modeButton->setText(tr(PUSH_MODE_LABEL)); connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode())); layout->addWidget(m_modeButton); m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); QHBoxLayout *volumeBox = new QHBoxLayout; m_volumeLabel = new QLabel; m_volumeLabel->setText(tr(VOLUME_LABEL)); m_volumeSlider = new QSlider(Qt::Horizontal); m_volumeSlider->setMinimum(0); m_volumeSlider->setMaximum(100); m_volumeSlider->setSingleStep(10); connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); volumeBox->addWidget(m_volumeLabel); volumeBox->addWidget(m_volumeSlider); layout->addLayout(volumeBox); window->setLayout(layout.data()); layout.take(); // ownership transferred setCentralWidget(window.data()); QWidget *const windowPtr = window.take(); // ownership transferred windowPtr->show();
}
void AudioTest::initializeAudio()
{
connect(m_pushTimer, SIGNAL(timeout()), SLOT(pushTimerExpired()));m_pullMode = true; m_format.setSampleRate(DataSampleRateHz); m_format.setChannelCount(1); m_format.setSampleSize(16); m_format.setCodec("audio/pcm"); m_format.setByteOrder(QAudioFormat::LittleEndian); m_format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if (!info.isFormatSupported(m_format)) { qWarning() << "Default format not supported - trying to use nearest"; m_format = info.nearestFormat(m_format); } m_generator = new Generator(m_format, DurationSeconds*1000000, ToneSampleRateHz, this); createAudioOutput();
}
void AudioTest::createAudioOutput()
{
delete m_audioOutput;
m_audioOutput = 0;
m_audioOutput = new QAudioOutput(m_device, m_format, this);
m_generator->start();
m_audioOutput->start(m_generator);
m_volumeSlider->setValue(int(m_audioOutput->volume()*100.0f));
}AudioTest::~AudioTest()
{}
void AudioTest::deviceChanged(int index)
{
m_pushTimer->stop();
m_generator->stop();
m_audioOutput->stop();
m_audioOutput->disconnect(this);
m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>();
createAudioOutput();
}void AudioTest::volumeChanged(int value)
{
if (m_audioOutput)
m_audioOutput->setVolume(qreal(value/100.0f));
}void AudioTest::pushTimerExpired()
{
if (m_audioOutput && m_audioOutput->state() != QAudio::StoppedState) {
int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize();
while (chunks) {
const qint64 len = m_generator->read(m_buffer.data(), m_audioOutput->periodSize());
if (len)
m_output->write(m_buffer.data(), len);
if (len != m_audioOutput->periodSize())
break;
--chunks;
}
}
}void AudioTest::toggleMode()
{
m_pushTimer->stop();
m_audioOutput->stop();if (m_pullMode) { //switch to push mode (periodically push to QAudioOutput using a timer) m_modeButton->setText(tr(PULL_MODE_LABEL)); m_output = m_audioOutput->start(); m_pullMode = false; m_pushTimer->start(20); } else { //switch to pull mode (QAudioOutput pulls from Generator as needed) m_modeButton->setText(tr(PUSH_MODE_LABEL)); m_pullMode = true; m_audioOutput->start(m_generator); } m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
}
void AudioTest::toggleSuspendResume()
{
if (m_audioOutput->state() == QAudio::SuspendedState) {
m_audioOutput->resume();
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
} else if (m_audioOutput->state() == QAudio::ActiveState) {
m_audioOutput->suspend();
m_suspendResumeButton->setText(tr(RESUME_LABEL));
} else if (m_audioOutput->state() == QAudio::StoppedState) {
m_audioOutput->resume();
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
} else if (m_audioOutput->state() == QAudio::IdleState) {
// no-op
}
} -
Hi and welcome to devnet,
Please practice some patience, this forum is community driven. Not all people active here are living in the same time zone as you.
In audio you generally use mili to microsecond for length. In the current case, it allows you to easily play with the duration in the example even though right now you have a one to one relation ship.