Skip to content

Commit f13e243

Browse files
committed
WIP add audio export
1 parent 1280289 commit f13e243

18 files changed

Lines changed: 2545 additions & 1 deletion

src/plugins/audio/audioexport/AudioExporter.cpp

Lines changed: 709 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#ifndef DIFFSCOPE_AUDIO_AUDIOEXPORTER_H
2+
#define DIFFSCOPE_AUDIO_AUDIOEXPORTER_H
3+
4+
#include <QObject>
5+
#include <QStringList>
6+
7+
#include <audio/AudioExporterConfig.h>
8+
#include <audio/audioglobal.h>
9+
10+
namespace Core {
11+
class ProjectWindowInterface;
12+
}
13+
14+
namespace Audio {
15+
16+
namespace Internal {
17+
class AudioExportDialog;
18+
}
19+
20+
class AudioExporter;
21+
class AudioExporterPrivate;
22+
23+
class AudioExporterListener {
24+
public:
25+
virtual ~AudioExporterListener() = default;
26+
virtual bool willStartCallback(AudioExporter *exporter) = 0;
27+
virtual void willFinishCallback(AudioExporter *exporter) = 0;
28+
};
29+
30+
class AUDIO_EXPORT AudioExporter : public QObject {
31+
Q_OBJECT
32+
Q_DECLARE_PRIVATE(AudioExporter)
33+
Q_PROPERTY(Core::ProjectWindowInterface *windowHandle READ windowHandle CONSTANT)
34+
Q_PROPERTY(Audio::AudioExporterConfig config READ config WRITE setConfig NOTIFY configChanged)
35+
Q_PROPERTY(PreflightWarnings preflightWarnings READ preflightWarnings NOTIFY preflightWarningsChanged)
36+
Q_PROPERTY(QStringList fileList READ fileList NOTIFY fileListChanged)
37+
Q_PROPERTY(Error error READ error NOTIFY errorChanged)
38+
Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
39+
Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged)
40+
41+
public:
42+
explicit AudioExporter(Core::ProjectWindowInterface *windowHandle, QObject *parent = nullptr);
43+
~AudioExporter() override;
44+
45+
Core::ProjectWindowInterface *windowHandle() const;
46+
47+
static void registerListener(AudioExporterListener *listener);
48+
49+
AudioExporterConfig config() const;
50+
void setConfig(const AudioExporterConfig &config);
51+
52+
enum PreflightWarningFlag {
53+
PW_NoFile = 0x0001,
54+
PW_DuplicatedFile = 0x0002,
55+
PW_WillOverwrite = 0x0004,
56+
PW_UnrecognizedTemplate = 0x0008,
57+
PW_LossyFormat = 0x0010,
58+
};
59+
Q_ENUM(PreflightWarningFlag)
60+
Q_DECLARE_FLAGS(PreflightWarnings, PreflightWarningFlag)
61+
Q_FLAG(PreflightWarnings)
62+
63+
PreflightWarnings preflightWarnings() const;
64+
static QStringList preflightWarningTexts(PreflightWarnings warnings);
65+
66+
QStringList fileList() const;
67+
QStringList dryRun() const;
68+
69+
enum Error {
70+
NoError,
71+
InvalidConfig,
72+
InvalidSource,
73+
CannotOpenFile,
74+
UnsupportedFormat,
75+
CannotStartExport,
76+
ExporterFailed,
77+
RenameTemporaryFileFailed,
78+
Cancelled,
79+
UnknownError,
80+
};
81+
Q_ENUM(Error)
82+
83+
Error error() const;
84+
QString errorString() const;
85+
86+
bool isRunning() const;
87+
88+
enum Result {
89+
R_Ok,
90+
R_Fail,
91+
R_Abort,
92+
};
93+
Q_ENUM(Result)
94+
95+
Q_INVOKABLE Result exec();
96+
Q_INVOKABLE void cleanUp();
97+
Q_INVOKABLE void cancel(bool isFail = false, const QString &message = {});
98+
Q_INVOKABLE void addRuntimeWarning(const QString &message, int sourceIndex = -1);
99+
100+
Q_SIGNALS:
101+
void configChanged();
102+
void preflightWarningsChanged();
103+
void fileListChanged();
104+
void errorChanged();
105+
void runningChanged();
106+
void progressChanged(double progressRatio, int sourceIndex);
107+
void clippingDetected(int sourceIndex);
108+
void runtimeWarningAdded(const QString &message, int sourceIndex);
109+
110+
private:
111+
friend class Internal::AudioExportDialog;
112+
QScopedPointer<AudioExporterPrivate> d_ptr;
113+
};
114+
115+
}
116+
117+
Q_DECLARE_OPERATORS_FOR_FLAGS(Audio::AudioExporter::PreflightWarnings)
118+
119+
using AudioExporter = Audio::AudioExporter;
120+
121+
#endif // DIFFSCOPE_AUDIO_AUDIOEXPORTER_H
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
#include "AudioExporterConfig.h"
2+
#include "AudioExporterConfig_p.h"
3+
4+
#include <QJsonArray>
5+
#include <QJsonValue>
6+
7+
namespace Audio {
8+
9+
AudioExporterConfig::AudioExporterConfig() : d(new AudioExporterConfigData) {
10+
}
11+
12+
AudioExporterConfig::AudioExporterConfig(const AudioExporterConfig &other) = default;
13+
14+
AudioExporterConfig::AudioExporterConfig(AudioExporterConfig &&other) noexcept = default;
15+
16+
AudioExporterConfig &AudioExporterConfig::operator=(const AudioExporterConfig &other) = default;
17+
18+
AudioExporterConfig &AudioExporterConfig::operator=(AudioExporterConfig &&other) noexcept = default;
19+
20+
AudioExporterConfig::~AudioExporterConfig() = default;
21+
22+
QString AudioExporterConfig::fileName() const {
23+
return d->fileName;
24+
}
25+
26+
void AudioExporterConfig::setFileName(const QString &fileName) {
27+
d->fileName = fileName;
28+
}
29+
30+
QString AudioExporterConfig::fileDirectory() const {
31+
return d->fileDirectory;
32+
}
33+
34+
void AudioExporterConfig::setFileDirectory(const QString &fileDirectory) {
35+
d->fileDirectory = fileDirectory;
36+
}
37+
38+
AudioExporterConfig::FileType AudioExporterConfig::fileType() const {
39+
return d->fileType;
40+
}
41+
42+
void AudioExporterConfig::setFileType(FileType fileType) {
43+
d->fileType = fileType;
44+
}
45+
46+
bool AudioExporterConfig::formatMono() const {
47+
return d->formatMono;
48+
}
49+
50+
void AudioExporterConfig::setFormatMono(bool formatMono) {
51+
d->formatMono = formatMono;
52+
}
53+
54+
QStringList AudioExporterConfig::formatOptionsOfType(FileType type) {
55+
switch (type) {
56+
case FT_Wav:
57+
return {
58+
tr("32-bit float (IEEE 754)"),
59+
tr("24-bit PCM"),
60+
tr("16-bit PCM"),
61+
tr("Unsigned 8-bit PCM"),
62+
};
63+
case FT_Flac:
64+
return {
65+
tr("24-bit PCM"),
66+
tr("16-bit PCM"),
67+
tr("8-bit PCM"),
68+
};
69+
default:
70+
return {};
71+
}
72+
}
73+
74+
QString AudioExporterConfig::extensionOfType(FileType type) {
75+
switch (type) {
76+
case FT_Wav:
77+
return QStringLiteral("wav");
78+
case FT_Flac:
79+
return QStringLiteral("flac");
80+
case FT_OggVorbis:
81+
return QStringLiteral("ogg");
82+
case FT_Mp3:
83+
return QStringLiteral("mp3");
84+
}
85+
return {};
86+
}
87+
88+
int AudioExporterConfig::formatOption() const {
89+
return d->formatOption;
90+
}
91+
92+
void AudioExporterConfig::setFormatOption(int formatOption) {
93+
d->formatOption = formatOption;
94+
}
95+
96+
int AudioExporterConfig::formatQuality() const {
97+
return d->formatQuality;
98+
}
99+
100+
void AudioExporterConfig::setFormatQuality(int formatQuality) {
101+
d->formatQuality = formatQuality;
102+
}
103+
104+
double AudioExporterConfig::formatSampleRate() const {
105+
return d->formatSampleRate;
106+
}
107+
108+
void AudioExporterConfig::setFormatSampleRate(double formatSampleRate) {
109+
d->formatSampleRate = formatSampleRate;
110+
}
111+
112+
AudioExporterConfig::MixingOption AudioExporterConfig::mixingOption() const {
113+
return d->mixingOption;
114+
}
115+
116+
void AudioExporterConfig::setMixingOption(MixingOption mixingOption) {
117+
d->mixingOption = mixingOption;
118+
}
119+
120+
bool AudioExporterConfig::isMuteSoloEnabled() const {
121+
return d->isMuteSoloEnabled;
122+
}
123+
124+
void AudioExporterConfig::setMuteSoloEnabled(bool enabled) {
125+
d->isMuteSoloEnabled = enabled;
126+
}
127+
128+
AudioExporterConfig::SourceOption AudioExporterConfig::sourceOption() const {
129+
return d->sourceOption;
130+
}
131+
132+
void AudioExporterConfig::setSourceOption(SourceOption sourceOption) {
133+
d->sourceOption = sourceOption;
134+
}
135+
136+
QList<int> AudioExporterConfig::source() const {
137+
return d->source;
138+
}
139+
140+
void AudioExporterConfig::setSource(const QList<int> &source) {
141+
d->source = source;
142+
}
143+
144+
AudioExporterConfig::TimeRange AudioExporterConfig::timeRange() const {
145+
return d->timeRange;
146+
}
147+
148+
void AudioExporterConfig::setTimeRange(TimeRange timeRange) {
149+
d->timeRange = timeRange;
150+
}
151+
152+
QJsonObject AudioExporterConfig::toJsonObject() const {
153+
QJsonArray sourceArray;
154+
for (const auto sourceIndex : d->source) {
155+
sourceArray.append(sourceIndex);
156+
}
157+
158+
return {
159+
{"fileName", d->fileName },
160+
{"fileDirectory", d->fileDirectory },
161+
{"fileType", static_cast<int>(d->fileType) },
162+
{"formatMono", d->formatMono },
163+
{"formatOption", d->formatOption },
164+
{"formatQuality", d->formatQuality },
165+
{"formatSampleRate", d->formatSampleRate },
166+
{"mixingOption", static_cast<int>(d->mixingOption) },
167+
{"isMuteSoloEnabled", d->isMuteSoloEnabled },
168+
{"sourceOption", static_cast<int>(d->sourceOption) },
169+
{"source", sourceArray },
170+
{"timeRange", static_cast<int>(d->timeRange) },
171+
};
172+
}
173+
174+
AudioExporterConfig AudioExporterConfig::fromJsonObject(const QJsonObject &object) {
175+
AudioExporterConfig config;
176+
const auto assignString = [&object](const QString &key, QString &out) {
177+
const auto value = object.value(key);
178+
if (value.isString()) {
179+
out = value.toString();
180+
}
181+
};
182+
const auto assignInt = [&object](const QString &key, int &out) {
183+
const auto value = object.value(key);
184+
if (value.isDouble()) {
185+
out = value.toInt();
186+
}
187+
};
188+
189+
assignString(QStringLiteral("fileName"), config.d->fileName);
190+
assignString(QStringLiteral("fileDirectory"), config.d->fileDirectory);
191+
192+
int fileType = config.d->fileType;
193+
assignInt(QStringLiteral("fileType"), fileType);
194+
config.d->fileType = static_cast<FileType>(fileType);
195+
196+
auto value = object.value(QStringLiteral("formatMono"));
197+
if (value.isBool()) {
198+
config.d->formatMono = value.toBool();
199+
}
200+
201+
assignInt(QStringLiteral("formatOption"), config.d->formatOption);
202+
assignInt(QStringLiteral("formatQuality"), config.d->formatQuality);
203+
204+
value = object.value(QStringLiteral("formatSampleRate"));
205+
if (value.isDouble()) {
206+
config.d->formatSampleRate = value.toDouble();
207+
}
208+
209+
int mixingOption = config.d->mixingOption;
210+
assignInt(QStringLiteral("mixingOption"), mixingOption);
211+
config.d->mixingOption = static_cast<MixingOption>(mixingOption);
212+
213+
value = object.value(QStringLiteral("isMuteSoloEnabled"));
214+
if (value.isBool()) {
215+
config.d->isMuteSoloEnabled = value.toBool();
216+
}
217+
218+
int sourceOption = config.d->sourceOption;
219+
assignInt(QStringLiteral("sourceOption"), sourceOption);
220+
config.d->sourceOption = static_cast<SourceOption>(sourceOption);
221+
222+
value = object.value(QStringLiteral("source"));
223+
if (value.isArray()) {
224+
QList<int> source;
225+
bool ok = true;
226+
for (const auto item : value.toArray()) {
227+
if (!item.isDouble()) {
228+
ok = false;
229+
break;
230+
}
231+
source.append(item.toInt());
232+
}
233+
if (ok) {
234+
config.d->source = source;
235+
}
236+
}
237+
238+
int timeRange = config.d->timeRange;
239+
assignInt(QStringLiteral("timeRange"), timeRange);
240+
config.d->timeRange = static_cast<TimeRange>(timeRange);
241+
return config;
242+
}
243+
244+
bool AudioExporterConfig::operator==(const AudioExporterConfig &other) const {
245+
// `source` is not compared
246+
return d->fileName == other.d->fileName && d->fileDirectory == other.d->fileDirectory &&
247+
d->fileType == other.d->fileType && d->formatMono == other.d->formatMono &&
248+
d->formatOption == other.d->formatOption && d->formatQuality == other.d->formatQuality &&
249+
d->formatSampleRate == other.d->formatSampleRate && d->mixingOption == other.d->mixingOption &&
250+
d->isMuteSoloEnabled == other.d->isMuteSoloEnabled && d->sourceOption == other.d->sourceOption &&
251+
d->timeRange == other.d->timeRange;
252+
}
253+
254+
}

0 commit comments

Comments
 (0)