Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
audiogenerationutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
6#include <QtCore/qscopeguard.h>
7
8#define DR_WAV_IMPLEMENTATION
9#define DR_WAV_NO_STDIO
10#define DR_WAV_NO_CONVERSION_API
11#define DR_WAV_NO_WCHAR
12#define DRWAV_API static
13#define DRWAV_PRIVATE static
14#define QtPrivate QtPrivateDrwavMultimediaTest
15#include <dr_wav.h>
16#undef QtPrivate
17
18using namespace QtPrivateDrwavMultimediaTest;
19
21
22unsigned char *writeSineSample(unsigned char *ptr, QAudioFormat::SampleFormat sampleFormat, qreal x)
23{
24 auto writeNextFrame = [&](auto value) {
25 *reinterpret_cast<decltype(value) *>(ptr) = value;
26 return ptr + sizeof(value);
27 };
28
29 switch (sampleFormat) {
30 case QAudioFormat::UInt8:
31 return writeNextFrame(quint8(std::round((1.0 + x) / 2 * 255)));
32 case QAudioFormat::Int16:
33 return writeNextFrame(qint16(std::round(x * std::numeric_limits<qint16>::max())));
34 case QAudioFormat::Int32:
35 return writeNextFrame(qint32(std::round(x * std::numeric_limits<qint32>::max())));
36 case QAudioFormat::Float:
37 return writeNextFrame(float(x));
38 case QAudioFormat::Unknown:
39 case QAudioFormat::NSampleFormats:
40 break;
41 }
42 return ptr;
43}
44
45QByteArray createSineWaveData(const QAudioFormat &format, std::chrono::microseconds duration,
46 qint32 sampleIndex, qreal frequency, qreal volume)
47{
48 if (!format.isValid())
49 return {};
50
51 const qint32 length = format.bytesForDuration(duration.count());
52
53 QByteArray data(format.bytesForDuration(duration.count()), Qt::Uninitialized);
54 unsigned char *ptr = reinterpret_cast<unsigned char *>(data.data());
55 const auto end = ptr + length;
56
57 const double initialPhase = 2.0 * M_PI * frequency * sampleIndex / format.sampleRate();
58 SineWaveSignal generator(frequency, format.sampleRate(), initialPhase);
59 for (double rawSample : generator) {
60 if (ptr >= end)
61 break;
62 const qreal x = rawSample * volume;
63 for (int channel = 0; channel < format.channelCount(); ++channel)
64 ptr = writeSineSample(ptr, format.sampleFormat(), x);
65 }
66
67 Q_ASSERT(ptr == end);
68
69 return data;
70}
71
73 std::chrono::microseconds duration,
74 qreal frequency, qreal volume)
75{
76 QAudioFormat format;
77 format.setSampleFormat(QAudioFormat::Int16);
78 format.setChannelCount(1);
79 format.setSampleRate(sampleRate);
80
81 const QByteArray pcmData =
82 createSineWaveData(format, duration, /*sampleIndex=*/0, frequency, volume);
83
84 drwav_data_format wavFormat{};
85 wavFormat.container = drwav_container_riff;
86 wavFormat.format = DR_WAVE_FORMAT_PCM;
87 wavFormat.channels = 1;
88 wavFormat.sampleRate = drwav_uint32(sampleRate);
89 wavFormat.bitsPerSample = 16;
90
91 void *wavData = nullptr;
92 size_t wavDataSize = 0;
93 drwav wav;
94 if (!drwav_init_memory_write(&wav, &wavData, &wavDataSize, &wavFormat, nullptr))
95 return nullptr;
96
97 auto dataGuard = qScopeGuard([&] {
98 drwav_uninit(&wav);
99 drwav_free(wavData, nullptr);
100 });
101
102 const auto framesToWrite = drwav_uint64(pcmData.size() / sizeof(qint16));
103 if (drwav_write_pcm_frames(&wav, framesToWrite, pcmData.constData()) != framesToWrite)
104 return nullptr;
105
106 auto file = std::make_unique<QTemporaryFile>();
107 if (!file->open())
108 return nullptr;
109 file->write(static_cast<const char *>(wavData), qint64(wavDataSize));
110 file->close();
111
112 return file;
113}
114
115QT_END_NAMESPACE
QByteArray createSineWaveData(const QAudioFormat &format, std::chrono::microseconds duration, qint32 sampleIndex, qreal frequency, qreal volume)
std::unique_ptr< QTemporaryFile > makeMonoPcm16WavFile(int sampleRate, std::chrono::microseconds duration, qreal frequency, qreal volume)
QT_BEGIN_NAMESPACE unsigned char * writeSineSample(unsigned char *ptr, QAudioFormat::SampleFormat sampleFormat, qreal x)
#define M_PI
Definition qmath.h:201