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:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() )
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>{};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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>{};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user