Integrate changes into SampleClip/SamplePlayHandle

This commit is contained in:
sakertooth
2023-08-27 20:21:08 -04:00
parent 7245b1abc4
commit d3ecea38f3
10 changed files with 65 additions and 67 deletions

View File

@@ -25,7 +25,9 @@
#ifndef LMMS_SAMPLE_CLIP_H
#define LMMS_SAMPLE_CLIP_H
#include <memory>
#include "Clip.h"
#include "Sample.h"
namespace lmms
{
@@ -52,7 +54,7 @@ public:
SampleClip& operator=( const SampleClip& that ) = delete;
void changeLength( const TimePos & _length ) override;
const QString & sampleFile() const;
QString sampleFile() const;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
@@ -61,9 +63,9 @@ public:
return "sampleclip";
}
SampleBuffer* sampleBuffer()
std::shared_ptr<Sample> sample()
{
return m_sampleBuffer;
return m_sample;
}
TimePos sampleLength() const;
@@ -76,7 +78,7 @@ public:
void setIsPlaying(bool isPlaying);
public slots:
void setSampleBuffer( lmms::SampleBuffer* sb );
void setSampleBuffer(SampleBuffer2* sb);
void setSampleFile( const QString & _sf );
void updateLength();
void toggleRecord();
@@ -85,7 +87,7 @@ public slots:
private:
SampleBuffer* m_sampleBuffer;
std::shared_ptr<Sample> m_sample = std::make_shared<Sample>();
BoolModel m_recordModel;
bool m_isPlaying;

View File

@@ -38,7 +38,7 @@ public:
static QString openAudioFile(const QString& previousFile = "");
static QString openWaveformFile(const QString& previousFile = "");
static std::unique_ptr<SampleBuffer2> createBufferFromFile(const QString& filePath);
static std::unique_ptr<SampleBuffer2> createBufferFromBase64(const QString& base64, int sampleRate);
static std::unique_ptr<SampleBuffer2> createBufferFromBase64(const QString& base64, int sampleRate = Engine::audioEngine()->processingSampleRate());
private:
static void displayError(const QString& message);
};

View File

@@ -26,6 +26,7 @@
#ifndef LMMS_SAMPLE_PLAY_HANDLE_H
#define LMMS_SAMPLE_PLAY_HANDLE_H
#include "Sample.h"
#include "SampleBuffer.h"
#include "AutomatableModel.h"
#include "PlayHandle.h"
@@ -43,7 +44,7 @@ class AudioPort;
class LMMS_EXPORT SamplePlayHandle : public PlayHandle
{
public:
SamplePlayHandle( SampleBuffer* sampleBuffer , bool ownAudioPort = true );
SamplePlayHandle(std::shared_ptr<const Sample> sampleBuffer , bool ownAudioPort = true);
SamplePlayHandle( const QString& sampleFile );
SamplePlayHandle( SampleClip* clip );
~SamplePlayHandle() override;
@@ -81,11 +82,11 @@ public:
private:
SampleBuffer * m_sampleBuffer;
std::shared_ptr<const Sample> m_sample;
bool m_doneMayReturnTrue;
f_cnt_t m_frame;
SampleBuffer::handleState m_state;
Sample::PlaybackState m_state;
const bool m_ownAudioPort;

View File

@@ -29,6 +29,7 @@
#include <QPair>
#include "PlayHandle.h"
#include "SampleBuffer2.h"
#include "TimePos.h"
namespace lmms
@@ -53,7 +54,7 @@ public:
bool isFromTrack( const Track * _track ) const override;
f_cnt_t framesRecorded() const;
void createSampleBuffer( SampleBuffer * * _sample_buf );
void createSampleBuffer(SampleBuffer2** _sample_buf);
private:

View File

@@ -28,6 +28,7 @@
#include "SampleBuffer.h"
#include "SampleClipView.h"
#include "SampleLoader.h"
#include "SampleTrack.h"
#include "TimeLineWidget.h"
@@ -38,7 +39,6 @@ namespace lmms
SampleClip::SampleClip( Track * _track ) :
Clip( _track ),
m_sampleBuffer( new SampleBuffer ),
m_isPlaying( false )
{
saveJournallingState( false );
@@ -90,10 +90,8 @@ SampleClip::SampleClip( Track * _track ) :
SampleClip::SampleClip(const SampleClip& orig) :
SampleClip(orig.getTrack())
{
// TODO: This creates a new SampleBuffer for the new Clip, eating up memory
// & eventually causing performance issues. Letting tracks share buffers
// when they're identical would fix this, but isn't possible right now.
*m_sampleBuffer = *orig.m_sampleBuffer;
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
std::atomic_store(&m_sample, orig.m_sample);
m_isPlaying = orig.m_isPlaying;
}
@@ -107,9 +105,6 @@ SampleClip::~SampleClip()
{
sampletrack->updateClips();
}
Engine::audioEngine()->requestChangeInModel();
sharedObject::unref( m_sampleBuffer );
Engine::audioEngine()->doneChangeInModel();
}
@@ -123,19 +118,18 @@ void SampleClip::changeLength( const TimePos & _length )
const QString & SampleClip::sampleFile() const
QString SampleClip::sampleFile() const
{
return m_sampleBuffer->audioFile();
return m_sample->buffer()->audioFile();
}
void SampleClip::setSampleBuffer( SampleBuffer* sb )
void SampleClip::setSampleBuffer( SampleBuffer2* sb )
{
Engine::audioEngine()->requestChangeInModel();
sharedObject::unref( m_sampleBuffer );
Engine::audioEngine()->doneChangeInModel();
m_sampleBuffer = sb;
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
auto buffer = std::shared_ptr<const SampleBuffer2>(sb);
std::atomic_store(&m_sample, std::make_shared<Sample>(buffer));
updateLength();
emit sampleChanged();
@@ -154,7 +148,9 @@ void SampleClip::setSampleFile( const QString & _sf )
}
else
{ //Otherwise set it to the sample's length
m_sampleBuffer->setAudioFile( _sf );
auto buffer = gui::SampleLoader::createBufferFromFile(_sf);
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
std::atomic_store(&m_sample, std::make_shared<Sample>(std::move(buffer)));
length = sampleLength();
}
changeLength(length);
@@ -225,7 +221,7 @@ void SampleClip::updateLength()
TimePos SampleClip::sampleLength() const
{
return (int)( m_sampleBuffer->frames() / Engine::framesPerTick() );
return static_cast<int>(m_sample->playbackSize() / Engine::framesPerTick());
}
@@ -233,7 +229,7 @@ TimePos SampleClip::sampleLength() const
void SampleClip::setSampleStartFrame(f_cnt_t startFrame)
{
m_sampleBuffer->setStartFrame( startFrame );
m_sample->setStartFrame(startFrame);
}
@@ -241,7 +237,7 @@ void SampleClip::setSampleStartFrame(f_cnt_t startFrame)
void SampleClip::setSamplePlayLength(f_cnt_t length)
{
m_sampleBuffer->setEndFrame( length );
m_sample->setEndFrame(length);
}
@@ -264,15 +260,15 @@ void SampleClip::saveSettings( QDomDocument & _doc, QDomElement & _this )
if( sampleFile() == "" )
{
QString s;
_this.setAttribute( "data", m_sampleBuffer->toBase64( s ) );
_this.setAttribute("data", m_sample->buffer()->toBase64());
}
_this.setAttribute( "sample_rate", m_sampleBuffer->sampleRate());
_this.setAttribute("sample_rate", m_sample->buffer()->sampleRate());
if( usesCustomClipColor() )
{
_this.setAttribute( "color", color().name() );
}
if (m_sampleBuffer->reversed())
if (m_sample->reversed())
{
_this.setAttribute("reversed", "true");
}
@@ -291,11 +287,12 @@ void SampleClip::loadSettings( const QDomElement & _this )
setSampleFile( _this.attribute( "src" ) );
if( sampleFile().isEmpty() && _this.hasAttribute( "data" ) )
{
m_sampleBuffer->loadFromBase64( _this.attribute( "data" ) );
if (_this.hasAttribute("sample_rate"))
{
m_sampleBuffer->setSampleRate(_this.attribute("sample_rate").toInt());
}
auto sampleRate = _this.hasAttribute("sample_rate") ? _this.attribute("sample_rate").toInt() :
Engine::audioEngine()->processingSampleRate();
auto buffer = gui::SampleLoader::createBufferFromBase64(_this.attribute("data"), sampleRate);
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
std::atomic_store(&m_sample, std::make_shared<Sample>(std::move(buffer)));
}
changeLength( _this.attribute( "len" ).toInt() );
setMuted( _this.attribute( "muted" ).toInt() );
@@ -313,7 +310,7 @@ void SampleClip::loadSettings( const QDomElement & _this )
if(_this.hasAttribute("reversed"))
{
m_sampleBuffer->setReversed(true);
m_sample->setReversed(true);
emit wasReversed(); // tell SampleClipView to update the view
}
}

View File

@@ -35,9 +35,9 @@ namespace lmms
{
SamplePlayHandle::SamplePlayHandle( SampleBuffer* sampleBuffer , bool ownAudioPort ) :
SamplePlayHandle::SamplePlayHandle(std::shared_ptr<const Sample> sample, bool ownAudioPort) :
PlayHandle( Type::SamplePlayHandle ),
m_sampleBuffer( sharedObject::ref( sampleBuffer ) ),
m_sample(sample),
m_doneMayReturnTrue( true ),
m_frame( 0 ),
m_ownAudioPort( ownAudioPort ),
@@ -56,16 +56,15 @@ SamplePlayHandle::SamplePlayHandle( SampleBuffer* sampleBuffer , bool ownAudioPo
SamplePlayHandle::SamplePlayHandle( const QString& sampleFile ) :
SamplePlayHandle( new SampleBuffer( sampleFile ) , true)
SamplePlayHandle(std::make_shared<const Sample>(sampleFile), true)
{
sharedObject::unref( m_sampleBuffer );
}
SamplePlayHandle::SamplePlayHandle( SampleClip* clip ) :
SamplePlayHandle( clip->sampleBuffer() , false)
SamplePlayHandle(clip->sample(), false)
{
m_track = clip->getTrack();
setAudioPort( ( (SampleTrack *)clip->getTrack() )->audioPort() );
@@ -76,7 +75,6 @@ SamplePlayHandle::SamplePlayHandle( SampleClip* clip ) :
SamplePlayHandle::~SamplePlayHandle()
{
sharedObject::unref( m_sampleBuffer );
if( m_ownAudioPort )
{
delete audioPort();
@@ -110,12 +108,12 @@ void SamplePlayHandle::play( sampleFrame * buffer )
if( !( m_track && m_track->isMuted() )
&& !(m_patternTrack && m_patternTrack->isMuted()))
{
/* StereoVolumeVector v =
/* StereoVolumeVector v
{ { m_volumeModel->value() / DefaultVolume,
m_volumeModel->value() / DefaultVolume } };*/
// SamplePlayHandle always plays the sample at its original pitch;
// it is used only for previews, SampleTracks and the metronome.
if (!m_sampleBuffer->play(workingBuffer, &m_state, frames, DefaultBaseFreq))
if (!m_sample->play(workingBuffer, &m_state, frames, DefaultBaseFreq))
{
memset(workingBuffer, 0, frames * sizeof(sampleFrame));
}
@@ -145,8 +143,8 @@ bool SamplePlayHandle::isFromTrack( const Track * _track ) const
f_cnt_t SamplePlayHandle::totalFrames() const
{
return ( m_sampleBuffer->endFrame() - m_sampleBuffer->startFrame() ) *
( Engine::audioEngine()->processingSampleRate() / m_sampleBuffer->sampleRate() );
return (m_sample->endFrame() - m_sample->startFrame()) *
(static_cast<float>(Engine::audioEngine()->processingSampleRate()) / m_sample->buffer()->sampleRate());
}

View File

@@ -53,9 +53,9 @@ SampleRecordHandle::~SampleRecordHandle()
{
if( !m_buffers.empty() )
{
SampleBuffer* sb;
SampleBuffer2* sb;
createSampleBuffer( &sb );
m_clip->setSampleBuffer( sb );
m_clip->setSampleBuffer(sb);
}
while( !m_buffers.empty() )
@@ -111,7 +111,7 @@ f_cnt_t SampleRecordHandle::framesRecorded() const
void SampleRecordHandle::createSampleBuffer( SampleBuffer** sampleBuf )
void SampleRecordHandle::createSampleBuffer(SampleBuffer2** sampleBuf)
{
const f_cnt_t frames = framesRecorded();
// create buffer to store all recorded buffers in
@@ -130,8 +130,7 @@ void SampleRecordHandle::createSampleBuffer( SampleBuffer** sampleBuf )
data_ptr += ( *it ).second;
}
// create according sample-buffer out of big buffer
*sampleBuf = new SampleBuffer( data, frames );
( *sampleBuf)->setSampleRate( Engine::audioEngine()->inputSampleRate() );
*sampleBuf = new SampleBuffer2(data, frames, Engine::audioEngine()->inputSampleRate());
delete[] data;
}

View File

@@ -95,7 +95,7 @@ std::unique_ptr<SampleBuffer2> SampleLoader::createBufferFromFile(const QString&
catch (const std::runtime_error& error)
{
displayError(QString::fromStdString(error.what()));
return nullptr;
return std::make_unique<SampleBuffer2>();
}
}
@@ -108,7 +108,7 @@ std::unique_ptr<SampleBuffer2> SampleLoader::createBufferFromBase64(const QStrin
catch (const std::runtime_error& error)
{
displayError(QString::fromStdString(error.what()));
return nullptr;
return std::make_unique<SampleBuffer2>();
}
}

View File

@@ -28,6 +28,7 @@
#include <QMenu>
#include <QPainter>
#include "SampleLoader.h"
#include "embed.h"
#include "PathUtil.h"
#include "SampleBuffer.h"
@@ -60,8 +61,8 @@ void SampleClipView::updateSample()
update();
// set tooltip to filename so that user can see what sample this
// sample-clip contains
setToolTip(m_clip->m_sampleBuffer->audioFile() != "" ?
PathUtil::toAbsolute(m_clip->m_sampleBuffer->audioFile()) :
setToolTip(m_clip->m_sample->buffer()->audioFile() != "" ?
PathUtil::toAbsolute(m_clip->m_sample->buffer()->audioFile()) :
tr( "Double-click to open sample" ) );
}
@@ -112,8 +113,7 @@ void SampleClipView::dropEvent( QDropEvent * _de )
}
else if( StringPairDrag::decodeKey( _de ) == "sampledata" )
{
m_clip->m_sampleBuffer->loadFromBase64(
StringPairDrag::decodeValue( _de ) );
auto buffer = SampleLoader::createBufferFromBase64(StringPairDrag::decodeValue(_de));
m_clip->updateLength();
update();
_de->accept();
@@ -171,12 +171,12 @@ void SampleClipView::mouseReleaseEvent(QMouseEvent *_me)
void SampleClipView::mouseDoubleClickEvent( QMouseEvent * )
{
QString af = m_clip->m_sampleBuffer->openAudioFile();
QString af = gui::SampleLoader::openAudioFile();
if ( af.isEmpty() ) {} //Don't do anything if no file is loaded
else if ( af == m_clip->m_sampleBuffer->audioFile() )
else if (af == m_clip->m_sample->buffer()->audioFile())
{ //Instead of reloading the existing file, just reset the size
int length = (int) ( m_clip->m_sampleBuffer->frames() / Engine::framesPerTick() );
int length = static_cast<int>(m_clip->m_sample->buffer()->size() / Engine::framesPerTick());
m_clip->changeLength(length);
}
else
@@ -263,9 +263,9 @@ void SampleClipView::paintEvent( QPaintEvent * pe )
float offset = m_clip->startTimeOffset() / ticksPerBar * pixelsPerBar();
QRect r = QRect( offset, spacing,
qMax( static_cast<int>( m_clip->sampleLength() * ppb / ticksPerBar ), 1 ), rect().bottom() - 2 * spacing );
m_clip->m_sampleBuffer->visualize( p, r, pe->rect() );
m_clip->m_sample->visualize(p, r);
QString name = PathUtil::cleanName(m_clip->m_sampleBuffer->audioFile());
QString name = PathUtil::cleanName(m_clip->m_sample->buffer()->audioFile());
paintTextLabel(name, p);
// disable antialiasing for borders, since its not needed
@@ -318,7 +318,7 @@ void SampleClipView::paintEvent( QPaintEvent * pe )
void SampleClipView::reverseSample()
{
m_clip->sampleBuffer()->setReversed(!m_clip->sampleBuffer()->reversed());
m_clip->sample()->setReversed(!m_clip->sample()->reversed());
Engine::getSong()->setModified();
update();
}

View File

@@ -108,10 +108,10 @@ bool SampleTrack::play( const TimePos & _start, const fpp_t _frames,
{
if( sClip->isPlaying() == false && _start >= (sClip->startPosition() + sClip->startTimeOffset()) )
{
auto bufferFramesPerTick = Engine::framesPerTick (sClip->sampleBuffer ()->sampleRate ());
auto bufferFramesPerTick = Engine::framesPerTick(sClip->sample()->buffer()->sampleRate());
f_cnt_t sampleStart = bufferFramesPerTick * ( _start - sClip->startPosition() - sClip->startTimeOffset() );
f_cnt_t clipFrameLength = bufferFramesPerTick * ( sClip->endPosition() - sClip->startPosition() - sClip->startTimeOffset() );
f_cnt_t sampleBufferLength = sClip->sampleBuffer()->frames();
f_cnt_t sampleBufferLength = sClip->sample()->buffer()->size();
//if the Clip smaller than the sample length we play only until Clip end
//else we play the sample to the end but nothing more
f_cnt_t samplePlayLength = clipFrameLength > sampleBufferLength ? sampleBufferLength : clipFrameLength;