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();
127 pcmData.resizeForOverwrite(wav.totalPCMFrameCount * bytesPerFrame);
130 uint64_t framesRead = 0;
132 switch (outputFormat.sampleFormat()) {
133 case QAudioFormat::UInt8:
134 framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount,
135 reinterpret_cast<uint8_t *>(pcmData.data()));
137 case QAudioFormat::Int16:
138 framesRead = drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount,
139 reinterpret_cast<int16_t *>(pcmData.data()));
141 case QAudioFormat::Int32:
142 framesRead = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount,
143 reinterpret_cast<int32_t *>(pcmData.data()));
145 case QAudioFormat::Float:
146 framesRead = drwav_read_pcm_frames_f32(&wav, wav.totalPCMFrameCount,
147 reinterpret_cast<
float *>(pcmData.data()));
150 return makeFormatError(QAudioDecoder::tr(
"Unsupported sample format"));
153 if (framesRead != wav.totalPCMFrameCount) {
154 qCDebug(qLcDrWavDecoder) <<
"Failed to read all frames:"
155 <<
"expected" << wav.totalPCMFrameCount <<
"got" << framesRead;
156 return makeFormatError(QAudioDecoder::tr(
"Unable to read audio data"));
159 QAudioBuffer buffer(pcmData, outputFormat);
160 if (!buffer.isValid()) {
161 return makeFormatError(QAudioDecoder::tr(
"Failed to create audio buffer"));
164 qCDebug(qLcDrWavDecoder) <<
"Successfully decoded:" << buffer.sampleCount() <<
"samples";
210 if (m_source.isEmpty() && !m_sourceDevice) {
211 error(QAudioDecoder::ResourceError, tr(
"No audio source specified"));
215 m_decodingStopped = std::make_shared<std::atomic_bool>(
false);
217 auto threadPool = QThreadPool::globalInstance();
218 threadPool->start([source = m_source, sourceDevice = m_sourceDevice,
219 requestedFormat = m_audioFormat, decodingStopped = m_decodingStopped,
this] {
220 auto state = loadAndDecodeFile(source, sourceDevice, requestedFormat, decodingStopped);
222 QMetaObject::invokeMethod(
this,
223 [
this, decodingStopped, state = std::move(state)]()
mutable {
224 if (*decodingStopped) {
225 qCDebug(qLcDrWavDecoder) <<
"Decoding was stopped, discarding result";
228 onDecodeFinished(std::move(state), *decodingStopped);