3
3
#include < QJsonDocument>
4
4
#include < QStringRef>
5
5
6
+ void checkConnection (bool connection){
7
+ if (!connection){
8
+ QMessageBox::warning (nullptr , " Qt connection error" , " Unable to connect UI component" );
9
+ }
10
+ }
11
+
6
12
bool AudioPlaybackWidget::serialize (std::vector<audioConfig>* pConf, const QString& outPath) {
7
13
QJsonObject audioJson;
8
14
audioJson[" Tracks" ] = (int )pConf->size ();
9
15
int x = 0 ;
10
16
for (const auto & audioConfig: *pConf){
11
17
QJsonObject track;
12
18
track[" Name" ] = audioConfig.audioName ;
13
- track[" Path" ] = audioConfig.audioPath .absolutePath ();
19
+ track[" Path" ] = audioConfig.audioPath .absoluteFilePath ();
14
20
track[" Playback" ] = audioConfig.playbackEnable ;
15
21
track[" Volume" ] = audioConfig.volume ;
16
22
track[" StartFrame" ] = audioConfig.startFrame ;
@@ -48,8 +54,8 @@ bool AudioPlaybackWidget::deserialize(const QJsonObject& pConf, std::vector<audi
48
54
49
55
void AudioPlaybackWidget::aPlayer (std::vector<audioConfig>* pConf, bool play, mediaState* state, int fps, int curFrame, int frameCount){
50
56
qDebug (" Media player requested" );
51
- for ( int x = 0 ; x < pConf-> size (); x++){
52
- if ( pConf-> size () > x + 1 ){ return ; }
57
+ int x = 0 ;
58
+ for ( auto conf: * pConf){
53
59
if (state->players .size () < x + 1 && state->outputs .size () < x + 1 ){
54
60
auto * mediaPlayer = new QMediaPlayer;
55
61
auto * audioOutput = new QAudioOutput;
@@ -59,45 +65,66 @@ void AudioPlaybackWidget::aPlayer(std::vector<audioConfig>* pConf, bool play, me
59
65
QMediaPlayer* player = state->players .at (x);
60
66
QAudioOutput* output = state->outputs .at (x);
61
67
const audioConfig& config = pConf->at (x);
62
- if (player->audioOutput () == nullptr ){
63
- player->setAudioOutput (output);
64
- }
68
+ if (player->audioOutput () == nullptr ){ player->setAudioOutput (output); }
65
69
if (player->source () != QUrl::fromLocalFile (config.audioPath .absoluteFilePath ())){
66
70
player->setSource (config.audioPath .absoluteFilePath ());
67
71
}
68
72
if (output->volume () != getVol (config.volume )){ output->setVolume (getVol (config.volume )); }
69
-
70
- // FIXME
71
- int framesInMs = (frameCount / fps) / 1000 ;
72
- int startFrameInMs = ((frameCount - (config.startFrame + 1 )) / fps) / 1000 ;
73
- int curFrameInMs = (((curFrame + 1 ) - frameCount)/ fps) / 1000 ;
74
-
75
- uint initialFrameInMs = framesInMs - startFrameInMs;
76
- uint posInMs = framesInMs - curFrameInMs;
77
-
78
- if (player->hasAudio () && posInMs >= initialFrameInMs) {
79
- player->setPosition (posInMs);
80
- }
81
-
82
- if (!play && player->isPlaying ()){ player->stop (); state->playing = false ;}
83
- if (play && config.startFrame < curFrame && config.endFrame < curFrame && config.playbackEnable && !player->isPlaying ()){
73
+ correctTrackPos (player, curFrame, frameCount, fps, const_cast <audioConfig&>(config));
74
+ qDebug (" ---" );
75
+ qDebug () << " x = " << x << " ; track = " << player->source () << " ; playing = " << player->isPlaying () << " ; play = " << play;
76
+ qDebug (" ---" );
77
+ if (!play){ player->stop (); state->playing = false ;}
78
+ if (play && config.startFrame < curFrame && config.endFrame > curFrame && config.playbackEnable ){
84
79
player->play ();
85
80
state->playing = true ;
86
81
}
82
+ x++;
87
83
}
88
84
}
89
85
90
86
void AudioPlaybackWidget::connect (QWidget *audioWidget, mediaState *state, std::vector<audioConfig>* config){
91
- Q_UNIMPLEMENTED ();
92
- }
87
+ checkConnection (QToolButton::connect (saveConfigButton, &QToolButton::clicked, [=](){
88
+ QFileDialog diag (audioWidget);
89
+ diag.setAcceptMode (QFileDialog::AcceptSave);
90
+ diag.setDirectory (QDir::currentPath ());
91
+ diag.setNameFilter (QCoreApplication::translate (" SaveMus" , " Anie audio configuration file (*.aemus)" , nullptr ));
92
+ if (diag.exec ()) {
93
+ QString fileName = diag.selectedFiles ().first ();
94
+ static QRegularExpression fileRegex (" \\ .aemus$" );
95
+ if (!fileRegex.match (fileName).hasMatch ()) { fileName.append (" .aemus" ); }
96
+ serialize (config, fileName);
97
+ }
98
+ }));
99
+ checkConnection (QToolButton::connect (loadConfigButton, &QToolButton::clicked, [=]()mutable {
100
+ QFileDialog diag (audioWidget);
101
+ diag.setAcceptMode (QFileDialog::AcceptOpen);
102
+ diag.setDirectory (QDir::currentPath ());
103
+ diag.setNameFilter (QCoreApplication::translate (" LoadMus" , " Anie audio configuration file (*.aemus)" , nullptr ));
104
+ if (diag.exec ()) {
105
+ QFile file = QFile (diag.selectedFiles ().first ());
106
+ if (!file.exists ()) {
107
+ QMessageBox::warning (audioWidget, " File does not exist" , " Qt was unable to load the requested file." );
108
+ return ;
109
+ }
110
+ QJsonDocument json = QJsonDocument::fromJson (file.readAll ());
111
+ if (!json.isObject ()){
112
+ QMessageBox::warning (audioWidget, " Invalid file" , " The requested file is not a valid aemus file." );
113
+ return ;
114
+ }
115
+ auto configBackup = *config;
116
+ if (!deserialize (json.object (), config)) {
117
+ *config = configBackup;
118
+ QMessageBox::warning (audioWidget, " Invalid file" , " The requested file is not a valid aemus file." );
119
+ return ;
120
+ }
121
+ rectifyUI (config, state);
122
+ }
123
+ }));
93
124
94
- void checkConnection (bool connection){
95
- if (!connection){
96
- QMessageBox::warning (nullptr , " Qt connection error" , " Unable to connect UI component" );
97
- }
98
125
}
99
126
100
- void AudioPlaybackWidget::rectifyUI (std::vector<audioConfig>* config, mediaState* mediaPlayer) {
127
+ void AudioPlaybackWidget::rectifyUI (std::vector<audioConfig>* config, mediaState* mediaPlayer, bool bulk ) {
101
128
// We reconstruct the entire state so we don't mismatch the UI indices
102
129
{
103
130
QLayoutItem* item;
@@ -117,18 +144,15 @@ void AudioPlaybackWidget::rectifyUI(std::vector<audioConfig>* config, mediaState
117
144
config->emplace_back ();
118
145
}
119
146
for (auto conf: *config){
120
- addUIState (config, x, mediaPlayer, true );
147
+ addUIState (config, x, mediaPlayer, bulk );
121
148
x++;
122
149
}
123
150
gridLayout_2->update ();
124
151
}
152
+
125
153
void AudioPlaybackWidget::addUIState (std::vector<audioConfig>* config, int index, mediaState* mediaPlayer, bool bulk) {
126
154
// This is a great time to tell you that we accept pull requests that fix this kind of nonsense
127
- auto newState = UIState{
128
- new QToolButton (musPlayer), new QToolButton (musPlayer), new QCheckBox (musPlayer),
129
- new QSpinBox (musPlayer), new QSpinBox (musPlayer), new QLabel (musPlayer), new QLabel (musPlayer),
130
- new QLabel (musPlayer), new QLabel (musPlayer), new QSlider (musPlayer), new QFrame (musPlayer),
131
- true };
155
+ auto newState = UIState ();
132
156
// Grid layout pos
133
157
int vecIdx = (int )vecUIState.size ();
134
158
int offset = vecIdx * 4 ;
@@ -141,9 +165,13 @@ void AudioPlaybackWidget::addUIState(std::vector<audioConfig>* config, int index
141
165
gridLayout_2->addWidget (newState.playAudio , idxRow1, 0 , 1 , 1 );
142
166
// Frame end
143
167
newState.endSpinBox ->setObjectName (QString::fromUtf8 (" endSpinBox" ));
168
+ newState.endSpinBox ->setMaximum (INT32_MAX);
169
+ newState.endSpinBox ->setMinimum (0 );
144
170
gridLayout_2->addWidget (newState.endSpinBox , idxRow1, 2 , 1 , 1 );
145
171
// Frame start
146
172
newState.startSpinBox ->setObjectName (QString::fromUtf8 (" startSpinBox" ));
173
+ newState.startSpinBox ->setMaximum (INT32_MAX);
174
+ newState.startSpinBox ->setMinimum (0 );
147
175
gridLayout_2->addWidget (newState.startSpinBox , idxRow1, 1 , 1 , 1 );
148
176
// New track
149
177
newState.addNewTrack ->setObjectName (QString::fromUtf8 (" startLabel" ));
@@ -213,6 +241,20 @@ void AudioPlaybackWidget::addUIState(std::vector<audioConfig>* config, int index
213
241
}
214
242
215
243
if (bulk){
244
+ if (index == 0 ) {
245
+ int x = 0 ;
246
+ for (const auto & conf: *config){
247
+ if (mediaPlayer->players .size () - 1 >= x){
248
+ mediaPlayer->players .at (x)->stop ();
249
+ mediaPlayer->players .at (x)->deleteLater ();
250
+ mediaPlayer->outputs .at (x)->deleteLater ();
251
+ mediaPlayer->players .clear ();
252
+ mediaPlayer->outputs .clear ();
253
+ }
254
+ addTrack (mediaPlayer, conf.audioPath .absoluteFilePath ());
255
+ modifyTrack (mediaPlayer, config, x);
256
+ }
257
+ }
216
258
if (index > 0 && index + 1 != config->size () || (index == 1 && config->size () == 2 )) {
217
259
newState.addNewTrack ->setText (QCoreApplication::translate (" audioWidget" , " Remove audio track" , nullptr ));
218
260
newState.addTrack = false ;
@@ -232,6 +274,7 @@ void AudioPlaybackWidget::addUIState(std::vector<audioConfig>* config, int index
232
274
));
233
275
config->at (index).audioPath = file;
234
276
config->at (index).audioName = file.fileName ();
277
+ modifyTrack (mediaPlayer, config, index);
235
278
236
279
{
237
280
QString ref = QStringRef (&config->at (index).audioName , 0 , 17 ).toString ();
@@ -258,6 +301,7 @@ void AudioPlaybackWidget::addUIState(std::vector<audioConfig>* config, int index
258
301
return ;
259
302
}
260
303
config->emplace_back ();
304
+ addTrack (mediaPlayer, QUrl ());
261
305
this ->addUIState (config, index + 1 , mediaPlayer);
262
306
if (index == 0 ) {
263
307
vecUIState.at (1 ).addNewTrack ->setText (QCoreApplication::translate (" audioWidget" , " Remove audio track" , nullptr ));
@@ -273,6 +317,7 @@ void AudioPlaybackWidget::addUIState(std::vector<audioConfig>* config, int index
273
317
}
274
318
}
275
319
else {
320
+ removeTrack (mediaPlayer, index);
276
321
config->erase (config->begin () + index);
277
322
if (config->size () >= vecUIState.size () && !config->empty ()) { config->pop_back (); }
278
323
rectifyUI (config, mediaPlayer);
@@ -295,26 +340,48 @@ void AudioPlaybackWidget::addUIState(std::vector<audioConfig>* config, int index
295
340
}));
296
341
checkConnection (QSlider::connect (newState.volumeSlider , &QSlider::valueChanged, [=](int val){
297
342
config->at (index).volume = val;
343
+ modifyTrack (mediaPlayer, config, index);
298
344
newState.volumeLabel ->setText (QCoreApplication::translate (" audioWidget" , " Media volume" , nullptr ) + " (" + QString::number (val) + " %)" );
299
345
}));
300
346
}
301
347
302
- void AudioPlaybackWidget::addTrack (mediaState* state, QUrl source) {
348
+ void AudioPlaybackWidget::addTrack (mediaState* state, const QUrl& source) {
303
349
auto * mediaPlayer = new QMediaPlayer;
304
350
auto * audioOutput = new QAudioOutput;
305
351
mediaPlayer->setSource (source);
306
352
mediaPlayer->setAudioOutput (audioOutput);
307
353
state->players .append (mediaPlayer);
308
354
state->outputs .append (audioOutput);
309
355
}
310
- void AudioPlaybackWidget::modifyTrack (mediaState* state, std::vector<audioConfig>* config, int index, audioConfig modifiedConfig) {
311
- config->at (index) = std::move (modifiedConfig);
356
+
357
+ void AudioPlaybackWidget::removeTrack (mediaState* state, int index) {
358
+ state->players .at (index)->stop ();
359
+ state->players .at (index)->deleteLater ();
360
+ state->outputs .at (index)->deleteLater ();
361
+ state->players .removeAt (index);
362
+ state->outputs .removeAt (index);
363
+ }
364
+
365
+ void AudioPlaybackWidget::modifyTrack (mediaState* state, std::vector<audioConfig>* config, int index) {
366
+ const auto & modifiedConfig = config->at (index);
367
+ if (state->players .isEmpty () || state->players .size () - 1 < index){
368
+ addTrack (state, QUrl ());
369
+ }
312
370
auto * currentPlayer = state->players .at (index);
313
371
auto * currentOutput = state->outputs .at (index);
314
372
if (currentPlayer->isPlaying ()) { currentPlayer->stop (); }
315
- currentPlayer->setSource (modifiedConfig.audioPath .absoluteFilePath ());
316
- currentOutput->setVolume ((float )modifiedConfig.volume );
373
+ if (currentPlayer->source ().isEmpty () || currentPlayer->source ().fileName () != modifiedConfig.audioPath .fileName ()){
374
+ currentPlayer->setSource (modifiedConfig.audioPath .absoluteFilePath ());
375
+ }
376
+ if (currentOutput->volume () != getVol (modifiedConfig.volume )){
377
+ currentOutput->setVolume (getVol (modifiedConfig.volume ));
378
+ }
317
379
}
318
- void AudioPlaybackWidget::removeTrack (mediaState* state, std::vector<audioConfig>* config, int index) {
319
- Q_UNIMPLEMENTED ();
380
+
381
+ void AudioPlaybackWidget::correctTrackPos (QMediaPlayer* player, int curFrame, int frameCount, int fps, audioConfig& config) {
382
+ // Calculate times in milliseconds
383
+ const float toMillis = 1000.0 ;
384
+ int frame = frameCount - ((frameCount - config.startFrame ) - curFrame);
385
+ auto positionMs = static_cast <qint64>((static_cast <float >(frame) / static_cast <float >(fps)) * toMillis);
386
+ if (player->hasAudio () && positionMs >= 0 ) { player->setPosition (positionMs); }
320
387
}
0 commit comments