Integrate changes into Oscillator
This commit is contained in:
@@ -86,7 +86,7 @@ protected:
|
||||
sample_t (*m_sampleFunction)( const float );
|
||||
|
||||
private:
|
||||
SampleBuffer * m_userDefSampleBuffer;
|
||||
std::shared_ptr<const SampleBuffer2> m_userDefSampleBuffer;
|
||||
|
||||
protected slots:
|
||||
void updatePhase();
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
#include <cassert>
|
||||
#include <fftw3.h>
|
||||
#include <cstdlib>
|
||||
#include "interpolation.h"
|
||||
|
||||
#include "Engine.h"
|
||||
#include "lmms_constants.h"
|
||||
#include "lmmsconfig.h"
|
||||
#include "AudioEngine.h"
|
||||
#include "OscillatorConstants.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "SampleBuffer2.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
@@ -46,7 +47,6 @@ class IntModel;
|
||||
|
||||
class LMMS_EXPORT Oscillator
|
||||
{
|
||||
MM_OPERATORS
|
||||
public:
|
||||
enum class WaveShape
|
||||
{
|
||||
@@ -91,14 +91,14 @@ public:
|
||||
|
||||
static void waveTableInit();
|
||||
static void destroyFFTPlans();
|
||||
static void generateAntiAliasUserWaveTable(SampleBuffer* sampleBuffer);
|
||||
static std::unique_ptr<OscillatorConstants::waveform_t> generateAntiAliasUserWaveTable(const SampleBuffer2 *sampleBuffer);
|
||||
|
||||
inline void setUseWaveTable(bool n)
|
||||
{
|
||||
m_useWaveTable = n;
|
||||
}
|
||||
|
||||
inline void setUserWave( const SampleBuffer * _wave )
|
||||
inline void setUserWave(std::shared_ptr<const SampleBuffer2> _wave)
|
||||
{
|
||||
m_userWave = _wave;
|
||||
}
|
||||
@@ -164,9 +164,18 @@ public:
|
||||
return 1.0f - fast_rand() * 2.0f / FAST_RAND_MAX;
|
||||
}
|
||||
|
||||
inline sample_t userWaveSample( const float _sample ) const
|
||||
static inline sample_t userWaveSample(const SampleBuffer2* buffer, const float sample)
|
||||
{
|
||||
return m_userWave->userWaveSample( _sample );
|
||||
if (buffer == nullptr || buffer->size() == 0) { return 0; }
|
||||
const auto frames = buffer->size();
|
||||
const auto frame = sample * frames;
|
||||
auto f1 = static_cast<f_cnt_t>(frame) % frames;
|
||||
if (f1 < 0)
|
||||
{
|
||||
f1 += frames;
|
||||
}
|
||||
|
||||
return linearInterpolate(buffer->data()[f1][0], buffer->data()[(f1 + 1) % frames][0], fraction(frame));
|
||||
}
|
||||
|
||||
struct wtSampleControl {
|
||||
@@ -203,7 +212,7 @@ public:
|
||||
table[control.band][control.f2], fraction(control.frame));
|
||||
}
|
||||
|
||||
inline sample_t wtSample(const std::unique_ptr<OscillatorConstants::waveform_t>& table, const float sample) const
|
||||
inline sample_t wtSample(const OscillatorConstants::waveform_t* table, const float sample) const
|
||||
{
|
||||
assert(table != nullptr);
|
||||
wtSampleControl control = getWtSampleControl(sample);
|
||||
@@ -247,7 +256,8 @@ private:
|
||||
Oscillator * m_subOsc;
|
||||
float m_phaseOffset;
|
||||
float m_phase;
|
||||
const SampleBuffer * m_userWave;
|
||||
std::shared_ptr<const SampleBuffer2> m_userWave;
|
||||
std::shared_ptr<const OscillatorConstants::waveform_t> m_userAntiAliasWaveTable;
|
||||
bool m_useWaveTable;
|
||||
// There are many update*() variants; the modulator flag is stored as a member variable to avoid
|
||||
// adding more explicit parameters to all of them. Can be converted to a parameter if needed.
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LMMS_SAMPLE_BUFFER_H
|
||||
#define LMMS_SAMPLE_BUFFER_H
|
||||
#ifndef LMMS_SAMPLE_BUFFER2_H
|
||||
#define LMMS_SAMPLE_BUFFER2_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
@@ -80,4 +80,4 @@ private:
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif // LMMS_SAMPLE_BUFFER_H
|
||||
#endif // LMMS_SAMPLE_BUFFER2_H
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
#include "SampleBuffer.h"
|
||||
#include "SampleBuffer2.h"
|
||||
#include "lmms_export.h"
|
||||
|
||||
namespace lmms::gui {
|
||||
@@ -37,8 +37,8 @@ class LMMS_EXPORT SampleLoader
|
||||
public:
|
||||
static QString openAudioFile(const QString& previousFile = "");
|
||||
static QString openWaveformFile(const QString& previousFile = "");
|
||||
static std::unique_ptr<SampleBuffer> createBufferFromFile(const QString& filePath);
|
||||
static std::unique_ptr<SampleBuffer> createBufferFromBase64(const QString& base64, int sampleRate);
|
||||
static std::unique_ptr<SampleBuffer2> createBufferFromFile(const QString& filePath);
|
||||
static std::unique_ptr<SampleBuffer2> createBufferFromBase64(const QString& base64, int sampleRate);
|
||||
private:
|
||||
static void displayError(const QString& message);
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <QDomElement>
|
||||
|
||||
#include "SampleLoader.h"
|
||||
#include "TripleOscillator.h"
|
||||
#include "AudioEngine.h"
|
||||
#include "AutomatableButton.h"
|
||||
@@ -92,7 +93,7 @@ OscillatorObject::OscillatorObject( Model * _parent, int _idx ) :
|
||||
tr( "Modulation type %1" ).arg( _idx+1 ) ),
|
||||
m_useWaveTableModel(true),
|
||||
|
||||
m_sampleBuffer( new SampleBuffer ),
|
||||
m_sampleBuffer( new SampleBuffer2 ),
|
||||
m_volumeLeft( 0.0f ),
|
||||
m_volumeRight( 0.0f ),
|
||||
m_detuningLeft( 0.0f ),
|
||||
@@ -136,17 +137,17 @@ OscillatorObject::OscillatorObject( Model * _parent, int _idx ) :
|
||||
|
||||
|
||||
|
||||
OscillatorObject::~OscillatorObject()
|
||||
{
|
||||
sharedObject::unref( m_sampleBuffer );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void OscillatorObject::oscUserDefWaveDblClick()
|
||||
{
|
||||
QString af = m_sampleBuffer->openAndSetWaveformFile();
|
||||
QString af = gui::SampleLoader::openWaveformFile();
|
||||
auto buffer = gui::SampleLoader::createBufferFromFile(af);
|
||||
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
|
||||
std::atomic_store(&m_sampleBuffer, std::shared_ptr<const SampleBuffer2>(std::move(buffer)));
|
||||
|
||||
if( af != "" )
|
||||
{
|
||||
// TODO:
|
||||
@@ -289,8 +290,10 @@ void TripleOscillator::loadSettings( const QDomElement & _this )
|
||||
"modalgo" + QString::number( i+1 ) );
|
||||
m_osc[i]->m_useWaveTableModel.loadSettings( _this,
|
||||
"useWaveTable" + QString::number (i+1 ) );
|
||||
m_osc[i]->m_sampleBuffer->setAudioFile( _this.attribute(
|
||||
"userwavefile" + is ) );
|
||||
|
||||
auto buffer = gui::SampleLoader::createBufferFromFile(_this.attribute("userwavefile" + is));
|
||||
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
|
||||
std::atomic_store(&m_osc[i]->m_sampleBuffer, std::shared_ptr<const SampleBuffer2>(std::move(buffer)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Instrument.h"
|
||||
#include "InstrumentView.h"
|
||||
#include "AutomatableModel.h"
|
||||
#include "SampleBuffer2.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
@@ -57,9 +58,6 @@ class OscillatorObject : public Model
|
||||
Q_OBJECT
|
||||
public:
|
||||
OscillatorObject( Model * _parent, int _idx );
|
||||
~OscillatorObject() override;
|
||||
|
||||
|
||||
private:
|
||||
FloatModel m_volumeModel;
|
||||
FloatModel m_panModel;
|
||||
@@ -71,7 +69,7 @@ private:
|
||||
IntModel m_waveShapeModel;
|
||||
IntModel m_modulationAlgoModel;
|
||||
BoolModel m_useWaveTableModel;
|
||||
SampleBuffer* m_sampleBuffer;
|
||||
std::shared_ptr<const SampleBuffer2> m_sampleBuffer;
|
||||
|
||||
float m_volumeLeft;
|
||||
float m_volumeRight;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "LfoController.h"
|
||||
#include "AudioEngine.h"
|
||||
#include "SampleLoader.h"
|
||||
#include "Song.h"
|
||||
|
||||
|
||||
@@ -48,7 +49,7 @@ LfoController::LfoController( Model * _parent ) :
|
||||
m_phaseOffset( 0 ),
|
||||
m_currentPhase( 0 ),
|
||||
m_sampleFunction( &Oscillator::sinSample ),
|
||||
m_userDefSampleBuffer( new SampleBuffer )
|
||||
m_userDefSampleBuffer(std::make_shared<SampleBuffer2>())
|
||||
{
|
||||
setSampleExact( true );
|
||||
connect( &m_waveModel, SIGNAL(dataChanged()),
|
||||
@@ -74,7 +75,6 @@ LfoController::LfoController( Model * _parent ) :
|
||||
|
||||
LfoController::~LfoController()
|
||||
{
|
||||
sharedObject::unref( m_userDefSampleBuffer );
|
||||
m_baseModel.disconnect( this );
|
||||
m_speedModel.disconnect( this );
|
||||
m_amountModel.disconnect( this );
|
||||
@@ -107,7 +107,7 @@ void LfoController::updateValueBuffer()
|
||||
{
|
||||
const float currentSample = m_sampleFunction != nullptr
|
||||
? m_sampleFunction( phase )
|
||||
: m_userDefSampleBuffer->userWaveSample( phase );
|
||||
: Oscillator::userWaveSample(m_userDefSampleBuffer.get(), phase);
|
||||
|
||||
f = std::clamp(m_baseModel.value() + (*amountPtr * currentSample / 2.0f), 0.0f, 1.0f);
|
||||
|
||||
@@ -211,7 +211,10 @@ void LfoController::loadSettings( const QDomElement & _this )
|
||||
m_phaseModel.loadSettings( _this, "phase" );
|
||||
m_waveModel.loadSettings( _this, "wave" );
|
||||
m_multiplierModel.loadSettings( _this, "multiplier" );
|
||||
m_userDefSampleBuffer->setAudioFile( _this.attribute("userwavefile" ) );
|
||||
|
||||
auto buffer = gui::SampleLoader::createBufferFromFile(_this.attribute("userwavefile"));
|
||||
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
|
||||
std::atomic_store(&m_userDefSampleBuffer, std::shared_ptr<const SampleBuffer2>(std::move(buffer)));
|
||||
|
||||
updateSampleFunction();
|
||||
}
|
||||
|
||||
@@ -182,19 +182,20 @@ void Oscillator::generateFromFFT(int bands, sample_t* table)
|
||||
normalize(s_sampleBuffer.data(), table, OscillatorConstants::WAVETABLE_LENGTH, 2*OscillatorConstants::WAVETABLE_LENGTH + 1);
|
||||
}
|
||||
|
||||
void Oscillator::generateAntiAliasUserWaveTable(SampleBuffer *sampleBuffer)
|
||||
std::unique_ptr<OscillatorConstants::waveform_t> Oscillator::generateAntiAliasUserWaveTable(const SampleBuffer2* sampleBuffer)
|
||||
{
|
||||
if (sampleBuffer->m_userAntiAliasWaveTable == nullptr) {return;}
|
||||
|
||||
auto userAntiAliasWaveTable = std::make_unique<OscillatorConstants::waveform_t>();
|
||||
for (int i = 0; i < OscillatorConstants::WAVE_TABLES_PER_WAVEFORM_COUNT; ++i)
|
||||
{
|
||||
for (int i = 0; i < OscillatorConstants::WAVETABLE_LENGTH; ++i)
|
||||
{
|
||||
s_sampleBuffer[i] = sampleBuffer->userWaveSample((float)i / (float)OscillatorConstants::WAVETABLE_LENGTH);
|
||||
s_sampleBuffer[i] = Oscillator::userWaveSample(sampleBuffer, (float)i / (float)OscillatorConstants::WAVETABLE_LENGTH);
|
||||
}
|
||||
fftwf_execute(s_fftPlan);
|
||||
Oscillator::generateFromFFT(OscillatorConstants::MAX_FREQ / freqFromWaveTableBand(i), (*(sampleBuffer->m_userAntiAliasWaveTable))[i].data());
|
||||
Oscillator::generateFromFFT(OscillatorConstants::MAX_FREQ / freqFromWaveTableBand(i), (*(userAntiAliasWaveTable))[i].data());
|
||||
}
|
||||
|
||||
return userAntiAliasWaveTable;
|
||||
}
|
||||
|
||||
|
||||
@@ -807,13 +808,13 @@ template<>
|
||||
inline sample_t Oscillator::getSample<Oscillator::WaveShape::UserDefined>(
|
||||
const float _sample )
|
||||
{
|
||||
if (m_useWaveTable && !m_isModulator)
|
||||
if (m_useWaveTable && m_userAntiAliasWaveTable && !m_isModulator)
|
||||
{
|
||||
return wtSample(m_userWave->m_userAntiAliasWaveTable, _sample);
|
||||
return wtSample(m_userAntiAliasWaveTable.get(), _sample);
|
||||
}
|
||||
else
|
||||
{
|
||||
return userWaveSample(_sample);
|
||||
return userWaveSample(m_userWave.get(), _sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -361,7 +361,6 @@ void SampleBuffer::update(bool keepSettings)
|
||||
{
|
||||
m_userAntiAliasWaveTable = std::make_unique<OscillatorConstants::waveform_t>();
|
||||
}
|
||||
Oscillator::generateAntiAliasUserWaveTable(this);
|
||||
|
||||
if (fileLoadError)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@ SET(LMMS_SRCS
|
||||
gui/PluginBrowser.cpp
|
||||
gui/ProjectNotes.cpp
|
||||
gui/RowTableView.cpp
|
||||
gui/SampleLoader.cpp
|
||||
gui/SampleTrackWindow.cpp
|
||||
gui/SendButtonIndicator.cpp
|
||||
gui/SideBar.cpp
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Knob.h"
|
||||
#include "TempoSyncKnob.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "SampleLoader.h"
|
||||
|
||||
namespace lmms::gui
|
||||
{
|
||||
@@ -210,9 +211,13 @@ LfoControllerDialog::~LfoControllerDialog()
|
||||
|
||||
void LfoControllerDialog::askUserDefWave()
|
||||
{
|
||||
SampleBuffer * sampleBuffer = dynamic_cast<LfoController*>(this->model())->
|
||||
m_userDefSampleBuffer;
|
||||
QString fileName = sampleBuffer->openAndSetWaveformFile();
|
||||
auto sampleBuffer = dynamic_cast<LfoController*>(this->model())->m_userDefSampleBuffer;
|
||||
QString fileName = SampleLoader::openWaveformFile();
|
||||
|
||||
auto buffer = SampleLoader::createBufferFromFile(fileName);
|
||||
// TODO C++20: Deprecated, use std::atomic<std::shared_ptr> instead
|
||||
std::atomic_store(&sampleBuffer, std::shared_ptr<const SampleBuffer2>(std::move(buffer)));
|
||||
|
||||
if( fileName.isEmpty() == false )
|
||||
{
|
||||
// TODO:
|
||||
|
||||
@@ -86,11 +86,11 @@ QString SampleLoader::openWaveformFile(const QString& previousFile)
|
||||
previousFile.isEmpty() ? ConfigManager::inst()->factorySamplesDir() + "waveforms/10saw.flac" : previousFile);
|
||||
}
|
||||
|
||||
std::unique_ptr<SampleBuffer> SampleLoader::createBufferFromFile(const QString& filePath)
|
||||
std::unique_ptr<SampleBuffer2> SampleLoader::createBufferFromFile(const QString& filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
return std::make_unique<SampleBuffer>(filePath);
|
||||
return std::make_unique<SampleBuffer2>(filePath);
|
||||
}
|
||||
catch (const std::runtime_error& error)
|
||||
{
|
||||
@@ -99,11 +99,11 @@ std::unique_ptr<SampleBuffer> SampleLoader::createBufferFromFile(const QString&
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<SampleBuffer> SampleLoader::createBufferFromBase64(const QString& base64, int sampleRate)
|
||||
std::unique_ptr<SampleBuffer2> SampleLoader::createBufferFromBase64(const QString& base64, int sampleRate)
|
||||
{
|
||||
try
|
||||
{
|
||||
return std::make_unique<SampleBuffer>(base64.toUtf8().toBase64(), sampleRate);
|
||||
return std::make_unique<SampleBuffer2>(base64.toUtf8().toBase64(), sampleRate);
|
||||
}
|
||||
catch (const std::runtime_error& error)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user