Skip to content

Commit

Permalink
Sound editor (#78)
Browse files Browse the repository at this point in the history
Re-do FileSelector and implement sound editor
  • Loading branch information
JoshDreamland authored Dec 14, 2019
2 parents 1897c16 + 0493fe0 commit a2bc5c2
Show file tree
Hide file tree
Showing 11 changed files with 298 additions and 52 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ find_package(OpenSSL REQUIRED)
target_link_libraries(${EXE} PRIVATE OpenSSL::SSL OpenSSL::Crypto)

# Find Qt
find_package(Qt5 COMPONENTS Core Widgets Gui PrintSupport REQUIRED)
target_link_libraries(${EXE} PRIVATE Qt5::Core Qt5::Widgets Qt5::Gui Qt5::PrintSupport)
find_package(Qt5 COMPONENTS Core Widgets Gui PrintSupport Multimedia REQUIRED)
target_link_libraries(${EXE} PRIVATE Qt5::Core Qt5::Widgets Qt5::Gui Qt5::PrintSupport Qt5::Multimedia)


if(MSVC)
Expand Down
110 changes: 82 additions & 28 deletions Components/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,94 @@
#include <QImageReader>
#include <QImageWriter>
#include <QMimeDatabase>
#include <QMap>

ImageDialog::ImageDialog(QWidget* parent, QString xmlExtension, bool writer) : QFileDialog(parent, "Select image") {
QString fileExt("*." + xmlExtension + ".gmx");
QString xmlName = xmlExtension;
xmlName[0] = xmlName[0].toUpper();

QStringList mimeTypeFilters;
const QByteArrayList supportedMimeTypes =
(writer) ? QImageWriter::supportedMimeTypes() : QImageReader::supportedMimeTypes();
foreach (const QByteArray& mimeTypeName, supportedMimeTypes) { mimeTypeFilters.append(mimeTypeName); }
mimeTypeFilters.sort(Qt::CaseInsensitive);

QMimeDatabase mimeDB;
QStringList allSupportedFormats;
for (const QString& mimeTypeFilter : mimeTypeFilters) {
QMimeType mimeType = mimeDB.mimeTypeForName(mimeTypeFilter);
if (mimeType.isValid()) {
allSupportedFormats.append(mimeType.globPatterns());
struct MimeType {
MimeType() {}
MimeType(QString filter, QString desc) : fileFilter(filter), description(desc) {}
QString fileFilter;
QString description;
};

class MimeTypeList {
public:
MimeTypeList() {}
MimeTypeList(const QList<QByteArray>& mimeTypes, const QList<MimeType> additionalMimeTypes) {
QStringList temp;
foreach(const QByteArray& mime, mimeTypes) temp.append(mime);

QMimeDatabase mimeDB;
for (const QString& mimeTypeFilter : temp) {
QMimeType mimeType = mimeDB.mimeTypeForName(mimeTypeFilter);
if (mimeType.isValid()) {
nameFilters.append(mimeType.name() + " " + QString("(%1)").arg(mimeType.globPatterns().join(' ')));
filters.append(QString("%1").arg(mimeType.globPatterns().join(' ')));
}
}

for (const MimeType& mime : additionalMimeTypes) {
filters.append(mime.fileFilter);
}

for (const MimeType& mime : additionalMimeTypes) {
nameFilters.append(mime.description);
}

filters.prepend(QString("(%1)").arg(filters.join(' ')));
nameFilters.prepend("All Supported " + filters[0]);
nameFilters.append("All Files (*)");
}
allSupportedFormats.append(fileExt);
QString allSupportedFormatsFilter = QString("All supported formats (%1)").arg(allSupportedFormats.join(' '));

setFileMode(QFileDialog::ExistingFile);
setMimeTypeFilters(mimeTypeFilters);
QStringList nameFilters = this->nameFilters();
QStringList nameFilters;
QStringList filters;
QString allSupported;
};

static const QMap<FileDialog_t, MimeTypeList> derp = {
{FileDialog_t::BackgroundLoad, MimeTypeList(QImageReader::supportedMimeTypes(),
{
MimeType("*.Background.gmx", "GMX Background (*.Background.gmx)"),
MimeType("*.bkg", "EGM Background (*.bkg)")
})
},

{FileDialog_t::BackgroundSave, MimeTypeList(QImageWriter::supportedMimeTypes(),
{
MimeType("*.bkg", "EGM Background (*.bkg)")
})
},

{FileDialog_t::SoundLoad, MimeTypeList({},
{
MimeType("*.Sound.gmx", "GMX Sound (*.Sound.gmx)"),
MimeType("*.snd", "EGM Sound (*.snd)"),
MimeType("*.ogg", "OGG (*.ogg)"),
MimeType("*.flac", "FLAC (*.flac)"),
MimeType("*.mp3", "MP3 (*.mp3)"),
MimeType("*.mod", "MOD (*.mod)"),
MimeType("*.wav", "Wav (*.wav)"),
})
},

{FileDialog_t::SoundSave, MimeTypeList({},
{
MimeType("*.snd", "EGM Sound (*.snd)")
})
}
};

FileDialog::FileDialog(QWidget* parent, FileDialog_t type, bool writer) :
QFileDialog(parent, "Select ") {

if (writer)
setAcceptMode(QFileDialog::AcceptSave);
else
nameFilters.append("GMX " + xmlName + " (" + fileExt + ")");
else {
setAcceptMode(QFileDialog::AcceptOpen);
setFileMode(QFileDialog::ExistingFile);
}

nameFilters.prepend(allSupportedFormatsFilter);
nameFilters.prepend("All Files (*)");
setNameFilters(nameFilters);
selectNameFilter(allSupportedFormatsFilter);
const MimeTypeList& mimes = derp[type];
setMimeTypeFilters(mimes.filters);
setNameFilters(mimes.nameFilters);
selectNameFilter(mimes.allSupported);
}
11 changes: 9 additions & 2 deletions Components/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@

#include <QFileDialog>

class ImageDialog : public QFileDialog {
enum FileDialog_t {
BackgroundLoad,
BackgroundSave,
SoundSave,
SoundLoad
};

class FileDialog : public QFileDialog {
public:
ImageDialog(QWidget* parent, QString xmlExtension, bool writer = false);
FileDialog(QWidget* parent, FileDialog_t type, bool writer);
};
33 changes: 19 additions & 14 deletions Editors/BackgroundEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <QDesktopServices>
#include <QPainter>
#include <QDebug>

using buffers::resources::Background;

Expand Down Expand Up @@ -67,34 +68,38 @@ void BackgroundEditor::on_actionNewImage_triggered() {
}

void BackgroundEditor::on_actionLoadImage_triggered() {
ImageDialog* dialog = new ImageDialog(this, "background");
dialog->exec();
FileDialog* dialog = new FileDialog(this, FileDialog_t::BackgroundLoad, false);

if (dialog->selectedFiles().size() > 0) {
if (dialog->exec() && dialog->selectedFiles().size() > 0) {
QString fName = dialog->selectedFiles()[0];
Background* bkg = gmx::LoadBackground(fName.toStdString());
if (bkg != nullptr) {
QString lastImage = GetModelData(Background::kImageFieldNumber).toString();
ReplaceBuffer(bkg);
QString newImage = GetModelData(Background::kImageFieldNumber).toString();
if (!ui->backgroundView->SetImage(newImage)) SetModelData(Background::kImageFieldNumber, lastImage);
if (fName.endsWith("Background.gmx")) {
Background* bkg = gmx::LoadBackground(fName.toStdString());
if (bkg != nullptr) {
// QString lastData = GetModelData(Background::kImageFieldNumber).toString();
ReplaceBuffer(bkg);
// QString newData = GetModelData(Background::kImageFieldNumber).toString();
// TODO: Copy data into our egm and reset the path
// SetModelData(Background::kImageFieldNumber, lastData);
} else qDebug() << "Failed to load gmx Background";
} else {
if (ui->backgroundView->SetImage(fName)) SetModelData(Background::kImageFieldNumber, fName);
// TODO: Copy data into our egm
SetModelData(Background::kImageFieldNumber, fName);
}
}
}

void BackgroundEditor::on_actionSaveImage_triggered() {
ImageDialog* dialog = new ImageDialog(this, "background", true);
dialog->exec();
FileDialog* dialog = new FileDialog(this, FileDialog_t::BackgroundSave, true);

if (dialog->selectedFiles().size() > 0) {
if (dialog->exec() && dialog->selectedFiles().size() > 0) {
QString fName = dialog->selectedFiles()[0];
ui->backgroundView->WriteImage(fName, dialog->selectedMimeTypeFilter());
}
}

void BackgroundEditor::on_actionEditImage_triggered() {
QString fName = GetModelData(Background::kImageFieldNumber).toString();
QDesktopServices::openUrl(fName); //TODO: file watcher reload
QDesktopServices::openUrl(QUrl::fromLocalFile(fName));
// TODO: file watcher reload
// TODO: editor settings
}
4 changes: 2 additions & 2 deletions Editors/BaseEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class BaseEditor : public QWidget {
void OnSave();

protected:
ModelMapper *nodeMapper;
ModelMapper *resMapper;
ModelMapper* nodeMapper;
ModelMapper* resMapper;
};

#endif // BASEEDTIOR_H
128 changes: 127 additions & 1 deletion Editors/SoundEditor.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,135 @@
#include "SoundEditor.h"
#include "ui_SoundEditor.h"

SoundEditor::SoundEditor(ProtoModelPtr model, QWidget* parent) : BaseEditor(model, parent), ui(new Ui::SoundEditor) {
#include "gmx.h"

#include "Components/ArtManager.h"
#include "Components/Utility.h"

#include <QDebug>
#include <QTime>
#include <QSlider>
#include <QDesktopServices>

SoundEditor::SoundEditor(ProtoModelPtr model, QWidget* parent) :
BaseEditor(model, parent), ui(new Ui::SoundEditor), mediaPlayer(new QMediaPlayer(this)),
playlist(new QMediaPlaylist(mediaPlayer)), userPaused(false) {
ui->setupUi(this);

nodeMapper->addMapping(ui->nameEdit, TreeNode::kNameFieldNumber);
nodeMapper->toFirst();

resMapper->addMapping(ui->volumeSpinBox, Sound::kVolumeFieldNumber);
resMapper->toFirst();

ui->volumeSlider->setValue(static_cast<int>(ui->volumeSpinBox->value() * 100));

connect(ui->saveButton, &QAbstractButton::pressed, this, &BaseEditor::OnSave);

ProtoModelPtr soundModel = model->GetSubModel(TreeNode::kSoundFieldNumber);
playlist->setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
playlist->addMedia(QUrl::fromLocalFile(soundModel->data(Sound::kDataFieldNumber).toString()));
mediaPlayer->setPlaylist(playlist);
// Update the signals every 50ms instead of Qt's default 1000ms to keep slider up to date
mediaPlayer->setNotifyInterval(50);

connect(mediaPlayer, &QMediaPlayer::positionChanged, [=]() {
if (mediaPlayer->duration() > 0) {
int percent = static_cast<int>(100*(static_cast<float>(mediaPlayer->position()) / mediaPlayer->duration()));
ui->playbackSlider->setSliderPosition(percent);
} else ui->playbackSlider->setSliderPosition(0);

QTime timestamp(0,0);
ui->playbackPositionLabel->setText(timestamp.addMSecs(static_cast<int>(mediaPlayer->position())).toString());
});

connect(mediaPlayer, &QMediaPlayer::mediaChanged, [=]() {
playlist->clear();
playlist->addMedia(QUrl::fromLocalFile(soundModel->data(Sound::kDataFieldNumber).toString()));
});

connect(mediaPlayer, &QMediaPlayer::stateChanged, [=]() {
if (mediaPlayer->state() == QMediaPlayer::PausedState || mediaPlayer->state() == QMediaPlayer::StoppedState)
ui->playButton->setIcon(ArtManager::GetIcon(":/actions/play.png"));
else
ui->playButton->setIcon(ArtManager::GetIcon(":/actions/pause.png"));
});

playlist->addMedia(QUrl::fromLocalFile(soundModel->data(Sound::kDataFieldNumber).toString()));
mediaPlayer->setPlaylist(playlist);
}

SoundEditor::~SoundEditor() { delete ui; }

void SoundEditor::on_playButton_clicked() {
if (mediaPlayer->state() == QMediaPlayer::PausedState || mediaPlayer->state() == QMediaPlayer::StoppedState) {
mediaPlayer->play();
userPaused = false;
} else {
mediaPlayer->pause();
userPaused = true;
}
}

void SoundEditor::on_loopButton_clicked() {
if (playlist->playbackMode() == QMediaPlaylist::CurrentItemOnce)
playlist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
else
playlist->setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
}

void SoundEditor::on_playbackSlider_sliderPressed() {
if (mediaPlayer->state() == QMediaPlayer::PlayingState) mediaPlayer->pause();
}

void SoundEditor::on_playbackSlider_sliderReleased() {
mediaPlayer->setPosition(static_cast<int>((ui->playbackSlider->value()/100.f)*mediaPlayer->duration()));
if (mediaPlayer->state() == QMediaPlayer::PausedState && !userPaused) mediaPlayer->play();
}

void SoundEditor::on_volumeSlider_sliderMoved(int position) {
ui->volumeSpinBox->setValue(position / 100.0);
mediaPlayer->setVolume(position);
}

void SoundEditor::on_volumeSpinBox_valueChanged(double arg1) {
ui->volumeSlider->setValue(static_cast<int>(arg1 * 100));
mediaPlayer->setVolume(static_cast<int>(arg1 * 100));
}

void SoundEditor::on_saveAsButton_clicked() {
// TODO: implement this when egm is done
}

void SoundEditor::on_loadButton_clicked() {
FileDialog* dialog = new FileDialog(this, FileDialog_t::SoundLoad, false);

if (dialog->exec() && dialog->selectedFiles().size() > 0) {
QString fName = dialog->selectedFiles()[0];
if (fName.endsWith("Sound.gmx")) {
Sound* snd = gmx::LoadSound(fName.toStdString());
if (snd != nullptr) {
// QString lastData = GetModelData(Sound::kDataFieldNumber).toString();
ReplaceBuffer(snd);
// QString newData = GetModelData(Sound::kDataFieldNumber).toString();
// TODO: Copy data into our egm and reset the path
// SetModelData(Sound::kDataFieldNumber, lastData);
} else qDebug() << "Failed to load gmx sound";
} else {
// TODO: Copy data into our egm
SetModelData(Sound::kDataFieldNumber, fName);
emit mediaPlayer->mediaChanged(mediaPlayer->media());
}
}
}

void SoundEditor::on_editButton_clicked() {
QString fName = GetModelData(Sound::kDataFieldNumber).toString();
QDesktopServices::openUrl(QUrl::fromLocalFile(fName));
// TODO: file watcher reload
// TODO: editor settings
}

void SoundEditor::on_stopButton_clicked() {
mediaPlayer->stop();
}
20 changes: 19 additions & 1 deletion Editors/SoundEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#include "BaseEditor.h"

#include <QMediaPlayer>
#include <QMediaPlaylist>

namespace Ui {
class SoundEditor;
}
Expand All @@ -14,8 +17,23 @@ class SoundEditor : public BaseEditor {
explicit SoundEditor(ProtoModelPtr model, QWidget* parent);
~SoundEditor();

private:
private slots:
void on_playButton_clicked();
void on_loopButton_clicked();
void on_playbackSlider_sliderPressed();
void on_playbackSlider_sliderReleased();
void on_volumeSlider_sliderMoved(int position);
void on_volumeSpinBox_valueChanged(double arg1);
void on_saveAsButton_clicked();
void on_loadButton_clicked();
void on_editButton_clicked();
void on_stopButton_clicked();

private:
Ui::SoundEditor* ui;
QMediaPlayer* mediaPlayer;
QMediaPlaylist *playlist; //it's only one song but Qt puts looping stuff here
bool userPaused;
};

#endif // SOUNDEDITOR_H
Loading

0 comments on commit a2bc5c2

Please sign in to comment.