CuteLogger
Fast and simple logging solution for Qt based applications
audiomixingassistantdialog.h
1/*
2 * Copyright (c) 2026 Meltytech, LLC
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef AUDIOMIXINGASSISTANTDIALOG_H
19#define AUDIOMIXINGASSISTANTDIALOG_H
20
21#include "models/multitrackmodel.h"
22
23#include <QDialog>
24#include <QHash>
25#include <QVector>
26
27class QTableWidget;
28class QTableWidgetItem;
29class QDialogButtonBox;
30class QPushButton;
31class QComboBox;
32class QDoubleSpinBox;
33class QStackedWidget;
34class QProgressBar;
35class TrackAudioReader;
36
37// The measurements gathered for a single track during analysis.
38struct TrackAnalysisResult
39{
40 int trackIndex = -1;
41 AudioTrackRole role = UnassignedAudioRole;
42 double integratedLoudness = -100.0;
43 QVector<float> frameLevels; // only populated for dialogue and premixed program tracks
44};
45
46// A single point in a keyframed gain envelope used to duck a track.
47struct DuckingKeyframe
48{
49 int frame = 0;
50 double gainDb = 0.0;
51};
52
53// Identifies what kind of change a recommendation represents, so the Apply
54// step knows how to act on it.
55enum class RecommendationKind {
56 Unknown = 0,
57 DialogueLoudnessGain,
58 DialogueHighPass,
59 DialogueCompressor,
60 BackgroundMusicGain,
61 BackgroundMusicDucking,
62 BackgroundMusicFrequencyCarving,
63 AmbienceGain,
64 AmbienceHighPass,
65 AmbienceLowPass,
66 SfxGain,
67 SfxHighPass,
68 SfxDucking,
69 PremixedProgramGain
70};
71
72// A single proposed filter to add to a track, pending user approval.
73struct MixRecommendation
74{
75 int trackIndex = -1;
76 RecommendationKind kind = RecommendationKind::Unknown;
77 QString title;
78 QString description;
79 bool enabled = true;
80 QString mltService;
81 QString shotcutFilterName;
82 QList<QPair<QString, double>> properties;
83};
84
85class AudioMixingAssistantDialog : public QDialog
86{
87 Q_OBJECT
88public:
89 explicit AudioMixingAssistantDialog(QString title, MultitrackModel *model, QWidget *parent = 0);
90
91public slots:
92 void reject() override;
93
94private slots:
95 void onTrackNameChanged(QTableWidgetItem *item);
96 void onTrackRoleChanged(int trackIndex, int roleComboIndex);
97 void onTargetPresetChanged(int index);
98 void onTargetLoudnessChanged(double value);
99 void onActionButtonPressed();
100 void onTrackAnalysisProgress(int trackIndex, int percent);
101 void onTrackAnalysisFinished(int trackIndex,
102 double integratedLoudness,
103 QVector<float> frameLevels);
104
105private:
106 enum Column { ColumnType = 0, ColumnName, ColumnRole };
107 enum RecommendationColumn {
108 RecommendationColumnEnabled = 0,
109 RecommendationColumnTrack,
110 RecommendationColumnDescription
111 };
112 enum TargetPreset { PresetWeb = 0, PresetBroadcast, PresetCustom };
113 enum Stage { StageConfigure = 0, StageProcessing, StageRecommendations };
114
115 QWidget *createConfigurePage();
116 QWidget *createProgressPage();
117 QWidget *createRecommendationsPage();
118 void populateTrackTable();
119 QString roleDisplayName(AudioTrackRole role) const;
120 void updateTargetPresetFromLoudness(double value);
121 void startProcessing();
122 void finishProcessing();
123 void generateRecommendations();
124 void addLoudnessRecommendation(const TrackAnalysisResult &result);
125 void addHighPassRecommendation(const TrackAnalysisResult &result);
126 void addCompressorRecommendation(const TrackAnalysisResult &result);
127 void addBackgroundMusicGainRecommendation(const TrackAnalysisResult &result,
128 double anchorLoudness);
129 void addDuckingRecommendation(const TrackAnalysisResult &result);
130 void addFrequencyCarvingRecommendation(const TrackAnalysisResult &result);
131 void addAmbienceGainRecommendation(const TrackAnalysisResult &result, double anchorLoudness);
132 void addAmbienceHighPassRecommendation(const TrackAnalysisResult &result);
133 void addAmbienceLowPassRecommendation(const TrackAnalysisResult &result);
134 void addSfxGainRecommendation(const TrackAnalysisResult &result, double anchorLoudness);
135 void addSfxHighPassRecommendation(const TrackAnalysisResult &result);
136 void addSfxDuckingRecommendation(const TrackAnalysisResult &result);
137 void addPremixedProgramGainRecommendation(const TrackAnalysisResult &result);
138 double dialogueAnchorLoudness() const;
139 double dialogueNormalizationGain(const TrackAnalysisResult &result) const;
140 void populateRecommendationsList();
141 void applyApprovedRecommendations();
142 QVector<QPair<int, int>> findDialogueEvents() const;
143 QVector<DuckingKeyframe> generateDuckingKeyframes(const QVector<QPair<int, int>> &events,
144 double maxGainDb,
145 double duckedGainDb,
146 int fadeDownFrames,
147 int fadeUpFrames) const;
148
149 MultitrackModel *m_model;
150 QTableWidget *m_table;
151 QComboBox *m_targetPresetCombo;
152 QDoubleSpinBox *m_targetLoudnessSpinner;
153 QStackedWidget *m_stack;
154 QProgressBar *m_progressBar;
155 QTableWidget *m_recommendationsTable;
156 QDialogButtonBox *m_buttonBox;
157 QPushButton *m_actionButton;
158 Stage m_stage;
159 bool m_blockUpdates;
160 bool m_processing = false;
161 bool m_cancelRequested = false;
162 QVector<TrackAnalysisResult> m_analysisResults;
163 QVector<MixRecommendation> m_recommendations;
164 QHash<int, int> m_trackProgressByIndex;
165 int m_pendingAnalysisCount;
166};
167
168#endif // AUDIOMIXINGASSISTANTDIALOG_H