8 #include <QStringBuilder>
16 using namespace swift::misc::audio;
17 using namespace swift::sound;
18 using namespace swift::sound::sample_provider;
20 namespace swift::core::afv::audio
23 :
QIODevice(parent), m_sampleProvider(sampleProvider)
25 Q_ASSERT_X(sampleProvider, Q_FUNC_INFO,
"need sample provide");
35 constexpr qint64 bufferLengthMs = 20;
36 const qint64 bufferSize = m_outputFormat.bytesForDuration(bufferLengthMs * 1000);
42 const int sampleBytes = m_outputFormat.bytesPerSample();
43 const int channelCount = m_outputFormat.channelCount();
44 const qint64 count = maxlen / (sampleBytes * channelCount);
48 for (
float sample : std::as_const(buffer))
50 const float absSample = qAbs(sample);
51 m_maxSampleOutput = std::max(absSample, m_maxSampleOutput);
54 m_sampleCount += buffer.size();
55 if (m_sampleCount >= SampleCountPerEvent)
58 outputVolumeStreamArgs.
PeakRaw = m_maxSampleOutput / 1.0;
59 outputVolumeStreamArgs.
PeakDb =
static_cast<float>(20 * std::log10(outputVolumeStreamArgs.
PeakRaw));
60 const double db = qBound(m_minDb, outputVolumeStreamArgs.
PeakDb, m_maxDb);
61 double ratio = (db - m_minDb) / (m_maxDb - m_minDb);
62 if (ratio < 0.30) { ratio = 0.0; }
63 ratio = std::min(ratio, 1.0);
64 outputVolumeStreamArgs.
PeakVU = ratio;
67 m_maxSampleOutput = 0;
70 if (channelCount == 2) { buffer = convertFromMonoToStereo(buffer); }
72 memcpy(data, buffer.constData(),
static_cast<size_t>(maxlen));
87 if (m_started) {
return; }
91 if (m_audioOutputBuffer) { m_audioOutputBuffer->
deleteLater(); }
95 m_device = outputDevice;
97 QAudioFormat outputFormat;
98 outputFormat.setSampleRate(48000);
99 outputFormat.setChannelCount(1);
100 outputFormat.setChannelConfig(QAudioFormat::ChannelConfigMono);
101 outputFormat.setSampleFormat(QAudioFormat::Float);
102 static_assert(Q_BYTE_ORDER == Q_LITTLE_ENDIAN);
104 const QString format = toQString(outputFormat);
105 const QAudioDevice selectedDevice = getLowestLatencyDevice(outputDevice, outputFormat);
106 CLogMessage(
this).
info(u
"Starting: '%1' with: %2") << selectedDevice.description() << format;
108 m_audioOutput.
reset(
new QAudioSink(selectedDevice, outputFormat));
111 m_audioOutput->start(m_audioOutputBuffer);
118 if (!m_started) {
return; }
120 m_audioOutput->stop();
121 m_audioOutput.
reset();
122 if (m_audioOutputBuffer)
125 m_audioOutputBuffer =
nullptr;
qint64 bytesAvailable() const
qint64 writeData(const char *data, qint64 len)
void outputVolumeStream(const OutputVolumeStreamArgs &args)
Volume stream.
void setAudioFormat(const QAudioFormat &format)
Set the format.
qint64 readData(char *data, qint64 maxlen)
void outputVolumeStream(const OutputVolumeStreamArgs &args)
Streaming data.
COutput(QObject *parent=nullptr)
Ctor.
void start(const swift::misc::audio::CAudioDeviceInfo &outputDevice, swift::sound::sample_provider::ISampleProvider *sampleProvider)
Start output.
Class for emitting a log message.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
Value object encapsulating information of a audio device.
bool isOutputDevice() const
Output device.
bool isValid() const
Valid audio device object?
Sample provider interface.
virtual int readSamples(QVector< float > &samples, qint64 count)=0
Read samples.
Free functions in swift::misc.
QString classNameShort(const QObject *object)
Class name as from QMetaObject::className without namespace.
virtual qint64 bytesAvailable() const const
virtual bool open(QIODeviceBase::OpenMode mode)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void setObjectName(QAnyStringView name)
QString arg(Args &&... args) const const
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.