gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 16f6de680dde96d2df9f02a7364a984922b5aba7
parent 48caab71162668459f466f404526b59fd688249d
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Fri,  7 Mar 2025 17:39:41 +0100

add ability to export wave as .wav file

Diffstat:
Msource/xtJucePlugin/xtWaveEditor.cpp | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msource/xtJucePlugin/xtWaveEditor.h | 3+++
2 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/source/xtJucePlugin/xtWaveEditor.cpp b/source/xtJucePlugin/xtWaveEditor.cpp @@ -11,12 +11,16 @@ #include "xtEditor.h" +#include "baseLib/filesystem.h" + #include "dsp56kEmu/fastmath.h" #include "jucePluginEditorLib/pluginProcessor.h" #include "juceUiLib/messageBox.h" +#include "synthLib/wavWriter.h" + #include "xtLib/xtState.h" namespace xtJucePlugin @@ -361,6 +365,11 @@ namespace xtJucePlugin menu.addSeparator(); + menu.addItem("Export as .wav", [this] + { + exportAsWav(m_graphData.getSource()); + }); + if (!xt::wave::isReadOnly(m_selectedWave)) { menu.addItem("Save (overwrite " + WaveTreeItem::getWaveName(m_selectedWave) + ')', true, false, [this] @@ -379,4 +388,59 @@ namespace xtJucePlugin menu.showMenuAsync({}); } + + void WaveEditor::exportAsWav(const xt::WaveData& _data) + { + const auto& config = m_editor.getProcessor().getConfig(); + + constexpr const char* configKey = "xt_wav_save_path"; + + const auto path = config.getValue(configKey, {}); + + m_fileChooser = std::make_unique<juce::FileChooser>("Save Wave as .wav", path, "*.wav", true); + + constexpr auto flags = juce::FileBrowserComponent::saveMode | juce::FileBrowserComponent::FileChooserFlags::canSelectFiles; + + auto onFileChosen = [this, _data](const juce::FileChooser& _chooser) + { + if (_chooser.getResults().isEmpty()) + return; + + const auto result = _chooser.getResult(); + getEditor().getProcessor().getConfig().setValue(configKey, result.getParentDirectory().getFullPathName()); + + if (!result.existsAsFile()) + { + exportAsWav(result.getFullPathName().toStdString(), _data); + } + else + { + genericUI::MessageBox::showYesNo(juce::MessageBoxIconType::WarningIcon, "File exists", "Do you want to overwrite the existing file?", + [this, _data, result](const genericUI::MessageBox::Result _result) + { + if (_result == genericUI::MessageBox::Result::Yes) + { + exportAsWav(result.getFullPathName().toStdString(), _data); + } + }); + } + }; + m_fileChooser->launchAsync(flags, onFileChosen); + } + + void WaveEditor::exportAsWav(const std::string& _filename, const xt::WaveData& _data) const + { + synthLib::WavWriter w; + + // 8 bit waves are unsigned + std::array<uint8_t, std::tuple_size_v<xt::WaveData>> data; + for (size_t i=0; i<_data.size(); ++i) + data[i] = static_cast<uint8_t>(_data[i] + 128); + + if (!w.write(_filename, 8, false, 1, 32000, data.data(), sizeof(_data))) + { + const auto productName = getEditor().getProcessor().getProperties().name; + genericUI::MessageBox::showOk(juce::AlertWindow::WarningIcon, productName + " - Error", "Failed to create file\n" + _filename + ".\n\nMake sure that the file is not write protected or opened in another application"); + } + } } diff --git a/source/xtJucePlugin/xtWaveEditor.h b/source/xtJucePlugin/xtWaveEditor.h @@ -61,6 +61,9 @@ namespace xtJucePlugin void openGraphPopupMenu(const Graph& _graph, const juce::MouseEvent& _event); + void exportAsWav(const xt::WaveData& _data); + void exportAsWav(const std::string& _filename, const xt::WaveData& _data) const; + private: // ComponentMovementWatcher void componentVisibilityChanged() override { checkFirstTimeVisible(); }