Integrate changes into AudioFileProcessor

This commit is contained in:
sakertooth
2023-08-27 23:12:11 -04:00
parent aca875b0e4
commit 0017f66629
2 changed files with 98 additions and 86 deletions

View File

@@ -27,7 +27,6 @@
#include <QPainter>
#include <QFileInfo>
#include <QDropEvent>
#include <samplerate.h>
#include "AudioEngine.h"
@@ -40,6 +39,7 @@
#include "NotePlayHandle.h"
#include "PathUtil.h"
#include "PixmapButton.h"
#include "SampleLoader.h"
#include "Song.h"
#include "StringPairDrag.h"
#include "Clipboard.h"
@@ -77,7 +77,7 @@ Plugin::Descriptor PLUGIN_EXPORT audiofileprocessor_plugin_descriptor =
AudioFileProcessor::AudioFileProcessor( InstrumentTrack * _instrument_track ) :
Instrument( _instrument_track, &audiofileprocessor_plugin_descriptor ),
m_sampleBuffer(),
m_sample(std::make_shared<Sample>()),
m_ampModel( 100, 0, 500, 1, this, tr( "Amplify" ) ),
m_startPointModel( 0, 0, 1, 0.0000001f, this, tr( "Start of sample" ) ),
m_endPointModel( 1, 0, 1, 0.0000001f, this, tr( "End of sample" ) ),
@@ -125,18 +125,18 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n,
// played.
if( m_stutterModel.value() == true && _n->frequency() < 20.0 )
{
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
m_nextPlayStartPoint = m_sample->startFrame();
m_nextPlayBackwards = false;
return;
}
if( !_n->m_pluginData )
{
if( m_stutterModel.value() == true && m_nextPlayStartPoint >= m_sampleBuffer.endFrame() )
if (m_stutterModel.value() == true && m_nextPlayStartPoint >= m_sample->endFrame())
{
// Restart playing the note if in stutter mode, not in loop mode,
// and we're at the end of the sample.
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
m_nextPlayStartPoint = m_sample->startFrame();
m_nextPlayBackwards = false;
}
// set interpolation mode for libsamplerate
@@ -153,28 +153,29 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n,
srcmode = SRC_SINC_MEDIUM_QUALITY;
break;
}
_n->m_pluginData = new handleState( _n->hasDetuningInfo(), srcmode );
((handleState *)_n->m_pluginData)->setFrameIndex( m_nextPlayStartPoint );
((handleState *)_n->m_pluginData)->setBackwards( m_nextPlayBackwards );
_n->m_pluginData = new Sample::PlaybackState(_n->hasDetuningInfo(), srcmode);
(static_cast<Sample::PlaybackState*>(_n->m_pluginData))->setFrameIndex(m_nextPlayStartPoint);
(static_cast<Sample::PlaybackState*>(_n->m_pluginData))->setBackwards(m_nextPlayBackwards);
// debug code
/* qDebug( "frames %d", m_sampleBuffer.frames() );
qDebug( "startframe %d", m_sampleBuffer.startFrame() );
/* qDebug( "frames %d", m_sample->frames() );
qDebug( "startframe %d", m_sample->startFrame() );
qDebug( "nextPlayStartPoint %d", m_nextPlayStartPoint );*/
}
if( ! _n->isFinished() )
{
if( m_sampleBuffer.play( _working_buffer + offset,
(handleState *)_n->m_pluginData,
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
if (std::atomic_load(&m_sample)->play(_working_buffer + offset,
static_cast<Sample::PlaybackState*>(_n->m_pluginData),
frames, _n->frequency(),
static_cast<SampleBuffer::LoopMode>( m_loopModel.value() ) ) )
static_cast<Sample::Loop>(m_loopModel.value())))
{
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer,
frames + offset, _n );
emit isPlaying( ((handleState *)_n->m_pluginData)->frameIndex() );
emit isPlaying((static_cast<Sample::PlaybackState*>(_n->m_pluginData)->frameIndex()));
}
else
{
@@ -188,8 +189,8 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n,
}
if( m_stutterModel.value() == true )
{
m_nextPlayStartPoint = ((handleState *)_n->m_pluginData)->frameIndex();
m_nextPlayBackwards = ((handleState *)_n->m_pluginData)->isBackwards();
m_nextPlayStartPoint = (static_cast<Sample::PlaybackState*>(_n->m_pluginData))->frameIndex();
m_nextPlayBackwards = (static_cast<Sample::PlaybackState*>(_n->m_pluginData)->isBackwards());
}
}
@@ -198,7 +199,7 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n,
void AudioFileProcessor::deleteNotePluginData( NotePlayHandle * _n )
{
delete (handleState *)_n->m_pluginData;
delete static_cast<Sample::PlaybackState*>(_n->m_pluginData);
}
@@ -206,11 +207,10 @@ void AudioFileProcessor::deleteNotePluginData( NotePlayHandle * _n )
void AudioFileProcessor::saveSettings(QDomDocument& doc, QDomElement& elem)
{
elem.setAttribute("src", m_sampleBuffer.audioFile());
if (m_sampleBuffer.audioFile().isEmpty())
elem.setAttribute("src", m_sample->sampleFile());
if (m_sample->sampleFile().isEmpty())
{
QString s;
elem.setAttribute("sampledata", m_sampleBuffer.toBase64(s));
elem.setAttribute("sampledata", m_sample->toBase64());
}
m_reverseModel.saveSettings(doc, elem, "reversed");
m_loopModel.saveSettings(doc, elem, "looped");
@@ -231,16 +231,18 @@ void AudioFileProcessor::loadSettings(const QDomElement& elem)
{
setAudioFile(elem.attribute("src"), false);
QString absolutePath = PathUtil::toAbsolute(m_sampleBuffer.audioFile());
QString absolutePath = PathUtil::toAbsolute(m_sample->sampleFile());
if (!QFileInfo(absolutePath).exists())
{
QString message = tr("Sample not found: %1").arg(m_sampleBuffer.audioFile());
QString message = tr("Sample not found: %1").arg(m_sample->sampleFile());
Engine::getSong()->collectError(message);
}
}
else if (!elem.attribute("sampledata").isEmpty())
{
m_sampleBuffer.loadFromBase64(elem.attribute("srcdata"));
auto buffer = gui::SampleLoader::createBufferFromBase64(elem.attribute("srcdata"));
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
std::atomic_store(&m_sample, std::make_shared<Sample>(std::move(buffer)));
}
m_loopModel.loadSettings(elem, "looped");
@@ -271,6 +273,7 @@ void AudioFileProcessor::loadSettings(const QDomElement& elem)
}
pointChanged();
emit sampleUpdated();
}
@@ -298,7 +301,7 @@ int AudioFileProcessor::getBeatLen( NotePlayHandle * _n ) const
const float freq_factor = baseFreq / _n->frequency() *
Engine::audioEngine()->processingSampleRate() / Engine::audioEngine()->baseSampleRate();
return static_cast<int>( floorf( ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() ) * freq_factor ) );
return static_cast<int>(floorf((m_sample->endFrame() - m_sample->startFrame()) * freq_factor));
}
@@ -319,16 +322,20 @@ void AudioFileProcessor::setAudioFile( const QString & _audio_file,
// is current channel-name equal to previous-filename??
if( _rename &&
( instrumentTrack()->name() ==
QFileInfo( m_sampleBuffer.audioFile() ).fileName() ||
m_sampleBuffer.audioFile().isEmpty() ) )
QFileInfo(m_sample->sampleFile()).fileName() ||
m_sample->sampleFile().isEmpty()))
{
// then set it to new one
instrumentTrack()->setName( PathUtil::cleanName( _audio_file ) );
}
// else we don't touch the track-name, because the user named it self
m_sampleBuffer.setAudioFile( _audio_file );
auto buffer = gui::SampleLoader::createBufferFromFile(_audio_file);
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
std::atomic_store(&m_sample, std::make_shared<Sample>(std::move(buffer)));
loopPointChanged();
emit sampleUpdated();
}
@@ -336,9 +343,10 @@ void AudioFileProcessor::setAudioFile( const QString & _audio_file,
void AudioFileProcessor::reverseModelChanged()
{
m_sampleBuffer.setReversed( m_reverseModel.value() );
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
m_sample->setReversed(m_reverseModel.value());
m_nextPlayStartPoint = m_sample->startFrame();
m_nextPlayBackwards = false;
emit sampleUpdated();
}
@@ -346,13 +354,14 @@ void AudioFileProcessor::reverseModelChanged()
void AudioFileProcessor::ampModelChanged()
{
m_sampleBuffer.setAmplification( m_ampModel.value() / 100.0f );
m_sample->setAmplification(m_ampModel.value() / 100.0f);
emit sampleUpdated();
}
void AudioFileProcessor::stutterModelChanged()
{
m_nextPlayStartPoint = m_sampleBuffer.startFrame();
m_nextPlayStartPoint = m_sample->startFrame();
m_nextPlayBackwards = false;
}
@@ -421,14 +430,14 @@ void AudioFileProcessor::loopPointChanged()
void AudioFileProcessor::pointChanged()
{
const auto f_start = static_cast<f_cnt_t>(m_startPointModel.value() * m_sampleBuffer.frames());
const auto f_end = static_cast<f_cnt_t>(m_endPointModel.value() * m_sampleBuffer.frames());
const auto f_loop = static_cast<f_cnt_t>(m_loopPointModel.value() * m_sampleBuffer.frames());
const auto f_start = static_cast<f_cnt_t>(m_startPointModel.value() * m_sample->sampleSize());
const auto f_end = static_cast<f_cnt_t>(m_endPointModel.value() * m_sample->sampleSize());
const auto f_loop = static_cast<f_cnt_t>(m_loopPointModel.value() * m_sample->sampleSize());
m_nextPlayStartPoint = f_start;
m_nextPlayBackwards = false;
m_sampleBuffer.setAllPointFrames( f_start, f_end, f_loop, f_end );
m_sample->setAllPointFrames(f_start, f_end, f_loop, f_end);
emit dataChanged();
}
@@ -596,7 +605,7 @@ void AudioFileProcessorView::newWaveView()
delete m_waveView;
m_waveView = 0;
}
m_waveView = new AudioFileProcessorWaveView( this, 245, 75, castModel<AudioFileProcessor>()->m_sampleBuffer );
m_waveView = new AudioFileProcessorWaveView(this, 245, 75, castModel<AudioFileProcessor>()->m_sample.get());
m_waveView->move( 2, 172 );
m_waveView->setKnobs(
dynamic_cast<AudioFileProcessorWaveView::knob *>( m_startKnob ),
@@ -642,7 +651,8 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * )
auto a = castModel<AudioFileProcessor>();
QString file_name = "";
int idx = a->m_sampleBuffer.audioFile().length();
int idx = a->m_sample->sampleFile().length();
p.setFont( pointSize<8>( font() ) );
@@ -653,7 +663,7 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * )
while( idx > 0 &&
fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 210 )
{
file_name = a->m_sampleBuffer.audioFile()[--idx] + file_name;
file_name = a->m_sample->sampleFile()[--idx] + file_name;
}
if( idx > 0 )
@@ -670,6 +680,7 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * )
void AudioFileProcessorView::sampleUpdated()
{
m_waveView->m_sample = castModel<AudioFileProcessor>()->m_sample.get();
m_waveView->updateSampleRange();
m_waveView->update();
update();
@@ -681,7 +692,7 @@ void AudioFileProcessorView::sampleUpdated()
void AudioFileProcessorView::openAudioFile()
{
QString af = castModel<AudioFileProcessor>()->m_sampleBuffer.openAudioFile();
QString af = SampleLoader::openAudioFile();
if (af.isEmpty()) { return; }
castModel<AudioFileProcessor>()->setAudioFile(af);
@@ -695,8 +706,7 @@ void AudioFileProcessorView::openAudioFile()
void AudioFileProcessorView::modelChanged()
{
auto a = castModel<AudioFileProcessor>();
connect( &a->m_sampleBuffer, SIGNAL( sampleUpdated() ),
this, SLOT( sampleUpdated() ) );
connect(a, &AudioFileProcessor::sampleUpdated, this, &AudioFileProcessorView::sampleUpdated);
m_ampKnob->setModel( &a->m_ampModel );
m_startKnob->setModel( &a->m_startPointModel );
m_endKnob->setModel( &a->m_endPointModel );
@@ -713,20 +723,20 @@ void AudioFileProcessorView::modelChanged()
void AudioFileProcessorWaveView::updateSampleRange()
{
if( m_sampleBuffer.frames() > 1 )
if (m_sample->sampleSize() > 1)
{
const f_cnt_t marging = ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() ) * 0.1;
m_from = qMax( 0, m_sampleBuffer.startFrame() - marging );
m_to = qMin( m_sampleBuffer.endFrame() + marging, m_sampleBuffer.frames() );
const f_cnt_t marging = (m_sample->endFrame() - m_sample->startFrame()) * 0.1;
m_from = qMax(0, m_sample->startFrame() - marging);
m_to = qMin(m_sample->endFrame() + marging, m_sample->sampleSize());
}
}
AudioFileProcessorWaveView::AudioFileProcessorWaveView( QWidget * _parent, int _w, int _h, SampleBuffer& buf ) :
AudioFileProcessorWaveView::AudioFileProcessorWaveView(QWidget * _parent, int _w, int _h, Sample* buf) :
QWidget( _parent ),
m_sampleBuffer( buf ),
m_sample(buf),
m_graph( QPixmap( _w - 2 * s_padding, _h - 2 * s_padding ) ),
m_from( 0 ),
m_to( m_sampleBuffer.frames() ),
m_to(m_sample->sampleSize()),
m_last_from( 0 ),
m_last_to( 0 ),
m_last_amp( 0 ),
@@ -874,11 +884,11 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe )
const QRect graph_rect( s_padding, s_padding, width() - 2 * s_padding, height() - 2 * s_padding );
const f_cnt_t frames = m_to - m_from;
m_startFrameX = graph_rect.x() + ( m_sampleBuffer.startFrame() - m_from ) *
m_startFrameX = graph_rect.x() + (m_sample->startFrame() - m_from) *
double( graph_rect.width() ) / frames;
m_endFrameX = graph_rect.x() + ( m_sampleBuffer.endFrame() - m_from ) *
m_endFrameX = graph_rect.x() + (m_sample->endFrame() - m_from) *
double( graph_rect.width() ) / frames;
m_loopFrameX = graph_rect.x() + ( m_sampleBuffer.loopStartFrame() - m_from ) *
m_loopFrameX = graph_rect.x() + (m_sample->loopStartFrame() - m_from) *
double( graph_rect.width() ) / frames;
const int played_width_px = ( m_framesPlayed - m_from ) *
double( graph_rect.width() ) / frames;
@@ -953,7 +963,7 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe )
p.setFont( pointSize<8>( font() ) );
QString length_text;
const int length = m_sampleBuffer.sampleLength();
const int length = m_sample->sampleDuration();
if( length > 20000 )
{
@@ -982,38 +992,38 @@ void AudioFileProcessorWaveView::updateGraph()
{
if( m_to == 1 )
{
m_to = m_sampleBuffer.frames() * 0.7;
m_to = m_sample->sampleSize() * 0.7;
slideSamplePointToFrames( Point::End, m_to * 0.7 );
}
if( m_from > m_sampleBuffer.startFrame() )
if (m_from > m_sample->startFrame())
{
m_from = m_sampleBuffer.startFrame();
m_from = m_sample->startFrame();
}
if( m_to < m_sampleBuffer.endFrame() )
if (m_to < m_sample->endFrame())
{
m_to = m_sampleBuffer.endFrame();
m_to = m_sample->endFrame();
}
if( m_sampleBuffer.reversed() != m_reversed )
if (m_sample->reversed() != m_reversed)
{
reverse();
}
else if( m_last_from == m_from && m_last_to == m_to && m_sampleBuffer.amplification() == m_last_amp )
else if (m_last_from == m_from && m_last_to == m_to && m_sample->amplification() == m_last_amp)
{
return;
}
m_last_from = m_from;
m_last_to = m_to;
m_last_amp = m_sampleBuffer.amplification();
m_last_amp = m_sample->amplification();
m_graph.fill( Qt::transparent );
QPainter p( &m_graph );
p.setPen( QColor( 255, 255, 255 ) );
m_sampleBuffer.visualize(
m_sample->visualize(
p,
QRect( 0, 0, m_graph.width(), m_graph.height() ),
m_from, m_to
@@ -1025,9 +1035,9 @@ void AudioFileProcessorWaveView::updateGraph()
void AudioFileProcessorWaveView::zoom( const bool _out )
{
const f_cnt_t start = m_sampleBuffer.startFrame();
const f_cnt_t end = m_sampleBuffer.endFrame();
const f_cnt_t frames = m_sampleBuffer.frames();
const f_cnt_t start = m_sample->startFrame();
const f_cnt_t end = m_sample->endFrame();
const f_cnt_t frames = m_sample->sampleSize();
const f_cnt_t d_from = start - m_from;
const f_cnt_t d_to = m_to - end;
@@ -1060,7 +1070,7 @@ void AudioFileProcessorWaveView::zoom( const bool _out )
);
}
if( double( new_to - new_from ) / m_sampleBuffer.sampleRate() > 0.05 )
if (static_cast<double>(new_to - new_from) / m_sample->sampleRate() > 0.05)
{
m_from = new_from;
m_to = new_to;
@@ -1079,8 +1089,8 @@ void AudioFileProcessorWaveView::slide( int _px )
step = -step;
}
f_cnt_t step_from = qBound( 0, m_from + step, m_sampleBuffer.frames() ) - m_from;
f_cnt_t step_to = qBound( m_from + 1, m_to + step, m_sampleBuffer.frames() ) - m_to;
f_cnt_t step_from = qBound(0, m_from + step, m_sample->sampleSize()) - m_from;
f_cnt_t step_to = qBound(m_from + 1, m_to + step, m_sample->sampleSize()) - m_to;
step = qAbs( step_from ) < qAbs( step_to ) ? step_from : step_to;
@@ -1141,7 +1151,7 @@ void AudioFileProcessorWaveView::slideSamplePointByFrames( Point _point, f_cnt_t
}
else
{
const double v = static_cast<double>( _frames ) / m_sampleBuffer.frames();
const double v = static_cast<double>(_frames) / m_sample->sampleSize();
if( _slide_to )
{
a_knob->slideTo( v );
@@ -1158,11 +1168,11 @@ void AudioFileProcessorWaveView::slideSamplePointByFrames( Point _point, f_cnt_t
void AudioFileProcessorWaveView::slideSampleByFrames( f_cnt_t _frames )
{
if( m_sampleBuffer.frames() <= 1 )
if (m_sample->sampleSize() <= 1)
{
return;
}
const double v = static_cast<double>( _frames ) / m_sampleBuffer.frames();
const double v = static_cast<double>(_frames) / m_sample->sampleSize();
if( m_startKnob ) {
m_startKnob->slideBy( v, false );
}
@@ -1180,14 +1190,14 @@ void AudioFileProcessorWaveView::slideSampleByFrames( f_cnt_t _frames )
void AudioFileProcessorWaveView::reverse()
{
slideSampleByFrames(
m_sampleBuffer.frames()
- m_sampleBuffer.endFrame()
- m_sampleBuffer.startFrame()
m_sample->sampleSize()
- m_sample->endFrame()
- m_sample->startFrame()
);
const f_cnt_t from = m_from;
m_from = m_sampleBuffer.frames() - m_to;
m_to = m_sampleBuffer.frames() - from;
m_from = m_sample->sampleSize() - m_to;
m_to = m_sample->sampleSize() - from;
m_reversed = ! m_reversed;
}
@@ -1229,8 +1239,7 @@ void AudioFileProcessorWaveView::knob::slideTo( double _v, bool _check_bound )
float AudioFileProcessorWaveView::knob::getValue( const QPoint & _p )
{
const double dec_fact = ! m_waveView ? 1 :
double( m_waveView->m_to - m_waveView->m_from )
/ m_waveView->m_sampleBuffer.frames();
static_cast<double>(m_waveView->m_to - m_waveView->m_from) / m_waveView->m_sample->sampleSize();
const float inc = Knob::getValue( _p ) * dec_fact;
return inc;
@@ -1251,12 +1260,12 @@ bool AudioFileProcessorWaveView::knob::checkBound( double _v ) const
return false;
const double d1 = qAbs( m_relatedKnob->model()->value() - model()->value() )
* ( m_waveView->m_sampleBuffer.frames() )
/ m_waveView->m_sampleBuffer.sampleRate();
* (m_waveView->m_sample->sampleSize())
/ m_waveView->m_sample->sampleRate();
const double d2 = qAbs( m_relatedKnob->model()->value() - _v )
* ( m_waveView->m_sampleBuffer.frames() )
/ m_waveView->m_sampleBuffer.sampleRate();
* (m_waveView->m_sample->sampleSize())
/ m_waveView->m_sample->sampleRate();
return d1 < d2 || d2 > 0.005;
}

View File

@@ -31,6 +31,7 @@
#include "ComboBoxModel.h"
#include "Instrument.h"
#include "InstrumentView.h"
#include "Sample.h"
#include "SampleBuffer.h"
#include "Knob.h"
@@ -93,12 +94,12 @@ private slots:
signals:
void isPlaying( lmms::f_cnt_t _current_frame );
void sampleUpdated();
private:
using handleState = SampleBuffer::handleState;
SampleBuffer m_sampleBuffer;
std::shared_ptr<Sample> m_sample;
FloatModel m_ampModel;
FloatModel m_startPointModel;
@@ -247,7 +248,7 @@ private:
SampleLoop
} ;
SampleBuffer& m_sampleBuffer;
Sample* m_sample;
QPixmap m_graph;
f_cnt_t m_from;
f_cnt_t m_to;
@@ -267,8 +268,10 @@ private:
f_cnt_t m_framesPlayed;
bool m_animation;
friend class AudioFileProcessorView;
public:
AudioFileProcessorWaveView( QWidget * _parent, int _w, int _h, SampleBuffer& buf );
AudioFileProcessorWaveView(QWidget * _parent, int _w, int _h, Sample* buf);
void setKnobs(knob *_start, knob *_end, knob *_loop );