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/Common.cpp
lib/DSPCodec.cpp lib/DSPCodec.cpp
lib/N64MusyXCodec.cpp lib/N64MusyXCodec.cpp
lib/VolumeTable.cpp
atdna_AudioGroupPool.cpp atdna_AudioGroupPool.cpp
atdna_AudioGroupProject.cpp atdna_AudioGroupProject.cpp
atdna_AudioGroupSampleDirectory.cpp) atdna_AudioGroupSampleDirectory.cpp)
@ -79,7 +80,8 @@ set(HEADERS
include/amuse/Common.hpp include/amuse/Common.hpp
include/amuse/amuse.hpp include/amuse/amuse.hpp
include/amuse/DSPCodec.hpp include/amuse/DSPCodec.hpp
include/amuse/N64MusyXCodec.hpp) include/amuse/N64MusyXCodec.hpp
include/amuse/VolumeTable.hpp)
unset(EXTRAS) unset(EXTRAS)
if(TARGET boo) if(TARGET boo)

View File

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

View File

@ -1,6 +1,7 @@
#include "EditorWidget.hpp" #include "EditorWidget.hpp"
#include "MainWindow.hpp" #include "MainWindow.hpp"
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QHBoxLayout>
EditorWidget::EditorWidget(QWidget* parent) EditorWidget::EditorWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
@ -18,6 +19,77 @@ void EditorUndoCommand::redo()
g_MainWindow->openEditor(m_node.get()); 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) FieldProjectNode::FieldProjectNode(ProjectModel::CollectionNode* collection, QWidget* parent)
: FieldComboBox(parent) : FieldComboBox(parent)
{ {
@ -77,3 +149,31 @@ AddRemoveButtons::AddRemoveButtons(QWidget* parent)
m_removeButton.move(32, 0); m_removeButton.move(32, 0);
m_removeAction.setEnabled(false); 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 <QItemEditorFactory>
#include <QToolButton> #include <QToolButton>
#include <QAction> #include <QAction>
#include <QPushButton>
#include <QLabel>
#include "ProjectModel.hpp" #include "ProjectModel.hpp"
class EditorWidget : public QWidget class EditorWidget : public QWidget
@ -68,6 +70,50 @@ public:
void wheelEvent(QWheelEvent* event) { event->ignore(); } 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 class FieldComboBox : public QComboBox
{ {
Q_OBJECT Q_OBJECT
@ -143,4 +189,13 @@ public:
QAction* removeAction() { return &m_removeAction; } 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 #endif //AMUSE_EDITOR_WIDGET_HPP

View File

@ -7,7 +7,6 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QtSvg/QtSvg> #include <QtSvg/QtSvg>
#include "amuse/ContainerRegistry.hpp" #include "amuse/ContainerRegistry.hpp"
#include "amuse/SongConverter.hpp"
#include "Common.hpp" #include "Common.hpp"
#include "SongGroupEditor.hpp" #include "SongGroupEditor.hpp"
#include "SoundGroupEditor.hpp" #include "SoundGroupEditor.hpp"
@ -45,6 +44,9 @@ MainWindow::MainWindow(QWidget* parent)
connectMessenger(&m_mainMessenger, Qt::DirectConnection); connectMessenger(&m_mainMessenger, Qt::DirectConnection);
m_ui.statusbar->connectKillClicked(this, SLOT(killSounds())); 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.keyboardContents->setStatusFocus(new StatusBarFocus(m_ui.statusbar));
m_ui.velocitySlider->setStatusFocus(new StatusBarFocus(m_ui.statusbar)); m_ui.velocitySlider->setStatusFocus(new StatusBarFocus(m_ui.statusbar));
@ -89,6 +91,7 @@ MainWindow::MainWindow(QWidget* parent)
updateRecentFileActions(); updateRecentFileActions();
connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(cleanChanged(bool)));
QAction* undoAction = m_undoStack->createUndoAction(this); QAction* undoAction = m_undoStack->createUndoAction(this);
undoAction->setShortcut(QKeySequence::Undo); undoAction->setShortcut(QKeySequence::Undo);
m_ui.menuEdit->insertAction(m_ui.actionCut, undoAction); 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->addWidget(m_sampleEditor);
m_ui.editorContents->setCurrentWidget(m_faceSvg); 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_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction()));
connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction())); connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction()));
connect(m_ui.actionNew_Song_Group, SIGNAL(triggered()), this, SLOT(newSongGroupAction())); connect(m_ui.actionNew_Song_Group, SIGNAL(triggered()), this, SLOT(newSongGroupAction()));
@ -145,6 +152,8 @@ MainWindow::MainWindow(QWidget* parent)
m_voxEngine = boo::NewAudioVoiceEngine(); m_voxEngine = boo::NewAudioVoiceEngine();
m_voxAllocator = std::make_unique<VoiceAllocator>(*m_voxEngine); m_voxAllocator = std::make_unique<VoiceAllocator>(*m_voxEngine);
m_engine = std::make_unique<amuse::Engine>(*m_voxAllocator); 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[7] = 127;
m_ctrlVals[10] = 64; m_ctrlVals[10] = 64;
@ -191,7 +200,7 @@ void MainWindow::updateWindowTitle()
{ {
if (!m_projectModel) if (!m_projectModel)
{ {
setWindowTitle(tr("Amuse")); setWindowTitle(tr("Amuse[*]"));
return; return;
} }
@ -199,12 +208,12 @@ void MainWindow::updateWindowTitle()
if (EditorWidget* w = getEditorWidget()) if (EditorWidget* w = getEditorWidget())
{ {
ProjectModel::BasePoolObjectNode* objNode = static_cast<ProjectModel::BasePoolObjectNode*>(w->currentNode()); 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())); m_projectModel->getGroupNode(objNode)->text()).arg(objNode->text()));
return; return;
} }
setWindowTitle(tr("Amuse [%1]").arg(dir.dirName())); setWindowTitle(tr("%1[*] - Amuse").arg(dir.dirName()));
} }
void MainWindow::updateRecentFileActions() void MainWindow::updateRecentFileActions()
@ -229,9 +238,6 @@ void MainWindow::updateRecentFileActions()
bool MainWindow::setProjectPath(const QString& path) bool MainWindow::setProjectPath(const QString& path)
{ {
if (m_projectModel && m_projectModel->path() == path)
return true;
QDir dir(path); QDir dir(path);
if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral("..")) if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral(".."))
{ {
@ -615,6 +621,44 @@ void MainWindow::aboutToDeleteNode(ProjectModel::INode* node)
closeEditor(); 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() void MainWindow::newAction()
{ {
QString path = QFileDialog::getSaveFileName(this, tr("New Project")); QString path = QFileDialog::getSaveFileName(this, tr("New Project"));
@ -626,7 +670,9 @@ void MainWindow::newAction()
return; return;
m_projectModel->clearProjectData(); 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) bool MainWindow::openProject(const QString& path)
@ -710,7 +756,11 @@ void MainWindow::clearRecentFilesAction()
void MainWindow::saveAction() void MainWindow::saveAction()
{ {
if (m_projectModel)
{
m_projectModel->saveToFile(m_mainMessenger);
m_undoStack->setClean();
}
} }
void MainWindow::revertAction() void MainWindow::revertAction()
@ -894,28 +944,7 @@ void MainWindow::importSongsAction()
return; return;
closeEditor(); closeEditor();
m_projectModel->importSongsData(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_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()));
}
}
}
} }
void MainWindow::exportAction() void MainWindow::exportAction()
@ -1201,6 +1230,19 @@ void MainWindow::killSounds()
v->kill(); 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() 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() void MainWindow::onBackgroundTaskFinished()
{ {
m_backgroundDialog->reset(); m_backgroundDialog->reset();
@ -1349,7 +1406,9 @@ void MainWindow::onBackgroundTaskFinished()
m_backgroundDialog = nullptr; m_backgroundDialog = nullptr;
m_backgroundTask->deleteLater(); m_backgroundTask->deleteLater();
m_backgroundTask = nullptr; 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); setEnabled(true);
} }

View File

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

View File

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

View File

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

View File

@ -118,34 +118,6 @@ FieldSoundMacroStep::FieldSoundMacroStep(FieldProjectNode* macroField, QWidget*
setLayout(layout); 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) CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, SoundMacroListing* listing)
: QWidget(nullptr), m_cmd(cmd), m_introspection(amuse::SoundMacro::GetCmdIntrospection(op)) : QWidget(nullptr), m_cmd(cmd), m_introspection(amuse::SoundMacro::GetCmdIntrospection(op))
{ {

View File

@ -24,6 +24,8 @@ public:
explicit TargetButton(QWidget* parent = Q_NULLPTR); explicit TargetButton(QWidget* parent = Q_NULLPTR);
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); } void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
void mouseMoveEvent(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 class FieldSoundMacroStep : public QWidget
@ -47,22 +49,13 @@ public:
void cancel(); 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 class CommandWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
friend class SoundMacroListing; friend class SoundMacroListing;
QFont m_numberFont; QFont m_numberFont;
QLabel m_titleLabel; QLabel m_titleLabel;
SoundMacroDeleteButton m_deleteButton; ListingDeleteButton m_deleteButton;
QStaticText m_numberText; QStaticText m_numberText;
int m_index = -1; int m_index = -1;
amuse::SoundMacro::ICmd* m_cmd; 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 <QStatusBar>
#include <QLabel> #include <QLabel>
#include <QPushButton> #include <QPushButton>
#include <QSlider>
#include <QMouseEvent>
#include <cmath>
class StatusBarFocus; 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 class StatusBarWidget : public QStatusBar
{ {
friend class StatusBarFocus; friend class StatusBarFocus;
Q_OBJECT Q_OBJECT
QLabel m_normalMessage; QLabel m_normalMessage;
QPushButton m_killButton; QPushButton m_killButton;
FXButton m_fxButton;
QIcon m_volumeIcons[4];
QLabel m_volumeIcon;
QSlider m_volumeSlider;
int m_lastVolIdx = 0;
QLabel m_voiceCount; QLabel m_voiceCount;
int m_cachedVoiceCount = -1; int m_cachedVoiceCount = -1;
StatusBarFocus* m_curFocus = nullptr; StatusBarFocus* m_curFocus = nullptr;
void setKillVisible(bool vis) { m_killButton.setVisible(vis); m_voiceCount.setVisible(vis); } void setKillVisible(bool vis) { m_killButton.setVisible(vis); m_voiceCount.setVisible(vis); }
public: public:
explicit StatusBarWidget(QWidget* parent = Q_NULLPTR) : QStatusBar(parent) explicit StatusBarWidget(QWidget* parent = Q_NULLPTR);
{
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);
}
void setNormalMessage(const QString& message) { m_normalMessage.setText(message); } void setNormalMessage(const QString& message) { m_normalMessage.setText(message); }
void setVoiceCount(int voices) void setVoiceCount(int voices);
{
if (voices != m_cachedVoiceCount)
{
m_voiceCount.setText(QString::number(voices));
m_cachedVoiceCount = voices;
setKillVisible(voices != 0);
}
}
void connectKillClicked(const QObject* receiver, const char* method) void connectKillClicked(const QObject* receiver, const char* method)
{ connect(&m_killButton, SIGNAL(clicked(bool)), receiver, 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 class StatusBarFocus : public QObject
@ -50,42 +61,9 @@ public:
explicit StatusBarFocus(StatusBarWidget* statusWidget) explicit StatusBarFocus(StatusBarWidget* statusWidget)
: QObject(statusWidget) {} : QObject(statusWidget) {}
~StatusBarFocus() { exit(); } ~StatusBarFocus() { exit(); }
void setMessage(const QString& message) void setMessage(const QString& message);
{ void enter();
m_message = message; void exit();
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;
}
}
}
}; };
#endif //AMUSE_STATUSBAR_WIDGET_HPP #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" borderopacity="1.0"
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="39.33" inkscape:zoom="119.2182"
inkscape:cx="14.81887" inkscape:cx="10.254924"
inkscape:cy="20.680873" inkscape:cy="16.654642"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="true" showgrid="true"
@ -56,7 +56,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -66,38 +66,53 @@
id="layer1" id="layer1"
transform="translate(0,-288.53332)"> transform="translate(0,-288.53332)">
<path <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" 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" id="path846"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="zccz" /> sodipodi:nodetypes="zccz" />
<path <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" 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" id="path848"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" /> sodipodi:nodetypes="cccc" />
<path <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" d="m 2.7321623,293.41165 c 0,0 -1.1446613,0.94249 -2.20299564,3.05917"
id="path850" id="path850"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" /> sodipodi:nodetypes="cc" />
<path <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" d="m 3.6041925,294.27028 c 0,0 -0.9583573,1.14221 -3.07502584,2.20054"
id="path852" id="path852"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" /> sodipodi:nodetypes="cc" />
<path <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" d="m 3.1750023,293.82499 -2.64583564,2.64583"
id="path854" id="path854"
inkscape:connector-curvature="0" /> 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 <path
style="fill:#fffffd;fill-opacity:1;stroke:none;stroke-width:0.26458356px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 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" id="path1960"
inkscape:connector-curvature="0" /> inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g> </g>
</svg> </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> <context>
<name>AddRemoveButtons</name> <name>AddRemoveButtons</name>
<message> <message>
<location filename="../EditorWidget.cpp" line="64"/> <location filename="../EditorWidget.cpp" line="136"/>
<source>Add Row</source> <source>Add Row</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../EditorWidget.cpp" line="65"/> <location filename="../EditorWidget.cpp" line="137"/>
<source>Remove Row</source> <source>Remove Row</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -112,7 +112,7 @@
<context> <context>
<name>CommandWidget</name> <name>CommandWidget</name>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="342"/> <location filename="../SoundMacroEditor.cpp" line="314"/>
<source>Change %1</source> <source>Change %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -146,6 +146,41 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </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> <context>
<name>KeymapControls</name> <name>KeymapControls</name>
<message> <message>
@ -283,6 +318,14 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>ListingDeleteButton</name>
<message>
<location filename="../EditorWidget.cpp" line="177"/>
<source>Delete this SoundMacro</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>MIDIFileDelegate</name> <name>MIDIFileDelegate</name>
<message> <message>
@ -322,7 +365,6 @@
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../MainWindow.ui" line="14"/> <location filename="../MainWindow.ui" line="14"/>
<location filename="../MainWindow.cpp" line="194"/>
<source>Amuse</source> <source>Amuse</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -517,269 +559,284 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="79"/> <location filename="../MainWindow.cpp" line="81"/>
<source>Clear Recent Projects</source> <source>Clear Recent Projects</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="85"/> <location filename="../MainWindow.cpp" line="87"/>
<source>Quit</source> <source>Quit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="202"/> <location filename="../MainWindow.cpp" line="203"/>
<source>Amuse [%1/%2/%3]</source> <source>Amuse[*]</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="207"/> <location filename="../MainWindow.cpp" line="211"/>
<source>Amuse [%1]</source> <source>%1/%2/%3[*] - Amuse</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="238"/> <location filename="../MainWindow.cpp" line="216"/>
<location filename="../MainWindow.cpp" line="637"/> <source>%1[*] - Amuse</source>
<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>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="244"/> <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> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="245"/> <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> <source>Directory does not exist</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="248"/> <location filename="../MainWindow.cpp" line="254"/>
<source>__amuse_test__</source> <source>__amuse_test__</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>The directory at &apos;%1&apos; must be writable for the Amuse editor: %2</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="255"/> <location filename="../MainWindow.cpp" line="261"/>
<source>Unable to write to directory</source> <source>Unable to write to directory</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="304"/> <location filename="../MainWindow.cpp" line="310"/>
<source>No Audio Devices Found</source> <source>No Audio Devices Found</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="327"/> <location filename="../MainWindow.cpp" line="333"/>
<source>No MIDI Devices Found</source> <source>No MIDI Devices Found</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="383"/> <location filename="../MainWindow.cpp" line="389"/>
<source>SUSTAIN</source> <source>SUSTAIN</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>New Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>The directory at &apos;%1&apos; does not exist.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="644"/> <location filename="../MainWindow.cpp" line="690"/>
<source>Bad Directory</source> <source>Bad Directory</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="659"/> <location filename="../MainWindow.cpp" line="705"/>
<source>Opening</source> <source>Opening</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="659"/> <location filename="../MainWindow.cpp" line="705"/>
<location filename="../MainWindow.cpp" line="738"/> <location filename="../MainWindow.cpp" line="788"/>
<location filename="../MainWindow.cpp" line="822"/> <location filename="../MainWindow.cpp" line="872"/>
<location filename="../MainWindow.cpp" line="867"/> <location filename="../MainWindow.cpp" line="917"/>
<source>Scanning Project</source> <source>Scanning Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="671"/> <location filename="../MainWindow.cpp" line="717"/>
<source>Opening %1</source> <source>Opening %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="684"/> <location filename="../MainWindow.cpp" line="730"/>
<source>Open Project</source> <source>Open Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="738"/> <location filename="../MainWindow.cpp" line="788"/>
<source>Reloading Samples</source> <source>Reloading Samples</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="750"/> <location filename="../MainWindow.cpp" line="800"/>
<source>Scanning %1</source> <source>Scanning %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="760"/> <location filename="../MainWindow.cpp" line="810"/>
<source>Import Project</source> <source>Import Project</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>The file at &apos;%1&apos; could not be interpreted as a MusyX container.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="771"/> <location filename="../MainWindow.cpp" line="821"/>
<source>Unsupported MusyX Container</source> <source>Unsupported MusyX Container</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="776"/> <location filename="../MainWindow.cpp" line="826"/>
<source>Sample Import Mode</source> <source>Sample Import Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <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> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="781"/> <location filename="../MainWindow.cpp" line="831"/>
<source>Import Compressed</source> <source>Import Compressed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="781"/> <location filename="../MainWindow.cpp" line="831"/>
<source>Import WAVs</source> <source>Import WAVs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="781"/> <location filename="../MainWindow.cpp" line="831"/>
<source>Import Both</source> <source>Import Both</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="797"/> <location filename="../MainWindow.cpp" line="847"/>
<source>Raw Import Mode</source> <source>Raw Import Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>Would you like to scan for all MusyX group files in this directory?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="808"/> <location filename="../MainWindow.cpp" line="858"/>
<source>Project Name</source> <source>Project Name</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="808"/> <location filename="../MainWindow.cpp" line="858"/>
<source>What should this project be named?</source> <source>What should this project be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="822"/> <location filename="../MainWindow.cpp" line="872"/>
<location filename="../MainWindow.cpp" line="867"/> <location filename="../MainWindow.cpp" line="917"/>
<source>Importing</source> <source>Importing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="834"/> <location filename="../MainWindow.cpp" line="884"/>
<location filename="../MainWindow.cpp" line="876"/> <location filename="../MainWindow.cpp" line="926"/>
<source>Importing %1</source> <source>Importing %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="892"/> <location filename="../MainWindow.cpp" line="942"/>
<source>Import Songs</source> <source>Import Songs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="994"/> <location filename="../MainWindow.cpp" line="1023"/>
<source>New Subproject</source> <source>New Subproject</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1010"/> <location filename="../MainWindow.cpp" line="1039"/>
<source>New SFX Group</source> <source>New SFX Group</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>What should the new SFX group in %1 be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1029"/> <location filename="../MainWindow.cpp" line="1058"/>
<source>New Song Group</source> <source>New Song Group</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>What should the new Song group in %1 be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1071"/> <location filename="../MainWindow.cpp" line="1100"/>
<source>New ADSR</source> <source>New ADSR</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>What should the new ADSR in %1 be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1090"/> <location filename="../MainWindow.cpp" line="1119"/>
<source>New Curve</source> <source>New Curve</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>What should the new Curve in %1 be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1109"/> <location filename="../MainWindow.cpp" line="1138"/>
<source>New Keymap</source> <source>New Keymap</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>What should the new Keymap in %1 be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1128"/> <location filename="../MainWindow.cpp" line="1157"/>
<source>New Layers</source> <source>New Layers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>What should the new Layers in %1 be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="995"/> <location filename="../MainWindow.cpp" line="1024"/>
<source>What should this subproject be named?</source> <source>What should this subproject be named?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -950,17 +1007,17 @@
<context> <context>
<name>PageObjectProxyModel</name> <name>PageObjectProxyModel</name>
<message> <message>
<location filename="../ProjectModel.cpp" line="239"/> <location filename="../ProjectModel.cpp" line="241"/>
<source>SoundMacros:</source> <source>SoundMacros:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="241"/> <location filename="../ProjectModel.cpp" line="243"/>
<source>Keymaps:</source> <source>Keymaps:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="243"/> <location filename="../ProjectModel.cpp" line="245"/>
<source>Layers:</source> <source>Layers:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -997,188 +1054,188 @@
<context> <context>
<name>ProjectModel</name> <name>ProjectModel</name>
<message> <message>
<location filename="../ProjectModel.cpp" line="566"/> <location filename="../ProjectModel.cpp" line="601"/>
<source>Sound Macros</source> <source>Sound Macros</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="585"/> <location filename="../ProjectModel.cpp" line="620"/>
<source>ADSRs</source> <source>ADSRs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="596"/> <location filename="../ProjectModel.cpp" line="631"/>
<source>Curves</source> <source>Curves</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="608"/> <location filename="../ProjectModel.cpp" line="643"/>
<source>Keymaps</source> <source>Keymaps</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="615"/> <location filename="../ProjectModel.cpp" line="650"/>
<source>Layers</source> <source>Layers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="622"/> <location filename="../ProjectModel.cpp" line="657"/>
<source>Samples</source> <source>Samples</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="887"/> <location filename="../ProjectModel.cpp" line="922"/>
<source>Subproject Conflict</source> <source>Subproject Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="887"/> <location filename="../ProjectModel.cpp" line="922"/>
<source>The subproject %1 is already defined</source> <source>The subproject %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="892"/> <location filename="../ProjectModel.cpp" line="927"/>
<source>Add Subproject %1</source> <source>Add Subproject %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="942"/> <location filename="../ProjectModel.cpp" line="977"/>
<source>Sound Group Conflict</source> <source>Sound Group Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="942"/> <location filename="../ProjectModel.cpp" line="977"/>
<location filename="../ProjectModel.cpp" line="967"/> <location filename="../ProjectModel.cpp" line="1002"/>
<source>The group %1 is already defined</source> <source>The group %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="946"/> <location filename="../ProjectModel.cpp" line="981"/>
<source>Add Sound Group %1</source> <source>Add Sound Group %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="967"/> <location filename="../ProjectModel.cpp" line="1002"/>
<source>Song Group Conflict</source> <source>Song Group Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="971"/> <location filename="../ProjectModel.cpp" line="1006"/>
<source>Add Song Group %1</source> <source>Add Song Group %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1052"/> <location filename="../ProjectModel.cpp" line="1087"/>
<source>Sound Macro Conflict</source> <source>Sound Macro Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1052"/> <location filename="../ProjectModel.cpp" line="1087"/>
<source>The macro %1 is already defined</source> <source>The macro %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1062"/> <location filename="../ProjectModel.cpp" line="1097"/>
<source>Add Sound Macro %1</source> <source>Add Sound Macro %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1083"/> <location filename="../ProjectModel.cpp" line="1118"/>
<source>ADSR Conflict</source> <source>ADSR Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1083"/> <location filename="../ProjectModel.cpp" line="1118"/>
<source>The ADSR %1 is already defined</source> <source>The ADSR %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1089"/> <location filename="../ProjectModel.cpp" line="1124"/>
<source>Add ADSR %1</source> <source>Add ADSR %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1110"/> <location filename="../ProjectModel.cpp" line="1145"/>
<source>Curve Conflict</source> <source>Curve Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1110"/> <location filename="../ProjectModel.cpp" line="1145"/>
<source>The Curve %1 is already defined</source> <source>The Curve %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1116"/> <location filename="../ProjectModel.cpp" line="1151"/>
<source>Add Curve %1</source> <source>Add Curve %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1137"/> <location filename="../ProjectModel.cpp" line="1172"/>
<source>Keymap Conflict</source> <source>Keymap Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1137"/> <location filename="../ProjectModel.cpp" line="1172"/>
<source>The Keymap %1 is already defined</source> <source>The Keymap %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1142"/> <location filename="../ProjectModel.cpp" line="1177"/>
<source>Add Keymap %1</source> <source>Add Keymap %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1163"/> <location filename="../ProjectModel.cpp" line="1198"/>
<source>Layers Conflict</source> <source>Layers Conflict</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1163"/> <location filename="../ProjectModel.cpp" line="1198"/>
<source>Layers %1 is already defined</source> <source>Layers %1 is already defined</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1168"/> <location filename="../ProjectModel.cpp" line="1203"/>
<source>Add Layers %1</source> <source>Add Layers %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1182"/> <location filename="../ProjectModel.cpp" line="1217"/>
<source>Delete Subproject %1</source> <source>Delete Subproject %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1185"/> <location filename="../ProjectModel.cpp" line="1220"/>
<source>Delete SongGroup %1</source> <source>Delete SongGroup %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1188"/> <location filename="../ProjectModel.cpp" line="1223"/>
<source>Delete SFXGroup %1</source> <source>Delete SFXGroup %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1191"/> <location filename="../ProjectModel.cpp" line="1226"/>
<source>Delete SoundMacro %1</source> <source>Delete SoundMacro %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1194"/> <location filename="../ProjectModel.cpp" line="1229"/>
<source>Delete ADSR %1</source> <source>Delete ADSR %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1197"/> <location filename="../ProjectModel.cpp" line="1232"/>
<source>Delete Curve %1</source> <source>Delete Curve %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1200"/> <location filename="../ProjectModel.cpp" line="1235"/>
<source>Delete Keymap %1</source> <source>Delete Keymap %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ProjectModel.cpp" line="1203"/> <location filename="../ProjectModel.cpp" line="1238"/>
<source>Delete Layers %1</source> <source>Delete Layers %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -1480,72 +1537,72 @@
<context> <context>
<name>SoundMacroCatalogue</name> <name>SoundMacroCatalogue</name>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="969"/> <location filename="../SoundMacroEditor.cpp" line="941"/>
<source>Control</source> <source>Control</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="970"/> <location filename="../SoundMacroEditor.cpp" line="942"/>
<source>Pitch</source> <source>Pitch</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="971"/> <location filename="../SoundMacroEditor.cpp" line="943"/>
<source>Sample</source> <source>Sample</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="972"/> <location filename="../SoundMacroEditor.cpp" line="944"/>
<source>Setup</source> <source>Setup</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="973"/> <location filename="../SoundMacroEditor.cpp" line="945"/>
<source>Special</source> <source>Special</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="974"/> <location filename="../SoundMacroEditor.cpp" line="946"/>
<source>Structure</source> <source>Structure</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="975"/> <location filename="../SoundMacroEditor.cpp" line="947"/>
<source>Volume</source> <source>Volume</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="980"/> <location filename="../SoundMacroEditor.cpp" line="952"/>
<source>Commands to control the voice</source> <source>Commands to control the voice</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="981"/> <location filename="../SoundMacroEditor.cpp" line="953"/>
<source>Commands to control the voice&apos;s pitch</source> <source>Commands to control the voice&apos;s pitch</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>Commands to control the voice&apos;s sample playback</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <source>Commands to setup the voice&apos;s mixing process</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="984"/> <location filename="../SoundMacroEditor.cpp" line="956"/>
<source>Miscellaneous commands</source> <source>Miscellaneous commands</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="985"/> <location filename="../SoundMacroEditor.cpp" line="957"/>
<source>Commands to control macro branching</source> <source>Commands to control macro branching</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="986"/> <location filename="../SoundMacroEditor.cpp" line="958"/>
<source>Commands to control the voice&apos;s volume</source> <source>Commands to control the voice&apos;s volume</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -1558,28 +1615,20 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>SoundMacroDeleteButton</name>
<message>
<location filename="../SoundMacroEditor.cpp" line="145"/>
<source>Delete this SoundMacro</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>SoundMacroListing</name> <name>SoundMacroListing</name>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="668"/> <location filename="../SoundMacroEditor.cpp" line="640"/>
<source>Reorder %1</source> <source>Reorder %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="800"/> <location filename="../SoundMacroEditor.cpp" line="772"/>
<source>Insert %1</source> <source>Insert %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../SoundMacroEditor.cpp" line="853"/> <location filename="../SoundMacroEditor.cpp" line="825"/>
<source>Delete %1</source> <source>Delete %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -1587,11 +1636,29 @@
<context> <context>
<name>StatusBarWidget</name> <name>StatusBarWidget</name>
<message> <message>
<location filename="../StatusBarWidget.hpp" line="26"/> <location filename="../StatusBarWidget.cpp" line="16"/>
<source>Immediately kill active voices</source> <source>Immediately kill active voices</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </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> <context>
<name>TargetButton</name> <name>TargetButton</name>
<message> <message>

View File

@ -29,6 +29,11 @@
<file>IconAdd.svg</file> <file>IconAdd.svg</file>
<file>IconRemove.svg</file> <file>IconRemove.svg</file>
<file>IconStop.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>
<qresource prefix="/bg"> <qresource prefix="/bg">
<file>FaceGrey.svg</file> <file>FaceGrey.svg</file>

View File

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

View File

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

View File

@ -69,6 +69,7 @@ public:
x3c_delay[chanIdx] = delay; x3c_delay[chanIdx] = delay;
m_dirty = true; m_dirty = true;
} }
uint32_t getChanDelay(int chanIdx) const { return x3c_delay[chanIdx]; }
void setFeedback(uint32_t feedback) void setFeedback(uint32_t feedback)
{ {
@ -84,6 +85,7 @@ public:
x48_feedback[chanIdx] = feedback; x48_feedback[chanIdx] = feedback;
m_dirty = true; m_dirty = true;
} }
uint32_t getChanFeedback(int chanIdx) const { return x48_feedback[chanIdx]; }
void setOutput(uint32_t output) void setOutput(uint32_t output)
{ {
@ -99,6 +101,7 @@ public:
x54_output[chanIdx] = output; x54_output[chanIdx] = output;
m_dirty = true; m_dirty = true;
} }
uint32_t getChanOutput(int chanIdx) const { return x54_output[chanIdx]; }
void setParams(const EffectDelayInfo& info) void setParams(const EffectDelayInfo& info)
{ {
@ -134,6 +137,8 @@ public:
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } 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); x140_x1c8_coloration = clamp(0.f, coloration, 1.f);
m_dirty = true; m_dirty = true;
} }
float getColoration() const { return x140_x1c8_coloration; }
void setMix(float mix) void setMix(float mix)
{ {
x144_x1cc_mix = clamp(0.f, mix, 1.f); x144_x1cc_mix = clamp(0.f, mix, 1.f);
m_dirty = true; m_dirty = true;
} }
float getMix() const { return x144_x1cc_mix; }
void setTime(float time) void setTime(float time)
{ {
x148_x1d0_time = clamp(0.01f, time, 10.f); x148_x1d0_time = clamp(0.01f, time, 10.f);
m_dirty = true; m_dirty = true;
} }
float getTime() const { return x148_x1d0_time; }
void setDamping(float damping) void setDamping(float damping)
{ {
x14c_x1d4_damping = clamp(0.f, damping, 1.f); x14c_x1d4_damping = clamp(0.f, damping, 1.f);
m_dirty = true; m_dirty = true;
} }
float getDamping() const { return x14c_x1d4_damping; }
void setPreDelay(float preDelay) void setPreDelay(float preDelay)
{ {
x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f); x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f);
m_dirty = true; m_dirty = true;
} }
float getPreDelay() const { return x150_x1d8_preDelay; }
void setParams(const EffectReverbStdInfo& info) void setParams(const EffectReverbStdInfo& info)
{ {
@ -136,6 +141,7 @@ public:
x1dc_crosstalk = clamp(0.f, crosstalk, 1.f); x1dc_crosstalk = clamp(0.f, crosstalk, 1.f);
m_dirty = true; m_dirty = true;
} }
float getCrosstalk() const { return x1dc_crosstalk; }
void setParams(const EffectReverbHiInfo& info) void setParams(const EffectReverbHiInfo& info)
{ {
@ -174,6 +180,8 @@ public:
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
EffectType Isa() const { return EffectType::ReverbStd; }
}; };
/** High-quality 3-stage reverb with per-channel low-pass and crosstalk */ /** 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 applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
EffectType Isa() const { return EffectType::ReverbHi; }
}; };
} }

View File

@ -29,34 +29,39 @@ class Submix
public: public:
Submix(Engine& engine); Submix(Engine& engine);
/** Add new effect to effect stack and assume ownership */ /** Construct new effect */
template <class T, class... Args> template <class T, class... Args>
T& makeEffect(Args... args) std::unique_ptr<EffectBaseTypeless> _makeEffect(Args... args)
{ {
switch (m_backendSubmix->getSampleFormat()) switch (m_backendSubmix->getSampleFormat())
{ {
case SubmixFormat::Int16: case SubmixFormat::Int16:
{ {
using ImpType = typename T::template ImpType<int16_t>; using ImpType = typename T::template ImpType<int16_t>;
m_effectStack.emplace_back(new ImpType(args..., m_backendSubmix->getSampleRate())); return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
return static_cast<ImpType&>(*m_effectStack.back());
} }
case SubmixFormat::Int32: case SubmixFormat::Int32:
default: default:
{ {
using ImpType = typename T::template ImpType<int32_t>; using ImpType = typename T::template ImpType<int32_t>;
m_effectStack.emplace_back(new ImpType(args..., m_backendSubmix->getSampleRate())); return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
return static_cast<ImpType&>(*m_effectStack.back());
} }
case SubmixFormat::Float: case SubmixFormat::Float:
{ {
using ImpType = typename T::template ImpType<float>; using ImpType = typename T::template ImpType<float>;
m_effectStack.emplace_back(new ImpType(args..., m_backendSubmix->getSampleRate())); return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
return static_cast<ImpType&>(*m_effectStack.back());
} }
} }
} }
/** 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 */ /** Add new chorus effect to effect stack and assume ownership */
EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period); EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
@ -101,6 +106,8 @@ public:
void resetOutputSampleRate(double sampleRate); void resetOutputSampleRate(double sampleRate);
Engine& getEngine() { return m_root; } 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::CmdTrapEvent;
friend class SoundMacro::CmdUntrapEvent; friend class SoundMacro::CmdUntrapEvent;
friend class SoundMacro::CmdGetMessage; 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; } 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 */ 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_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 */ 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 */ VoiceState m_voxState = VoiceState::Dead; /**< Current high-level state of voice */
bool m_sustained = false; /**< Sustain pedal pressed for this 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 */ 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_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */
bool m_needsSlew = false; /**< next _setTotalPitch will be slewed */ 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 */ Envelope m_volAdsr; /**< Volume envelope */
double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */ 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 _macroKeyOff();
void _macroSampleEnd(); void _macroSampleEnd();
void _procSamplePre(int16_t& samp); void _procSamplePre(int16_t& samp);
VolumeCache m_masterCache;
template <typename T> template <typename T>
T _procSampleMaster(double time, T samp); T _procSampleMaster(double time, T samp);
VolumeCache m_auxACache;
template <typename T> template <typename T>
T _procSampleAuxA(double time, T samp); T _procSampleAuxA(double time, T samp);
VolumeCache m_auxBCache;
template <typename T> template <typename T>
T _procSampleAuxB(double time, T samp); T _procSampleAuxB(double time, T samp);
void _setTotalPitch(int32_t cents, bool slew); 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,6 +80,7 @@ void type##DNA<DNAE>::_write(athena::io::YAMLDocWriter& w) \
if (id.id == 0xffff) \ if (id.id == 0xffff) \
return; \ return; \
std::string_view name = type::CurNameDB->resolveNameFromId(id); \ std::string_view name = type::CurNameDB->resolveNameFromId(id); \
if (!name.empty()) \
w.writeString(nullptr, name); \ w.writeString(nullptr, name); \
} \ } \
template <athena::Endian DNAE> \ template <athena::Endian DNAE> \
@ -188,16 +189,19 @@ void PageObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w)
if (id.id & 0x8000) if (id.id & 0x8000)
{ {
std::string_view name = LayersId::CurNameDB->resolveNameFromId(id); std::string_view name = LayersId::CurNameDB->resolveNameFromId(id);
if (!name.empty())
w.writeString(nullptr, name); w.writeString(nullptr, name);
} }
else if (id.id & 0x4000) else if (id.id & 0x4000)
{ {
std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id); std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id);
if (!name.empty())
w.writeString(nullptr, name); w.writeString(nullptr, name);
} }
else else
{ {
std::string_view name = SoundMacroId::CurNameDB->resolveNameFromId(id); std::string_view name = SoundMacroId::CurNameDB->resolveNameFromId(id);
if (!name.empty())
w.writeString(nullptr, name); w.writeString(nullptr, name);
} }
} }

View File

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

View File

@ -7,12 +7,27 @@
#include "amuse/Engine.hpp" #include "amuse/Engine.hpp"
#include "amuse/DSPCodec.hpp" #include "amuse/DSPCodec.hpp"
#include "amuse/N64MusyXCodec.hpp" #include "amuse/N64MusyXCodec.hpp"
#include "amuse/VolumeTable.hpp"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
namespace amuse 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() void Voice::_destroy()
{ {
Entity::_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); float l = clamp(0.f, m_lastLevel * (1.f - t) + m_nextLevel * t, 1.f);
/* Apply total volume to sample using decibel scale */ /* 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; return;
} }
@ -318,14 +333,14 @@ void Voice::_procSamplePre(int16_t& samp)
m_nextLevel = clamp(0.f, m_nextLevel, 1.f); m_nextLevel = clamp(0.f, m_nextLevel, 1.f);
/* Apply total volume to sample using decibel scale */ /* 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> template <typename T>
T Voice::_procSampleMaster(double time, T samp) 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; 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> 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; 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_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; 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> 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; 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_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; 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) 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)];
}
}