Fix LMMS plugin issues (#6670)

* Fix Organic automated harmonic parameter loading

* Fix Kicker automated end distortion parameter loading

* Fix AudioFileProcessor automated interpolation parameter loading

* Fix Vibed automated volume parameter loading

* Improve coding style/formatting

* Fix #6671

* Fix Vibed memory leaks

* Refactor Vibed instrument

* Fix build

* Try to fix build again

* Revert previous commit

* Replace more raw pointers with smart pointers

* Remove unused files

* Minor changes

* Update plugins/Vibed/Vibed.cpp

Co-authored-by: Kevin Zander <veratil@gmail.com>

* Implement suggestions from review

* Minor changes

* Only check plugin data pointer

* Refactor NineButtonSelector

* Fix memory leaks during heavy tempo automation

* Fix build

* Use s_stringCount

* Replace some vectors with arrays

* Use array instead of switch

* Allow compiler to generate move assignment operator

* Fix loading of old automated detune values

* Fix member variable names

* Address review comments

---------

Co-authored-by: Kevin Zander <veratil@gmail.com>
This commit is contained in:
Dalton Messmer
2023-08-21 23:07:09 -04:00
committed by GitHub
parent 793f096c4f
commit 5cbf2c5287
29 changed files with 781 additions and 1425 deletions

View File

@@ -1,5 +1,5 @@
/*
* AudioFileProcessor.cpp - instrument for using audio-files
* AudioFileProcessor.cpp - instrument for using audio files
*
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -47,7 +47,6 @@
#include "embed.h"
#include "plugin_export.h"
namespace lmms
{
@@ -205,74 +204,70 @@ void AudioFileProcessor::deleteNotePluginData( NotePlayHandle * _n )
void AudioFileProcessor::saveSettings( QDomDocument & _doc,
QDomElement & _this )
void AudioFileProcessor::saveSettings(QDomDocument& doc, QDomElement& elem)
{
_this.setAttribute( "src", m_sampleBuffer.audioFile() );
if( m_sampleBuffer.audioFile() == "" )
elem.setAttribute("src", m_sampleBuffer.audioFile());
if (m_sampleBuffer.audioFile().isEmpty())
{
QString s;
_this.setAttribute( "sampledata",
m_sampleBuffer.toBase64( s ) );
elem.setAttribute("sampledata", m_sampleBuffer.toBase64(s));
}
m_reverseModel.saveSettings( _doc, _this, "reversed" );
m_loopModel.saveSettings( _doc, _this, "looped" );
m_ampModel.saveSettings( _doc, _this, "amp" );
m_startPointModel.saveSettings( _doc, _this, "sframe" );
m_endPointModel.saveSettings( _doc, _this, "eframe" );
m_loopPointModel.saveSettings( _doc, _this, "lframe" );
m_stutterModel.saveSettings( _doc, _this, "stutter" );
m_interpolationModel.saveSettings( _doc, _this, "interp" );
m_reverseModel.saveSettings(doc, elem, "reversed");
m_loopModel.saveSettings(doc, elem, "looped");
m_ampModel.saveSettings(doc, elem, "amp");
m_startPointModel.saveSettings(doc, elem, "sframe");
m_endPointModel.saveSettings(doc, elem, "eframe");
m_loopPointModel.saveSettings(doc, elem, "lframe");
m_stutterModel.saveSettings(doc, elem, "stutter");
m_interpolationModel.saveSettings(doc, elem, "interp");
}
void AudioFileProcessor::loadSettings( const QDomElement & _this )
void AudioFileProcessor::loadSettings(const QDomElement& elem)
{
if( _this.attribute( "src" ) != "" )
if (!elem.attribute("src").isEmpty())
{
setAudioFile( _this.attribute( "src" ), false );
setAudioFile(elem.attribute("src"), false);
QString absolutePath = PathUtil::toAbsolute( m_sampleBuffer.audioFile() );
if ( !QFileInfo( absolutePath ).exists() )
QString absolutePath = PathUtil::toAbsolute(m_sampleBuffer.audioFile());
if (!QFileInfo(absolutePath).exists())
{
QString message = tr( "Sample not found: %1" ).arg( m_sampleBuffer.audioFile() );
Engine::getSong()->collectError( message );
QString message = tr("Sample not found: %1").arg(m_sampleBuffer.audioFile());
Engine::getSong()->collectError(message);
}
}
else if( _this.attribute( "sampledata" ) != "" )
else if (!elem.attribute("sampledata").isEmpty())
{
m_sampleBuffer.loadFromBase64( _this.attribute( "srcdata" ) );
m_sampleBuffer.loadFromBase64(elem.attribute("srcdata"));
}
m_loopModel.loadSettings( _this, "looped" );
m_ampModel.loadSettings( _this, "amp" );
m_endPointModel.loadSettings( _this, "eframe" );
m_startPointModel.loadSettings( _this, "sframe" );
m_loopModel.loadSettings(elem, "looped");
m_ampModel.loadSettings(elem, "amp");
m_endPointModel.loadSettings(elem, "eframe");
m_startPointModel.loadSettings(elem, "sframe");
// compat code for not having a separate loopback point
if (_this.hasAttribute("lframe") || !(_this.firstChildElement("lframe").isNull()))
if (elem.hasAttribute("lframe") || !elem.firstChildElement("lframe").isNull())
{
m_loopPointModel.loadSettings( _this, "lframe" );
m_loopPointModel.loadSettings(elem, "lframe");
}
else
{
m_loopPointModel.loadSettings( _this, "sframe" );
m_loopPointModel.loadSettings(elem, "sframe");
}
m_reverseModel.loadSettings( _this, "reversed" );
m_reverseModel.loadSettings(elem, "reversed");
m_stutterModel.loadSettings( _this, "stutter" );
if( _this.hasAttribute( "interp" ) )
m_stutterModel.loadSettings(elem, "stutter");
if (elem.hasAttribute("interp") || !elem.firstChildElement("interp").isNull())
{
m_interpolationModel.loadSettings( _this, "interp" );
m_interpolationModel.loadSettings(elem, "interp");
}
else
{
m_interpolationModel.setValue( 1 ); //linear by default
m_interpolationModel.setValue(1.0f); // linear by default
}
pointChanged();
@@ -686,14 +681,12 @@ void AudioFileProcessorView::sampleUpdated()
void AudioFileProcessorView::openAudioFile()
{
QString af = castModel<AudioFileProcessor>()->m_sampleBuffer.
openAudioFile();
if( af != "" )
{
castModel<AudioFileProcessor>()->setAudioFile( af );
Engine::getSong()->setModified();
m_waveView->updateSampleRange();
}
QString af = castModel<AudioFileProcessor>()->m_sampleBuffer.openAudioFile();
if (af.isEmpty()) { return; }
castModel<AudioFileProcessor>()->setAudioFile(af);
Engine::getSong()->setModified();
m_waveView->updateSampleRange();
}

View File

@@ -23,9 +23,8 @@
*
*/
#ifndef AUDIO_FILE_PROCESSOR_H
#define AUDIO_FILE_PROCESSOR_H
#ifndef LMMS_AUDIO_FILE_PROCESSOR_H
#define LMMS_AUDIO_FILE_PROCESSOR_H
#include <QPixmap>
@@ -61,9 +60,8 @@ public:
sampleFrame * _working_buffer ) override;
void deleteNotePluginData( NotePlayHandle * _n ) override;
void saveSettings( QDomDocument & _doc,
QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
void saveSettings(QDomDocument& doc, QDomElement& elem) override;
void loadSettings(const QDomElement& elem) override;
void loadFile( const QString & _file ) override;
@@ -303,4 +301,4 @@ private:
} // namespace lmms
#endif
#endif // LMMS_AUDIO_FILE_PROCESSOR_H

View File

@@ -274,9 +274,8 @@ QString BitInvader::nodeName() const
void BitInvader::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!_n->m_pluginData)
{
float factor;
if( !m_normalize.value() )
{

View File

@@ -250,7 +250,7 @@ void FreeBoyInstrument::playNote(NotePlayHandle* nph, sampleFrame* workingBuffer
int data = 0;
int freq = nph->frequency();
if ( tfp == 0 )
if (!nph->m_pluginData)
{
auto papu = new GbApuWrapper{};
papu->setSampleRate(samplerate, CLOCK_RATE);

View File

@@ -293,8 +293,6 @@ void GigInstrument::playNote( NotePlayHandle * _n, sampleFrame * )
{
const float LOG440 = 2.643452676f;
const f_cnt_t tfp = _n->totalFramesPlayed();
int midiNote = (int) floor( 12.0 * ( log2( _n->unpitchedFrequency() ) - LOG440 ) - 4.0 );
// out of range?
@@ -303,7 +301,7 @@ void GigInstrument::playNote( NotePlayHandle * _n, sampleFrame * )
return;
}
if( tfp == 0 )
if (!_n->m_pluginData)
{
auto pluginData = new GIGPluginData;
pluginData->midiNote = midiNote;

View File

@@ -23,11 +23,10 @@
*
*/
#include "Kicker.h"
#include <QDomElement>
#include "Kicker.h"
#include "AudioEngine.h"
#include "Engine.h"
#include "InstrumentTrack.h"
@@ -85,65 +84,64 @@ KickerInstrument::KickerInstrument( InstrumentTrack * _instrument_track ) :
void KickerInstrument::saveSettings( QDomDocument & _doc,
QDomElement & _this )
void KickerInstrument::saveSettings(QDomDocument& doc, QDomElement& elem)
{
m_startFreqModel.saveSettings( _doc, _this, "startfreq" );
m_endFreqModel.saveSettings( _doc, _this, "endfreq" );
m_decayModel.saveSettings( _doc, _this, "decay" );
m_distModel.saveSettings( _doc, _this, "dist" );
m_distEndModel.saveSettings( _doc, _this, "distend" );
m_gainModel.saveSettings( _doc, _this, "gain" );
m_envModel.saveSettings( _doc, _this, "env" );
m_noiseModel.saveSettings( _doc, _this, "noise" );
m_clickModel.saveSettings( _doc, _this, "click" );
m_slopeModel.saveSettings( _doc, _this, "slope" );
m_startNoteModel.saveSettings( _doc, _this, "startnote" );
m_endNoteModel.saveSettings( _doc, _this, "endnote" );
m_versionModel.saveSettings( _doc, _this, "version" );
m_startFreqModel.saveSettings(doc, elem, "startfreq");
m_endFreqModel.saveSettings(doc, elem, "endfreq");
m_decayModel.saveSettings(doc, elem, "decay");
m_distModel.saveSettings(doc, elem, "dist");
m_distEndModel.saveSettings(doc, elem, "distend");
m_gainModel.saveSettings(doc, elem, "gain");
m_envModel.saveSettings(doc, elem, "env");
m_noiseModel.saveSettings(doc, elem, "noise");
m_clickModel.saveSettings(doc, elem, "click");
m_slopeModel.saveSettings(doc, elem, "slope");
m_startNoteModel.saveSettings(doc, elem, "startnote");
m_endNoteModel.saveSettings(doc, elem, "endnote");
m_versionModel.saveSettings(doc, elem, "version");
}
void KickerInstrument::loadSettings( const QDomElement & _this )
void KickerInstrument::loadSettings(const QDomElement& elem)
{
m_versionModel.loadSettings( _this, "version" );
m_versionModel.loadSettings(elem, "version");
m_startFreqModel.loadSettings( _this, "startfreq" );
m_endFreqModel.loadSettings( _this, "endfreq" );
m_decayModel.loadSettings( _this, "decay" );
m_distModel.loadSettings( _this, "dist" );
if( _this.hasAttribute( "distend" ) )
m_startFreqModel.loadSettings(elem, "startfreq");
m_endFreqModel.loadSettings(elem, "endfreq");
m_decayModel.loadSettings(elem, "decay");
m_distModel.loadSettings(elem, "dist");
if (elem.hasAttribute("distend") || !elem.firstChildElement("distend").isNull())
{
m_distEndModel.loadSettings( _this, "distend" );
m_distEndModel.loadSettings(elem, "distend");
}
else
{
m_distEndModel.setValue( m_distModel.value() );
m_distEndModel.setValue(m_distModel.value());
}
m_gainModel.loadSettings( _this, "gain" );
m_envModel.loadSettings( _this, "env" );
m_noiseModel.loadSettings( _this, "noise" );
m_clickModel.loadSettings( _this, "click" );
m_slopeModel.loadSettings( _this, "slope" );
m_startNoteModel.loadSettings( _this, "startnote" );
if( m_versionModel.value() < 1 )
m_gainModel.loadSettings(elem, "gain");
m_envModel.loadSettings(elem, "env");
m_noiseModel.loadSettings(elem, "noise");
m_clickModel.loadSettings(elem, "click");
m_slopeModel.loadSettings(elem, "slope");
m_startNoteModel.loadSettings(elem, "startnote");
if (m_versionModel.value() < 1)
{
m_startNoteModel.setValue( false );
m_startNoteModel.setValue(false);
}
m_endNoteModel.loadSettings( _this, "endnote" );
m_endNoteModel.loadSettings(elem, "endnote");
// Try to maintain backwards compatibility
if( !_this.hasAttribute( "version" ) )
if (!elem.hasAttribute("version"))
{
m_startNoteModel.setValue( false );
m_decayModel.setValue( m_decayModel.value() * 1.33f );
m_envModel.setValue( 1.0f );
m_slopeModel.setValue( 1.0f );
m_clickModel.setValue( 0.0f );
m_startNoteModel.setValue(false);
m_decayModel.setValue(m_decayModel.value() * 1.33f);
m_envModel.setValue(1.0f);
m_slopeModel.setValue(1.0f);
m_clickModel.setValue(0.0f);
}
m_versionModel.setValue( KICKER_PRESET_VERSION );
m_versionModel.setValue(KICKER_PRESET_VERSION);
}
@@ -165,7 +163,7 @@ void KickerInstrument::playNote( NotePlayHandle * _n,
const float decfr = m_decayModel.value() * Engine::audioEngine()->processingSampleRate() / 1000.0f;
const f_cnt_t tfp = _n->totalFramesPlayed();
if ( tfp == 0 )
if (!_n->m_pluginData)
{
_n->m_pluginData = new SweepOsc(
DistFX( m_distModel.value(),

View File

@@ -23,9 +23,8 @@
*
*/
#ifndef KICKER_H
#define KICKER_H
#ifndef LMMS_KICKER_H
#define LMMS_KICKER_H
#include "AutomatableModel.h"
#include "Instrument.h"
@@ -60,8 +59,8 @@ public:
sampleFrame * _working_buffer ) override;
void deleteNotePluginData( NotePlayHandle * _n ) override;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
void saveSettings(QDomDocument& doc, QDomElement& elem) override;
void loadSettings(const QDomElement& elem) override;
QString nodeName() const override;
@@ -135,4 +134,4 @@ private:
} // namespace lmms
#endif
#endif // LMMS_KICKER_H

View File

@@ -746,7 +746,7 @@ void Lb302Synth::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer )
void Lb302Synth::processNote( NotePlayHandle * _n )
{
/// Start a new note.
if( _n->m_pluginData != this )
if (_n->m_pluginData != this)
{
m_playingNote = _n;
new_freq = true;

View File

@@ -1030,7 +1030,7 @@ void MonstroInstrument::playNote( NotePlayHandle * _n,
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!_n->m_pluginData)
{
_n->m_pluginData = new MonstroSynth( this, _n );
}

View File

@@ -550,7 +550,7 @@ void NesInstrument::playNote( NotePlayHandle * n, sampleFrame * workingBuffer )
const fpp_t frames = n->framesLeftForCurrentPeriod();
const f_cnt_t offset = n->noteOffset();
if ( n->totalFramesPlayed() == 0 || n->m_pluginData == nullptr )
if (!n->m_pluginData)
{
auto nes = new NesObject(this, Engine::audioEngine()->processingSampleRate(), n);
n->m_pluginData = nes;

View File

@@ -22,13 +22,10 @@
*
*/
#include "Organic.h"
#include <QDomElement>
#include "Engine.h"
#include "AudioEngine.h"
#include "InstrumentTrack.h"
@@ -38,7 +35,6 @@
#include "PixmapButton.h"
#include "embed.h"
#include "plugin_export.h"
namespace lmms
@@ -159,61 +155,59 @@ OrganicInstrument::~OrganicInstrument()
void OrganicInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this )
void OrganicInstrument::saveSettings(QDomDocument& doc, QDomElement& elem)
{
_this.setAttribute( "num_osc", QString::number( m_numOscillators ) );
m_fx1Model.saveSettings( _doc, _this, "foldback" );
m_volModel.saveSettings( _doc, _this, "vol" );
elem.setAttribute("num_osc", QString::number(m_numOscillators));
m_fx1Model.saveSettings(doc, elem, "foldback");
m_volModel.saveSettings(doc, elem, "vol");
for( int i = 0; i < m_numOscillators; ++i )
for (int i = 0; i < m_numOscillators; ++i)
{
QString is = QString::number( i );
m_osc[i]->m_volModel.saveSettings( _doc, _this, "vol" + is );
m_osc[i]->m_panModel.saveSettings( _doc, _this, "pan" + is );
m_osc[i]->m_harmModel.saveSettings( _doc, _this, "newharmonic" + is );
m_osc[i]->m_detuneModel.saveSettings( _doc, _this, "newdetune"
+ is );
m_osc[i]->m_oscModel.saveSettings( _doc, _this, "wavetype"
+ is );
const auto is = QString::number(i);
m_osc[i]->m_volModel.saveSettings(doc, elem, "vol" + is);
m_osc[i]->m_panModel.saveSettings(doc, elem, "pan" + is);
m_osc[i]->m_harmModel.saveSettings(doc, elem, "newharmonic" + is);
m_osc[i]->m_detuneModel.saveSettings(doc, elem, "newdetune" + is);
m_osc[i]->m_oscModel.saveSettings(doc, elem, "wavetype" + is);
}
}
void OrganicInstrument::loadSettings( const QDomElement & _this )
void OrganicInstrument::loadSettings(const QDomElement& elem)
{
// m_numOscillators = _this.attribute( "num_osc" ).
// toInt();
for( int i = 0; i < m_numOscillators; ++i )
for (int i = 0; i < m_numOscillators; ++i)
{
QString is = QString::number( i );
m_osc[i]->m_volModel.loadSettings( _this, "vol" + is );
if( _this.hasAttribute( "detune" + is ) )
{
m_osc[i]->m_detuneModel.setValue( _this.attribute( "detune" ).toInt() * 12 );
}
else
{
m_osc[i]->m_detuneModel.loadSettings( _this, "newdetune" + is );
}
m_osc[i]->m_panModel.loadSettings( _this, "pan" + is );
m_osc[i]->m_oscModel.loadSettings( _this, "wavetype" + is );
const auto is = QString::number(i);
if( _this.hasAttribute( "newharmonic" + is ) )
m_osc[i]->m_volModel.loadSettings(elem, "vol" + is);
if (elem.hasAttribute("detune" + is) || !elem.firstChildElement("detune" + is).isNull())
{
m_osc[i]->m_harmModel.loadSettings( _this, "newharmonic" + is );
m_osc[i]->m_detuneModel.loadSettings(elem, "detune" + is);
m_osc[i]->m_detuneModel.setValue(m_osc[i]->m_detuneModel.value() * 12); // compat
}
else
{
m_osc[i]->m_harmModel.setValue( static_cast<float>( i ) );
m_osc[i]->m_detuneModel.loadSettings(elem, "newdetune" + is);
}
m_osc[i]->m_panModel.loadSettings(elem, "pan" + is);
m_osc[i]->m_oscModel.loadSettings(elem, "wavetype" + is);
if (elem.hasAttribute("newharmonic" + is) || !elem.firstChildElement("newharmonic" + is).isNull())
{
m_osc[i]->m_harmModel.loadSettings(elem, "newharmonic" + is);
}
else
{
m_osc[i]->m_harmModel.setValue(static_cast<float>(i));
}
}
m_volModel.loadSettings( _this, "vol" );
m_fx1Model.loadSettings( _this, "foldback" );
m_volModel.loadSettings(elem, "vol");
m_fx1Model.loadSettings(elem, "foldback");
}
@@ -231,7 +225,7 @@ void OrganicInstrument::playNote( NotePlayHandle * _n,
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!_n->m_pluginData)
{
auto oscs_l = std::array<Oscillator*, NUM_OSCILLATORS>{};
auto oscs_r = std::array<Oscillator*, NUM_OSCILLATORS>{};

View File

@@ -22,9 +22,8 @@
*
*/
#ifndef ORGANIC_H
#define ORGANIC_H
#ifndef LMMS_ORGANIC_H
#define LMMS_ORGANIC_H
#include <QString>
@@ -131,8 +130,8 @@ public:
void deleteNotePluginData( NotePlayHandle * _n ) override;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
void saveSettings(QDomDocument& doc, QDomElement& elem) override;
void loadSettings(const QDomElement& elem) override;
QString nodeName() const override;
@@ -239,4 +238,4 @@ protected slots:
} // namespace lmms
#endif
#endif // LMMS_ORGANIC_H

View File

@@ -144,7 +144,7 @@ void PatmanInstrument::playNote( NotePlayHandle * _n,
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if( !_n->m_pluginData )
if (!_n->m_pluginData)
{
selectSample( _n );
}

View File

@@ -663,8 +663,6 @@ void Sf2Instrument::playNote( NotePlayHandle * _n, sampleFrame * )
return;
}
const f_cnt_t tfp = _n->totalFramesPlayed();
int masterPitch = instrumentTrack()->useMasterPitchModel()->value() ? Engine::getSong()->masterPitch() : 0;
int baseNote = instrumentTrack()->baseNoteModel()->value();
int midiNote = _n->midiKey() - baseNote + DefaultBaseKey + masterPitch;
@@ -675,7 +673,7 @@ void Sf2Instrument::playNote( NotePlayHandle * _n, sampleFrame * )
return;
}
if (tfp == 0)
if (!_n->m_pluginData)
{
const int baseVelocity = instrumentTrack()->midiPort()->baseVelocity();

View File

@@ -446,9 +446,9 @@ void SfxrInstrument::playNote( NotePlayHandle * _n, sampleFrame * _working_buffe
{
float currentSampleRate = Engine::audioEngine()->processingSampleRate();
fpp_t frameNum = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
fpp_t frameNum = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if (!_n->m_pluginData)
{
_n->m_pluginData = new SfxrSynth( this );
}

View File

@@ -297,12 +297,10 @@ static int sid_fillbuffer(unsigned char* sidreg, SID *sid, int tdelta, short *pt
void SidInstrument::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
const f_cnt_t tfp = _n->totalFramesPlayed();
const int clockrate = C64_PAL_CYCLES_PER_SEC;
const int samplerate = Engine::audioEngine()->processingSampleRate();
if ( tfp == 0 )
if (!_n->m_pluginData)
{
SID *sid = new SID();
sid->set_sampling_parameters( clockrate, SAMPLE_FAST, samplerate );

View File

@@ -286,7 +286,7 @@ void MalletsInstrument::playNote( NotePlayHandle * _n,
int p = m_presetsModel.value();
const float freq = _n->frequency();
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!_n->m_pluginData)
{
// If newer projects, adjust velocity to within stk's limits
float velocityAdjust =

View File

@@ -308,7 +308,7 @@ QString TripleOscillator::nodeName() const
void TripleOscillator::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
if( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!_n->m_pluginData)
{
auto oscs_l = std::array<Oscillator*, NUM_OF_OSCILLATORS>{};
auto oscs_r = std::array<Oscillator*, NUM_OF_OSCILLATORS>{};

View File

@@ -1,3 +1,6 @@
INCLUDE(BuildPlugin)
BUILD_PLUGIN(vibedstrings Vibed.cpp NineButtonSelector.cpp StringContainer.cpp VibratingString.cpp Vibed.h NineButtonSelector.h StringContainer.h VibratingString.h MOCFILES Vibed.h NineButtonSelector.h EMBEDDED_RESOURCES *.png)
BUILD_PLUGIN(vibedstrings Vibed.cpp NineButtonSelector.cpp VibratingString.cpp
Vibed.h NineButtonSelector.h VibratingString.h
MOCFILES Vibed.h NineButtonSelector.h
EMBEDDED_RESOURCES *.png)

View File

@@ -3,7 +3,7 @@
*
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/yahoo/com>
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -23,237 +23,69 @@
*
*/
#include "NineButtonSelector.h"
#include "CaptionMenu.h"
#include "PixmapButton.h"
namespace lmms::gui
{
NineButtonSelector::NineButtonSelector( QPixmap _button0_on,
QPixmap _button0_off,
QPixmap _button1_on,
QPixmap _button1_off,
QPixmap _button2_on,
QPixmap _button2_off,
QPixmap _button3_on,
QPixmap _button3_off,
QPixmap _button4_on,
QPixmap _button4_off,
QPixmap _button5_on,
QPixmap _button5_off,
QPixmap _button6_on,
QPixmap _button6_off,
QPixmap _button7_on,
QPixmap _button7_off,
QPixmap _button8_on,
QPixmap _button8_off,
int _default,
int _x, int _y,
QWidget * _parent ):
QWidget( _parent ),
IntModelView( new NineButtonSelectorModel(0, 8, _default, nullptr,
QString(), true ), this )
NineButtonSelector::NineButtonSelector(std::array<QPixmap, 18> onOffIcons, int defaultButton, int x, int y, QWidget* parent) :
QWidget{parent},
IntModelView{new NineButtonSelectorModel{defaultButton, 0, 8, nullptr, QString{}, true}, this}
{
setFixedSize( 50, 50 );
move( _x, _y );
setFixedSize(50, 50);
move(x, y);
m_button = new PixmapButton( this, nullptr );
m_button->move( 1, 1 );
m_button->setActiveGraphic( _button0_on );
m_button->setInactiveGraphic( _button0_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button0Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 18, 1 );
m_button->setActiveGraphic( _button1_on );
m_button->setInactiveGraphic( _button1_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button1Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 35, 1 );
m_button->setActiveGraphic( _button2_on );
m_button->setInactiveGraphic( _button2_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button2Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 1, 18 );
m_button->setActiveGraphic( _button3_on );
m_button->setInactiveGraphic( _button3_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button3Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 18, 18 );
m_button->setActiveGraphic( _button4_on );
m_button->setInactiveGraphic( _button4_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button4Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 35, 18 );
m_button->setActiveGraphic( _button5_on );
m_button->setInactiveGraphic( _button5_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button5Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 1, 35 );
m_button->setActiveGraphic( _button6_on );
m_button->setInactiveGraphic( _button6_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button6Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 18, 35 );
m_button->setActiveGraphic( _button7_on );
m_button->setInactiveGraphic( _button7_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button7Clicked() ) );
m_buttons.append( m_button );
m_button = new PixmapButton( this, nullptr );
m_button->move( 35, 35 );
m_button->setActiveGraphic( _button8_on );
m_button->setInactiveGraphic( _button8_off );
m_button->setChecked( false );
connect( m_button, SIGNAL ( clicked () ),
this, SLOT ( button8Clicked() ) );
m_buttons.append( m_button );
m_lastBtn = m_buttons[_default];
m_lastBtn->setChecked( true );
}
NineButtonSelector::~ NineButtonSelector()
{
for( int i = 0; i < 9; i++ )
for (int i = 0; i < 9; ++i)
{
delete m_buttons[i];
m_buttons[i] = std::make_unique<PixmapButton>(this, nullptr);
const int buttonX = 1 + (i % 3) * 17;
const int buttonY = 1 + (i / 3) * 17;
m_buttons[i]->move(buttonX, buttonY);
m_buttons[i]->setActiveGraphic(onOffIcons[i * 2]);
m_buttons[i]->setInactiveGraphic(onOffIcons[(i * 2) + 1]);
m_buttons[i]->setChecked(false);
connect(m_buttons[i].get(), &PixmapButton::clicked, this, [=](){ this->buttonClicked(i); });
}
m_lastBtn = m_buttons[defaultButton].get();
m_lastBtn->setChecked(true);
}
void NineButtonSelector::button0Clicked()
void NineButtonSelector::buttonClicked(int id)
{
setSelected( 0 );
}
void NineButtonSelector::button1Clicked()
{
setSelected( 1 );
}
void NineButtonSelector::button2Clicked()
{
setSelected( 2 );
}
void NineButtonSelector::button3Clicked()
{
setSelected( 3 );
}
void NineButtonSelector::button4Clicked()
{
setSelected( 4 );
}
void NineButtonSelector::button5Clicked()
{
setSelected( 5 );
}
void NineButtonSelector::button6Clicked()
{
setSelected( 6 );
}
void NineButtonSelector::button7Clicked()
{
setSelected( 7 );
}
void NineButtonSelector::button8Clicked()
{
setSelected( 8 );
setSelected(id);
}
void NineButtonSelector::modelChanged()
{
updateButton( model()->value() );
updateButton(model()->value());
}
void NineButtonSelector::setSelected( int _new_button )
void NineButtonSelector::setSelected(int newButton)
{
model()->setValue(_new_button);
updateButton( _new_button );
model()->setValue(newButton);
updateButton(newButton);
}
void NineButtonSelector::updateButton( int _new_button )
void NineButtonSelector::updateButton(int newButton)
{
m_lastBtn->setChecked( false );
m_lastBtn->setChecked(false);
m_lastBtn->update();
m_lastBtn = m_buttons[_new_button];
m_lastBtn->setChecked( true );
m_lastBtn = m_buttons[newButton].get();
m_lastBtn->setChecked(true);
m_lastBtn->update();
emit NineButtonSelection( _new_button );
emit NineButtonSelection(newButton);
}
void NineButtonSelector::contextMenuEvent( QContextMenuEvent * )
void NineButtonSelector::contextMenuEvent(QContextMenuEvent*)
{
CaptionMenu contextMenu( windowTitle(), this );
contextMenu.exec( QCursor::pos() );
CaptionMenu contextMenu{windowTitle(), this};
contextMenu.exec(QCursor::pos());
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/yahoo/com>
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -22,87 +22,56 @@
* Boston, MA 02110-1301 USA.
*
*/
#ifndef _NINE_BUTTON_SELECTOR_H
#define _NINE_BUTTON_SELECTOR_H
#ifndef LMMS_GUI_NINE_BUTTON_SELECTOR_H
#define LMMS_GUI_NINE_BUTTON_SELECTOR_H
#include <array>
#include <memory>
#include <QWidget>
#include "AutomatableModelView.h"
#include "PixmapButton.h"
namespace lmms
{
class graphModel;
}
namespace lmms::gui
namespace gui
{
class Knob;
class PixmapButton;
class NineButtonSelector: public QWidget , public IntModelView
class NineButtonSelector : public QWidget, public IntModelView
{
Q_OBJECT
public:
NineButtonSelector( QPixmap _button0_on,
QPixmap _button0_off,
QPixmap _button1_on,
QPixmap _button1_off,
QPixmap _button2_on,
QPixmap _button2_off,
QPixmap _button3_on,
QPixmap _button3_off,
QPixmap _button4_on,
QPixmap _button4_off,
QPixmap _button5_on,
QPixmap _button5_off,
QPixmap _button6_on,
QPixmap _button6_off,
QPixmap _button7_on,
QPixmap _button7_off,
QPixmap _button8_on,
QPixmap _button8_off,
int _default,
int _x, int _y,
QWidget * _parent);
~NineButtonSelector() override;
// inline int getSelected() {
// return( castModel<NineButtonSelectorModel>()->value() );
// };
NineButtonSelector(std::array<QPixmap, 18> onOffIcons, int defaultButton, int x, int y, QWidget* parent);
~NineButtonSelector() override = default;
protected:
void setSelected( int _new_button );
void setSelected(int newButton);
public slots:
void button0Clicked();
void button1Clicked();
void button2Clicked();
void button3Clicked();
void button4Clicked();
void button5Clicked();
void button6Clicked();
void button7Clicked();
void button8Clicked();
void contextMenuEvent( QContextMenuEvent * ) override;
void buttonClicked(int id);
void contextMenuEvent(QContextMenuEvent*) override;
signals:
void NineButtonSelection( int );
void NineButtonSelection(int);
private:
void modelChanged() override;
void updateButton( int );
void updateButton(int);
QList<PixmapButton *> m_buttons;
PixmapButton * m_button;
PixmapButton * m_lastBtn;
std::array<std::unique_ptr<PixmapButton>, 9> m_buttons;
PixmapButton* m_lastBtn;
};
} ;
} // namespace gui
using NineButtonSelectorModel = IntModel;
} // namespace lmms::gui
#endif
} // namespace lmms
#endif // LMMS_GUI_NINE_BUTTON_SELECTOR_H

View File

@@ -1,108 +0,0 @@
/*
* StringContainer.cpp - contains a collection of strings
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/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.
*
*/
#include "StringContainer.h"
namespace lmms
{
StringContainer::StringContainer(const float _pitch,
const sample_rate_t _sample_rate,
const int _buffer_length,
const int _strings ) :
m_pitch( _pitch ),
m_sampleRate( _sample_rate ),
m_bufferLength( _buffer_length )
{
for( int i = 0; i < _strings; i++ )
{
m_exists.append( false );
}
}
void StringContainer::addString(int _harm,
const float _pick,
const float _pickup,
const float * _impulse,
const float _randomize,
const float _string_loss,
const float _detune,
const int _oversample,
const bool _state,
const int _id )
{
float harm;
switch( _harm )
{
case 0:
harm = 0.25f;
break;
case 1:
harm = 0.5f;
break;
case 2:
harm = 1.0f;
break;
case 3:
harm = 2.0f;
break;
case 4:
harm = 3.0f;
break;
case 5:
harm = 4.0f;
break;
case 6:
harm = 5.0f;
break;
case 7:
harm = 6.0f;
break;
case 8:
harm = 7.0f;
break;
default:
harm = 1.0f;
}
m_strings.append( new VibratingString( m_pitch * harm,
_pick,
_pickup,
const_cast<float*>(_impulse),
m_bufferLength,
m_sampleRate,
_oversample,
_randomize,
_string_loss,
_detune,
_state ) );
m_exists[_id] = true;
}
} // namespace lmms

View File

@@ -1,86 +0,0 @@
/* StringContainer.h - contains a collection of strings
*
* Copyright (c) 2006 Danny McRae <khjklujn/at/yahoo/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 _STRING_CONTAINER_H
#define _STRING_CONTAINER_H
#include <QVector>
#include "VibratingString.h"
#include "MemoryManager.h"
namespace lmms
{
class StringContainer
{
MM_OPERATORS
public:
StringContainer(const float _pitch,
const sample_rate_t _sample_rate,
const int _buffer_length,
const int _strings = 9 );
void addString( int _harm,
const float _pick,
const float _pickup,
const float * _impluse,
const float _randomize,
const float _string_loss,
const float _detune,
const int _oversample,
const bool _state,
const int _id );
bool exists( int _id ) const
{
return m_exists[_id];
}
~StringContainer()
{
int strings = m_strings.count();
for( int i = 0; i < strings; i++ )
{
delete m_strings[i];
}
}
float getStringSample( int _string )
{
return m_strings[_string]->nextSample();
}
private:
QVector<VibratingString *> m_strings;
const float m_pitch;
const sample_rate_t m_sampleRate;
const int m_bufferLength;
QVector<bool> m_exists;
} ;
} // namespace lmms
#endif

View File

@@ -22,21 +22,20 @@
*
*/
#include "Vibed.h"
#include <array>
#include <cassert>
#include <QDomElement>
#include "Vibed.h"
#include "AudioEngine.h"
#include "Engine.h"
#include "Graph.h"
#include "InstrumentTrack.h"
#include "Knob.h"
#include "LedCheckBox.h"
#include "NotePlayHandle.h"
#include "PixmapButton.h"
#include "VibratingString.h"
#include "MemoryManager.h"
#include "base64.h"
#include "CaptionMenu.h"
#include "StringContainer.h"
#include "volume.h"
#include "Song.h"
@@ -52,628 +51,472 @@ extern "C"
Plugin::Descriptor PLUGIN_EXPORT vibedstrings_plugin_descriptor =
{
LMMS_STRINGIFY( PLUGIN_NAME ),
LMMS_STRINGIFY(PLUGIN_NAME),
"Vibed",
QT_TRANSLATE_NOOP( "PluginBrowser",
"Vibrating string modeler" ),
QT_TRANSLATE_NOOP("PluginBrowser", "Vibrating string modeler"),
"Danny McRae <khjklujn/at/yahoo/com>",
0x0100,
Plugin::Instrument,
new PluginPixmapLoader( "logo" ),
nullptr,
new PluginPixmapLoader("logo"),
nullptr,
nullptr
};
}
Vibed::Vibed( InstrumentTrack * _instrumentTrack ) :
Instrument( _instrumentTrack, &vibedstrings_plugin_descriptor )
class Vibed::StringContainer
{
MM_OPERATORS
public:
StringContainer(float pitch, sample_rate_t sampleRate, int bufferLength) :
m_pitch(pitch), m_sampleRate(sampleRate), m_bufferLength(bufferLength) {}
FloatModel * knob;
BoolModel * led;
gui::NineButtonSelectorModel * harmonic;
graphModel * graphTmp;
~StringContainer() = default;
for( int harm = 0; harm < 9; harm++ )
void addString(int harm, float pick, float pickup, const float* impulse, float randomize,
float stringLoss, float detune, int oversample, bool state, int id)
{
knob = new FloatModel( DefaultVolume, MinVolume, MaxVolume,
1.0f, this, tr( "String %1 volume" ).arg( harm+1 ) );
m_volumeKnobs.append( knob );
constexpr auto octave = std::array{0.25f, 0.5f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
assert(harm >= 0 && harm < octave.size());
knob = new FloatModel( 0.0f, 0.0f, 0.05f, 0.001f, this,
tr( "String %1 stiffness" ).arg( harm+1 ) );
m_stiffnessKnobs.append( knob );
m_strings[id] = VibratingString{m_pitch * octave[harm], pick, pickup, impulse, m_bufferLength,
m_sampleRate, oversample, randomize, stringLoss, detune, state};
knob = new FloatModel( 0.0f, 0.0f, 0.05f, 0.005f, this,
tr( "Pick %1 position" ).arg( harm+1 ) );
m_pickKnobs.append( knob );
m_exists[id] = true;
}
knob = new FloatModel( 0.05f, 0.0f, 0.05f, 0.005f, this,
tr( "Pickup %1 position" ).arg( harm+1 ) );
m_pickupKnobs.append( knob );
bool exists(int id) const { return m_exists[id]; }
knob = new FloatModel( 0.0f, -1.0f, 1.0f, 0.01f, this,
tr( "String %1 panning" ).arg( harm+1 ) );
m_panKnobs.append( knob );
sample_t getStringSample(int id) { return m_strings[id].nextSample(); }
knob = new FloatModel( 0.0f, -0.1f, 0.1f, 0.001f, this,
tr( "String %1 detune" ).arg( harm+1 ) );
m_detuneKnobs.append( knob );
private:
const float m_pitch;
const sample_rate_t m_sampleRate;
const int m_bufferLength;
std::array<VibratingString, s_stringCount> m_strings{};
std::array<bool, s_stringCount> m_exists{};
};
knob = new FloatModel( 0.0f, 0.0f, 0.75f, 0.01f, this,
tr( "String %1 fuzziness" ).arg( harm+1 ) );
m_randomKnobs.append( knob );
knob = new FloatModel( 1, 1, 16, 1, this,
tr( "String %1 length" ).arg( harm+1 ) );
m_lengthKnobs.append( knob );
led = new BoolModel( false, this,
tr( "Impulse %1" ).arg( harm+1 ) );
m_impulses.append( led );
led = new BoolModel( harm==0, this,
tr( "String %1" ).arg( harm+1 ) );
m_powerButtons.append( led );
harmonic = new gui::NineButtonSelectorModel( 2, 0, 8, this );
m_harmonics.append( harmonic );
graphTmp = new graphModel( -1.0, 1.0, __sampleLength, this );
graphTmp->setWaveToSine();
m_graphs.append( graphTmp );
Vibed::Vibed(InstrumentTrack* instrumentTrack) :
Instrument(instrumentTrack, &vibedstrings_plugin_descriptor)
{
for (int harm = 0; harm < s_stringCount; ++harm)
{
m_volumeModels[harm] = std::make_unique<FloatModel>(
DefaultVolume, MinVolume, MaxVolume, 1.0f, this, tr("String %1 volume").arg(harm + 1));
m_stiffnessModels[harm] = std::make_unique<FloatModel>(
0.0f, 0.0f, 0.05f, 0.001f, this, tr("String %1 stiffness").arg(harm + 1));
m_pickModels[harm] = std::make_unique<FloatModel>(
0.0f, 0.0f, 0.05f, 0.005f, this, tr("Pick %1 position").arg(harm + 1));
m_pickupModels[harm] = std::make_unique<FloatModel>(
0.05f, 0.0f, 0.05f, 0.005f, this, tr("Pickup %1 position").arg( harm + 1));
m_panModels[harm] = std::make_unique<FloatModel>(
0.0f, -1.0f, 1.0f, 0.01f, this, tr("String %1 panning").arg(harm + 1));
m_detuneModels[harm] = std::make_unique<FloatModel>(
0.0f, -0.1f, 0.1f, 0.001f, this, tr("String %1 detune").arg(harm + 1));
m_randomModels[harm] = std::make_unique<FloatModel>(
0.0f, 0.0f, 0.75f, 0.01f, this, tr("String %1 fuzziness").arg(harm + 1));
m_lengthModels[harm] = std::make_unique<FloatModel>(
1, 1, 16, 1, this, tr("String %1 length").arg(harm + 1));
m_impulseModels[harm] = std::make_unique<BoolModel>(false, this, tr("Impulse %1").arg(harm + 1));
m_powerModels[harm] = std::make_unique<BoolModel>(harm == 0, this, tr("String %1").arg(harm + 1));
m_harmonicModels[harm] = std::make_unique<NineButtonSelectorModel>(2, 0, 8, this);
m_graphModels[harm] = std::make_unique<graphModel>(-1.0, 1.0, s_sampleLength, this);
m_graphModels[harm]->setWaveToSine();
}
}
void Vibed::saveSettings( QDomDocument & _doc, QDomElement & _this )
void Vibed::saveSettings(QDomDocument& doc, QDomElement& elem)
{
QString name;
// Save plugin version
_this.setAttribute( "version", "0.1" );
for( int i = 0; i < 9; i++ )
elem.setAttribute("version", "0.2");
for (int i = 0; i < s_stringCount; ++i)
{
name = "active" + QString::number( i );
_this.setAttribute( name, QString::number(
m_powerButtons[i]->value() ) );
const auto is = QString::number(i);
if( m_powerButtons[i]->value() )
{
name = "volume" + QString::number( i );
m_volumeKnobs[i]->saveSettings( _doc, _this, name );
name = "stiffness" + QString::number( i );
m_stiffnessKnobs[i]->saveSettings( _doc, _this, name );
elem.setAttribute("active" + is, QString::number(m_powerModels[i]->value()));
name = "pick" + QString::number( i );
m_pickKnobs[i]->saveSettings( _doc, _this, name );
m_volumeModels[i]->saveSettings(doc, elem, "volume" + is);
m_stiffnessModels[i]->saveSettings(doc, elem, "stiffness" + is);
m_pickModels[i]->saveSettings(doc, elem, "pick" + is);
m_pickupModels[i]->saveSettings(doc, elem, "pickup" + is);
m_harmonicModels[i]->saveSettings(doc, elem, "octave" + is);
m_lengthModels[i]->saveSettings(doc, elem, "length" + is);
m_panModels[i]->saveSettings(doc, elem, "pan" + is);
m_detuneModels[i]->saveSettings(doc, elem, "detune" + is);
m_randomModels[i]->saveSettings(doc, elem, "slap" + is);
m_impulseModels[i]->saveSettings(doc, elem, "impulse" + is);
name = "pickup" + QString::number( i );
m_pickupKnobs[i]->saveSettings( _doc, _this, name );
QString sampleString;
base64::encode((const char*)m_graphModels[i]->samples(), s_sampleLength * sizeof(float), sampleString);
name = "octave" + QString::number( i );
m_harmonics[i]->saveSettings( _doc, _this, name );
name = "length" + QString::number( i );
m_lengthKnobs[i]->saveSettings( _doc, _this, name );
name = "pan" + QString::number( i );
m_panKnobs[i]->saveSettings( _doc, _this, name );
name = "detune" + QString::number( i );
m_detuneKnobs[i]->saveSettings( _doc, _this, name );
name = "slap" + QString::number( i );
m_randomKnobs[i]->saveSettings( _doc, _this, name );
name = "impulse" + QString::number( i );
m_impulses[i]->saveSettings( _doc, _this, name );
QString sampleString;
base64::encode(
(const char *)m_graphs[i]->samples(),
__sampleLength * sizeof(float),
sampleString );
name = "graph" + QString::number( i );
_this.setAttribute( name, sampleString );
}
elem.setAttribute("graph" + is, sampleString);
}
}
void Vibed::loadSettings( const QDomElement & _this )
void Vibed::loadSettings(const QDomElement& elem)
{
QString name;
for( int i = 0; i < 9; i++ )
// Load plugin version
bool newVersion = false;
if (elem.hasAttribute("version"))
{
name = "active" + QString::number( i );
m_powerButtons[i]->setValue( _this.attribute( name ).toInt() );
if( m_powerButtons[i]->value() &&
_this.hasAttribute( "volume" + QString::number( i ) ) )
newVersion = elem.attribute("version").toFloat() >= 0.2f;
}
for (int i = 0; i < s_stringCount; ++i)
{
const auto is = QString::number(i);
m_powerModels[i]->setValue(elem.attribute("active" + is).toInt());
// Version 0.2 saves/loads all instrument data unconditionally
const bool hasVolumeAttr = elem.hasAttribute("volume" + is) || !elem.firstChildElement("volume" + is).isNull();
if (newVersion || (m_powerModels[i]->value() && hasVolumeAttr))
{
name = "volume" + QString::number( i );
m_volumeKnobs[i]->loadSettings( _this, name );
name = "stiffness" + QString::number( i );
m_stiffnessKnobs[i]->loadSettings( _this, name );
name = "pick" + QString::number( i );
m_pickKnobs[i]->loadSettings( _this, name );
name = "pickup" + QString::number( i );
m_pickupKnobs[i]->loadSettings( _this, name );
name = "octave" + QString::number( i );
m_harmonics[i]->loadSettings( _this, name );
name = "length" + QString::number( i );
m_lengthKnobs[i]->loadSettings( _this, name );
name = "pan" + QString::number( i );
m_panKnobs[i]->loadSettings( _this, name );
name = "detune" + QString::number( i );
m_detuneKnobs[i]->loadSettings( _this, name );
name = "slap" + QString::number( i );
m_randomKnobs[i]->loadSettings( _this, name );
name = "impulse" + QString::number( i );
m_impulses[i]->loadSettings( _this, name );
m_volumeModels[i]->loadSettings(elem, "volume" + is);
m_stiffnessModels[i]->loadSettings(elem, "stiffness" + is);
m_pickModels[i]->loadSettings(elem, "pick" + is);
m_pickupModels[i]->loadSettings(elem, "pickup" + is);
m_harmonicModels[i]->loadSettings(elem, "octave" + is);
m_lengthModels[i]->loadSettings(elem, "length" + is);
m_panModels[i]->loadSettings(elem, "pan" + is);
m_detuneModels[i]->loadSettings(elem, "detune" + is);
m_randomModels[i]->loadSettings(elem, "slap" + is);
m_impulseModels[i]->loadSettings(elem, "impulse" + is);
int size = 0;
float * shp = 0;
base64::decode( _this.attribute( "graph" +
QString::number( i ) ),
&shp,
&size );
// TODO: check whether size == 128 * sizeof( float ),
// otherwise me might and up in a segfault
m_graphs[i]->setSamples( shp );
delete[] shp;
float* shp = nullptr;
base64::decode(elem.attribute("graph" + is), &shp, &size);
// TODO: do one of the following to avoid
// "uninitialized" wave-shape-buttongroup
// - activate random-wave-shape-button here
// - make wave-shape-buttons simple toggle-buttons
// instead of checkable buttons
// - save and restore selected wave-shape-button
assert(size == 128 * sizeof(float));
m_graphModels[i]->setSamples(shp);
delete[] shp;
}
}
// update();
}
QString Vibed::nodeName() const
{
return( vibedstrings_plugin_descriptor.name );
return vibedstrings_plugin_descriptor.name;
}
void Vibed::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer )
void Vibed::playNote(NotePlayHandle* n, sampleFrame* workingBuffer)
{
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!n->m_pluginData)
{
_n->m_pluginData = new StringContainer( _n->frequency(),
Engine::audioEngine()->processingSampleRate(),
__sampleLength );
for( int i = 0; i < 9; ++i )
const auto newContainer = new StringContainer{n->frequency(),
Engine::audioEngine()->processingSampleRate(), s_sampleLength};
n->m_pluginData = newContainer;
for (int i = 0; i < s_stringCount; ++i)
{
if( m_powerButtons[i]->value() )
if (m_powerModels[i]->value())
{
static_cast<StringContainer*>(
_n->m_pluginData )->addString(
m_harmonics[i]->value(),
m_pickKnobs[i]->value(),
m_pickupKnobs[i]->value(),
m_graphs[i]->samples(),
m_randomKnobs[i]->value(),
m_stiffnessKnobs[i]->value(),
m_detuneKnobs[i]->value(),
static_cast<int>(
m_lengthKnobs[i]->value() ),
m_impulses[i]->value(),
i );
newContainer->addString(
m_harmonicModels[i]->value(),
m_pickModels[i]->value(),
m_pickupModels[i]->value(),
m_graphModels[i]->samples(),
m_randomModels[i]->value(),
m_stiffnessModels[i]->value(),
m_detuneModels[i]->value(),
static_cast<int>(m_lengthModels[i]->value()),
m_impulseModels[i]->value(),
i);
}
}
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
auto ps = static_cast<StringContainer*>(_n->m_pluginData);
const fpp_t frames = n->framesLeftForCurrentPeriod();
const f_cnt_t offset = n->noteOffset();
auto ps = static_cast<StringContainer*>(n->m_pluginData);
for( fpp_t i = offset; i < frames + offset; ++i )
for (fpp_t i = offset; i < frames + offset; ++i)
{
_working_buffer[i][0] = 0.0f;
_working_buffer[i][1] = 0.0f;
int s = 0;
for( int string = 0; string < 9; ++string )
workingBuffer[i][0] = 0.0f;
workingBuffer[i][1] = 0.0f;
for (int str = 0; str < s_stringCount; ++str)
{
if( ps->exists( string ) )
if (ps->exists(str))
{
// pan: 0 -> left, 1 -> right
const float pan = ( m_panKnobs[string]->value() + 1 ) / 2.0f;
const sample_t sample = ps->getStringSample( s ) * m_volumeKnobs[string]->value() / 100.0f;
_working_buffer[i][0] += ( 1.0f - pan ) * sample;
_working_buffer[i][1] += pan * sample;
s++;
const float pan = (m_panModels[str]->value() + 1) / 2.0f;
const sample_t sample = ps->getStringSample(str) * m_volumeModels[str]->value() / 100.0f;
workingBuffer[i][0] += (1.0f - pan) * sample;
workingBuffer[i][1] += pan * sample;
}
}
}
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
instrumentTrack()->processAudioBuffer(workingBuffer, frames + offset, n);
}
void Vibed::deleteNotePluginData( NotePlayHandle * _n )
void Vibed::deleteNotePluginData(NotePlayHandle* n)
{
delete static_cast<StringContainer *>( _n->m_pluginData );
delete static_cast<StringContainer*>(n->m_pluginData);
}
gui::PluginView * Vibed::instantiateView( QWidget * _parent )
gui::PluginView* Vibed::instantiateView(QWidget* parent)
{
return( new gui::VibedView( this, _parent ) );
return new gui::VibedView(this, parent);
}
namespace gui
{
VibedView::VibedView( Instrument * _instrument,
QWidget * _parent ) :
InstrumentViewFixedSize( _instrument, _parent )
VibedView::VibedView(Instrument* instrument, QWidget* parent) :
InstrumentViewFixedSize(instrument, parent),
m_volumeKnob(knobBright_26, this),
m_stiffnessKnob(knobBright_26, this),
m_pickKnob(knobBright_26, this),
m_pickupKnob(knobBright_26, this),
m_panKnob(knobBright_26, this),
m_detuneKnob(knobBright_26, this),
m_randomKnob(knobBright_26, this),
m_lengthKnob(knobBright_26, this),
m_graph(this),
m_impulse("", this),
m_power("", this, tr("Enable waveform")),
m_smoothBtn(this, tr("Smooth waveform")),
m_normalizeBtn(this, tr("Normalize waveform")),
m_sinWaveBtn(this, tr("Sine wave")),
m_triangleWaveBtn(this, tr("Triangle wave")),
m_sawWaveBtn(this, tr("Saw wave")),
m_sqrWaveBtn(this, tr("Square wave")),
m_whiteNoiseWaveBtn(this, tr("White noise")),
m_usrWaveBtn(this, tr("User-defined wave"))
{
setAutoFillBackground( true );
setAutoFillBackground(true);
QPalette pal;
pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap(
"artwork" ) );
setPalette( pal );
m_volumeKnob = new Knob( knobBright_26, this );
m_volumeKnob->setVolumeKnob( true );
m_volumeKnob->move( 103, 142 );
m_volumeKnob->setHintText( tr( "String volume:" ), "" );
pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("artwork"));
setPalette(pal);
m_stiffnessKnob = new Knob( knobBright_26, this );
m_stiffnessKnob->move( 129, 142 );
m_stiffnessKnob->setHintText( tr( "String stiffness:" )
, "" );
m_pickKnob = new Knob( knobBright_26, this );
m_pickKnob->move( 153, 142 );
m_pickKnob->setHintText( tr( "Pick position:" ), "" );
m_volumeKnob.setVolumeKnob(true);
m_volumeKnob.move(103, 142);
m_volumeKnob.setHintText(tr("String volume:"), "");
m_pickupKnob = new Knob( knobBright_26, this );
m_pickupKnob->move( 177, 142 );
m_pickupKnob->setHintText( tr( "Pickup position:" )
, "" );
m_stiffnessKnob.move(129, 142);
m_stiffnessKnob.setHintText(tr("String stiffness:"), "");
m_panKnob = new Knob( knobBright_26, this );
m_panKnob->move( 105, 187 );
m_panKnob->setHintText( tr( "String panning:" ), "" );
m_detuneKnob = new Knob( knobBright_26, this );
m_detuneKnob->move( 150, 187 );
m_detuneKnob->setHintText( tr( "String detune:" ), "" );
m_pickKnob.move(153, 142);
m_pickKnob.setHintText(tr("Pick position:"), "");
m_randomKnob = new Knob( knobBright_26, this );
m_randomKnob->move( 194, 187 );
m_randomKnob->setHintText( tr( "String fuzziness:" )
, "" );
m_pickupKnob.move(177, 142);
m_pickupKnob.setHintText(tr("Pickup position:"), "");
m_lengthKnob = new Knob( knobBright_26, this );
m_lengthKnob->move( 23, 193 );
m_lengthKnob->setHintText( tr( "String length:" )
, "" );
m_panKnob.move(105, 187);
m_panKnob.setHintText(tr("String panning:"), "");
m_impulse = new LedCheckBox( "", this );
m_impulse->move( 23, 94 );
m_impulse->setToolTip(
tr( "Impulse" ) );
m_detuneKnob.move(150, 187);
m_detuneKnob.setHintText(tr("String detune:"), "");
m_harmonic = new NineButtonSelector(
PLUGIN_NAME::getIconPixmap( "button_-2_on" ),
PLUGIN_NAME::getIconPixmap( "button_-2_off" ),
PLUGIN_NAME::getIconPixmap( "button_-1_on" ),
PLUGIN_NAME::getIconPixmap( "button_-1_off" ),
PLUGIN_NAME::getIconPixmap( "button_f_on" ),
PLUGIN_NAME::getIconPixmap( "button_f_off" ),
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
m_randomKnob.move(194, 187);
m_randomKnob.setHintText(tr("String fuzziness:"), "");
m_lengthKnob.move(23, 193);
m_lengthKnob.setHintText(tr("String length:"), "");
m_graph.setWindowTitle(tr("Impulse Editor"));
m_graph.setForeground(PLUGIN_NAME::getIconPixmap("wavegraph4"));
m_graph.move(76, 21);
m_graph.resize(132, 104);
m_impulse.move(23, 94);
m_impulse.setToolTip(tr("Impulse"));
m_power.move(212, 130);
m_power.setToolTip(tr("Enable/disable string"));
m_harmonic = std::make_unique<NineButtonSelector>(
std::array{
PLUGIN_NAME::getIconPixmap("button_-2_on"),
PLUGIN_NAME::getIconPixmap("button_-2_off"),
PLUGIN_NAME::getIconPixmap("button_-1_on"),
PLUGIN_NAME::getIconPixmap("button_-1_off"),
PLUGIN_NAME::getIconPixmap("button_f_on"),
PLUGIN_NAME::getIconPixmap("button_f_off"),
PLUGIN_NAME::getIconPixmap("button_2_on"),
PLUGIN_NAME::getIconPixmap("button_2_off"),
PLUGIN_NAME::getIconPixmap("button_3_on"),
PLUGIN_NAME::getIconPixmap("button_3_off"),
PLUGIN_NAME::getIconPixmap("button_4_on"),
PLUGIN_NAME::getIconPixmap("button_4_off"),
PLUGIN_NAME::getIconPixmap("button_5_on"),
PLUGIN_NAME::getIconPixmap("button_5_off"),
PLUGIN_NAME::getIconPixmap("button_6_on"),
PLUGIN_NAME::getIconPixmap("button_6_off"),
PLUGIN_NAME::getIconPixmap("button_7_on"),
PLUGIN_NAME::getIconPixmap("button_7_off")},
2,
21, 127,
this );
this);
m_harmonic->setWindowTitle( tr( "Octave" ) );
m_harmonic->setWindowTitle(tr("Octave"));
m_stringSelector = new NineButtonSelector(
PLUGIN_NAME::getIconPixmap( "button_1_on" ),
PLUGIN_NAME::getIconPixmap( "button_1_off" ),
PLUGIN_NAME::getIconPixmap( "button_2_on" ),
PLUGIN_NAME::getIconPixmap( "button_2_off" ),
PLUGIN_NAME::getIconPixmap( "button_3_on" ),
PLUGIN_NAME::getIconPixmap( "button_3_off" ),
PLUGIN_NAME::getIconPixmap( "button_4_on" ),
PLUGIN_NAME::getIconPixmap( "button_4_off" ),
PLUGIN_NAME::getIconPixmap( "button_5_on" ),
PLUGIN_NAME::getIconPixmap( "button_5_off" ),
PLUGIN_NAME::getIconPixmap( "button_6_on" ),
PLUGIN_NAME::getIconPixmap( "button_6_off" ),
PLUGIN_NAME::getIconPixmap( "button_7_on" ),
PLUGIN_NAME::getIconPixmap( "button_7_off" ),
PLUGIN_NAME::getIconPixmap( "button_8_on" ),
PLUGIN_NAME::getIconPixmap( "button_8_off" ),
PLUGIN_NAME::getIconPixmap( "button_9_on" ),
PLUGIN_NAME::getIconPixmap( "button_9_off" ),
0,
21, 39,
this);
m_stringSelector = std::make_unique<NineButtonSelector>(
std::array{
PLUGIN_NAME::getIconPixmap("button_1_on"),
PLUGIN_NAME::getIconPixmap("button_1_off"),
PLUGIN_NAME::getIconPixmap("button_2_on"),
PLUGIN_NAME::getIconPixmap("button_2_off"),
PLUGIN_NAME::getIconPixmap("button_3_on"),
PLUGIN_NAME::getIconPixmap("button_3_off"),
PLUGIN_NAME::getIconPixmap("button_4_on"),
PLUGIN_NAME::getIconPixmap("button_4_off"),
PLUGIN_NAME::getIconPixmap("button_5_on"),
PLUGIN_NAME::getIconPixmap("button_5_off"),
PLUGIN_NAME::getIconPixmap("button_6_on"),
PLUGIN_NAME::getIconPixmap("button_6_off"),
PLUGIN_NAME::getIconPixmap("button_7_on"),
PLUGIN_NAME::getIconPixmap("button_7_off"),
PLUGIN_NAME::getIconPixmap("button_8_on"),
PLUGIN_NAME::getIconPixmap("button_8_off"),
PLUGIN_NAME::getIconPixmap("button_9_on"),
PLUGIN_NAME::getIconPixmap("button_9_off")},
0,
21, 39,
this);
m_graph = new Graph( this );
m_graph->setWindowTitle( tr( "Impulse Editor" ) );
m_graph->setForeground( PLUGIN_NAME::getIconPixmap( "wavegraph4" ) );
m_graph->move( 76, 21 );
m_graph->resize(132, 104);
m_power = new LedCheckBox( "", this, tr( "Enable waveform" ) );
m_power->move( 212, 130 );
m_power->setToolTip(
tr( "Enable/disable string" ) );
// String selector is not a part of the model
m_stringSelector->setWindowTitle( tr( "String" ) );
m_stringSelector->setWindowTitle(tr("String"));
connect( m_stringSelector, SIGNAL( NineButtonSelection( int ) ),
this, SLOT( showString( int ) ) );
connect(m_stringSelector.get(), SIGNAL(NineButtonSelection(int)), this, SLOT(showString(int)));
showString( 0 );
showString(0);
m_sinWaveBtn = new PixmapButton( this, tr( "Sine wave" ) );
m_sinWaveBtn->move( 212, 24 );
m_sinWaveBtn->setActiveGraphic( embed::getIconPixmap(
"sin_wave_active" ) );
m_sinWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"sin_wave_inactive" ) );
m_sinWaveBtn->setToolTip(
tr( "Sine wave" ) );
connect( m_sinWaveBtn, SIGNAL (clicked () ),
this, SLOT ( sinWaveClicked() ) );
m_smoothBtn.move(79, 129);
m_smoothBtn.setActiveGraphic(PLUGIN_NAME::getIconPixmap("smooth_active"));
m_smoothBtn.setInactiveGraphic(PLUGIN_NAME::getIconPixmap("smooth_inactive"));
m_smoothBtn.setChecked(false);
m_smoothBtn.setToolTip(tr("Smooth waveform"));
connect(&m_smoothBtn, SIGNAL(clicked()), this, SLOT(smoothClicked()));
m_triangleWaveBtn = new PixmapButton( this, tr( "Triangle wave" ) );
m_triangleWaveBtn->move( 212, 41 );
m_triangleWaveBtn->setActiveGraphic(
embed::getIconPixmap( "triangle_wave_active" ) );
m_triangleWaveBtn->setInactiveGraphic(
embed::getIconPixmap( "triangle_wave_inactive" ) );
m_triangleWaveBtn->setToolTip(
tr( "Triangle wave" ) );
connect( m_triangleWaveBtn, SIGNAL ( clicked () ),
this, SLOT ( triangleWaveClicked() ) );
m_normalizeBtn.move(96, 129);
m_normalizeBtn.setActiveGraphic(PLUGIN_NAME::getIconPixmap("normalize_active"));
m_normalizeBtn.setInactiveGraphic(PLUGIN_NAME::getIconPixmap("normalize_inactive"));
m_normalizeBtn.setChecked(false);
m_normalizeBtn.setToolTip(tr("Normalize waveform"));
connect(&m_normalizeBtn, SIGNAL(clicked()), this, SLOT(normalizeClicked()));
m_sawWaveBtn = new PixmapButton( this, tr( "Saw wave" ) );
m_sawWaveBtn->move( 212, 58 );
m_sawWaveBtn->setActiveGraphic( embed::getIconPixmap(
"saw_wave_active" ) );
m_sawWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"saw_wave_inactive" ) );
m_sawWaveBtn->setToolTip(
tr( "Saw wave" ) );
connect( m_sawWaveBtn, SIGNAL (clicked () ),
this, SLOT ( sawWaveClicked() ) );
m_sinWaveBtn.move(212, 24);
m_sinWaveBtn.setActiveGraphic(embed::getIconPixmap("sin_wave_active"));
m_sinWaveBtn.setInactiveGraphic(embed::getIconPixmap("sin_wave_inactive"));
m_sinWaveBtn.setToolTip(tr("Sine wave"));
connect(&m_sinWaveBtn, SIGNAL(clicked()), this, SLOT(sinWaveClicked()));
m_sqrWaveBtn = new PixmapButton( this, tr( "Square wave" ) );
m_sqrWaveBtn->move( 212, 75 );
m_sqrWaveBtn->setActiveGraphic( embed::getIconPixmap(
"square_wave_active" ) );
m_sqrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"square_wave_inactive" ) );
m_sqrWaveBtn->setToolTip(
tr( "Square wave" ) );
connect( m_sqrWaveBtn, SIGNAL ( clicked () ),
this, SLOT ( sqrWaveClicked() ) );
m_triangleWaveBtn.move(212, 41);
m_triangleWaveBtn.setActiveGraphic(embed::getIconPixmap("triangle_wave_active"));
m_triangleWaveBtn.setInactiveGraphic(embed::getIconPixmap("triangle_wave_inactive"));
m_triangleWaveBtn.setToolTip(tr("Triangle wave"));
connect(&m_triangleWaveBtn, SIGNAL(clicked()), this, SLOT(triangleWaveClicked()));
m_whiteNoiseWaveBtn = new PixmapButton( this, tr( "White noise" ) );
m_whiteNoiseWaveBtn->move( 212, 92 );
m_whiteNoiseWaveBtn->setActiveGraphic(
embed::getIconPixmap( "white_noise_wave_active" ) );
m_whiteNoiseWaveBtn->setInactiveGraphic(
embed::getIconPixmap( "white_noise_wave_inactive" ) );
m_whiteNoiseWaveBtn->setToolTip(
tr( "White noise" ) );
connect( m_whiteNoiseWaveBtn, SIGNAL ( clicked () ),
this, SLOT ( noiseWaveClicked() ) );
m_sawWaveBtn.move(212, 58);
m_sawWaveBtn.setActiveGraphic(embed::getIconPixmap("saw_wave_active"));
m_sawWaveBtn.setInactiveGraphic(embed::getIconPixmap("saw_wave_inactive"));
m_sawWaveBtn.setToolTip(tr("Saw wave"));
connect(&m_sawWaveBtn, SIGNAL(clicked()), this, SLOT(sawWaveClicked()));
m_usrWaveBtn = new PixmapButton( this, tr( "User-defined wave" ) );
m_usrWaveBtn->move( 212, 109 );
m_usrWaveBtn->setActiveGraphic( embed::getIconPixmap(
"usr_wave_active" ) );
m_usrWaveBtn->setInactiveGraphic( embed::getIconPixmap(
"usr_wave_inactive" ) );
m_usrWaveBtn->setToolTip(
tr( "User-defined wave" ) );
connect( m_usrWaveBtn, SIGNAL ( clicked () ),
this, SLOT ( usrWaveClicked() ) );
m_sqrWaveBtn.move(212, 75);
m_sqrWaveBtn.setActiveGraphic(embed::getIconPixmap("square_wave_active"));
m_sqrWaveBtn.setInactiveGraphic(embed::getIconPixmap("square_wave_inactive"));
m_sqrWaveBtn.setToolTip(tr("Square wave"));
connect(&m_sqrWaveBtn, SIGNAL(clicked()), this, SLOT(sqrWaveClicked()));
m_whiteNoiseWaveBtn.move(212, 92);
m_whiteNoiseWaveBtn.setActiveGraphic(embed::getIconPixmap("white_noise_wave_active"));
m_whiteNoiseWaveBtn.setInactiveGraphic(embed::getIconPixmap("white_noise_wave_inactive"));
m_whiteNoiseWaveBtn.setToolTip(tr("White noise"));
connect(&m_whiteNoiseWaveBtn, SIGNAL(clicked()), this, SLOT(noiseWaveClicked()));
m_smoothBtn = new PixmapButton( this, tr( "Smooth waveform" ) );
m_smoothBtn->move( 79, 129 );
m_smoothBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"smooth_active" ) );
m_smoothBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
"smooth_inactive" ) );
m_smoothBtn->setChecked( false );
m_smoothBtn->setToolTip(
tr( "Smooth waveform" ) );
connect( m_smoothBtn, SIGNAL ( clicked () ),
this, SLOT ( smoothClicked() ) );
m_normalizeBtn = new PixmapButton( this, tr( "Normalize waveform" ) );
m_normalizeBtn->move( 96, 129 );
m_normalizeBtn->setActiveGraphic( PLUGIN_NAME::getIconPixmap(
"normalize_active" ) );
m_normalizeBtn->setInactiveGraphic( PLUGIN_NAME::getIconPixmap(
"normalize_inactive" ) );
m_normalizeBtn->setChecked( false );
m_normalizeBtn->setToolTip(
tr( "Normalize waveform" ) );
connect( m_normalizeBtn, SIGNAL ( clicked () ),
this, SLOT ( normalizeClicked() ) );
m_usrWaveBtn.move(212, 109);
m_usrWaveBtn.setActiveGraphic(embed::getIconPixmap("usr_wave_active"));
m_usrWaveBtn.setInactiveGraphic(embed::getIconPixmap("usr_wave_inactive"));
m_usrWaveBtn.setToolTip(tr("User-defined wave"));
connect(&m_usrWaveBtn, SIGNAL(clicked()),this, SLOT(usrWaveClicked()));
}
void VibedView::modelChanged()
{
showString( 0 );
showString(0);
}
void VibedView::showString( int _string )
void VibedView::showString(int str)
{
auto v = castModel<Vibed>();
m_pickKnob->setModel( v->m_pickKnobs[_string] );
m_pickupKnob->setModel( v->m_pickupKnobs[_string] );
m_stiffnessKnob->setModel( v->m_stiffnessKnobs[_string] );
m_volumeKnob->setModel( v->m_volumeKnobs[_string] );
m_panKnob->setModel( v->m_panKnobs[_string] );
m_detuneKnob->setModel( v->m_detuneKnobs[_string] );
m_randomKnob->setModel( v->m_randomKnobs[_string] );
m_lengthKnob->setModel( v->m_lengthKnobs[_string] );
m_graph->setModel( v->m_graphs[_string] );
m_impulse->setModel( v->m_impulses[_string] );
m_harmonic->setModel( v->m_harmonics[_string] );
m_power->setModel( v->m_powerButtons[_string] );
m_pickKnob.setModel(v->m_pickModels[str].get());
m_pickupKnob.setModel(v->m_pickupModels[str].get());
m_stiffnessKnob.setModel(v->m_stiffnessModels[str].get());
m_volumeKnob.setModel(v->m_volumeModels[str].get());
m_panKnob.setModel(v->m_panModels[str].get());
m_detuneKnob.setModel(v->m_detuneModels[str].get());
m_randomKnob.setModel(v->m_randomModels[str].get());
m_lengthKnob.setModel(v->m_lengthModels[str].get());
m_graph.setModel(v->m_graphModels[str].get());
m_impulse.setModel(v->m_impulseModels[str].get());
m_harmonic->setModel(v->m_harmonicModels[str].get());
m_power.setModel(v->m_powerModels[str].get());
}
void VibedView::sinWaveClicked()
{
m_graph->model()->setWaveToSine();
m_graph.model()->setWaveToSine();
Engine::getSong()->setModified();
}
void VibedView::triangleWaveClicked()
{
m_graph->model()->setWaveToTriangle();
m_graph.model()->setWaveToTriangle();
Engine::getSong()->setModified();
}
void VibedView::sawWaveClicked()
{
m_graph->model()->setWaveToSaw();
m_graph.model()->setWaveToSaw();
Engine::getSong()->setModified();
}
void VibedView::sqrWaveClicked()
{
m_graph->model()->setWaveToSquare();
m_graph.model()->setWaveToSquare();
Engine::getSong()->setModified();
}
void VibedView::noiseWaveClicked()
{
m_graph->model()->setWaveToNoise();
m_graph.model()->setWaveToNoise();
Engine::getSong()->setModified();
}
void VibedView::usrWaveClicked()
{
QString fileName = m_graph->model()->setWaveToUser();
m_usrWaveBtn->setToolTip(fileName);
QString fileName = m_graph.model()->setWaveToUser();
m_usrWaveBtn.setToolTip(fileName);
Engine::getSong()->setModified();
}
void VibedView::smoothClicked()
{
m_graph->model()->smooth();
m_graph.model()->smooth();
Engine::getSong()->setModified();
}
void VibedView::normalizeClicked()
{
m_graph->model()->normalize();
m_graph.model()->normalize();
Engine::getSong()->setModified();
}
void VibedView::contextMenuEvent( QContextMenuEvent * )
void VibedView::contextMenuEvent(QContextMenuEvent*)
{
CaptionMenu contextMenu( model()->displayName(), this );
contextMenu.exec( QCursor::pos() );
CaptionMenu contextMenu(model()->displayName(), this);
contextMenu.exec(QCursor::pos());
}
@@ -683,12 +526,11 @@ extern "C"
{
// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
PLUGIN_EXPORT Plugin* lmms_plugin_main(Model* m, void*)
{
return( new Vibed( static_cast<InstrumentTrack *>( m ) ) );
return new Vibed(static_cast<InstrumentTrack*>(m));
}
}

View File

@@ -2,7 +2,7 @@
* Vibed.h - combination of PluckedStringSynth and BitInvader
*
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/yahoo/com>
*
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -21,12 +21,20 @@
* Boston, MA 02110-1301 USA.
*
*/
#ifndef _VIBED_H
#define _VIBED_H
#ifndef LMMS_VIBED_H
#define LMMS_VIBED_H
#include "Instrument.h"
#include "InstrumentView.h"
#include "NineButtonSelector.h"
#include "Knob.h"
#include "LedCheckBox.h"
#include "Graph.h"
#include "PixmapButton.h"
#include <array>
#include <memory>
namespace lmms
{
@@ -46,45 +54,42 @@ class Vibed : public Instrument
{
Q_OBJECT
public:
Vibed( InstrumentTrack * _instrument_track );
Vibed(InstrumentTrack* instrumentTrack);
~Vibed() override = default;
void playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer ) override;
void deleteNotePluginData( NotePlayHandle * _n ) override;
void playNote(NotePlayHandle* n, sampleFrame* workingBuffer) override;
void deleteNotePluginData(NotePlayHandle* n) override;
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
void loadSettings( const QDomElement & _this ) override;
void saveSettings(QDomDocument& doc, QDomElement& elem) override;
void loadSettings(const QDomElement& elem) override;
QString nodeName() const override;
Flags flags() const override
{
return IsNotBendable;
}
gui::PluginView* instantiateView( QWidget * _parent ) override;
Flags flags() const override { return IsNotBendable; }
gui::PluginView* instantiateView(QWidget* parent) override;
private:
QList<FloatModel*> m_pickKnobs;
QList<FloatModel*> m_pickupKnobs;
QList<FloatModel*> m_stiffnessKnobs;
QList<FloatModel*> m_volumeKnobs;
QList<FloatModel*> m_panKnobs;
QList<FloatModel*> m_detuneKnobs;
QList<FloatModel*> m_randomKnobs;
QList<FloatModel*> m_lengthKnobs;
QList<BoolModel*> m_powerButtons;
QList<graphModel*> m_graphs;
QList<BoolModel*> m_impulses;
QList<gui::NineButtonSelectorModel*> m_harmonics;
class StringContainer;
static const int __sampleLength = 128;
static constexpr int s_sampleLength = 128;
static constexpr int s_stringCount = 9;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_pickModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_pickupModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_stiffnessModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_volumeModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_panModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_detuneModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_randomModels;
std::array<std::unique_ptr<FloatModel>, s_stringCount> m_lengthModels;
std::array<std::unique_ptr<BoolModel>, s_stringCount> m_powerModels;
std::array<std::unique_ptr<graphModel>, s_stringCount> m_graphModels;
std::array<std::unique_ptr<BoolModel>, s_stringCount> m_impulseModels;
std::array<std::unique_ptr<NineButtonSelectorModel>, s_stringCount> m_harmonicModels;
friend class gui::VibedView;
} ;
};
namespace gui
@@ -95,13 +100,12 @@ class VibedView : public InstrumentViewFixedSize
{
Q_OBJECT
public:
VibedView( Instrument * _instrument,
QWidget * _parent );
VibedView(Instrument* instrument, QWidget* parent);
~VibedView() override = default;
public slots:
void showString( int _string );
void contextMenuEvent( QContextMenuEvent * ) override;
void showString(int str);
void contextMenuEvent(QContextMenuEvent*) override;
protected slots:
void sinWaveClicked();
@@ -116,35 +120,32 @@ protected slots:
private:
void modelChanged() override;
// String-related
Knob * m_pickKnob;
Knob * m_pickupKnob;
Knob * m_stiffnessKnob;
Knob * m_volumeKnob;
Knob * m_panKnob;
Knob * m_detuneKnob;
Knob * m_randomKnob;
Knob * m_lengthKnob;
Graph * m_graph;
NineButtonSelector * m_harmonic;
LedCheckBox * m_impulse;
LedCheckBox * m_power;
Knob m_volumeKnob;
Knob m_stiffnessKnob;
Knob m_pickKnob;
Knob m_pickupKnob;
Knob m_panKnob;
Knob m_detuneKnob;
Knob m_randomKnob;
Knob m_lengthKnob;
Graph m_graph;
LedCheckBox m_impulse;
LedCheckBox m_power;
std::unique_ptr<NineButtonSelector> m_harmonic;
// Not in model
NineButtonSelector * m_stringSelector;
PixmapButton * m_smoothBtn;
PixmapButton * m_normalizeBtn;
std::unique_ptr<NineButtonSelector> m_stringSelector;
PixmapButton m_smoothBtn;
PixmapButton m_normalizeBtn;
// From impulse editor
PixmapButton * m_sinWaveBtn;
PixmapButton * m_triangleWaveBtn;
PixmapButton * m_sqrWaveBtn;
PixmapButton * m_sawWaveBtn;
PixmapButton * m_whiteNoiseWaveBtn;
PixmapButton * m_usrWaveBtn;
PixmapButton m_sinWaveBtn;
PixmapButton m_triangleWaveBtn;
PixmapButton m_sawWaveBtn;
PixmapButton m_sqrWaveBtn;
PixmapButton m_whiteNoiseWaveBtn;
PixmapButton m_usrWaveBtn;
};
@@ -152,4 +153,4 @@ private:
} // namespace lmms
#endif
#endif // LMMS_VIBED_H

View File

@@ -1,8 +1,8 @@
/*
* vibrating_sring.h - model of a vibrating string lifted from pluckedSynth
* VibratingString.cpp - model of a vibrating string lifted from pluckedSynth
*
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/yahoo/com>
*
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -21,93 +21,66 @@
* Boston, MA 02110-1301 USA.
*
*/
#include <cmath>
#include "VibratingString.h"
#include "interpolation.h"
#include "AudioEngine.h"
#include "Engine.h"
#include <algorithm>
#include <cstdlib>
namespace lmms
{
VibratingString::VibratingString( float _pitch,
float _pick,
float _pickup,
float * _impulse,
int _len,
sample_rate_t _sample_rate,
int _oversample,
float _randomize,
float _string_loss,
float _detune,
bool _state ) :
m_oversample( 2 * _oversample / (int)( _sample_rate /
Engine::audioEngine()->baseSampleRate() ) ),
m_randomize( _randomize ),
m_stringLoss( 1.0f - _string_loss ),
m_state( 0.1f )
VibratingString::VibratingString(float pitch, float pick, float pickup, const float* impulse, int len,
sample_rate_t sampleRate, int oversample, float randomize, float stringLoss, float detune, bool state) :
m_oversample{2 * oversample / static_cast<int>(sampleRate / Engine::audioEngine()->baseSampleRate())},
m_randomize{randomize},
m_stringLoss{1.0f - stringLoss},
m_choice{static_cast<int>(m_oversample * static_cast<float>(std::rand()) / RAND_MAX)},
m_state{0.1f},
m_outsamp{std::make_unique<sample_t[]>(m_oversample)}
{
m_outsamp = new sample_t[m_oversample];
int string_length;
string_length = static_cast<int>( m_oversample * _sample_rate /
_pitch ) + 1;
string_length += static_cast<int>( string_length * -_detune );
int stringLength = static_cast<int>(m_oversample * sampleRate / pitch) + 1;
stringLength += static_cast<int>(stringLength * -detune);
int pick = static_cast<int>( ceil( string_length * _pick ) );
if( ! _state )
const int pickInt = static_cast<int>(std::ceil(stringLength * pick));
if (!state)
{
m_impulse = new float[string_length];
resample( _impulse, _len, string_length );
m_impulse = std::make_unique<float[]>(stringLength);
resample(impulse, len, stringLength);
}
else
{
m_impulse = new float[_len];
for( int i = 0; i < _len; i++ )
{
m_impulse[i] = _impulse[i];
}
{
m_impulse = std::make_unique<float[]>(len);
std::copy_n(impulse, len, m_impulse.get());
}
m_toBridge = VibratingString::initDelayLine( string_length, pick );
m_fromBridge = VibratingString::initDelayLine( string_length, pick );
VibratingString::setDelayLine( m_toBridge, pick,
m_impulse, _len, 0.5f,
_state );
VibratingString::setDelayLine( m_fromBridge, pick,
m_impulse, _len, 0.5f,
_state);
m_choice = static_cast<int>( m_oversample *
static_cast<float>( rand() ) / RAND_MAX );
m_pickupLoc = static_cast<int>( _pickup * string_length );
m_toBridge = VibratingString::initDelayLine(stringLength);
m_fromBridge = VibratingString::initDelayLine(stringLength);
VibratingString::setDelayLine(m_toBridge.get(), pickInt, m_impulse.get(), len, 0.5f, state);
VibratingString::setDelayLine(m_fromBridge.get(), pickInt, m_impulse.get(), len, 0.5f, state);
m_pickupLoc = static_cast<int>(pickup * stringLength);
}
VibratingString::delayLine * VibratingString::initDelayLine( int _len,
int _pick )
std::unique_ptr<VibratingString::DelayLine> VibratingString::initDelayLine(int len)
{
auto dl = new VibratingString::delayLine[_len];
dl->length = _len;
if( _len > 0 )
auto dl = std::make_unique<VibratingString::DelayLine>();
dl->length = len;
if (len > 0)
{
dl->data = new sample_t[_len];
dl->data = std::make_unique<sample_t[]>(len);
float r;
float offset = 0.0f;
for( int i = 0; i < dl->length; i++ )
for (int i = 0; i < dl->length; ++i)
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
r = static_cast<float>(std::rand()) / RAND_MAX;
offset = (m_randomize / 2.0f - m_randomize) * r;
dl->data[i] = offset;
}
}
@@ -116,46 +89,25 @@ VibratingString::delayLine * VibratingString::initDelayLine( int _len,
dl->data = nullptr;
}
dl->pointer = dl->data;
dl->end = dl->data + _len - 1;
dl->pointer = dl->data.get();
dl->end = dl->data.get() + len - 1;
return( dl );
return dl;
}
void VibratingString::freeDelayLine( delayLine * _dl )
void VibratingString::resample(const float* src, f_cnt_t srcFrames, f_cnt_t dstFrames)
{
if( _dl )
for (f_cnt_t frame = 0; frame < dstFrames; ++frame)
{
delete[] _dl->data;
delete[] _dl;
}
}
void VibratingString::resample( float *_src, f_cnt_t _src_frames,
f_cnt_t _dst_frames )
{
for( f_cnt_t frame = 0; frame < _dst_frames; ++frame )
{
const float src_frame_float = frame *
(float) _src_frames /
_dst_frames;
const float frac_pos = src_frame_float -
static_cast<f_cnt_t>( src_frame_float );
const f_cnt_t src_frame = qBound<f_cnt_t>(
1, static_cast<f_cnt_t>( src_frame_float ),
_src_frames - 3 );
const float srcFrameFloat = frame * static_cast<float>(srcFrames) / dstFrames;
const float fracPos = srcFrameFloat - static_cast<f_cnt_t>(srcFrameFloat);
const f_cnt_t srcFrame = std::clamp(static_cast<f_cnt_t>(srcFrameFloat), 1, srcFrames - 3);
m_impulse[frame] = cubicInterpolate(
_src[src_frame - 1],
_src[src_frame + 0],
_src[src_frame + 1],
_src[src_frame + 2],
frac_pos );
src[srcFrame - 1],
src[srcFrame + 0],
src[srcFrame + 1],
src[srcFrame + 2],
fracPos);
}
}

View File

@@ -2,7 +2,7 @@
* VibratingString.h - model of a vibrating string lifted from pluckedSynth
*
* Copyright (c) 2006-2007 Danny McRae <khjklujn/at/yahoo/com>
*
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
@@ -21,10 +21,12 @@
* Boston, MA 02110-1301 USA.
*
*/
#ifndef _VIBRATING_STRING_H
#define _VIBRATING_STRING_H
#include <stdlib.h>
#ifndef LMMS_VIBRATING_STRING_H
#define LMMS_VIBRATING_STRING_H
#include <memory>
#include <cstdlib>
#include "lmms_basics.h"
@@ -34,244 +36,219 @@ namespace lmms
class VibratingString
{
public:
VibratingString( float _pitch,
float _pick,
float _pickup,
float * impluse,
int _len,
sample_rate_t _sample_rate,
int _oversample,
float _randomize,
float _string_loss,
float _detune,
bool _state );
inline ~VibratingString()
{
delete[] m_outsamp;
delete[] m_impulse;
VibratingString::freeDelayLine( m_fromBridge );
VibratingString::freeDelayLine( m_toBridge );
}
VibratingString() = default;
VibratingString(float pitch, float pick, float pickup, const float* impulse, int len,
sample_rate_t sampleRate, int oversample, float randomize, float stringLoss, float detune, bool state);
~VibratingString() = default;
inline sample_t nextSample()
{
VibratingString(const VibratingString&) = delete;
VibratingString& operator=(const VibratingString&) = delete;
VibratingString(VibratingString&&) noexcept = delete;
VibratingString& operator=(VibratingString&&) noexcept = default;
sample_t nextSample()
{
sample_t ym0;
sample_t ypM;
for( int i = 0; i < m_oversample; i++)
for (int i = 0; i < m_oversample; ++i)
{
// Output at pickup position
m_outsamp[i] = fromBridgeAccess( m_fromBridge,
m_pickupLoc );
m_outsamp[i] += toBridgeAccess( m_toBridge,
m_pickupLoc );
m_outsamp[i] = fromBridgeAccess(m_fromBridge.get(), m_pickupLoc);
m_outsamp[i] += toBridgeAccess(m_toBridge.get(), m_pickupLoc);
// Sample traveling into "bridge"
ym0 = toBridgeAccess( m_toBridge, 1 );
ym0 = toBridgeAccess(m_toBridge.get(), 1);
// Sample to "nut"
ypM = fromBridgeAccess( m_fromBridge,
m_fromBridge->length - 2 );
ypM = fromBridgeAccess(m_fromBridge.get(), m_fromBridge->length - 2);
// String state update
// Decrement pointer and then update
fromBridgeUpdate( m_fromBridge,
-bridgeReflection( ym0 ) );
fromBridgeUpdate(m_fromBridge.get(), -bridgeReflection(ym0));
// Update and then increment pointer
toBridgeUpdate( m_toBridge, -ypM );
toBridgeUpdate(m_toBridge.get(), -ypM);
}
return( m_outsamp[m_choice] );
return m_outsamp[m_choice];
}
private:
struct delayLine
struct DelayLine
{
sample_t * data;
std::unique_ptr<sample_t[]> data;
int length;
sample_t * pointer;
sample_t * end;
} ;
sample_t* pointer;
sample_t* end;
};
delayLine * m_fromBridge;
delayLine * m_toBridge;
std::unique_ptr<DelayLine> m_fromBridge;
std::unique_ptr<DelayLine> m_toBridge;
int m_pickupLoc;
int m_oversample;
float m_randomize;
float m_stringLoss;
float * m_impulse;
std::unique_ptr<float[]> m_impulse;
int m_choice;
float m_state;
sample_t * m_outsamp;
delayLine * initDelayLine( int _len, int _pick );
static void freeDelayLine( delayLine * _dl );
void resample( float *_src, f_cnt_t _src_frames, f_cnt_t _dst_frames );
/* setDelayLine initializes the string with an impulse at the pick
std::unique_ptr<sample_t[]> m_outsamp;
std::unique_ptr<DelayLine> initDelayLine(int len);
void resample(const float* src, f_cnt_t srcFrames, f_cnt_t dstFrames);
/**
* setDelayLine initializes the string with an impulse at the pick
* position unless the impulse is longer than the string, in which
* case the impulse gets truncated. */
inline void setDelayLine( delayLine * _dl,
int _pick,
const float * _values,
int _len,
float _scale,
bool _state )
* case the impulse gets truncated.
*/
void setDelayLine(DelayLine* dl, int pick, const float* values, int len, float scale, bool state)
{
float r;
float offset;
if( ! _state )
if (!state)
{
for( int i = 0; i < _pick; i++ )
for (int i = 0; i < pick; ++i)
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i] = _scale *
_values[_dl->length - i - 1] +
offset;
r = static_cast<float>(std::rand()) / RAND_MAX;
offset = (m_randomize / 2.0f - m_randomize) * r;
dl->data[i] = scale * values[dl->length - i - 1] + offset;
}
for( int i = _pick; i < _dl->length; i++ )
for (int i = pick; i < dl->length; ++i)
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i] = _scale *
_values[i - _pick] + offset ;
r = static_cast<float>(std::rand()) / RAND_MAX;
offset = (m_randomize / 2.0f - m_randomize) * r;
dl->data[i] = scale * values[i - pick] + offset;
}
}
else
{
if( _len + _pick > _dl->length )
if (len + pick > dl->length)
{
for( int i = _pick; i < _dl->length; i++ )
for (int i = pick; i < dl->length; ++i)
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i] = _scale *
_values[i-_pick] +
offset;
r = static_cast<float>(std::rand()) / RAND_MAX;
offset = (m_randomize / 2.0f - m_randomize) * r;
dl->data[i] = scale * values[i - pick] + offset;
}
}
else
{
for( int i = 0; i < _len; i++ )
for (int i = 0; i < len; ++i)
{
r = static_cast<float>( rand() ) /
RAND_MAX;
offset = ( m_randomize / 2.0f -
m_randomize ) * r;
_dl->data[i+_pick] = _scale *
_values[i] +
offset;
r = static_cast<float>(std::rand()) / RAND_MAX;
offset = (m_randomize / 2.0f - m_randomize) * r;
dl->data[i+pick] = scale * values[i] + offset;
}
}
}
}
/* toBridgeUpdate(dl, insamp);
* Places "nut-reflected" sample from upper delay-line into
* current lower delay-line pointer position (which represents
* x = 0 position). The pointer is then incremented (i.e. the
* wave travels one sample to the left), turning the previous
* position into an "effective" x = L position for the next
* iteration. */
inline void toBridgeUpdate( delayLine * _dl, sample_t _insamp )
/**
* toBridgeUpdate(dl, insamp);
* Places "nut-reflected" sample from upper delay-line into
* current lower delay-line pointer position (which represents
* x = 0 position). The pointer is then incremented (i.e. the
* wave travels one sample to the left), turning the previous
* position into an "effective" x = L position for the next
* iteration.
*/
void toBridgeUpdate(DelayLine* dl, sample_t insamp)
{
sample_t * ptr = _dl->pointer;
*ptr = _insamp * m_stringLoss;
sample_t* ptr = dl->pointer;
*ptr = insamp * m_stringLoss;
++ptr;
if( ptr > _dl->end )
if (ptr > dl->end)
{
ptr = _dl->data;
ptr = dl->data.get();
}
_dl->pointer = ptr;
dl->pointer = ptr;
}
/* fromBridgeUpdate(dl, insamp);
* Decrements current upper delay-line pointer position (i.e.
* the wave travels one sample to the right), moving it to the
* "effective" x = 0 position for the next iteration. The
* "bridge-reflected" sample from lower delay-line is then placed
* into this position. */
inline void fromBridgeUpdate( delayLine * _dl,
sample_t _insamp )
/**
* fromBridgeUpdate(dl, insamp);
* Decrements current upper delay-line pointer position (i.e.
* the wave travels one sample to the right), moving it to the
* "effective" x = 0 position for the next iteration. The
* "bridge-reflected" sample from lower delay-line is then placed
* into this position.
*/
void fromBridgeUpdate(DelayLine* dl, sample_t insamp)
{
sample_t * ptr = _dl->pointer;
sample_t* ptr = dl->pointer;
--ptr;
if( ptr < _dl->data )
if (ptr < dl->data.get())
{
ptr = _dl->end;
ptr = dl->end;
}
*ptr = _insamp * m_stringLoss;
_dl->pointer = ptr;
*ptr = insamp * m_stringLoss;
dl->pointer = ptr;
}
/* dlAccess(dl, position);
* Returns sample "position" samples into delay-line's past.
* Position "0" points to the most recently inserted sample. */
static inline sample_t dlAccess( delayLine * _dl, int _position )
/**
* dlAccess(dl, position);
* Returns sample "position" samples into delay-line's past.
* Position "0" points to the most recently inserted sample.
*/
static sample_t dlAccess(DelayLine* dl, int position)
{
sample_t * outpos = _dl->pointer + _position;
while( outpos < _dl->data )
sample_t* outpos = dl->pointer + position;
while (outpos < dl->data.get())
{
outpos += _dl->length;
outpos += dl->length;
}
while( outpos > _dl->end )
while (outpos > dl->end)
{
outpos -= _dl->length;
outpos -= dl->length;
}
return( *outpos );
return *outpos;
}
/*
* Right-going delay line:
* -->---->---->---
* x=0
* (pointer)
* Left-going delay line:
* --<----<----<---
* x=0
* (pointer)
*/
* Right-going delay line:
* -->---->---->---
* x=0
* (pointer)
* Left-going delay line:
* --<----<----<---
* x=0
* (pointer)
*/
/* fromBridgeAccess(dl, position);
* Returns spatial sample at position "position", where position zero
* is equal to the current upper delay-line pointer position (x = 0).
* In a right-going delay-line, position increases to the right, and
* delay increases to the right => left = past and right = future. */
static inline sample_t fromBridgeAccess( delayLine * _dl,
int _position )
/**
* fromBridgeAccess(dl, position);
* Returns spatial sample at position "position", where position zero
* is equal to the current upper delay-line pointer position (x = 0).
* In a right-going delay-line, position increases to the right, and
* delay increases to the right => left = past and right = future.
*/
static sample_t fromBridgeAccess(DelayLine* dl, int position)
{
return( dlAccess( _dl, _position ) );
return dlAccess(dl, position);
}
/* toBridgeAccess(dl, position);
* Returns spatial sample at position "position", where position zero
* is equal to the current lower delay-line pointer position (x = 0).
* In a left-going delay-line, position increases to the right, and
* delay DEcreases to the right => left = future and right = past. */
static inline sample_t toBridgeAccess( delayLine * _dl, int _position )
/**
* toBridgeAccess(dl, position);
* Returns spatial sample at position "position", where position zero
* is equal to the current lower delay-line pointer position (x = 0).
* In a left-going delay-line, position increases to the right, and
* delay DEcreases to the right => left = future and right = past.
*/
static sample_t toBridgeAccess(DelayLine* dl, int position)
{
return( dlAccess( _dl, _position ) );
return dlAccess(dl, position);
}
inline sample_t bridgeReflection( sample_t _insamp )
sample_t bridgeReflection(sample_t insamp)
{
return( m_state = ( m_state + _insamp ) * 0.5 );
m_state = (m_state + insamp) * 0.5;
return m_state;
}
} ;
};
} // namespace lmms
#endif
#endif // LMMS_VIBRATING_STRING_H

View File

@@ -329,7 +329,7 @@ WatsynInstrument::WatsynInstrument( InstrumentTrack * _instrument_track ) :
void WatsynInstrument::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == nullptr )
if (!_n->m_pluginData)
{
auto w = new WatsynObject(&A1_wave[0], &A2_wave[0], &B1_wave[0], &B2_wave[0], m_amod.value(), m_bmod.value(),
Engine::audioEngine()->processingSampleRate(), _n, Engine::audioEngine()->framesPerPeriod(), this);

View File

@@ -201,7 +201,7 @@ void Xpressive::playNote(NotePlayHandle* nph, sampleFrame* working_buffer) {
m_A2=m_parameterA2.value();
m_A3=m_parameterA3.value();
if (nph->totalFramesPlayed() == 0 || nph->m_pluginData == nullptr) {
if (!nph->m_pluginData) {
auto exprO1 = new ExprFront(m_outputExpression[0].constData(),
Engine::audioEngine()->processingSampleRate()); // give the "last" function a whole second