Integrate changes into SampleClip/SamplePlayHandle
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user