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:
Sotonye Atemie
2026-01-04 21:18:37 -05:00
committed by GitHub
parent 11b4a9bddc
commit ed0f288c8a
23 changed files with 159 additions and 264 deletions

View File

@@ -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();
};

View File

@@ -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&;

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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);
}

View File

@@ -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)); }

View File

@@ -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)); }
}

View File

@@ -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)); }
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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() );

View File

@@ -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)
{
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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();

View File

@@ -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

View File

@@ -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()));