Skip to content

Commit

Permalink
Implement sample caching (#6390)
Browse files Browse the repository at this point in the history
  • Loading branch information
sakertooth committed Jun 8, 2022
1 parent 3964c53 commit 39e1b90
Show file tree
Hide file tree
Showing 9 changed files with 989 additions and 2 deletions.
9 changes: 7 additions & 2 deletions include/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include <QString>
#include <QObject>


#include "lmmsconfig.h"
#include "lmms_export.h"
#include "lmms_basics.h"
Expand All @@ -40,7 +39,7 @@ class PatternStore;
class ProjectJournal;
class Song;
class Ladspa2LMMS;

class SampleBufferCache;

// Note: This class is called 'LmmsCore' instead of 'Engine' because of naming
// conflicts caused by ZynAddSubFX. See https://github.com/LMMS/lmms/issues/2269
Expand Down Expand Up @@ -87,6 +86,11 @@ class LMMS_EXPORT LmmsCore : public QObject
return s_projectJournal;
}

static SampleBufferCache* sampleBufferCache()
{
return s_sampleBufferCache;
}

static bool ignorePluginBlacklist();

#ifdef LMMS_HAVE_LV2
Expand Down Expand Up @@ -143,6 +147,7 @@ class LMMS_EXPORT LmmsCore : public QObject
static AudioEngine *s_audioEngine;
static Mixer * s_mixer;
static Song * s_song;
static SampleBufferCache * s_sampleBufferCache;
static PatternStore * s_patternStore;
static ProjectJournal * s_projectJournal;

Expand Down
115 changes: 115 additions & 0 deletions include/Sample.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Sample.h - a SampleBuffer with its own characteristics
*
* Copyright (c) 2022 sakertooth <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 SAMPLE_H
#define SAMPLE_H

#include <QPainter>
#include <QRect>
#include <memory>
#include <samplerate.h>
#include <string>

#include "Note.h"
#include "SampleBufferCache.h"
#include "SampleBufferV2.h"
#include "lmms_basics.h"

class Sample
{
public:
enum class PlaybackType
{
Regular,
LoopPoints,
PingPong
};

Sample() = default;
Sample(const std::string& strData, const SampleBufferV2::StrDataType dataType);
Sample(const sampleFrame* data, const int numFrames);
explicit Sample(const SampleBufferV2* buffer);
explicit Sample(const int numFrames);
Sample(const Sample& other);
Sample(Sample&& other);

Sample& operator=(Sample other);
friend void swap(Sample& first, Sample& second);

bool play(sampleFrame* dst, const int numFrames, const float freq);
void visualize(QPainter& painter, const QRect& drawingRect, const int fromFrame = 0, const int toFrame = 0);

std::string sampleFile() const;
std::shared_ptr<const SampleBufferV2> sampleBuffer() const;
int sampleRate() const;
float amplification() const;
float frequency() const;
bool reversed() const;
bool varyingPitch() const;
int interpolationMode() const;
int startFrame() const;
int endFrame() const;
int loopStartFrame() const;
int loopEndFrame() const;
int frameIndex() const;
int numFrames() const;
PlaybackType playback() const;

void setSampleData(const std::string& str, const SampleBufferV2::StrDataType dataType);
void setSampleBuffer(const SampleBufferV2* buffer);
void setAmplification(const float amplification);
void setFrequency(const float frequency);
void setReversed(const bool reversed);
void setVaryingPitch(const bool varyingPitch);
void setInterpolationMode(const int interpolationMode);
void setStartFrame(const int start);
void setEndFrame(const int end);
void setLoopStartFrame(const int loopStart);
void setLoopEndFrame(const int loopEnd);
void setFrameIndex(const int frameIndex);
void setPlayback(const PlaybackType playback);

void loadAudioFile(const std::string& audioFile);
void loadBase64(const std::string& base64);
void resetMarkers();
int calculateTickLength() const;

private:
std::shared_ptr<const SampleBufferV2> m_sampleBuffer;
float m_amplification = 1.0f;
float m_frequency = DefaultBaseFreq;
bool m_reversed = false;
bool m_varyingPitch = false;
bool m_pingPongBackwards = false;
int m_interpolationMode = SRC_LINEAR;
int m_startFrame = 0;
int m_endFrame = 0;
int m_loopStartFrame = 0;
int m_loopEndFrame = 0;
int m_frameIndex = 0;
PlaybackType m_playback = PlaybackType::Regular;
SRC_STATE* m_resampleState = nullptr;
};

#endif
43 changes: 43 additions & 0 deletions include/SampleBufferCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* SampleBufferCache.h - Used to cache sample buffers
*
* Copyright (c) 2022 sakertooth <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 SAMPLE_BUFFER_CACHE_H
#define SAMPLE_BUFFER_CACHE_H

#include <memory>
#include <string>

#include "SampleBufferV2.h"

class SampleBufferCache
{
public:
std::shared_ptr<const SampleBufferV2> get(const std::string& id);
std::shared_ptr<const SampleBufferV2> add(const std::string& id, const SampleBufferV2* buffer);
bool contains(const std::string& id);
private:
std::unordered_map<std::string, std::weak_ptr<const SampleBufferV2>> m_map;
};

#endif
74 changes: 74 additions & 0 deletions include/SampleBufferV2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SampleBufferV2.h - container class for immutable sample data
*
* Copyright (c) 2022 sakertooth <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 SAMPLE_BUFFER_V2_H
#define SAMPLE_BUFFER_V2_H

#include <filesystem>
#include <memory>
#include <optional>
#include <vector>

#include "AudioEngine.h"
#include "Engine.h"
#include "lmms_basics.h"

class SampleBufferV2
{
public:
enum class StrDataType
{
AudioFile,
Base64
};

SampleBufferV2(const std::string& strData, const StrDataType dataType);
SampleBufferV2(const sampleFrame* data, const int numFrames);
SampleBufferV2(const SampleBufferV2& other) = delete;
SampleBufferV2(SampleBufferV2&& other);
explicit SampleBufferV2(const int numFrames);

SampleBufferV2& operator=(SampleBufferV2& other) = delete;
SampleBufferV2& operator=(SampleBufferV2&& other);

const std::vector<sampleFrame>& sampleData() const;
const std::optional<std::filesystem::path>& filePath() const;
int originalSampleRate() const;

std::string toBase64() const;
int numFrames() const;

private:
void loadFromAudioFile(const std::filesystem::path& audioFilePath);
void loadFromDrumSynthFile(const std::filesystem::path& drumSynthFilePath);
void loadFromBase64(const std::string& base64);
void resample(const int oldSampleRate, const int newSampleRate);

private:
std::vector<sampleFrame> m_sampleData;
std::optional<std::filesystem::path> m_filePath;
int m_originalSampleRate = 0;
};

#endif
3 changes: 3 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ set(LMMS_SRCS
core/RemotePlugin.cpp
core/RenderManager.cpp
core/RingBuffer.cpp
core/Sample.cpp
core/SampleBuffer.cpp
core/SampleBufferCache.cpp
core/SampleBufferV2.cpp
core/SampleClip.cpp
core/SamplePlayHandle.cpp
core/SampleRecordHandle.cpp
Expand Down
6 changes: 6 additions & 0 deletions src/core/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@
#include "Plugin.h"
#include "PresetPreviewPlayHandle.h"
#include "ProjectJournal.h"
#include "SampleBufferCache.h"
#include "Song.h"
#include "BandLimitedWave.h"
#include "Oscillator.h"

float LmmsCore::s_framesPerTick;

AudioEngine* LmmsCore::s_audioEngine = nullptr;
Mixer * LmmsCore::s_mixer = nullptr;
PatternStore * LmmsCore::s_patternStore = nullptr;
SampleBufferCache * LmmsCore::s_sampleBufferCache = nullptr;
Song * LmmsCore::s_song = nullptr;
ProjectJournal * LmmsCore::s_projectJournal = nullptr;
#ifdef LMMS_HAVE_LV2
Expand All @@ -65,6 +68,7 @@ void LmmsCore::init( bool renderOnly )
emit engine->initProgress(tr("Initializing data structures"));
s_projectJournal = new ProjectJournal;
s_audioEngine = new AudioEngine( renderOnly );
s_sampleBufferCache = new SampleBufferCache;
s_song = new Song;
s_mixer = new Mixer;
s_patternStore = new PatternStore;
Expand Down Expand Up @@ -113,6 +117,8 @@ void LmmsCore::destroy()

deleteHelper( &s_song );

deleteHelper( &s_sampleBufferCache );

delete ConfigManager::inst();

// The oscillator FFT plans remain throughout the application lifecycle
Expand Down
Loading

0 comments on commit 39e1b90

Please sign in to comment.