Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sound editor #78

Merged
merged 10 commits into from
Dec 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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