Remove SampleLoader (#8186)
Removes `SampleLoader`. File dialog functions were moved into `FileDialog`. Creation functions were moved into `SampleBuffer`. --------- Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
This commit is contained in:
@@ -50,6 +50,8 @@ public:
|
||||
const QString &directory = QString(),
|
||||
const QString &filter = QString(),
|
||||
QString *selectedFilter = 0);
|
||||
static QString openAudioFile(const QString& previousFile = "");
|
||||
static QString openWaveformFile(const QString& previousFile = "");
|
||||
void clearSelection();
|
||||
};
|
||||
|
||||
|
||||
@@ -69,11 +69,9 @@ public:
|
||||
|
||||
Sample() = default;
|
||||
|
||||
Sample(const QByteArray& base64, int sampleRate = Engine::audioEngine()->outputSampleRate());
|
||||
Sample(const SampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
|
||||
Sample(const Sample& other);
|
||||
Sample(Sample&& other) noexcept;
|
||||
explicit Sample(const QString& audioFile);
|
||||
explicit Sample(std::shared_ptr<const SampleBuffer> buffer);
|
||||
|
||||
auto operator=(const Sample&) -> Sample&;
|
||||
|
||||
@@ -49,9 +49,7 @@ public:
|
||||
using const_reverse_iterator = std::vector<SampleFrame>::const_reverse_iterator;
|
||||
|
||||
SampleBuffer() = default;
|
||||
explicit SampleBuffer(const QString& audioFile);
|
||||
SampleBuffer(const QString& base64, int sampleRate);
|
||||
SampleBuffer(std::vector<SampleFrame> data, int sampleRate);
|
||||
SampleBuffer(std::vector<SampleFrame> data, int sampleRate, const QString& audioFile = "");
|
||||
SampleBuffer(
|
||||
const SampleFrame* data, size_t numFrames, int sampleRate = Engine::audioEngine()->outputSampleRate());
|
||||
|
||||
@@ -85,6 +83,10 @@ public:
|
||||
|
||||
static auto emptyBuffer() -> std::shared_ptr<const SampleBuffer>;
|
||||
|
||||
static std::shared_ptr<const SampleBuffer> fromFile(const QString& path);
|
||||
static std::shared_ptr<const SampleBuffer> fromBase64(
|
||||
const QString& str, int sampleRate = Engine::audioEngine()->outputSampleRate());
|
||||
|
||||
private:
|
||||
std::vector<SampleFrame> m_data;
|
||||
QString m_audioFile;
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* SampleLoader.h - Load audio and waveform files
|
||||
*
|
||||
* Copyright (c) 2023 saker <sakertooth@gmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LMMS_GUI_SAMPLE_LOADER_H
|
||||
#define LMMS_GUI_SAMPLE_LOADER_H
|
||||
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
#include "SampleBuffer.h"
|
||||
#include "lmms_export.h"
|
||||
|
||||
namespace lmms::gui {
|
||||
class LMMS_EXPORT SampleLoader
|
||||
{
|
||||
public:
|
||||
static QString openAudioFile(const QString& previousFile = "");
|
||||
static QString openWaveformFile(const QString& previousFile = "");
|
||||
static std::shared_ptr<const SampleBuffer> createBufferFromFile(const QString& filePath);
|
||||
static std::shared_ptr<const SampleBuffer> createBufferFromBase64(
|
||||
const QString& base64, int sampleRate = Engine::audioEngine()->outputSampleRate());
|
||||
private:
|
||||
static void displayError(const QString& message);
|
||||
};
|
||||
} // namespace lmms::gui
|
||||
|
||||
#endif // LMMS_GUI_SAMPLE_LOADER_H
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "InstrumentTrack.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Song.h"
|
||||
|
||||
#include "LmmsTypes.h"
|
||||
@@ -225,7 +224,7 @@ void AudioFileProcessor::loadSettings(const QDomElement& elem)
|
||||
}
|
||||
else if (auto sampleData = elem.attribute("sampledata"); !sampleData.isEmpty())
|
||||
{
|
||||
m_sample = Sample(gui::SampleLoader::createBufferFromBase64(sampleData));
|
||||
m_sample = Sample(SampleBuffer::fromBase64(sampleData));
|
||||
}
|
||||
|
||||
m_loopModel.loadSettings(elem, "looped");
|
||||
@@ -319,7 +318,7 @@ void AudioFileProcessor::setAudioFile(const QString& _audio_file, bool _rename)
|
||||
}
|
||||
// else we don't touch the track-name, because the user named it self
|
||||
|
||||
m_sample = Sample(gui::SampleLoader::createBufferFromFile(_audio_file));
|
||||
m_sample = Sample(SampleBuffer::fromFile(_audio_file));
|
||||
loopPointChanged();
|
||||
reverseModelChanged();
|
||||
emit sampleUpdated();
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
#include "ComboBox.h"
|
||||
#include "DataFile.h"
|
||||
#include "FileDialog.h"
|
||||
#include "FontHelper.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Song.h"
|
||||
#include "StringPairDrag.h"
|
||||
#include "Track.h"
|
||||
@@ -257,7 +257,7 @@ void AudioFileProcessorView::sampleUpdated()
|
||||
|
||||
void AudioFileProcessorView::openAudioFile()
|
||||
{
|
||||
QString af = SampleLoader::openAudioFile();
|
||||
QString af = FileDialog::openAudioFile();
|
||||
if (af.isEmpty()) { return; }
|
||||
|
||||
castModel<AudioFileProcessor>()->setAudioFile(af);
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "Engine.h"
|
||||
#include "InstrumentTrack.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "SlicerTView.h"
|
||||
#include "Song.h"
|
||||
#include "embed.h"
|
||||
@@ -307,7 +306,7 @@ std::vector<Note> SlicerT::getMidi()
|
||||
|
||||
void SlicerT::updateFile(QString file)
|
||||
{
|
||||
if (auto buffer = gui::SampleLoader::createBufferFromFile(file)) { m_originalSample = Sample(std::move(buffer)); }
|
||||
if (auto buffer = SampleBuffer::fromFile(file)) { m_originalSample = Sample(std::move(buffer)); }
|
||||
|
||||
findBPM();
|
||||
findSlices();
|
||||
@@ -352,7 +351,7 @@ void SlicerT::loadSettings(const QDomElement& element)
|
||||
{
|
||||
if (QFileInfo(PathUtil::toAbsolute(srcFile)).exists())
|
||||
{
|
||||
auto buffer = gui::SampleLoader::createBufferFromFile(srcFile);
|
||||
auto buffer = SampleBuffer::fromFile(srcFile);
|
||||
m_originalSample = Sample(std::move(buffer));
|
||||
}
|
||||
else
|
||||
@@ -363,7 +362,7 @@ void SlicerT::loadSettings(const QDomElement& element)
|
||||
}
|
||||
else if (auto sampleData = element.attribute("sampledata"); !sampleData.isEmpty())
|
||||
{
|
||||
auto buffer = gui::SampleLoader::createBufferFromBase64(sampleData);
|
||||
auto buffer = SampleBuffer::fromBase64(sampleData);
|
||||
m_originalSample = Sample(std::move(buffer));
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
#include "Clipboard.h"
|
||||
#include "ComboBox.h"
|
||||
#include "DataFile.h"
|
||||
#include "FileDialog.h"
|
||||
#include "InstrumentView.h"
|
||||
#include "Knob.h"
|
||||
#include "LcdSpinBox.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "SlicerT.h"
|
||||
#include "SlicerTWaveform.h"
|
||||
#include "StringPairDrag.h"
|
||||
@@ -158,7 +158,7 @@ void SlicerTView::exportMidi()
|
||||
|
||||
void SlicerTView::openFiles()
|
||||
{
|
||||
const auto audioFile = SampleLoader::openAudioFile();
|
||||
const auto audioFile = FileDialog::openAudioFile();
|
||||
if (audioFile.isEmpty()) { return; }
|
||||
m_slicerTParent->updateFile(audioFile);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "AudioEngine.h"
|
||||
#include "AutomatableButton.h"
|
||||
#include "Engine.h"
|
||||
#include "FileDialog.h"
|
||||
#include "InstrumentTrack.h"
|
||||
#include "Knob.h"
|
||||
#include "NotePlayHandle.h"
|
||||
@@ -37,7 +38,6 @@
|
||||
#include "PathUtil.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Song.h"
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
@@ -136,10 +136,10 @@ OscillatorObject::OscillatorObject( Model * _parent, int _idx ) :
|
||||
|
||||
void OscillatorObject::oscUserDefWaveDblClick()
|
||||
{
|
||||
auto af = gui::SampleLoader::openWaveformFile();
|
||||
auto af = gui::FileDialog::openWaveformFile();
|
||||
if( af != "" )
|
||||
{
|
||||
m_sampleBuffer = gui::SampleLoader::createBufferFromFile(af);
|
||||
m_sampleBuffer = SampleBuffer::fromFile(af);
|
||||
m_userAntiAliasWaveTable = Oscillator::generateAntiAliasUserWaveTable(m_sampleBuffer.get());
|
||||
// TODO:
|
||||
//m_usrWaveBtn->setToolTip(m_sampleBuffer->audioFile());
|
||||
@@ -284,7 +284,7 @@ void TripleOscillator::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
if (QFileInfo(PathUtil::toAbsolute(userWaveFile)).exists())
|
||||
{
|
||||
m_osc[i]->m_sampleBuffer = gui::SampleLoader::createBufferFromFile(userWaveFile);
|
||||
m_osc[i]->m_sampleBuffer = SampleBuffer::fromFile(userWaveFile);
|
||||
m_osc[i]->m_userAntiAliasWaveTable = Oscillator::generateAntiAliasUserWaveTable(m_osc[i]->m_sampleBuffer.get());
|
||||
}
|
||||
else { Engine::getSong()->collectError(QString("%1: %2").arg(tr("Sample not found"), userWaveFile)); }
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "Engine.h"
|
||||
#include "Oscillator.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Song.h"
|
||||
|
||||
namespace lmms
|
||||
@@ -389,7 +388,7 @@ void EnvelopeAndLfoParameters::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
if (QFileInfo(PathUtil::toAbsolute(userWaveFile)).exists())
|
||||
{
|
||||
m_userWave = gui::SampleLoader::createBufferFromFile(_this.attribute("userwavefile"));
|
||||
m_userWave = SampleBuffer::fromFile(_this.attribute("userwavefile"));
|
||||
}
|
||||
else { Engine::getSong()->collectError(QString("%1: %2").arg(tr("Sample not found"), userWaveFile)); }
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "AudioEngine.h"
|
||||
#include "Oscillator.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Song.h"
|
||||
|
||||
namespace lmms
|
||||
@@ -244,7 +243,7 @@ void LfoController::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
if (QFileInfo(PathUtil::toAbsolute(userWaveFile)).exists())
|
||||
{
|
||||
m_userDefSampleBuffer = gui::SampleLoader::createBufferFromFile(_this.attribute("userwavefile"));
|
||||
m_userDefSampleBuffer = SampleBuffer::fromFile(_this.attribute("userwavefile"));
|
||||
}
|
||||
else { Engine::getSong()->collectError(QString("%1: %2").arg(tr("Sample not found"), userWaveFile)); }
|
||||
}
|
||||
|
||||
@@ -26,24 +26,6 @@
|
||||
|
||||
namespace lmms {
|
||||
|
||||
Sample::Sample(const QString& audioFile)
|
||||
: m_buffer(std::make_shared<SampleBuffer>(audioFile))
|
||||
, m_startFrame(0)
|
||||
, m_endFrame(m_buffer->size())
|
||||
, m_loopStartFrame(0)
|
||||
, m_loopEndFrame(m_buffer->size())
|
||||
{
|
||||
}
|
||||
|
||||
Sample::Sample(const QByteArray& base64, int sampleRate)
|
||||
: m_buffer(std::make_shared<SampleBuffer>(base64, sampleRate))
|
||||
, m_startFrame(0)
|
||||
, m_endFrame(m_buffer->size())
|
||||
, m_loopStartFrame(0)
|
||||
, m_loopEndFrame(m_buffer->size())
|
||||
{
|
||||
}
|
||||
|
||||
Sample::Sample(const SampleFrame* data, size_t numFrames, int sampleRate)
|
||||
: m_buffer(std::make_shared<SampleBuffer>(data, numFrames, sampleRate))
|
||||
, m_startFrame(0)
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
*/
|
||||
|
||||
#include "SampleBuffer.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <cstring>
|
||||
|
||||
#include "GuiApplication.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleDecoder.h"
|
||||
|
||||
@@ -36,35 +40,9 @@ SampleBuffer::SampleBuffer(const SampleFrame* data, size_t numFrames, int sample
|
||||
{
|
||||
}
|
||||
|
||||
SampleBuffer::SampleBuffer(const QString& audioFile)
|
||||
{
|
||||
if (audioFile.isEmpty()) { throw std::runtime_error{"Failure loading audio file: Audio file path is empty."}; }
|
||||
const auto absolutePath = PathUtil::toAbsolute(audioFile);
|
||||
|
||||
if (auto decodedResult = SampleDecoder::decode(absolutePath))
|
||||
{
|
||||
auto& [data, sampleRate] = *decodedResult;
|
||||
m_data = std::move(data);
|
||||
m_sampleRate = sampleRate;
|
||||
m_audioFile = PathUtil::toShortestRelative(audioFile);
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error{
|
||||
"Failed to decode audio file: Either the audio codec is unsupported, or the file is corrupted."};
|
||||
}
|
||||
|
||||
SampleBuffer::SampleBuffer(const QString& base64, int sampleRate)
|
||||
: m_sampleRate(sampleRate)
|
||||
{
|
||||
// TODO: Replace with non-Qt equivalent
|
||||
const auto bytes = QByteArray::fromBase64(base64.toUtf8());
|
||||
m_data.resize(bytes.size() / sizeof(SampleFrame));
|
||||
std::memcpy(reinterpret_cast<char*>(m_data.data()), bytes, m_data.size() * sizeof(SampleFrame));
|
||||
}
|
||||
|
||||
SampleBuffer::SampleBuffer(std::vector<SampleFrame> data, int sampleRate)
|
||||
SampleBuffer::SampleBuffer(std::vector<SampleFrame> data, int sampleRate, const QString& audioFile)
|
||||
: m_data(std::move(data))
|
||||
, m_audioFile(audioFile)
|
||||
, m_sampleRate(sampleRate)
|
||||
{
|
||||
}
|
||||
@@ -92,4 +70,64 @@ auto SampleBuffer::emptyBuffer() -> std::shared_ptr<const SampleBuffer>
|
||||
return s_buffer;
|
||||
}
|
||||
|
||||
std::shared_ptr<const SampleBuffer> SampleBuffer::fromFile(const QString& filePath)
|
||||
{
|
||||
if (filePath.isEmpty()) { return SampleBuffer::emptyBuffer(); }
|
||||
|
||||
const auto absolutePath = PathUtil::toAbsolute(filePath);
|
||||
const auto storedPath = PathUtil::toShortestRelative(filePath);
|
||||
|
||||
auto result = SampleDecoder::decode(absolutePath);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// TODO: Improve error handling. We dont always want to show a message box on failure when there is a GUI (e.g.
|
||||
// when loading the project), and this function also shouldn't be concerned with handling the error.
|
||||
if (gui::getGUI())
|
||||
{
|
||||
QMessageBox::warning(nullptr, QObject::tr("Failed to load sample"),
|
||||
QObject::tr("The sample may be corrupted or unsupported."));
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << QObject::tr(
|
||||
"Failed to load sample at path %1, the file may not exist, be corrupted, or is unsupported.")
|
||||
.arg(absolutePath);
|
||||
}
|
||||
|
||||
return SampleBuffer::emptyBuffer();
|
||||
}
|
||||
|
||||
auto& [data, sampleRate] = *result;
|
||||
return std::make_shared<SampleBuffer>(std::move(data), sampleRate, storedPath);
|
||||
}
|
||||
|
||||
std::shared_ptr<const SampleBuffer> SampleBuffer::fromBase64(const QString& str, int sampleRate)
|
||||
{
|
||||
if (str.isEmpty()) { return SampleBuffer::emptyBuffer(); }
|
||||
|
||||
const auto bytes = QByteArray::fromBase64(str.toUtf8());
|
||||
|
||||
if (bytes.size() % sizeof(SampleFrame) != 0)
|
||||
{
|
||||
// TODO: Improve error handling. We dont always want to show a message box on failure when there is a GUI (e.g.
|
||||
// when loading the project), and this function also shouldn't be concerned with handling the error.
|
||||
if (gui::getGUI())
|
||||
{
|
||||
QMessageBox::warning(
|
||||
nullptr, QObject::tr("Failed to load sample"), QObject::tr("The sample size is invalid."));
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << QObject::tr("Failed to load Base64 sample, invalid size");
|
||||
}
|
||||
|
||||
return SampleBuffer::emptyBuffer();
|
||||
}
|
||||
|
||||
auto data = std::vector<SampleFrame>(bytes.size() / sizeof(SampleFrame));
|
||||
std::memcpy(reinterpret_cast<char*>(data.data()), bytes, bytes.size());
|
||||
return std::make_shared<SampleBuffer>(std::move(data), sampleRate);
|
||||
}
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include "PathUtil.h"
|
||||
#include "SampleClipView.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "SampleTrack.h"
|
||||
#include "Song.h"
|
||||
|
||||
@@ -158,7 +157,7 @@ void SampleClip::setSampleFile(const QString& sf)
|
||||
setStartTimeOffset(0);
|
||||
if (!sf.isEmpty())
|
||||
{
|
||||
m_sample = Sample(gui::SampleLoader::createBufferFromFile(sf));
|
||||
m_sample = Sample(SampleBuffer::fromFile(sf));
|
||||
updateLength();
|
||||
}
|
||||
else
|
||||
@@ -321,7 +320,7 @@ void SampleClip::loadSettings( const QDomElement & _this )
|
||||
auto sampleRate = _this.hasAttribute("sample_rate") ? _this.attribute("sample_rate").toInt() :
|
||||
Engine::audioEngine()->outputSampleRate();
|
||||
|
||||
auto buffer = gui::SampleLoader::createBufferFromBase64(_this.attribute("data"), sampleRate);
|
||||
auto buffer = SampleBuffer::fromBase64(_this.attribute("data"), sampleRate);
|
||||
m_sample = Sample(std::move(buffer));
|
||||
}
|
||||
changeLength( _this.attribute( "len" ).toInt() );
|
||||
|
||||
@@ -56,7 +56,7 @@ SamplePlayHandle::SamplePlayHandle(Sample* sample, bool ownAudioBusHandle) :
|
||||
|
||||
|
||||
SamplePlayHandle::SamplePlayHandle( const QString& sampleFile ) :
|
||||
SamplePlayHandle(new Sample(sampleFile), true)
|
||||
SamplePlayHandle(new Sample(SampleBuffer::fromFile(sampleFile)), true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ SET(LMMS_SRCS
|
||||
gui/PluginBrowser.cpp
|
||||
gui/ProjectNotes.cpp
|
||||
gui/RowTableView.cpp
|
||||
gui/SampleLoader.cpp
|
||||
gui/SampleTrackWindow.cpp
|
||||
gui/SampleThumbnail.cpp
|
||||
gui/SendButtonIndicator.cpp
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
#include "PresetPreviewPlayHandle.h"
|
||||
#include "Sample.h"
|
||||
#include "SampleClip.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "SamplePlayHandle.h"
|
||||
#include "SampleTrack.h"
|
||||
#include "Song.h"
|
||||
@@ -767,7 +766,7 @@ void FileBrowserTreeWidget::previewFileItem(FileItem* file)
|
||||
embed::getIconPixmap("sample_file", 24, 24), 0);
|
||||
// TODO: this can be removed once we do this outside the event thread
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
if (auto buffer = SampleLoader::createBufferFromFile(fileName))
|
||||
if (auto buffer = SampleBuffer::fromFile(fileName))
|
||||
{
|
||||
auto s = new SamplePlayHandle(new lmms::Sample{std::move(buffer)});
|
||||
s->setDoneMayReturnTrue(false);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "FileDialog.h"
|
||||
#include "embed.h"
|
||||
|
||||
|
||||
@@ -32,7 +33,6 @@
|
||||
#include "Knob.h"
|
||||
#include "TempoSyncKnob.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "SampleLoader.h"
|
||||
|
||||
namespace lmms::gui
|
||||
{
|
||||
@@ -208,12 +208,12 @@ LfoControllerDialog::~LfoControllerDialog()
|
||||
|
||||
void LfoControllerDialog::askUserDefWave()
|
||||
{
|
||||
const auto fileName = SampleLoader::openWaveformFile();
|
||||
const auto fileName = FileDialog::openWaveformFile();
|
||||
if (fileName.isEmpty()) { return; }
|
||||
|
||||
auto lfoModel = dynamic_cast<LfoController*>(model());
|
||||
auto& buffer = lfoModel->m_userDefSampleBuffer;
|
||||
buffer = SampleLoader::createBufferFromFile(fileName);
|
||||
buffer = SampleBuffer::fromFile(fileName);
|
||||
|
||||
m_userWaveBtn->setToolTip(buffer->audioFile());
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* SampleLoader.cpp - Static functions that open audio files
|
||||
*
|
||||
* Copyright (c) 2023 saker <sakertooth@gmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "SampleLoader.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <memory>
|
||||
|
||||
#include "ConfigManager.h"
|
||||
#include "FileDialog.h"
|
||||
#include "GuiApplication.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleDecoder.h"
|
||||
|
||||
namespace lmms::gui {
|
||||
QString SampleLoader::openAudioFile(const QString& previousFile)
|
||||
{
|
||||
auto openFileDialog = FileDialog(nullptr, QObject::tr("Open audio file"));
|
||||
auto dir = !previousFile.isEmpty() ? QFileInfo(PathUtil::toAbsolute(previousFile)).absolutePath() : ConfigManager::inst()->userSamplesDir();
|
||||
|
||||
// change dir to position of previously opened file
|
||||
openFileDialog.setDirectory(dir);
|
||||
openFileDialog.setFileMode(FileDialog::ExistingFiles);
|
||||
|
||||
// set filters
|
||||
auto fileTypes = QStringList{};
|
||||
auto allFileTypes = QStringList{};
|
||||
auto nameFilters = QStringList{};
|
||||
const auto& supportedAudioTypes = SampleDecoder::supportedAudioTypes();
|
||||
|
||||
for (const auto& audioType : supportedAudioTypes)
|
||||
{
|
||||
const auto name = QString::fromStdString(audioType.name);
|
||||
const auto extension = QString::fromStdString(audioType.extension);
|
||||
const auto displayExtension = QString{"*.%1"}.arg(extension);
|
||||
fileTypes.append(QString{"%1 (%2)"}.arg(FileDialog::tr("%1 files").arg(name), displayExtension));
|
||||
allFileTypes.append(displayExtension);
|
||||
}
|
||||
|
||||
nameFilters.append(QString{"%1 (%2)"}.arg(FileDialog::tr("All audio files"), allFileTypes.join(" ")));
|
||||
nameFilters.append(fileTypes);
|
||||
nameFilters.append(QString("%1 (*)").arg(FileDialog::tr("Other files")));
|
||||
|
||||
openFileDialog.setNameFilters(nameFilters);
|
||||
|
||||
if (!previousFile.isEmpty())
|
||||
{
|
||||
// select previously opened file
|
||||
openFileDialog.selectFile(QFileInfo{previousFile}.fileName());
|
||||
}
|
||||
|
||||
if (openFileDialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
if (openFileDialog.selectedFiles().isEmpty()) { return ""; }
|
||||
|
||||
return PathUtil::toShortestRelative(openFileDialog.selectedFiles()[0]);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
QString SampleLoader::openWaveformFile(const QString& previousFile)
|
||||
{
|
||||
return openAudioFile(
|
||||
previousFile.isEmpty() ? ConfigManager::inst()->factorySamplesDir() + "waveforms/10saw.flac" : previousFile);
|
||||
}
|
||||
|
||||
std::shared_ptr<const SampleBuffer> SampleLoader::createBufferFromFile(const QString& filePath)
|
||||
{
|
||||
if (filePath.isEmpty()) { return SampleBuffer::emptyBuffer(); }
|
||||
|
||||
try
|
||||
{
|
||||
return std::make_shared<SampleBuffer>(filePath);
|
||||
}
|
||||
catch (const std::runtime_error& error)
|
||||
{
|
||||
if (getGUI()) { displayError(QString::fromStdString(error.what())); }
|
||||
return SampleBuffer::emptyBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const SampleBuffer> SampleLoader::createBufferFromBase64(const QString& base64, int sampleRate)
|
||||
{
|
||||
if (base64.isEmpty()) { return SampleBuffer::emptyBuffer(); }
|
||||
|
||||
try
|
||||
{
|
||||
return std::make_shared<SampleBuffer>(base64, sampleRate);
|
||||
}
|
||||
catch (const std::runtime_error& error)
|
||||
{
|
||||
if (getGUI()) { displayError(QString::fromStdString(error.what())); }
|
||||
return SampleBuffer::emptyBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void SampleLoader::displayError(const QString& message)
|
||||
{
|
||||
QMessageBox::critical(nullptr, QObject::tr("Error loading sample"), message);
|
||||
}
|
||||
|
||||
} // namespace lmms::gui
|
||||
@@ -28,12 +28,12 @@
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
|
||||
#include "FileDialog.h"
|
||||
#include "GuiApplication.h"
|
||||
#include "AutomationEditor.h"
|
||||
#include "embed.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleClip.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "SampleThumbnail.h"
|
||||
#include "Song.h"
|
||||
#include "StringPairDrag.h"
|
||||
@@ -129,7 +129,7 @@ void SampleClipView::dropEvent( QDropEvent * _de )
|
||||
}
|
||||
else if( StringPairDrag::decodeKey( _de ) == "sampledata" )
|
||||
{
|
||||
m_clip->setSampleBuffer(SampleLoader::createBufferFromBase64(StringPairDrag::decodeValue(_de)));
|
||||
m_clip->setSampleBuffer(SampleBuffer::fromBase64(StringPairDrag::decodeValue(_de)));
|
||||
m_clip->updateLength();
|
||||
update();
|
||||
_de->accept();
|
||||
@@ -188,13 +188,13 @@ void SampleClipView::mouseDoubleClickEvent( QMouseEvent * )
|
||||
{
|
||||
if (m_trackView->trackContainerView()->knifeMode()) { return; }
|
||||
|
||||
const QString selectedAudioFile = SampleLoader::openAudioFile();
|
||||
const QString selectedAudioFile = FileDialog::openAudioFile();
|
||||
|
||||
if (selectedAudioFile.isEmpty()) { return; }
|
||||
|
||||
if (!m_clip->hasSampleFileLoaded(selectedAudioFile))
|
||||
{
|
||||
auto sampleBuffer = SampleLoader::createBufferFromFile(selectedAudioFile);
|
||||
auto sampleBuffer = SampleBuffer::fromFile(selectedAudioFile);
|
||||
if (sampleBuffer != SampleBuffer::emptyBuffer())
|
||||
{
|
||||
m_clip->setSampleBuffer(sampleBuffer);
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "EnvelopeGraph.h"
|
||||
#include "LfoGraph.h"
|
||||
#include "EnvelopeAndLfoParameters.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Knob.h"
|
||||
#include "LedCheckBox.h"
|
||||
#include "DataFile.h"
|
||||
@@ -242,7 +241,7 @@ void EnvelopeAndLfoView::dropEvent( QDropEvent * _de )
|
||||
QString value = StringPairDrag::decodeValue( _de );
|
||||
if( type == "samplefile" )
|
||||
{
|
||||
m_params->m_userWave = SampleLoader::createBufferFromFile(value);
|
||||
m_params->m_userWave = SampleBuffer::fromFile(value);
|
||||
m_userLfoBtn->model()->setValue( true );
|
||||
m_params->m_lfoWaveModel.setValue(static_cast<int>(EnvelopeAndLfoParameters::LfoShape::UserDefinedWave));
|
||||
_de->accept();
|
||||
@@ -254,7 +253,7 @@ void EnvelopeAndLfoView::dropEvent( QDropEvent * _de )
|
||||
auto file = dataFile.content().
|
||||
firstChildElement().firstChildElement().
|
||||
firstChildElement().attribute("src");
|
||||
m_params->m_userWave = SampleLoader::createBufferFromFile(file);
|
||||
m_params->m_userWave = SampleBuffer::fromFile(file);
|
||||
m_userLfoBtn->model()->setValue( true );
|
||||
m_params->m_lfoWaveModel.setValue(static_cast<int>(EnvelopeAndLfoParameters::LfoShape::UserDefinedWave));
|
||||
_de->accept();
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include <QStringList>
|
||||
|
||||
#include "ConfigManager.h"
|
||||
#include "PathUtil.h"
|
||||
#include "SampleDecoder.h"
|
||||
#include "FileDialog.h"
|
||||
|
||||
namespace lmms::gui
|
||||
@@ -142,5 +144,57 @@ void FileDialog::clearSelection()
|
||||
view->clearSelection();
|
||||
}
|
||||
|
||||
QString FileDialog::openAudioFile(const QString& previousFile)
|
||||
{
|
||||
auto openFileDialog = FileDialog(nullptr, tr("Open audio file"));
|
||||
auto dir = !previousFile.isEmpty() ? QFileInfo(PathUtil::toAbsolute(previousFile)).absolutePath() : ConfigManager::inst()->userSamplesDir();
|
||||
|
||||
} // namespace lmms::gui
|
||||
// change dir to position of previously opened file
|
||||
openFileDialog.setDirectory(dir);
|
||||
openFileDialog.setFileMode(QFileDialog::ExistingFiles);
|
||||
|
||||
// set filters
|
||||
auto fileTypes = QStringList{};
|
||||
auto allFileTypes = QStringList{};
|
||||
auto nameFilters = QStringList{};
|
||||
const auto& supportedAudioTypes = SampleDecoder::supportedAudioTypes();
|
||||
|
||||
for (const auto& audioType : supportedAudioTypes)
|
||||
{
|
||||
const auto name = QString::fromStdString(audioType.name);
|
||||
const auto extension = QString::fromStdString(audioType.extension);
|
||||
const auto displayExtension = QString{"*.%1"}.arg(extension);
|
||||
fileTypes.append(QString{"%1 (%2)"}.arg(tr("%1 files").arg(name), displayExtension));
|
||||
allFileTypes.append(displayExtension);
|
||||
}
|
||||
|
||||
nameFilters.append(QString{"%1 (%2)"}.arg(tr("All audio files"), allFileTypes.join(" ")));
|
||||
nameFilters.append(fileTypes);
|
||||
nameFilters.append(QString("%1 (*)").arg(tr("Other files")));
|
||||
|
||||
openFileDialog.setNameFilters(nameFilters);
|
||||
|
||||
if (!previousFile.isEmpty())
|
||||
{
|
||||
// select previously opened file
|
||||
openFileDialog.selectFile(QFileInfo{previousFile}.fileName());
|
||||
}
|
||||
|
||||
if (openFileDialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
if (openFileDialog.selectedFiles().isEmpty()) { return ""; }
|
||||
|
||||
return PathUtil::toShortestRelative(openFileDialog.selectedFiles()[0]);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
QString FileDialog::openWaveformFile(const QString& previousFile)
|
||||
{
|
||||
return openAudioFile(
|
||||
previousFile.isEmpty() ? ConfigManager::inst()->factorySamplesDir() + "waveforms/10saw.flac" : previousFile);
|
||||
}
|
||||
|
||||
|
||||
} // namespace lmms::gui
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "Graph.h"
|
||||
#include "DeprecationHelper.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "FileDialog.h"
|
||||
#include "StringPairDrag.h"
|
||||
#include "Oscillator.h"
|
||||
|
||||
@@ -585,10 +585,10 @@ void graphModel::setWaveToNoise()
|
||||
|
||||
QString graphModel::setWaveToUser()
|
||||
{
|
||||
QString fileName = gui::SampleLoader::openWaveformFile();
|
||||
QString fileName = gui::FileDialog::openWaveformFile();
|
||||
if( fileName.isEmpty() == false )
|
||||
{
|
||||
auto sampleBuffer = gui::SampleLoader::createBufferFromFile(fileName);
|
||||
auto sampleBuffer = SampleBuffer::fromFile(fileName);
|
||||
for( int i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = Oscillator::userWaveSample(sampleBuffer.get(), i / static_cast<float>(length()));
|
||||
|
||||
Reference in New Issue
Block a user