40 const QAudioFormat &requestedFormat)
42 using namespace QtPrivate;
45 if (!drwav_init_memory(&wav, data.data(), data.size(),
nullptr)) {
46 qCDebug(qLcDrWavDecoder) <<
"Failed to initialize dr_wav decoder";
47 return makeFormatError(QAudioDecoder::tr(
"Unable to decode audio file"));
50 auto cleanup = qScopeGuard([&] {
55 QAudioFormat outputFormat;
58 if (requestedFormat.isValid()) {
60 if (requestedFormat.sampleRate() !=
static_cast<
int>(wav.sampleRate))
61 return makeFormatError(
62 QAudioDecoder::tr(
"Audio file sample rate does not match requested format"));
63 if (requestedFormat.channelCount() !=
static_cast<
int>(wav.channels))
64 return makeFormatError(
65 QAudioDecoder::tr(
"Audio file channel count does not match requested format"));
66 outputFormat = requestedFormat;
69 switch (requestedFormat.sampleFormat()) {
70 case QAudioFormat::UInt8:
71 bytesPerFrame = wav.channels *
sizeof(uint8_t);
73 case QAudioFormat::Int16:
74 bytesPerFrame = wav.channels *
sizeof(int16_t);
76 case QAudioFormat::Int32:
77 bytesPerFrame = wav.channels *
sizeof(int32_t);
79 case QAudioFormat::Float:
80 bytesPerFrame = wav.channels *
sizeof(
float);
83 return makeFormatError(QAudioDecoder::tr(
"Unsupported sample format"));
87 QAudioFormat::SampleFormat sampleFormat;
89 switch (wav.bitsPerSample) {
91 sampleFormat = QAudioFormat::UInt8;
92 bytesPerFrame = wav.channels *
sizeof(uint8_t);
95 sampleFormat = QAudioFormat::Int16;
96 bytesPerFrame = wav.channels *
sizeof(int16_t);
99 sampleFormat = QAudioFormat::Int32;
100 bytesPerFrame = wav.channels *
sizeof(int32_t);
103 sampleFormat = QAudioFormat::Int32;
104 bytesPerFrame = wav.channels *
sizeof(int32_t);
107 sampleFormat = QAudioFormat::Float;
108 bytesPerFrame = wav.channels *
sizeof(
float);
112 outputFormat.setChannelCount(wav.channels);
113 outputFormat.setSampleFormat(sampleFormat);
114 outputFormat.setSampleRate(wav.sampleRate);
115 outputFormat.setChannelConfig(
116 QAudioFormat::defaultChannelConfigForChannelCount(wav.channels));
119 qCDebug(qLcDrWavDecoder) <<
"Decoded WAV:"
120 <<
"channels=" << wav.channels <<
"sampleRate=" << wav.sampleRate
121 <<
"bitsPerSample=" << wav.bitsPerSample
122 <<
"totalPCMFrameCount=" << wav.totalPCMFrameCount
123 <<
"outputFormat=" << outputFormat.sampleFormat();
125 const QAudioFormat::SampleFormat readFormat = outputFormat.sampleFormat();
126 switch (readFormat) {
127 case QAudioFormat::UInt8:
128 case QAudioFormat::Int16:
129 case QAudioFormat::Int32:
130 case QAudioFormat::Float:
133 return makeFormatError(QAudioDecoder::tr(
"Unsupported sample format"));
136 std::optional<QByteArray> decoded = readFramesInChunks(
137 wav.totalPCMFrameCount, bytesPerFrame, [&](uint64_t frameCount,
char *out) -> uint64_t {
138 switch (readFormat) {
139 case QAudioFormat::UInt8:
140 return drwav_read_pcm_frames(&wav, frameCount, out);
141 case QAudioFormat::Int16:
142 return drwav_read_pcm_frames_s16(&wav, frameCount,
reinterpret_cast<int16_t *>(out));
143 case QAudioFormat::Int32:
144 return drwav_read_pcm_frames_s32(&wav, frameCount,
reinterpret_cast<int32_t *>(out));
145 case QAudioFormat::Float:
146 return drwav_read_pcm_frames_f32(&wav, frameCount,
reinterpret_cast<
float *>(out));
148 Q_UNREACHABLE_RETURN(0);
153 qCDebug(qLcDrWavDecoder) <<
"Failed to read all frames:"
154 <<
"expected" << wav.totalPCMFrameCount;
155 return makeFormatError(QAudioDecoder::tr(
"Unable to read audio data"));
158 const QByteArray &pcmData = *decoded;
160 QAudioBuffer buffer(pcmData, outputFormat);
161 if (!buffer.isValid()) {
162 return makeFormatError(QAudioDecoder::tr(
"Failed to create audio buffer"));
165 qCDebug(qLcDrWavDecoder) <<
"Successfully decoded:" << buffer.sampleCount() <<
"samples";
211 if (m_source.isEmpty() && !m_sourceDevice) {
212 error(QAudioDecoder::ResourceError, tr(
"No audio source specified"));
216 m_decodingStopped = std::make_shared<std::atomic_bool>(
false);
218 auto threadPool = QThreadPool::globalInstance();
219 threadPool->start([source = m_source, sourceDevice = m_sourceDevice,
220 requestedFormat = m_audioFormat, decodingStopped = m_decodingStopped,
this] {
221 auto state = loadAndDecodeFile(source, sourceDevice, requestedFormat, decodingStopped);
223 QMetaObject::invokeMethod(
this,
224 [
this, decodingStopped, state = std::move(state)]()
mutable {
225 if (*decodingStopped) {
226 qCDebug(qLcDrWavDecoder) <<
"Decoding was stopped, discarding result";
229 onDecodeFinished(std::move(state), *decodingStopped);