Studio setup window and volume LUT

This commit is contained in:
Jack Andersen 2018-08-15 20:26:44 -10:00
parent 5e89954094
commit fec074ad30
33 changed files with 2744 additions and 331 deletions

View File

@ -45,6 +45,7 @@ set(SOURCES
lib/Common.cpp
lib/DSPCodec.cpp
lib/N64MusyXCodec.cpp
lib/VolumeTable.cpp
atdna_AudioGroupPool.cpp
atdna_AudioGroupProject.cpp
atdna_AudioGroupSampleDirectory.cpp)
@ -79,7 +80,8 @@ set(HEADERS
include/amuse/Common.hpp
include/amuse/amuse.hpp
include/amuse/DSPCodec.hpp
include/amuse/N64MusyXCodec.hpp)
include/amuse/N64MusyXCodec.hpp
include/amuse/VolumeTable.hpp)
unset(EXTRAS)
if(TARGET boo)

View File

@ -46,13 +46,14 @@ QT5_WRAP_CPP(AMUSE_MOC
SampleEditor.hpp
SoundGroupEditor.hpp
SongGroupEditor.hpp
NewSoundMacroDialog.hpp)
NewSoundMacroDialog.hpp
StudioSetupWidget.hpp)
add_executable(amuse-gui WIN32 MACOSX_BUNDLE
Common.hpp Common.cpp
MainWindow.ui ${MAIN_WINDOW_UI} MainWindow.hpp MainWindow.cpp
KeyboardWidget.hpp KeyboardWidget.cpp
StatusBarWidget.hpp
StatusBarWidget.hpp StatusBarWidget.cpp
ProjectModel.hpp ProjectModel.cpp
EditorWidget.hpp EditorWidget.cpp
SoundMacroEditor.hpp SoundMacroEditor.cpp
@ -64,6 +65,7 @@ add_executable(amuse-gui WIN32 MACOSX_BUNDLE
SoundGroupEditor.hpp SoundGroupEditor.cpp
SongGroupEditor.hpp SongGroupEditor.cpp
NewSoundMacroDialog.hpp NewSoundMacroDialog.cpp
StudioSetupWidget.hpp StudioSetupWidget.cpp
MIDIReader.hpp MIDIReader.cpp
resources/resources.qrc qrc_resources.cpp
${QM_FILES} qrc_translation_res.cpp

View File

@ -1,6 +1,7 @@
#include "EditorWidget.hpp"
#include "MainWindow.hpp"
#include <QStandardItemModel>
#include <QHBoxLayout>
EditorWidget::EditorWidget(QWidget* parent)
: QWidget(parent)
@ -18,6 +19,77 @@ void EditorUndoCommand::redo()
g_MainWindow->openEditor(m_node.get());
}
FieldSlider::FieldSlider(QWidget* parent)
: QWidget(parent), m_slider(Qt::Horizontal)
{
setFixedHeight(22);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(&m_slider);
layout->addWidget(&m_value);
layout->setContentsMargins(QMargins());
setLayout(layout);
m_value.setFixedWidth(42);
connect(&m_slider, SIGNAL(valueChanged(int)), this, SLOT(doValueChanged(int)));
m_slider.setValue(0);
}
void FieldSlider::doValueChanged(int value)
{
m_value.setText(QString::number(value));
emit valueChanged(value);
}
FieldDoubleSlider::FieldDoubleSlider(QWidget* parent)
: QWidget(parent), m_slider(Qt::Horizontal)
{
setFixedHeight(22);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(&m_slider);
layout->addWidget(&m_value);
layout->setContentsMargins(QMargins());
setLayout(layout);
m_value.setFixedWidth(42);
connect(&m_slider, SIGNAL(valueChanged(int)), this, SLOT(doValueChanged(int)));
m_slider.setRange(0, 1000);
m_slider.setValue(0);
}
double FieldDoubleSlider::value() const
{
double t = m_slider.value() / 1000.0;
return t * (m_max - m_min) + m_min;
}
void FieldDoubleSlider::setValue(double value)
{
if (value < m_min)
value = m_min;
else if (value > m_max)
value = m_max;
double t = (value - m_min) / (m_max - m_min);
m_slider.setValue(int(t * 1000.0));
doValueChanged(int(t * 1000.0));
}
void FieldDoubleSlider::setRange(double min, double max)
{
m_min = min; m_max = max;
double curValue = value();
if (curValue < min)
setValue(min);
else if (curValue > max)
setValue(max);
}
void FieldDoubleSlider::doValueChanged(int value)
{
double t = value / 1000.0;
t = t * (m_max - m_min) + m_min;
m_value.setText(QString::number(t, 'g', 2));
emit valueChanged(t);
}
FieldProjectNode::FieldProjectNode(ProjectModel::CollectionNode* collection, QWidget* parent)
: FieldComboBox(parent)
{
@ -77,3 +149,31 @@ AddRemoveButtons::AddRemoveButtons(QWidget* parent)
m_removeButton.move(32, 0);
m_removeAction.setEnabled(false);
}
static QIcon ListingDeleteIcon;
static QIcon ListingDeleteHoveredIcon;
void ListingDeleteButton::enterEvent(QEvent* event)
{
setIcon(ListingDeleteHoveredIcon);
}
void ListingDeleteButton::leaveEvent(QEvent* event)
{
setIcon(ListingDeleteIcon);
}
ListingDeleteButton::ListingDeleteButton(QWidget* parent)
: QPushButton(parent)
{
if (ListingDeleteIcon.isNull())
ListingDeleteIcon = QIcon(QStringLiteral(":/icons/IconSoundMacroDelete.svg"));
if (ListingDeleteHoveredIcon.isNull())
ListingDeleteHoveredIcon = QIcon(QStringLiteral(":/icons/IconSoundMacroDeleteHovered.svg"));
setVisible(false);
setFixedSize(21, 21);
setFlat(true);
setToolTip(tr("Delete this SoundMacro"));
setIcon(ListingDeleteIcon);
}

View File

@ -10,6 +10,8 @@
#include <QItemEditorFactory>
#include <QToolButton>
#include <QAction>
#include <QPushButton>
#include <QLabel>
#include "ProjectModel.hpp"
class EditorWidget : public QWidget
@ -68,6 +70,50 @@ public:
void wheelEvent(QWheelEvent* event) { event->ignore(); }
};
class FieldSlider : public QWidget
{
Q_OBJECT
QSlider m_slider;
QLabel m_value;
public:
explicit FieldSlider(QWidget* parent = Q_NULLPTR);
/* Don't scroll */
void wheelEvent(QWheelEvent* event) { event->ignore(); }
int value() const { return m_slider.value(); }
void setValue(int value) { m_slider.setValue(value); doValueChanged(value); }
void setRange(int min, int max) { m_slider.setRange(min, max); }
private slots:
void doValueChanged(int value);
signals:
void valueChanged(int value);
};
class FieldDoubleSlider : public QWidget
{
Q_OBJECT
QSlider m_slider;
QLabel m_value;
double m_min = 0.0;
double m_max = 1.0;
public:
explicit FieldDoubleSlider(QWidget* parent = Q_NULLPTR);
/* Don't scroll */
void wheelEvent(QWheelEvent* event) { event->ignore(); }
double value() const;
void setValue(double value);
void setRange(double min, double max);
private slots:
void doValueChanged(int value);
signals:
void valueChanged(double value);
};
class FieldComboBox : public QComboBox
{
Q_OBJECT
@ -143,4 +189,13 @@ public:
QAction* removeAction() { return &m_removeAction; }
};
class ListingDeleteButton : public QPushButton
{
Q_OBJECT
public:
explicit ListingDeleteButton(QWidget* parent = Q_NULLPTR);
void enterEvent(QEvent* event);
void leaveEvent(QEvent* event);
};
#endif //AMUSE_EDITOR_WIDGET_HPP

View File

@ -7,7 +7,6 @@
#include <QMouseEvent>
#include <QtSvg/QtSvg>
#include "amuse/ContainerRegistry.hpp"
#include "amuse/SongConverter.hpp"
#include "Common.hpp"
#include "SongGroupEditor.hpp"
#include "SoundGroupEditor.hpp"
@ -45,6 +44,9 @@ MainWindow::MainWindow(QWidget* parent)
connectMessenger(&m_mainMessenger, Qt::DirectConnection);
m_ui.statusbar->connectKillClicked(this, SLOT(killSounds()));
m_ui.statusbar->connectFXPressed(this, SLOT(fxPressed()));
m_ui.statusbar->setVolumeValue(70);
m_ui.statusbar->connectVolumeSlider(this, SLOT(volumeChanged(int)));
m_ui.keyboardContents->setStatusFocus(new StatusBarFocus(m_ui.statusbar));
m_ui.velocitySlider->setStatusFocus(new StatusBarFocus(m_ui.statusbar));
@ -89,6 +91,7 @@ MainWindow::MainWindow(QWidget* parent)
updateRecentFileActions();
connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(cleanChanged(bool)));
QAction* undoAction = m_undoStack->createUndoAction(this);
undoAction->setShortcut(QKeySequence::Undo);
m_ui.menuEdit->insertAction(m_ui.actionCut, undoAction);
@ -128,6 +131,10 @@ MainWindow::MainWindow(QWidget* parent)
m_ui.editorContents->addWidget(m_sampleEditor);
m_ui.editorContents->setCurrentWidget(m_faceSvg);
m_studioSetup = new StudioSetupWidget(this);
connect(m_studioSetup, SIGNAL(hidden()), this, SLOT(studioSetupHidden()));
connect(m_studioSetup, SIGNAL(shown()), this, SLOT(studioSetupShown()));
connect(m_ui.actionNew_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction()));
connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction()));
connect(m_ui.actionNew_Song_Group, SIGNAL(triggered()), this, SLOT(newSongGroupAction()));
@ -145,6 +152,8 @@ MainWindow::MainWindow(QWidget* parent)
m_voxEngine = boo::NewAudioVoiceEngine();
m_voxAllocator = std::make_unique<VoiceAllocator>(*m_voxEngine);
m_engine = std::make_unique<amuse::Engine>(*m_voxAllocator);
m_voxEngine->setVolume(0.7f);
m_studioSetup->loadData(m_engine->getDefaultStudio().get());
m_ctrlVals[7] = 127;
m_ctrlVals[10] = 64;
@ -191,7 +200,7 @@ void MainWindow::updateWindowTitle()
{
if (!m_projectModel)
{
setWindowTitle(tr("Amuse"));
setWindowTitle(tr("Amuse[*]"));
return;
}
@ -199,12 +208,12 @@ void MainWindow::updateWindowTitle()
if (EditorWidget* w = getEditorWidget())
{
ProjectModel::BasePoolObjectNode* objNode = static_cast<ProjectModel::BasePoolObjectNode*>(w->currentNode());
setWindowTitle(tr("Amuse [%1/%2/%3]").arg(dir.dirName()).arg(
setWindowTitle(tr("%1/%2/%3[*] - Amuse").arg(dir.dirName()).arg(
m_projectModel->getGroupNode(objNode)->text()).arg(objNode->text()));
return;
}
setWindowTitle(tr("Amuse [%1]").arg(dir.dirName()));
setWindowTitle(tr("%1[*] - Amuse").arg(dir.dirName()));
}
void MainWindow::updateRecentFileActions()
@ -229,9 +238,6 @@ void MainWindow::updateRecentFileActions()
bool MainWindow::setProjectPath(const QString& path)
{
if (m_projectModel && m_projectModel->path() == path)
return true;
QDir dir(path);
if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral(".."))
{
@ -615,6 +621,44 @@ void MainWindow::aboutToDeleteNode(ProjectModel::INode* node)
closeEditor();
}
void MainWindow::closeEvent(QCloseEvent* ev)
{
if (!m_projectModel)
{
ev->accept();
return;
}
if (!m_undoStack->isClean())
{
QDir dir(m_projectModel->path());
int result = QMessageBox::question(this, tr("Unsaved Changes"), tr("Save Changes in %1?").arg(dir.dirName()),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save);
if (result == QMessageBox::Save)
{
saveAction();
ev->accept();
}
else if (result == QMessageBox::Discard)
{
ev->accept();
}
else
{
ev->ignore();
}
}
else
{
ev->accept();
}
}
void MainWindow::showEvent(QShowEvent* ev)
{
m_studioSetup->updateWindowPosition();
}
void MainWindow::newAction()
{
QString path = QFileDialog::getSaveFileName(this, tr("New Project"));
@ -626,7 +670,9 @@ void MainWindow::newAction()
return;
m_projectModel->clearProjectData();
m_ui.actionImport_Groups->setDisabled(m_projectModel->ensureModelData());
bool hasGroups = m_projectModel->ensureModelData();
m_ui.actionImport_Groups->setDisabled(hasGroups);
m_ui.actionImport_Songs->setEnabled(hasGroups);
}
bool MainWindow::openProject(const QString& path)
@ -710,7 +756,11 @@ void MainWindow::clearRecentFilesAction()
void MainWindow::saveAction()
{
if (m_projectModel)
{
m_projectModel->saveToFile(m_mainMessenger);
m_undoStack->setClean();
}
}
void MainWindow::revertAction()
@ -894,28 +944,7 @@ void MainWindow::importSongsAction()
return;
closeEditor();
std::vector<std::pair<amuse::SystemString, amuse::ContainerRegistry::SongData>> songs =
amuse::ContainerRegistry::LoadSongs(QStringToSysString(path).c_str());
for (const auto& song : songs)
{
int version;
bool isBig;
auto midiData =
amuse::SongConverter::SongToMIDI(song.second.m_data.get(), version, isBig);
if (!midiData.empty())
{
QFileInfo fi(m_projectModel->dir(), SysStringToQString(song.first + ".mid"));
QFile f(fi.filePath());
if (f.open(QFile::WriteOnly))
{
f.write((const char*)midiData.data(), midiData.size());
m_projectModel->setMIDIPathOfSong(
song.second.m_setupId, m_projectModel->dir().relativeFilePath(fi.filePath()));
}
}
}
m_projectModel->importSongsData(path);
}
void MainWindow::exportAction()
@ -1201,6 +1230,19 @@ void MainWindow::killSounds()
v->kill();
}
void MainWindow::fxPressed()
{
if (m_studioSetup->isVisible())
m_studioSetup->hide();
else
m_studioSetup->show();
}
void MainWindow::volumeChanged(int vol)
{
m_engine->setVolume(vol / 100.f);
}
void MainWindow::outlineCutAction()
{
@ -1342,6 +1384,21 @@ void MainWindow::onTextDelete()
}
}
void MainWindow::cleanChanged(bool clean)
{
setWindowModified(!clean);
}
void MainWindow::studioSetupHidden()
{
m_ui.statusbar->setFXDown(false);
}
void MainWindow::studioSetupShown()
{
m_ui.statusbar->setFXDown(true);
}
void MainWindow::onBackgroundTaskFinished()
{
m_backgroundDialog->reset();
@ -1349,7 +1406,9 @@ void MainWindow::onBackgroundTaskFinished()
m_backgroundDialog = nullptr;
m_backgroundTask->deleteLater();
m_backgroundTask = nullptr;
m_ui.actionImport_Groups->setDisabled(m_projectModel->ensureModelData());
bool hasGroups = m_projectModel->ensureModelData();
m_ui.actionImport_Groups->setDisabled(hasGroups);
m_ui.actionImport_Songs->setEnabled(hasGroups);
setEnabled(true);
}

View File

@ -14,6 +14,7 @@
#include "ProjectModel.hpp"
#include "EditorWidget.hpp"
#include "MIDIReader.hpp"
#include "StudioSetupWidget.hpp"
#define MaxRecentFiles 4
@ -89,6 +90,7 @@ class MainWindow : public QMainWindow
KeymapEditor* m_keymapEditor = nullptr;
LayersEditor* m_layersEditor = nullptr;
SampleEditor* m_sampleEditor = nullptr;
StudioSetupWidget* m_studioSetup = nullptr;
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
std::unique_ptr<VoiceAllocator> m_voxAllocator;
@ -154,6 +156,8 @@ public:
void pushUndoCommand(QUndoCommand* cmd);
void updateFocus();
void aboutToDeleteNode(ProjectModel::INode* node);
void closeEvent(QCloseEvent* ev);
void showEvent(QShowEvent* ev);
QString getGroupName(ProjectModel::GroupNode* group) const;
ProjectModel::GroupNode* getSelectedGroupNode() const;
@ -197,6 +201,8 @@ public slots:
void modulationChanged(int mod);
void pitchChanged(int pitch);
void killSounds();
void fxPressed();
void volumeChanged(int vol);
void outlineCutAction();
void outlineCopyAction();
@ -211,6 +217,10 @@ public slots:
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
void onTextSelect();
void onTextDelete();
void cleanChanged(bool clean);
void studioSetupHidden();
void studioSetupShown();
void onBackgroundTaskFinished();

View File

@ -4,6 +4,8 @@
#include "Common.hpp"
#include "athena/YAMLDocWriter.hpp"
#include "MainWindow.hpp"
#include "amuse/SongConverter.hpp"
#include "amuse/ContainerRegistry.hpp"
#include <QUndoCommand>
QIcon ProjectModel::GroupNode::Icon;
@ -409,13 +411,32 @@ bool ProjectModel::openGroupData(const QString& groupName, UIMessenger& messenge
return true;
}
bool ProjectModel::openSongsData()
void ProjectModel::_resetSongRefCount()
{
for (auto& song : m_midiFiles)
song.second.m_refCount = 0;
for (const auto& g : m_groups)
for (const auto& g2 : g.second.getProj().songGroups())
for (const auto& m : g2.second->m_midiSetups)
++m_midiFiles[m.first].m_refCount;
for (auto it = m_midiFiles.begin(); it != m_midiFiles.end();)
{
if (it->second.m_refCount == 0)
{
it = m_midiFiles.erase(it);
continue;
}
++it;
}
}
void ProjectModel::openSongsData()
{
m_midiFiles.clear();
QFileInfo songsFile(m_dir, QStringLiteral("!songs.yaml"));
if (songsFile.exists())
{
athena::io::FileReader r(QStringToSysString(songsFile.path()));
athena::io::FileReader r(QStringToSysString(songsFile.filePath()));
if (!r.hasError())
{
athena::io::YAMLDocReader dr;
@ -425,35 +446,44 @@ bool ProjectModel::openSongsData()
for (auto& p : dr.getRootNode()->m_mapChildren)
{
char* endPtr;
amuse::SongId id = uint16_t(strtoul(p.first.c_str(), &endPtr, 0));
amuse::SongId id = uint16_t(strtoul(p.first.c_str(), &endPtr, 16));
if (endPtr == p.first.c_str() || id.id == 0xffff)
continue;
m_midiFiles.clear();
QString path = QString::fromStdString(p.second->m_scalarString);
m_root->oneLevelTraverse([this, id, path](INode* n)
{
GroupNode* gn = static_cast<GroupNode*>(n);
amuse::AudioGroupDatabase* db = gn->getAudioGroup();
for (const auto& p : db->getProj().songGroups())
{
for (const auto& m : p.second->m_midiSetups)
{
if (id == m.first)
{
Song& song = m_midiFiles[id];
song.m_path = path;
++song.m_refCount;
}
}
}
return true;
});
setMIDIPathOfSong(id, path);
}
_resetSongRefCount();
}
}
}
return true;
}
void ProjectModel::importSongsData(const QString& path)
{
std::vector<std::pair<amuse::SystemString, amuse::ContainerRegistry::SongData>> songs =
amuse::ContainerRegistry::LoadSongs(QStringToSysString(path).c_str());
for (const auto& song : songs)
{
int version;
bool isBig;
auto midiData =
amuse::SongConverter::SongToMIDI(song.second.m_data.get(), version, isBig);
if (!midiData.empty())
{
QFileInfo fi(m_dir, SysStringToQString(song.first + ".mid"));
QFile f(fi.filePath());
if (f.open(QFile::WriteOnly))
{
f.write((const char*)midiData.data(), midiData.size());
setMIDIPathOfSong(
song.second.m_setupId, m_dir.relativeFilePath(fi.filePath()));
}
}
}
saveSongsIndex();
_resetSongRefCount();
}
bool ProjectModel::reloadSampleData(const QString& groupName, UIMessenger& messenger)
@ -509,6 +539,24 @@ bool ProjectModel::importGroupData(const QString& groupName, const amuse::AudioG
return true;
}
void ProjectModel::saveSongsIndex()
{
if (!m_midiFiles.empty())
{
QFileInfo songsFile(m_dir, QStringLiteral("!songs.yaml"));
athena::io::YAMLDocWriter dw("amuse::Songs");
for (auto& p : amuse::SortUnorderedMap(m_midiFiles))
{
char id[16];
snprintf(id, 16, "%04X", p.first.id);
dw.writeString(id, p.second.get().m_path.toUtf8().data());
}
athena::io::FileWriter w(QStringToSysString(songsFile.filePath()));
if (!w.hasError())
dw.finish(&w);
}
}
bool ProjectModel::saveToFile(UIMessenger& messenger)
{
m_projectDatabase.setIdDatabases();
@ -528,20 +576,7 @@ bool ProjectModel::saveToFile(UIMessenger& messenger)
g.second.getPool().toYAML(groupPath);
}
if (!m_midiFiles.empty())
{
QFileInfo songsFile(m_dir, QStringLiteral("!songs.yaml"));
athena::io::YAMLDocWriter dw("amuse::Songs");
for (auto& p : m_midiFiles)
{
char id[16];
snprintf(id, 16, "%04X", p.first.id);
dw.writeString(id, p.second.m_path.toUtf8().data());
}
athena::io::FileWriter w(QStringToSysString(songsFile.path()));
if (!w.hasError())
dw.finish(&w);
}
saveSongsIndex();
return true;
}

View File

@ -349,16 +349,19 @@ public:
bool m_needsReset = false;
void _buildGroupNode(GroupNode& gn);
void _resetModelData();
void _resetSongRefCount();
public:
explicit ProjectModel(const QString& path, QObject* parent = Q_NULLPTR);
bool clearProjectData();
bool openGroupData(const QString& groupName, UIMessenger& messenger);
bool openSongsData();
void openSongsData();
void importSongsData(const QString& path);
bool reloadSampleData(const QString& groupName, UIMessenger& messenger);
bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
ImportMode mode, UIMessenger& messenger);
void saveSongsIndex();
bool saveToFile(UIMessenger& messenger);
bool ensureModelData();

View File

@ -118,34 +118,6 @@ FieldSoundMacroStep::FieldSoundMacroStep(FieldProjectNode* macroField, QWidget*
setLayout(layout);
}
static QIcon SoundMacroDeleteIcon;
static QIcon SoundMacroDeleteHoveredIcon;
void SoundMacroDeleteButton::enterEvent(QEvent* event)
{
setIcon(SoundMacroDeleteHoveredIcon);
}
void SoundMacroDeleteButton::leaveEvent(QEvent* event)
{
setIcon(SoundMacroDeleteIcon);
}
SoundMacroDeleteButton::SoundMacroDeleteButton(QWidget* parent)
: QPushButton(parent)
{
if (SoundMacroDeleteIcon.isNull())
SoundMacroDeleteIcon = QIcon(QStringLiteral(":/icons/IconSoundMacroDelete.svg"));
if (SoundMacroDeleteHoveredIcon.isNull())
SoundMacroDeleteHoveredIcon = QIcon(QStringLiteral(":/icons/IconSoundMacroDeleteHovered.svg"));
setVisible(false);
setFixedSize(21, 21);
setFlat(true);
setToolTip(tr("Delete this SoundMacro"));
setIcon(SoundMacroDeleteIcon);
}
CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing)
: QWidget(nullptr), m_cmd(cmd), m_introspection(amuse::SoundMacro::GetCmdIntrospection(op))
{

View File

@ -24,6 +24,8 @@ public:
explicit TargetButton(QWidget* parent = Q_NULLPTR);
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
void mouseMoveEvent(QMouseEvent* event) { event->ignore(); }
void focusOutEvent(QFocusEvent* event) { event->ignore(); }
void keyPressEvent(QKeyEvent* event) { event->ignore(); }
};
class FieldSoundMacroStep : public QWidget
@ -47,22 +49,13 @@ public:
void cancel();
};
class SoundMacroDeleteButton : public QPushButton
{
Q_OBJECT
public:
explicit SoundMacroDeleteButton(QWidget* parent = Q_NULLPTR);
void enterEvent(QEvent* event);
void leaveEvent(QEvent* event);
};
class CommandWidget : public QWidget
{
Q_OBJECT
friend class SoundMacroListing;
QFont m_numberFont;
QLabel m_titleLabel;
SoundMacroDeleteButton m_deleteButton;
ListingDeleteButton m_deleteButton;
QStaticText m_numberText;
int m_index = -1;
amuse::SoundMacro::ICmd* m_cmd;

View File

@ -0,0 +1,91 @@
#include "StatusBarWidget.hpp"
FXButton::FXButton(QWidget* parent)
: QPushButton(parent)
{
setIcon(QIcon(QStringLiteral(":/icons/IconFX.svg")));
setToolTip(tr("Access studio setup window for experimenting with audio effects"));
}
StatusBarWidget::StatusBarWidget(QWidget* parent)
: QStatusBar(parent), m_volumeSlider(Qt::Horizontal)
{
addWidget(&m_normalMessage);
m_killButton.setIcon(QIcon(QStringLiteral(":/icons/IconKill.svg")));
m_killButton.setVisible(false);
m_killButton.setToolTip(tr("Immediately kill active voices"));
m_voiceCount.setVisible(false);
m_volumeIcons[0] = QIcon(QStringLiteral(":/icons/IconVolume0"));
m_volumeIcons[1] = QIcon(QStringLiteral(":/icons/IconVolume1"));
m_volumeIcons[2] = QIcon(QStringLiteral(":/icons/IconVolume2"));
m_volumeIcons[3] = QIcon(QStringLiteral(":/icons/IconVolume3"));
m_volumeIcon.setFixedSize(16, 16);
m_volumeIcon.setPixmap(m_volumeIcons[0].pixmap(16, 16));
connect(&m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
m_volumeSlider.setRange(0, 100);
m_volumeSlider.setFixedWidth(100);
addPermanentWidget(&m_voiceCount);
addPermanentWidget(&m_killButton);
addPermanentWidget(&m_fxButton);
addPermanentWidget(&m_volumeIcon);
addPermanentWidget(&m_volumeSlider);
}
void StatusBarWidget::setVoiceCount(int voices)
{
if (voices != m_cachedVoiceCount)
{
m_voiceCount.setText(QString::number(voices));
m_cachedVoiceCount = voices;
setKillVisible(voices != 0);
}
}
void StatusBarWidget::volumeChanged(int vol)
{
int idx = int(std::round(vol * (3.f / 100.f)));
if (idx != m_lastVolIdx)
{
m_lastVolIdx = idx;
m_volumeIcon.setPixmap(m_volumeIcons[idx].pixmap(16, 16));
}
}
void StatusBarFocus::setMessage(const QString& message)
{
m_message = message;
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
{
if (widget->m_curFocus == this)
{
if (m_message.isEmpty())
widget->clearMessage();
else
widget->showMessage(m_message);
}
}
}
void StatusBarFocus::enter()
{
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
{
widget->m_curFocus = this;
if (m_message.isEmpty())
widget->clearMessage();
else
widget->showMessage(m_message);
}
}
void StatusBarFocus::exit()
{
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
{
if (widget->m_curFocus == this)
{
widget->clearMessage();
widget->m_curFocus = nullptr;
}
}
}

View File

@ -4,42 +4,53 @@
#include <QStatusBar>
#include <QLabel>
#include <QPushButton>
#include <QSlider>
#include <QMouseEvent>
#include <cmath>
class StatusBarFocus;
class FXButton : public QPushButton
{
Q_OBJECT
public:
explicit FXButton(QWidget* parent = Q_NULLPTR);
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
void mouseMoveEvent(QMouseEvent* event) { event->ignore(); }
void focusOutEvent(QFocusEvent* event) { event->ignore(); }
void keyPressEvent(QKeyEvent* event) { event->ignore(); }
};
class StatusBarWidget : public QStatusBar
{
friend class StatusBarFocus;
Q_OBJECT
QLabel m_normalMessage;
QPushButton m_killButton;
FXButton m_fxButton;
QIcon m_volumeIcons[4];
QLabel m_volumeIcon;
QSlider m_volumeSlider;
int m_lastVolIdx = 0;
QLabel m_voiceCount;
int m_cachedVoiceCount = -1;
StatusBarFocus* m_curFocus = nullptr;
void setKillVisible(bool vis) { m_killButton.setVisible(vis); m_voiceCount.setVisible(vis); }
public:
explicit StatusBarWidget(QWidget* parent = Q_NULLPTR) : QStatusBar(parent)
{
addWidget(&m_normalMessage);
m_killButton.setIcon(QIcon(QStringLiteral(":/icons/IconKill.svg")));
m_killButton.setVisible(false);
m_killButton.setToolTip(tr("Immediately kill active voices"));
m_voiceCount.setVisible(false);
addPermanentWidget(&m_voiceCount);
addPermanentWidget(&m_killButton);
}
explicit StatusBarWidget(QWidget* parent = Q_NULLPTR);
void setNormalMessage(const QString& message) { m_normalMessage.setText(message); }
void setVoiceCount(int voices)
{
if (voices != m_cachedVoiceCount)
{
m_voiceCount.setText(QString::number(voices));
m_cachedVoiceCount = voices;
setKillVisible(voices != 0);
}
}
void setVoiceCount(int voices);
void connectKillClicked(const QObject* receiver, const char* method)
{ connect(&m_killButton, SIGNAL(clicked(bool)), receiver, method); }
void connectFXPressed(const QObject* receiver, const char* method)
{ connect(&m_fxButton, SIGNAL(pressed()), receiver, method); }
void setFXDown(bool down) { m_fxButton.setDown(down); }
void connectVolumeSlider(const QObject* receiver, const char* method)
{ connect(&m_volumeSlider, SIGNAL(valueChanged(int)), receiver, method); }
void setVolumeValue(int vol) { m_volumeSlider.setValue(vol); }
private slots:
void volumeChanged(int vol);
};
class StatusBarFocus : public QObject
@ -50,42 +61,9 @@ public:
explicit StatusBarFocus(StatusBarWidget* statusWidget)
: QObject(statusWidget) {}
~StatusBarFocus() { exit(); }
void setMessage(const QString& message)
{
m_message = message;
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
{
if (widget->m_curFocus == this)
{
if (m_message.isEmpty())
widget->clearMessage();
else
widget->showMessage(m_message);
}
}
}
void enter()
{
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
{
widget->m_curFocus = this;
if (m_message.isEmpty())
widget->clearMessage();
else
widget->showMessage(m_message);
}
}
void exit()
{
if (StatusBarWidget* widget = qobject_cast<StatusBarWidget*>(parent()))
{
if (widget->m_curFocus == this)
{
widget->clearMessage();
widget->m_curFocus = nullptr;
}
}
}
void setMessage(const QString& message);
void enter();
void exit();
};
#endif //AMUSE_STATUSBAR_WIDGET_HPP

1058
Editor/StudioSetupWidget.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,177 @@
#ifndef AMUSE_STUDIO_SETUP_WIDGET_HPP
#define AMUSE_STUDIO_SETUP_WIDGET_HPP
#include "EditorWidget.hpp"
#include <QWidget>
#include <QTreeWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QLayoutItem>
#include <QStaticText>
#include <QPropertyAnimation>
#include <QScrollArea>
#include <QSplitter>
#include "amuse/Studio.hpp"
struct EffectIntrospection
{
struct Field
{
enum class Type
{
Invalid,
UInt32,
UInt32x8,
Float
};
Type m_tp;
std::string_view m_name;
float m_min, m_max, m_default;
};
amuse::EffectType m_tp;
std::string_view m_name;
std::string_view m_description;
Field m_fields[7];
};
class EffectListing;
class EffectWidget : public QWidget
{
Q_OBJECT
friend class EffectListing;
QFont m_numberFont;
QLabel m_titleLabel;
ListingDeleteButton m_deleteButton;
QStaticText m_numberText;
int m_index = -1;
amuse::EffectBaseTypeless* m_effect;
const EffectIntrospection* m_introspection;
void setIndex(int index);
private slots:
void numChanged(int);
void numChanged(double);
void deleteClicked();
private:
EffectWidget(amuse::EffectBaseTypeless* effect, amuse::EffectType type);
public:
EffectListing* getParent() const;
EffectWidget(amuse::EffectBaseTypeless* effect);
EffectWidget(amuse::EffectType op);
void paintEvent(QPaintEvent* event);
QString getText() const { return m_titleLabel.text(); }
};
class EffectWidgetContainer : public QWidget
{
Q_OBJECT
friend class EffectListing;
EffectWidget* m_effectWidget;
QPropertyAnimation* m_animation = nullptr;
void animateOpen();
void animateClosed();
void snapOpen();
void snapClosed();
private slots:
void animationDestroyed();
public:
EffectWidgetContainer(EffectWidget* child, QWidget* parent = Q_NULLPTR);
};
class EffectListing : public QWidget
{
Q_OBJECT
friend class EffectWidget;
friend class StudioSetupWidget;
amuse::Submix* m_submix = nullptr;
QVBoxLayout* m_layout;
QLayoutItem* m_dragItem = nullptr;
int m_origIdx = -1;
int m_dragOpenIdx = -1;
EffectWidgetContainer* m_prevDragOpen = nullptr;
int m_autoscrollTimer = -1;
int m_autoscrollDelta = 0;
QWidget* m_autoscrollSource = nullptr;
QMouseEvent m_autoscrollEvent = {{}, {}, {}, {}, {}};
void startAutoscroll(QWidget* source, QMouseEvent* event, int delta);
void stopAutoscroll();
bool beginDrag(EffectWidget* widget);
void endDrag();
void cancelDrag();
void _moveDrag(int hoverIdx, const QPoint& pt, QWidget* source, QMouseEvent* event);
void moveDrag(EffectWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event);
int moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event);
void insertDragout();
void insert(amuse::EffectType type, const QString& text);
void deleteEffect(int index);
void reindex();
void clear();
public:
explicit EffectListing(QWidget* parent = Q_NULLPTR);
bool loadData(amuse::Submix* submix);
void unloadData();
void timerEvent(QTimerEvent* event);
};
class EffectCatalogueItem : public QWidget
{
Q_OBJECT
amuse::EffectType m_type;
QLabel m_iconLab;
QLabel m_label;
public:
explicit EffectCatalogueItem(amuse::EffectType type, const QString& name,
const QString& doc, QWidget* parent = Q_NULLPTR);
explicit EffectCatalogueItem(const EffectCatalogueItem& other, QWidget* parent = Q_NULLPTR);
amuse::EffectType getType() const { return m_type; }
QString getText() const { return m_label.text(); }
};
class EffectCatalogue : public QTreeWidget
{
Q_OBJECT
public:
explicit EffectCatalogue(QWidget* parent = Q_NULLPTR);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
};
class StudioSetupWidget : public QWidget
{
Q_OBJECT
friend class EffectCatalogue;
QSplitter* m_splitter;
QTabWidget* m_tabs;
EffectListing* m_listing[2];
EffectCatalogue* m_catalogue;
EffectWidget* m_draggedCmd = nullptr;
EffectCatalogueItem* m_draggedItem = nullptr;
QPoint m_draggedPt;
int m_dragInsertIdx = -1;
EffectListing* getCurrentListing() const;
void beginCommandDrag(EffectWidget* widget, const QPoint& eventPt, const QPoint& pt);
void beginCatalogueDrag(EffectCatalogueItem* item, const QPoint& eventPt, const QPoint& pt);
public:
explicit StudioSetupWidget(QWidget* parent = Q_NULLPTR);
bool loadData(amuse::Studio* studio);
void unloadData();
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void keyPressEvent(QKeyEvent* event);
void hideEvent(QHideEvent* event);
void showEvent(QShowEvent* event);
void updateWindowPosition();
public slots:
void catalogueDoubleClicked(QTreeWidgetItem* item, int column);
signals:
void hidden();
void shown();
};
#endif // AMUSE_STUDIO_SETUP_WIDGET_HPP

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="20"
height="20"
viewBox="0 0 5.2916665 5.2916668"
version="1.1"
id="svg8"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconFX.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#353535"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="42.15"
inkscape:cx="31.643198"
inkscape:cy="20.391101"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
gridtolerance="10"
showguides="false"
objecttolerance="17">
<inkscape:grid
type="xygrid"
id="grid817"
empspacing="0"
spacingx="0.52916666"
spacingy="0.52916666"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-291.70832)">
<g
aria-label="fx"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.17202616px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';letter-spacing:0px;word-spacing:0px;fill:#fffffa;fill-opacity:1;stroke:none;stroke-width:0.96975476"
id="text5280">
<path
d="m 0.31713132,296.97813 q -0.0775804,0 -0.16033281,-0.0155 -0.08792445,-0.0104 -0.13964471,-0.0259 l 0.04654823,-0.23792 q 0.04137621,0.0103 0.11378458,0.0207 0.0672363,0.0155 0.12412863,0.0155 0.25342928,0 0.39824601,-0.21723 0.13964471,-0.21722 0.25342928,-0.73442 L 1.4963533,293.25945 H 1.0256989 l 0.031032,-0.1862 0.4965145,-0.10861 0.056892,-0.28446 q 0.082752,-0.43962 0.3206656,-0.68271 0.2379132,-0.24308 0.6620193,-0.24308 0.3310097,0 0.4965145,0.10861 0.1706769,0.10344 0.1706769,0.27412 0,0.17067 -0.1137846,0.25343 -0.1086125,0.0827 -0.3154936,0.0827 0,-0.19654 -0.05172,-0.33618 -0.05172,-0.14482 -0.2120531,-0.14482 -0.191365,0 -0.2948055,0.16033 -0.1034405,0.15516 -0.1655048,0.481 l -0.067236,0.33101 H 2.613511 L 2.556619,293.2594 H 1.9773517 l -0.5378907,2.51877 q -0.098269,0.46031 -0.2534293,0.71891 -0.1551608,0.26378 -0.37238587,0.37239 -0.2172251,0.10861 -0.49651451,0.10861 z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Italic';fill:#fffffa;fill-opacity:1;stroke-width:0.96975476"
id="path5282"
inkscape:connector-curvature="0" />
<path
d="m 2.28436,295.73685 0.056892,-0.21723 h 0.067236 q 0.098269,0 0.1706769,-0.0259 0.07758,-0.0259 0.1603328,-0.10344 0.082752,-0.0776 0.206881,-0.22757 l 0.6620194,-0.80166 -0.3361817,-0.80684 q -0.093097,-0.2224 -0.1603328,-0.2948 -0.062064,-0.0776 -0.2120531,-0.0776 h -0.067236 l 0.041376,-0.21723 H 3.56185 l 0.3930739,1.04475 0.6878795,-1.04475 h 0.6361592 l -0.056892,0.21723 h -0.067236 q -0.098268,0 -0.1758489,0.031 -0.07758,0.031 -0.1603328,0.11378 -0.082752,0.0776 -0.201709,0.22757 l -0.5430628,0.69823 0.3568698,0.89476 q 0.082752,0.22757 0.1499888,0.29997 0.072408,0.0724 0.2223971,0.0724 h 0.067236 l -0.041376,0.21723 H 4.1359454 L 3.7170112,294.599 2.9412073,295.73685 Z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Italic';fill:#fffffa;fill-opacity:1;stroke-width:0.96975476"
id="path5284"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -25,9 +25,9 @@
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="39.33"
inkscape:cx="14.81887"
inkscape:cy="20.680873"
inkscape:zoom="119.2182"
inkscape:cx="10.254924"
inkscape:cy="16.654642"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
@ -56,7 +56,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -66,38 +66,53 @@
id="layer1"
transform="translate(0,-288.53332)">
<path
style="fill:#333333;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:type="inkscape:offset"
inkscape:radius="0.24255499"
inkscape:original="M 7.9375 289.0625 C 7.6711732 288.79616 2.6464844 293.29492 2.6464844 293.29492 L 3.7050781 294.35352 C 3.7050781 294.35352 8.2038267 289.32882 7.9375 289.0625 z "
style="fill:none;fill-opacity:1;stroke:#000019;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5257"
d="m 7.8886719,288.80859 c -0.056389,0.002 -0.097096,0.0152 -0.1367188,0.0293 -0.079245,0.0282 -0.1534463,0.068 -0.2421875,0.12109 -0.1774822,0.10627 -0.4004054,0.26416 -0.6582031,0.45899 -0.5155954,0.38965 -1.1699607,0.92941 -1.8164063,1.47656 -1.2928911,1.0943 -2.5507812,2.21875 -2.5507812,2.21875 a 0.24257925,0.24257925 0 0 0 -0.00977,0.35352 l 1.0585937,1.05859 a 0.24257925,0.24257925 0 0 0 0.3535157,-0.01 c 0,0 1.1244523,-1.25788 2.21875,-2.55078 0.5471488,-0.64644 1.0869076,-1.30081 1.4765624,-1.8164 0.1948275,-0.2578 0.3527187,-0.48072 0.4589844,-0.65821 0.053133,-0.0887 0.092867,-0.16294 0.1210938,-0.24218 0.014113,-0.0396 0.027013,-0.0803 0.029297,-0.13672 0.00228,-0.0564 -0.00982,-0.1485 -0.082031,-0.22071 -0.072205,-0.0722 -0.1643139,-0.0843 -0.2207031,-0.082 z" />
<path
style="fill:#333333;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7.9375067,289.06249 c 0.2663267,0.26632 -4.2333372,5.29165 -4.2333372,5.29165 l -1.0583343,-1.05832 c 0,0 5.0253447,-4.49967 5.2916715,-4.23333 z"
id="path846"
inkscape:connector-curvature="0"
sodipodi:nodetypes="zccz" />
<path
style="fill:#333333;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:#333333;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 3.7041695,294.35414 c 0.7934571,0.79347 -2.1166685,2.11668 -3.17500284,2.11668 0,-1.05833 1.32960554,-3.96208 2.11666854,-3.175 z"
id="path848"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.26458334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.7321623,293.41165 c 0,0 -1.1446613,0.94249 -2.20299564,3.05917"
id="path850"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.26458334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 3.6041925,294.27028 c 0,0 -0.9583573,1.14221 -3.07502584,2.20054"
id="path852"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.26458334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;stroke:#ffffff;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 3.1750023,293.82499 -2.64583564,2.64583"
id="path854"
inkscape:connector-curvature="0" />
<path
sodipodi:type="inkscape:offset"
inkscape:radius="0.25359377"
inkscape:original="M 2.6464844 293.29492 C 1.8594214 292.50784 0.52929688 295.41237 0.52929688 296.4707 C 1.5876312 296.4707 4.4985352 295.14699 3.7050781 294.35352 L 2.6464844 293.29492 z "
style="fill:none;fill-opacity:1;stroke:#00001b;stroke-width:0.26458335;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5261"
d="m 2.3164062,292.9082 c -0.181907,0.01 -0.3430295,0.0908 -0.4863281,0.19922 -0.2865971,0.21692 -0.5328425,0.56219 -0.7578125,0.95899 -0.44993989,0.79359 -0.79687498,1.76889 -0.79687498,2.40429 a 0.25361913,0.25361913 0 0 0 0.25390626,0.25391 c 0.63489452,0 1.61169302,-0.34575 2.40625002,-0.79492 0.3972785,-0.22459 0.7421604,-0.47049 0.9589843,-0.75781 0.108412,-0.14367 0.1899049,-0.30393 0.1992188,-0.48633 0.00931,-0.1824 -0.069928,-0.37266 -0.2089844,-0.51172 l -1.0585937,-1.0586 C 2.6875905,292.97665 2.4983133,292.89817 2.3164062,292.9082 Z" />
<path
style="fill:#fffffd;fill-opacity:1;stroke:none;stroke-width:0.26458356px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3.4564631,292.56098 0.9825481,0.98255 -0.7348417,0.81061 -1.0583343,-1.05832 z"
d="m 3.3534735,292.49828 1.1682763,1.12584 -0.6609111,0.75797 -1.2383055,-1.2582 z"
id="path1960"
inkscape:connector-curvature="0" />
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconVolume0.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="39.383707"
inkscape:cx="6.3383887"
inkscape:cy="7.7203454"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
showborder="true"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
type="xygrid"
id="grid4173"
empspacing="1"
visible="false" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-292.76665)">
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.3028571;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.26458333,293.82498 0.009775,2.11667 H 1.0583333 l 1.3229167,1.05833 v -4.23333 l -1.3229167,1.05833 z"
id="path841"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconVolume1.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="39.383707"
inkscape:cx="6.3383887"
inkscape:cy="7.7203454"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
showborder="true"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
type="xygrid"
id="grid4173"
empspacing="1"
visible="false" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-292.76665)">
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.3028571;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.26458333,293.82498 0.009775,2.11667 H 1.0583333 l 1.3229167,1.05833 v -4.23333 l -1.3229167,1.05833 z"
id="path841"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2.6458333,294.08957 v 1.5875 h 0.2645834 v -1.5875 z"
id="path825"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconVolume2.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="39.383707"
inkscape:cx="6.3383887"
inkscape:cy="7.7203454"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
showborder="true"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
type="xygrid"
id="grid4173"
empspacing="1"
visible="false" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-292.76665)">
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.3028571;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.26458333,293.82498 0.009775,2.11667 H 1.0583333 l 1.3229167,1.05833 v -4.23333 l -1.3229167,1.05833 z"
id="path841"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2.6458333,294.08957 v 1.5875 h 0.2645834 v -1.5875 z"
id="path825"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3.175,293.5604 v 2.64583 h 0.2645833 v -2.64583 z"
id="path827"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 4.2333332 4.2333335"
id="svg2"
version="1.1"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="IconVolume3.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#393939"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="39.383707"
inkscape:cx="6.3383887"
inkscape:cy="7.7203454"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2079"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="1"
showborder="true"
objecttolerance="4"
gridtolerance="4"
guidetolerance="5">
<inkscape:grid
type="xygrid"
id="grid4173"
empspacing="1"
visible="false" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-292.76665)">
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.3028571;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.26458333,293.82498 0.009775,2.11667 H 1.0583333 l 1.3229167,1.05833 v -4.23333 l -1.3229167,1.05833 z"
id="path841"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2.6458333,294.08957 v 1.5875 h 0.2645834 v -1.5875 z"
id="path825"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3.175,293.5604 v 2.64583 h 0.2645833 v -2.64583 z"
id="path827"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3.7041666,293.03123 v 3.70417 H 3.96875 v -3.70417 z"
id="path829"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -99,12 +99,12 @@
<context>
<name>AddRemoveButtons</name>
<message>
<location filename="../EditorWidget.cpp" line="64"/>
<location filename="../EditorWidget.cpp" line="136"/>
<source>Add Row</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../EditorWidget.cpp" line="65"/>
<location filename="../EditorWidget.cpp" line="137"/>
<source>Remove Row</source>
<translation type="unfinished"></translation>
</message>
@ -112,7 +112,7 @@
<context>
<name>CommandWidget</name>
<message>
<location filename="../SoundMacroEditor.cpp" line="342"/>
<location filename="../SoundMacroEditor.cpp" line="314"/>
<source>Change %1</source>
<translation type="unfinished"></translation>
</message>
@ -146,6 +146,41 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EffectCatalogue</name>
<message>
<location filename="../StudioSetupWidget.cpp" line="779"/>
<location filename="../StudioSetupWidget.cpp" line="787"/>
<source>Reverb Standard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../StudioSetupWidget.cpp" line="780"/>
<location filename="../StudioSetupWidget.cpp" line="788"/>
<source>Reverb High</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../StudioSetupWidget.cpp" line="781"/>
<location filename="../StudioSetupWidget.cpp" line="789"/>
<source>Delay</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../StudioSetupWidget.cpp" line="782"/>
<location filename="../StudioSetupWidget.cpp" line="790"/>
<source>Chorus</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FXButton</name>
<message>
<location filename="../StatusBarWidget.cpp" line="7"/>
<source>Access studio setup window for experimenting with audio effects</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KeymapControls</name>
<message>
@ -283,6 +318,14 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ListingDeleteButton</name>
<message>
<location filename="../EditorWidget.cpp" line="177"/>
<source>Delete this SoundMacro</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MIDIFileDelegate</name>
<message>
@ -322,7 +365,6 @@
<name>MainWindow</name>
<message>
<location filename="../MainWindow.ui" line="14"/>
<location filename="../MainWindow.cpp" line="194"/>
<source>Amuse</source>
<translation type="unfinished"></translation>
</message>
@ -517,269 +559,284 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="79"/>
<location filename="../MainWindow.cpp" line="81"/>
<source>Clear Recent Projects</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="85"/>
<location filename="../MainWindow.cpp" line="87"/>
<source>Quit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="202"/>
<source>Amuse [%1/%2/%3]</source>
<location filename="../MainWindow.cpp" line="203"/>
<source>Amuse[*]</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="207"/>
<source>Amuse [%1]</source>
<location filename="../MainWindow.cpp" line="211"/>
<source>%1/%2/%3[*] - Amuse</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="238"/>
<location filename="../MainWindow.cpp" line="637"/>
<source>The directory at &apos;%1&apos; must not be empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="239"/>
<location filename="../MainWindow.cpp" line="638"/>
<source>Directory empty</source>
<location filename="../MainWindow.cpp" line="216"/>
<source>%1[*] - Amuse</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="244"/>
<source>The directory at &apos;%1&apos; must exist for the Amuse editor.</source>
<location filename="../MainWindow.cpp" line="683"/>
<source>The directory at &apos;%1&apos; must not be empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="245"/>
<location filename="../MainWindow.cpp" line="684"/>
<source>Directory empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="250"/>
<source>The directory at &apos;%1&apos; must exist for the Amuse editor.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="251"/>
<source>Directory does not exist</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="248"/>
<location filename="../MainWindow.cpp" line="254"/>
<source>__amuse_test__</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="253"/>
<location filename="../MainWindow.cpp" line="259"/>
<source>The directory at &apos;%1&apos; must be writable for the Amuse editor: %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="255"/>
<location filename="../MainWindow.cpp" line="261"/>
<source>Unable to write to directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="304"/>
<location filename="../MainWindow.cpp" line="310"/>
<source>No Audio Devices Found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="327"/>
<location filename="../MainWindow.cpp" line="333"/>
<source>No MIDI Devices Found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="383"/>
<location filename="../MainWindow.cpp" line="389"/>
<source>SUSTAIN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="620"/>
<location filename="../MainWindow.cpp" line="635"/>
<source>Unsaved Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="635"/>
<source>Save Changes in %1?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="664"/>
<source>New Project</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="643"/>
<location filename="../MainWindow.cpp" line="689"/>
<source>The directory at &apos;%1&apos; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="644"/>
<location filename="../MainWindow.cpp" line="690"/>
<source>Bad Directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="659"/>
<location filename="../MainWindow.cpp" line="705"/>
<source>Opening</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="659"/>
<location filename="../MainWindow.cpp" line="738"/>
<location filename="../MainWindow.cpp" line="822"/>
<location filename="../MainWindow.cpp" line="867"/>
<location filename="../MainWindow.cpp" line="705"/>
<location filename="../MainWindow.cpp" line="788"/>
<location filename="../MainWindow.cpp" line="872"/>
<location filename="../MainWindow.cpp" line="917"/>
<source>Scanning Project</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="671"/>
<location filename="../MainWindow.cpp" line="717"/>
<source>Opening %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="684"/>
<location filename="../MainWindow.cpp" line="730"/>
<source>Open Project</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="738"/>
<location filename="../MainWindow.cpp" line="788"/>
<source>Reloading Samples</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="750"/>
<location filename="../MainWindow.cpp" line="800"/>
<source>Scanning %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="760"/>
<location filename="../MainWindow.cpp" line="810"/>
<source>Import Project</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="770"/>
<location filename="../MainWindow.cpp" line="820"/>
<source>The file at &apos;%1&apos; could not be interpreted as a MusyX container.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="771"/>
<location filename="../MainWindow.cpp" line="821"/>
<source>Unsupported MusyX Container</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="776"/>
<location filename="../MainWindow.cpp" line="826"/>
<source>Sample Import Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="777"/>
<location filename="../MainWindow.cpp" line="827"/>
<source>Amuse can import samples as WAV files for ease of editing, import original compressed data for lossless repacking, or both. Exporting the project will prefer whichever version was modified most recently.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="781"/>
<location filename="../MainWindow.cpp" line="831"/>
<source>Import Compressed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="781"/>
<location filename="../MainWindow.cpp" line="831"/>
<source>Import WAVs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="781"/>
<location filename="../MainWindow.cpp" line="831"/>
<source>Import Both</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="797"/>
<location filename="../MainWindow.cpp" line="847"/>
<source>Raw Import Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="798"/>
<location filename="../MainWindow.cpp" line="848"/>
<source>Would you like to scan for all MusyX group files in this directory?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="808"/>
<location filename="../MainWindow.cpp" line="858"/>
<source>Project Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="808"/>
<location filename="../MainWindow.cpp" line="858"/>
<source>What should this project be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="822"/>
<location filename="../MainWindow.cpp" line="867"/>
<location filename="../MainWindow.cpp" line="872"/>
<location filename="../MainWindow.cpp" line="917"/>
<source>Importing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="834"/>
<location filename="../MainWindow.cpp" line="876"/>
<location filename="../MainWindow.cpp" line="884"/>
<location filename="../MainWindow.cpp" line="926"/>
<source>Importing %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="892"/>
<location filename="../MainWindow.cpp" line="942"/>
<source>Import Songs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="994"/>
<location filename="../MainWindow.cpp" line="1023"/>
<source>New Subproject</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1010"/>
<location filename="../MainWindow.cpp" line="1039"/>
<source>New SFX Group</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1011"/>
<location filename="../MainWindow.cpp" line="1040"/>
<source>What should the new SFX group in %1 be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1029"/>
<location filename="../MainWindow.cpp" line="1058"/>
<source>New Song Group</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1030"/>
<location filename="../MainWindow.cpp" line="1059"/>
<source>What should the new Song group in %1 be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1071"/>
<location filename="../MainWindow.cpp" line="1100"/>
<source>New ADSR</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1072"/>
<location filename="../MainWindow.cpp" line="1101"/>
<source>What should the new ADSR in %1 be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1090"/>
<location filename="../MainWindow.cpp" line="1119"/>
<source>New Curve</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1091"/>
<location filename="../MainWindow.cpp" line="1120"/>
<source>What should the new Curve in %1 be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1109"/>
<location filename="../MainWindow.cpp" line="1138"/>
<source>New Keymap</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1110"/>
<location filename="../MainWindow.cpp" line="1139"/>
<source>What should the new Keymap in %1 be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1128"/>
<location filename="../MainWindow.cpp" line="1157"/>
<source>New Layers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="1129"/>
<location filename="../MainWindow.cpp" line="1158"/>
<source>What should the new Layers in %1 be named?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../MainWindow.cpp" line="995"/>
<location filename="../MainWindow.cpp" line="1024"/>
<source>What should this subproject be named?</source>
<translation type="unfinished"></translation>
</message>
@ -950,17 +1007,17 @@
<context>
<name>PageObjectProxyModel</name>
<message>
<location filename="../ProjectModel.cpp" line="239"/>
<location filename="../ProjectModel.cpp" line="241"/>
<source>SoundMacros:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="241"/>
<location filename="../ProjectModel.cpp" line="243"/>
<source>Keymaps:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="243"/>
<location filename="../ProjectModel.cpp" line="245"/>
<source>Layers:</source>
<translation type="unfinished"></translation>
</message>
@ -997,188 +1054,188 @@
<context>
<name>ProjectModel</name>
<message>
<location filename="../ProjectModel.cpp" line="566"/>
<location filename="../ProjectModel.cpp" line="601"/>
<source>Sound Macros</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="585"/>
<location filename="../ProjectModel.cpp" line="620"/>
<source>ADSRs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="596"/>
<location filename="../ProjectModel.cpp" line="631"/>
<source>Curves</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="608"/>
<location filename="../ProjectModel.cpp" line="643"/>
<source>Keymaps</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="615"/>
<location filename="../ProjectModel.cpp" line="650"/>
<source>Layers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="622"/>
<location filename="../ProjectModel.cpp" line="657"/>
<source>Samples</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="887"/>
<location filename="../ProjectModel.cpp" line="922"/>
<source>Subproject Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="887"/>
<location filename="../ProjectModel.cpp" line="922"/>
<source>The subproject %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="892"/>
<location filename="../ProjectModel.cpp" line="927"/>
<source>Add Subproject %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="942"/>
<location filename="../ProjectModel.cpp" line="977"/>
<source>Sound Group Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="942"/>
<location filename="../ProjectModel.cpp" line="967"/>
<location filename="../ProjectModel.cpp" line="977"/>
<location filename="../ProjectModel.cpp" line="1002"/>
<source>The group %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="946"/>
<location filename="../ProjectModel.cpp" line="981"/>
<source>Add Sound Group %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="967"/>
<location filename="../ProjectModel.cpp" line="1002"/>
<source>Song Group Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="971"/>
<location filename="../ProjectModel.cpp" line="1006"/>
<source>Add Song Group %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1052"/>
<location filename="../ProjectModel.cpp" line="1087"/>
<source>Sound Macro Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1052"/>
<location filename="../ProjectModel.cpp" line="1087"/>
<source>The macro %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1062"/>
<location filename="../ProjectModel.cpp" line="1097"/>
<source>Add Sound Macro %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1083"/>
<location filename="../ProjectModel.cpp" line="1118"/>
<source>ADSR Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1083"/>
<location filename="../ProjectModel.cpp" line="1118"/>
<source>The ADSR %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1089"/>
<location filename="../ProjectModel.cpp" line="1124"/>
<source>Add ADSR %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1110"/>
<location filename="../ProjectModel.cpp" line="1145"/>
<source>Curve Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1110"/>
<location filename="../ProjectModel.cpp" line="1145"/>
<source>The Curve %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1116"/>
<location filename="../ProjectModel.cpp" line="1151"/>
<source>Add Curve %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1137"/>
<location filename="../ProjectModel.cpp" line="1172"/>
<source>Keymap Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1137"/>
<location filename="../ProjectModel.cpp" line="1172"/>
<source>The Keymap %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1142"/>
<location filename="../ProjectModel.cpp" line="1177"/>
<source>Add Keymap %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1163"/>
<location filename="../ProjectModel.cpp" line="1198"/>
<source>Layers Conflict</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1163"/>
<location filename="../ProjectModel.cpp" line="1198"/>
<source>Layers %1 is already defined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1168"/>
<location filename="../ProjectModel.cpp" line="1203"/>
<source>Add Layers %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1182"/>
<location filename="../ProjectModel.cpp" line="1217"/>
<source>Delete Subproject %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1185"/>
<location filename="../ProjectModel.cpp" line="1220"/>
<source>Delete SongGroup %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1188"/>
<location filename="../ProjectModel.cpp" line="1223"/>
<source>Delete SFXGroup %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1191"/>
<location filename="../ProjectModel.cpp" line="1226"/>
<source>Delete SoundMacro %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1194"/>
<location filename="../ProjectModel.cpp" line="1229"/>
<source>Delete ADSR %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1197"/>
<location filename="../ProjectModel.cpp" line="1232"/>
<source>Delete Curve %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1200"/>
<location filename="../ProjectModel.cpp" line="1235"/>
<source>Delete Keymap %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ProjectModel.cpp" line="1203"/>
<location filename="../ProjectModel.cpp" line="1238"/>
<source>Delete Layers %1</source>
<translation type="unfinished"></translation>
</message>
@ -1480,72 +1537,72 @@
<context>
<name>SoundMacroCatalogue</name>
<message>
<location filename="../SoundMacroEditor.cpp" line="969"/>
<location filename="../SoundMacroEditor.cpp" line="941"/>
<source>Control</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="970"/>
<location filename="../SoundMacroEditor.cpp" line="942"/>
<source>Pitch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="971"/>
<location filename="../SoundMacroEditor.cpp" line="943"/>
<source>Sample</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="972"/>
<location filename="../SoundMacroEditor.cpp" line="944"/>
<source>Setup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="973"/>
<location filename="../SoundMacroEditor.cpp" line="945"/>
<source>Special</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="974"/>
<location filename="../SoundMacroEditor.cpp" line="946"/>
<source>Structure</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="975"/>
<location filename="../SoundMacroEditor.cpp" line="947"/>
<source>Volume</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="980"/>
<location filename="../SoundMacroEditor.cpp" line="952"/>
<source>Commands to control the voice</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="981"/>
<location filename="../SoundMacroEditor.cpp" line="953"/>
<source>Commands to control the voice&apos;s pitch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="982"/>
<location filename="../SoundMacroEditor.cpp" line="954"/>
<source>Commands to control the voice&apos;s sample playback</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="983"/>
<location filename="../SoundMacroEditor.cpp" line="955"/>
<source>Commands to setup the voice&apos;s mixing process</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="984"/>
<location filename="../SoundMacroEditor.cpp" line="956"/>
<source>Miscellaneous commands</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="985"/>
<location filename="../SoundMacroEditor.cpp" line="957"/>
<source>Commands to control macro branching</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="986"/>
<location filename="../SoundMacroEditor.cpp" line="958"/>
<source>Commands to control the voice&apos;s volume</source>
<translation type="unfinished"></translation>
</message>
@ -1558,28 +1615,20 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SoundMacroDeleteButton</name>
<message>
<location filename="../SoundMacroEditor.cpp" line="145"/>
<source>Delete this SoundMacro</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SoundMacroListing</name>
<message>
<location filename="../SoundMacroEditor.cpp" line="668"/>
<location filename="../SoundMacroEditor.cpp" line="640"/>
<source>Reorder %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="800"/>
<location filename="../SoundMacroEditor.cpp" line="772"/>
<source>Insert %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../SoundMacroEditor.cpp" line="853"/>
<location filename="../SoundMacroEditor.cpp" line="825"/>
<source>Delete %1</source>
<translation type="unfinished"></translation>
</message>
@ -1587,11 +1636,29 @@
<context>
<name>StatusBarWidget</name>
<message>
<location filename="../StatusBarWidget.hpp" line="26"/>
<location filename="../StatusBarWidget.cpp" line="16"/>
<source>Immediately kill active voices</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>StudioSetupWidget</name>
<message>
<location filename="../StudioSetupWidget.cpp" line="1017"/>
<source>Studio Setup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../StudioSetupWidget.cpp" line="1035"/>
<source>Aux A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../StudioSetupWidget.cpp" line="1036"/>
<source>Aux B</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TargetButton</name>
<message>

View File

@ -29,6 +29,11 @@
<file>IconAdd.svg</file>
<file>IconRemove.svg</file>
<file>IconStop.svg</file>
<file>IconVolume0.svg</file>
<file>IconVolume1.svg</file>
<file>IconVolume2.svg</file>
<file>IconVolume3.svg</file>
<file>IconFX.svg</file>
</qresource>
<qresource prefix="/bg">
<file>FaceGrey.svg</file>

View File

@ -8,11 +8,22 @@ namespace amuse
{
struct ChannelMap;
enum class EffectType
{
Invalid,
ReverbStd,
ReverbHi,
Delay,
Chorus,
EffectTypeMAX
};
class EffectBaseTypeless
{
public:
virtual ~EffectBaseTypeless() = default;
virtual void resetOutputSampleRate(double sampleRate) = 0;
virtual EffectType Isa() const = 0;
};
template <typename T>

View File

@ -46,6 +46,7 @@ public:
x90_baseDelay = baseDelay;
m_dirty = true;
}
uint32_t getBaseDelay() const { return x90_baseDelay; }
void setVariation(uint32_t variation)
{
@ -53,6 +54,7 @@ public:
x94_variation = variation;
m_dirty = true;
}
uint32_t getVariation() const { return x94_variation; }
void setPeriod(uint32_t period)
{
@ -60,6 +62,7 @@ public:
x98_period = period;
m_dirty = true;
}
uint32_t getPeriod() const { return x98_period; }
void updateParams(const EffectChorusInfo& info)
{
@ -115,6 +118,8 @@ public:
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
EffectType Isa() const { return EffectType::Chorus; }
};
}

View File

@ -69,6 +69,7 @@ public:
x3c_delay[chanIdx] = delay;
m_dirty = true;
}
uint32_t getChanDelay(int chanIdx) const { return x3c_delay[chanIdx]; }
void setFeedback(uint32_t feedback)
{
@ -84,6 +85,7 @@ public:
x48_feedback[chanIdx] = feedback;
m_dirty = true;
}
uint32_t getChanFeedback(int chanIdx) const { return x48_feedback[chanIdx]; }
void setOutput(uint32_t output)
{
@ -99,6 +101,7 @@ public:
x54_output[chanIdx] = output;
m_dirty = true;
}
uint32_t getChanOutput(int chanIdx) const { return x54_output[chanIdx]; }
void setParams(const EffectDelayInfo& info)
{
@ -134,6 +137,8 @@ public:
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
EffectType Isa() const { return EffectType::Delay; }
};
}

View File

@ -83,30 +83,35 @@ public:
x140_x1c8_coloration = clamp(0.f, coloration, 1.f);
m_dirty = true;
}
float getColoration() const { return x140_x1c8_coloration; }
void setMix(float mix)
{
x144_x1cc_mix = clamp(0.f, mix, 1.f);
m_dirty = true;
}
float getMix() const { return x144_x1cc_mix; }
void setTime(float time)
{
x148_x1d0_time = clamp(0.01f, time, 10.f);
m_dirty = true;
}
float getTime() const { return x148_x1d0_time; }
void setDamping(float damping)
{
x14c_x1d4_damping = clamp(0.f, damping, 1.f);
m_dirty = true;
}
float getDamping() const { return x14c_x1d4_damping; }
void setPreDelay(float preDelay)
{
x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f);
m_dirty = true;
}
float getPreDelay() const { return x150_x1d8_preDelay; }
void setParams(const EffectReverbStdInfo& info)
{
@ -136,6 +141,7 @@ public:
x1dc_crosstalk = clamp(0.f, crosstalk, 1.f);
m_dirty = true;
}
float getCrosstalk() const { return x1dc_crosstalk; }
void setParams(const EffectReverbHiInfo& info)
{
@ -174,6 +180,8 @@ public:
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
EffectType Isa() const { return EffectType::ReverbStd; }
};
/** High-quality 3-stage reverb with per-channel low-pass and crosstalk */
@ -207,6 +215,8 @@ public:
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
EffectType Isa() const { return EffectType::ReverbHi; }
};
}

View File

@ -29,34 +29,39 @@ class Submix
public:
Submix(Engine& engine);
/** Add new effect to effect stack and assume ownership */
/** Construct new effect */
template <class T, class... Args>
T& makeEffect(Args... args)
std::unique_ptr<EffectBaseTypeless> _makeEffect(Args... args)
{
switch (m_backendSubmix->getSampleFormat())
{
case SubmixFormat::Int16:
{
using ImpType = typename T::template ImpType<int16_t>;
m_effectStack.emplace_back(new ImpType(args..., m_backendSubmix->getSampleRate()));
return static_cast<ImpType&>(*m_effectStack.back());
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
case SubmixFormat::Int32:
default:
{
using ImpType = typename T::template ImpType<int32_t>;
m_effectStack.emplace_back(new ImpType(args..., m_backendSubmix->getSampleRate()));
return static_cast<ImpType&>(*m_effectStack.back());
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
case SubmixFormat::Float:
{
using ImpType = typename T::template ImpType<float>;
m_effectStack.emplace_back(new ImpType(args..., m_backendSubmix->getSampleRate()));
return static_cast<ImpType&>(*m_effectStack.back());
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
}
}
/** Add new effect to effect stack and assume ownership */
template <class T, class... Args>
T& makeEffect(Args... args)
{
m_effectStack.push_back(_makeEffect<T>(args...));
return static_cast<typename T::template ImpType<float>&>(*m_effectStack.back());
}
/** Add new chorus effect to effect stack and assume ownership */
EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
@ -101,6 +106,8 @@ public:
void resetOutputSampleRate(double sampleRate);
Engine& getEngine() { return m_root; }
std::vector<std::unique_ptr<EffectBaseTypeless>>& getEffectStack() { return m_effectStack; }
};
}

View File

@ -42,6 +42,16 @@ class Voice : public Entity
friend class SoundMacro::CmdTrapEvent;
friend class SoundMacro::CmdUntrapEvent;
friend class SoundMacro::CmdGetMessage;
friend class SoundMacro::CmdModeSelect;
struct VolumeCache
{
bool m_curDLS = false; /**< Current DLS status of cached lookup */
float m_curVolLUTKey = -1.f; /**< Current input level cached out of LUT */
float m_curVolLUTVal = 0.f; /**< Current output level cached out of LUT */
float getVolume(float vol, bool dls);
float getCachedVolume() const { return m_curVolLUTVal; }
};
void _setObjectId(ObjectId id) { m_objectId = id; }
@ -72,6 +82,8 @@ class Voice : public Entity
uint64_t m_voiceSamples = 0; /**< Count of samples processed over voice's lifetime */
float m_lastLevel = 0.f; /**< Last computed level ([0,1] mapped to [-10,0] clamped decibels) */
float m_nextLevel = 0.f; /**< Next computed level used for lerp-mode amplitude */
VolumeCache m_nextLevelCache;
VolumeCache m_lerpedCache;
VoiceState m_voxState = VoiceState::Dead; /**< Current high-level state of voice */
bool m_sustained = false; /**< Sustain pedal pressed for this voice */
@ -92,6 +104,7 @@ class Voice : public Entity
int32_t m_curPitch; /**< Current base pitch in cents */
bool m_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */
bool m_needsSlew = false; /**< next _setTotalPitch will be slewed */
bool m_dlsVol = false; /**< Use DLS LUT for resolving voice volume */
Envelope m_volAdsr; /**< Volume envelope */
double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */
@ -147,10 +160,13 @@ class Voice : public Entity
void _macroKeyOff();
void _macroSampleEnd();
void _procSamplePre(int16_t& samp);
VolumeCache m_masterCache;
template <typename T>
T _procSampleMaster(double time, T samp);
VolumeCache m_auxACache;
template <typename T>
T _procSampleAuxA(double time, T samp);
VolumeCache m_auxBCache;
template <typename T>
T _procSampleAuxB(double time, T samp);
void _setTotalPitch(int32_t cents, bool slew);

View File

@ -0,0 +1,10 @@
#ifndef __AMUSE_VOLUME_TABLE_HPP__
#define __AMUSE_VOLUME_TABLE_HPP__
namespace amuse
{
float LookupVolume(float vol);
float LookupDLSVolume(float vol);
}
#endif // __AMUSE_VOLUME_TABLE_HPP__

View File

@ -80,7 +80,8 @@ void type##DNA<DNAE>::_write(athena::io::YAMLDocWriter& w) \
if (id.id == 0xffff) \
return; \
std::string_view name = type::CurNameDB->resolveNameFromId(id); \
w.writeString(nullptr, name); \
if (!name.empty()) \
w.writeString(nullptr, name); \
} \
template <athena::Endian DNAE> \
const char* type##DNA<DNAE>::DNAType() \
@ -188,17 +189,20 @@ void PageObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
if (id.id & 0x8000)
{
std::string_view name = LayersId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
if (!name.empty())
w.writeString(nullptr, name);
}
else if (id.id & 0x4000)
{
std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
if (!name.empty())
w.writeString(nullptr, name);
}
else
{
std::string_view name = SoundMacroId::CurNameDB->resolveNameFromId(id);
w.writeString(nullptr, name);
if (!name.empty())
w.writeString(nullptr, name);
}
}
template <athena::Endian DNAE>

View File

@ -2707,6 +2707,7 @@ const SoundMacro::CmdIntrospection SoundMacro::CmdModeSelect::Introspective =
};
bool SoundMacro::CmdModeSelect::Do(SoundMacroState& st, Voice& vox) const
{
vox.m_dlsVol = dlsVol;
return false;
}

View File

@ -7,12 +7,27 @@
#include "amuse/Engine.hpp"
#include "amuse/DSPCodec.hpp"
#include "amuse/N64MusyXCodec.hpp"
#include "amuse/VolumeTable.hpp"
#include <cmath>
#include <cstring>
namespace amuse
{
float Voice::VolumeCache::getVolume(float vol, bool dls)
{
if (vol != m_curVolLUTKey || dls != m_curDLS)
{
m_curVolLUTKey = vol;
m_curDLS = dls;
if (dls)
m_curVolLUTVal = LookupDLSVolume(vol);
else
m_curVolLUTVal = LookupVolume(vol);
}
return m_curVolLUTVal;
}
void Voice::_destroy()
{
Entity::_destroy();
@ -224,7 +239,7 @@ void Voice::_procSamplePre(int16_t& samp)
float l = clamp(0.f, m_lastLevel * (1.f - t) + m_nextLevel * t, 1.f);
/* Apply total volume to sample using decibel scale */
samp = ApplyVolume(l * m_engine.m_masterVolume, samp);
samp = ApplyVolume(m_lerpedCache.getVolume(l * m_engine.m_masterVolume, m_dlsVol), samp);
return;
}
@ -318,14 +333,14 @@ void Voice::_procSamplePre(int16_t& samp)
m_nextLevel = clamp(0.f, m_nextLevel, 1.f);
/* Apply total volume to sample using decibel scale */
samp = ApplyVolume(m_nextLevel * m_engine.m_masterVolume, samp);
samp = ApplyVolume(m_nextLevelCache.getVolume(m_nextLevel * m_engine.m_masterVolume, m_dlsVol), samp);
}
template <typename T>
T Voice::_procSampleMaster(double time, T samp)
{
float evalVol = m_state.m_volumeSel ? (m_state.m_volumeSel.evaluate(time, *this, m_state) / 127.f) : 1.f;
return ApplyVolume(clamp(0.f, evalVol, 1.f), samp);
return ApplyVolume(m_masterCache.getVolume(clamp(0.f, evalVol, 1.f), m_dlsVol), samp);
}
template <typename T>
@ -334,7 +349,7 @@ T Voice::_procSampleAuxA(double time, T samp)
float evalVol = m_state.m_volumeSel ? (m_state.m_volumeSel.evaluate(time, *this, m_state) / 127.f) : 1.f;
evalVol *= m_state.m_reverbSel ? (m_state.m_reverbSel.evaluate(time, *this, m_state) / 127.f) : m_curReverbVol;
evalVol += m_state.m_preAuxASel ? (m_state.m_preAuxASel.evaluate(time, *this, m_state) / 127.f) : 0.f;
return ApplyVolume(clamp(0.f, evalVol, 1.f), samp);
return ApplyVolume(m_auxACache.getVolume(clamp(0.f, evalVol, 1.f), m_dlsVol), samp);
}
template <typename T>
@ -343,7 +358,7 @@ T Voice::_procSampleAuxB(double time, T samp)
float evalVol = m_state.m_volumeSel ? (m_state.m_volumeSel.evaluate(time, *this, m_state) / 127.f) : 1.f;
evalVol *= m_state.m_postAuxB ? (m_state.m_postAuxB.evaluate(time, *this, m_state) / 127.f) : m_curAuxBVol;
evalVol += m_state.m_preAuxBSel ? (m_state.m_preAuxBSel.evaluate(time, *this, m_state) / 127.f) : 0.f;
return ApplyVolume(clamp(0.f, evalVol, 1.f), samp);
return ApplyVolume(m_auxBCache.getVolume(clamp(0.f, evalVol, 1.f), m_dlsVol), samp);
}
uint32_t Voice::_GetBlockSampleCount(SampleFormat fmt)

295
lib/VolumeTable.cpp Normal file
View File

@ -0,0 +1,295 @@
#include "amuse/VolumeTable.hpp"
#include "amuse/Common.hpp"
namespace amuse
{
static const float VolumeTable[] =
{
0.000000,
0.000031,
0.000153,
0.000397,
0.000702,
0.001129,
0.001648,
0.002228,
0.002930,
0.003723,
0.004608,
0.005585,
0.006653,
0.007843,
0.009125,
0.010498,
0.011963,
0.013550,
0.015198,
0.016999,
0.018860,
0.020844,
0.022919,
0.025117,
0.027406,
0.029817,
0.032319,
0.034944,
0.037660,
0.040468,
0.043428,
0.046480,
0.049623,
0.052889,
0.056276,
0.059786,
0.063387,
0.067110,
0.070956,
0.074923,
0.078982,
0.083163,
0.087466,
0.091922,
0.096469,
0.101138,
0.105930,
0.110843,
0.115879,
0.121036,
0.126347,
0.131748,
0.137303,
0.142979,
0.148778,
0.154729,
0.160772,
0.166997,
0.173315,
0.179785,
0.186407,
0.193121,
0.200018,
0.207007,
0.214179,
0.221473,
0.228919,
0.236488,
0.244209,
0.252083,
0.260079,
0.268258,
0.276559,
0.285012,
0.293649,
0.302408,
0.311319,
0.320383,
0.329600,
0.339000,
0.348521,
0.358226,
0.368084,
0.378094,
0.388287,
0.398633,
0.409131,
0.419813,
0.430647,
0.441664,
0.452864,
0.464217,
0.475753,
0.487442,
0.499313,
0.511399,
0.523606,
0.536027,
0.548631,
0.561419,
0.574389,
0.587542,
0.600879,
0.614399,
0.628132,
0.642018,
0.656148,
0.670431,
0.684927,
0.699637,
0.714530,
0.729637,
0.744926,
0.760430,
0.776147,
0.792077,
0.808191,
0.824549,
0.841090,
0.857845,
0.874844,
0.892056,
0.909452,
0.927122,
0.945006,
0.963073,
0.981414,
1.000000,
1.000000
};
static const float DLSVolumeTable[] =
{
0.000000,
0.000062,
0.000248,
0.000558,
0.000992,
0.001550,
0.002232,
0.003038,
0.003968,
0.005022,
0.006200,
0.007502,
0.008928,
0.010478,
0.012152,
0.013950,
0.015872,
0.017918,
0.020088,
0.022382,
0.024800,
0.027342,
0.030008,
0.032798,
0.035712,
0.038750,
0.041912,
0.045198,
0.048608,
0.052142,
0.055800,
0.059582,
0.063488,
0.067518,
0.071672,
0.075950,
0.080352,
0.084878,
0.089528,
0.094302,
0.099200,
0.104222,
0.109368,
0.114638,
0.120032,
0.125550,
0.131192,
0.136958,
0.142848,
0.148862,
0.155000,
0.161262,
0.167648,
0.174158,
0.180792,
0.187550,
0.194432,
0.201438,
0.208568,
0.215822,
0.223200,
0.230702,
0.238328,
0.246078,
0.253953,
0.261951,
0.270073,
0.278319,
0.286689,
0.295183,
0.303801,
0.312543,
0.321409,
0.330399,
0.339513,
0.348751,
0.358113,
0.367599,
0.377209,
0.386943,
0.396801,
0.406783,
0.416889,
0.427119,
0.437473,
0.447951,
0.458553,
0.469279,
0.480129,
0.491103,
0.502201,
0.513423,
0.524769,
0.536239,
0.547833,
0.559551,
0.571393,
0.583359,
0.595449,
0.607663,
0.620001,
0.632463,
0.645049,
0.657759,
0.670593,
0.683551,
0.696633,
0.709839,
0.723169,
0.736623,
0.750202,
0.763904,
0.777730,
0.791680,
0.805754,
0.819952,
0.834274,
0.848720,
0.863290,
0.877984,
0.892802,
0.907744,
0.922810,
0.938000,
0.953314,
0.968752,
0.984314,
1.000000,
1.000000
};
float LookupVolume(float vol)
{
vol = amuse::clamp(0.f, vol * 127.f, 127.f);
float f = std::floor(vol);
float c = std::ceil(vol);
if (f == c)
return VolumeTable[int(f)];
float t = vol - f;
return (1.f - t) * VolumeTable[int(f)] + t * VolumeTable[int(c)];
}
float LookupDLSVolume(float vol)
{
vol = amuse::clamp(0.f, vol * 127.f, 127.f);
float f = std::floor(vol);
float c = std::ceil(vol);
if (f == c)
return DLSVolumeTable[int(f)];
float t = vol - f;
return (1.f - t) * DLSVolumeTable[int(f)] + t * DLSVolumeTable[int(c)];
}
}