Skip to content

Commit

Permalink
Rebase sample caching branch
Browse files Browse the repository at this point in the history
Remove HandleState

Make SampleBufferV2 a QObject
Connect SampleBufferV2 to a sampleRateChanged slot
Add draft for Sample class

Add support for base64 encoding/decoding

Alter implementation for base64 encoding/decoding

Fix compiler error with Sample.h 'loopEnd'

Add resampling

Add implementation to Sample
* Add Sample to CMakeLists

Add numFrames() function
Add const to sampleFrame* in constructor

Rework SampleBufferCache implementation
Use std::weak_ptr to keep track of buffers instead

Im tired, brush up on implementation

Add play functionality
Add SRC_STATE for resampling when changing pitch
Remove userWaveSample (might add it back in)
General cleanup

Use deleteLater() instead of delete

Add original sample rate
Make numFrames only constructor explicit

Integrate the Sample class with other classes
* SampleClip
* SamplePlayHandle
* SampleClipView
* SampleTrack

Add sample rate functionality
Brush up on implementation

Switch ToolTip::add to setToolTip

Reimplement Sample::play
Cleanup header and source

Cleanup SampleBufferV2 header and source
Store only the original sample rate

Refactor SampleClip

Switch const_cast to delete in removeFromCache

Minor refactoring on SamplePlayHandle
Adjust formatting
Use std::memset instead of memset

Comment out setSampleBuffer
Will fix later

Use loadSample instead of setSampleFile
Add cloning capability for SampleClip
Minor changes in SampleTrack

Reverse SampleClip on load based on attribute

Reset frameIndex for SampleTracks in PatternContainer on play

Add DrumSynth Decoding
Switch to SRC_LINEAR for interpolation when resampling
Formatting adjustments
Assign to m_sampleData when loading from Base64

Set minimum length to 1 bar when loading sample

Revert "Set minimum length to 1 bar when loading sample"

This reverts commit 22cc042.

Add SampleWaveform class

Add SampleWaveform class to Sample
Implement calculateWavform for SampleWaveform
Cleanup

Simplify for loop

Show message box when loading a missing sample
Adjust formatting

Handle missing sample error with collectError
Rename calculateNumTicks to calculateTickLength

Add playblack options to Sample
Rename calculateNumTicks to calculateTickLength
Adjustments to Sample::play

Rewrite SampleWaveform implementation (Draft)
Format SampleClipView

Revert "Rewrite SampleWaveform implementation (Draft)"

This reverts commit 582a90c.

Remove std::unique_ptr comment in Engine

Remove SampleWaveform and restore original visualization code
+ Extra formatting

Make single parameter constructors explicit in Sample

Rename Sample::audioFile to Sample::sampleFile

Simplify SampleBufferCache header

Removing unused sampleRateChanged slot
+ Decouple DrumSynth decoding in loadFromAudioFile

Cleanup SamplePlayHandle

Cleanup SampleClip header

Simplify SampleBufferCache.cpp

Simplify sample access in SampleTrack

Simplify sample access in SampleClipView

Fix bug with false missing sample errors

Rename Sample::audioFile to Sample::sampleFile again
  • Loading branch information
sakertooth committed May 19, 2022
1 parent 3964c53 commit e55dc17
Show file tree
Hide file tree
Showing 18 changed files with 1,322 additions and 387 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
119 changes: 119 additions & 0 deletions include/Sample.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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 <QObject>
#include <QPainter>
#include <QRect>
#include <QString>
#include <memory>
#include <samplerate.h>

#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 QString& strData, SampleBufferV2::StrDataType dataType);
Sample(const sampleFrame* data, const f_cnt_t numFrames);
explicit Sample(const SampleBufferV2* buffer);
explicit Sample(const f_cnt_t numFrames);

Sample(const Sample& other);
Sample& operator=(const Sample& other);

Sample(Sample&& other);
Sample& operator=(Sample&& other);

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

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

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

void loadAudioFile(const QString& audioFile);
void loadBase64(const QString& base64);

void resetMarkers();
int calculateTickLength() const;
QString openSample();

private:
std::shared_ptr<const SampleBufferV2> m_sampleBuffer = nullptr;
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;
f_cnt_t m_startFrame = 0;
f_cnt_t m_endFrame = 0;
f_cnt_t m_loopStartFrame = 0;
f_cnt_t m_loopEndFrame = 0;
f_cnt_t m_frameIndex = 0;
PlaybackType m_playback = PlaybackType::Regular;
SRC_STATE* resampleState = nullptr;
};

#endif
44 changes: 44 additions & 0 deletions include/SampleBufferCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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 <QHash>
#include <QString>
#include <memory>

#include "SampleBufferV2.h"

class SampleBufferCache
{
public:
std::shared_ptr<const SampleBufferV2> get(const QString& id);
std::shared_ptr<const SampleBufferV2> add(const QString& id, const SampleBufferV2* buffer);

private:
QHash<QString, std::weak_ptr<const SampleBufferV2>> m_hash;
};

#endif
78 changes: 78 additions & 0 deletions include/SampleBufferV2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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 "Engine.h"
#include "AudioEngine.h"
#include "lmms_basics.h"

#include <QObject>
#include <QString>
#include <memory>
#include <vector>


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

SampleBufferV2(const QString& strData, StrDataType dataType);
SampleBufferV2(const sampleFrame* data, const f_cnt_t numFrames);
explicit SampleBufferV2(const f_cnt_t numFrames);

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

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

const std::vector<sampleFrame>& sampleData() const;
sample_rate_t originalSampleRate() const;
f_cnt_t numFrames() const;

const QString& filePath() const;
bool hasFilePath() const;

QString toBase64() const;

private:
void loadFromAudioFile(const QString& audioFilePath);
void loadFromDrumSynthFile(const QString& drumSynthFilePath);
void loadFromBase64(const QString& str);
void resample(const sample_rate_t oldSampleRate, const sample_rate_t newSampleRate);

private:
std::vector<sampleFrame> m_sampleData;
sample_rate_t m_originalSampleRate;
QString m_filePath;
};

#endif
55 changes: 19 additions & 36 deletions include/SampleClip.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,72 +21,55 @@
* Boston, MA 02110-1301 USA.
*
*/

#ifndef SAMPLE_CLIP_H
#define SAMPLE_CLIP_H

#include "Clip.h"

class SampleBuffer;

#include "Sample.h"

class SampleClip : public Clip
{
Q_OBJECT
mapPropertyFromModel(bool,isRecord,setRecord,m_recordModel);
public:
SampleClip( Track * _track );
SampleClip( const SampleClip& orig );
virtual ~SampleClip();
mapPropertyFromModel(bool, isRecord, setRecord, m_recordModel);

SampleClip& operator=( const SampleClip& that ) = delete;
public:
explicit SampleClip(Track* _track);
~SampleClip() override;

void changeLength( const TimePos & _length ) override;
const QString & sampleFile() const;
void changeLength(const TimePos& _length) override;
QString sampleFile() const;

void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
inline QString nodeName() const override
{
return "sampleclip";
}
void saveSettings(QDomDocument& _doc, QDomElement& _parent) override;
void loadSettings(const QDomElement& _this) override;

SampleBuffer* sampleBuffer()
{
return m_sampleBuffer;
}
void loadSample(const QString& strData, SampleBufferV2::StrDataType dataType);

QString nodeName() const override;
Sample& sample();
TimePos sampleLength() const;
void setSampleStartFrame( f_cnt_t startFrame );
void setSamplePlayLength( f_cnt_t length );
ClipView * createView( TrackView * _tv ) override;


ClipView* createView(TrackView* _tv) override;

bool isPlaying() const;
void setIsPlaying(bool isPlaying);

std::unique_ptr<SampleClip> clone();

public slots:
void setSampleBuffer( SampleBuffer* sb );
void setSampleFile( const QString & _sf );
void updateLength();
void toggleRecord();
void playbackPositionChanged();
void updateTrackClips();


private:
SampleBuffer* m_sampleBuffer;
Sample m_sample;
BoolModel m_recordModel;
bool m_isPlaying;

friend class SampleClipView;


signals:
void sampleChanged();
void wasReversed();
} ;



};
#endif
Loading

0 comments on commit e55dc17

Please sign in to comment.