mirror of
https://github.com/LMMS/lmms.git
synced 2026-03-09 09:37:17 -04:00
Remove identical calls to `InstrumentTrack::processAudioBuffer` which appear in the overridden implementations of `Instrument::play` and `Instrument::playNotes`. Instead the call to `processAudioBuffer` has been moved into `InstrumentPlayHandle::play` and `InstrumentTrack::playNote`. These two methods call the aforementioned methods of `Instrument`. Especially in the case of `InstrumentTrack::playNote` the previous implementation resulted in some unncessary "ping pong" where `InstrumentTrack` called a method on an `Instrument` which then in turn called a method on `InstrumentTrack`. And this was done in almost every instrument.
In `InstrumentTrack::playNote` an additional check was added which only calls `processAudioBuffer` if the buffer is not `nullptr`. The reason is that under certain circumstances `PlayHandle::doProcessing` calls the `play` method by explicitly passing a `nullptr` as the buffer. This behavior was added with commit 7bc97f5d5b. Because it is unknown if this was done for some side effects the code was adjusted so that it behaves identical in this case.
Move the complex implementation for `InstrumentPlayHandle::play` and `InstrumentPlayHandle::isFromTrack` into the cpp file and optimize the includes.
536 lines
17 KiB
C++
536 lines
17 KiB
C++
/*
|
|
* Vibed.cpp - 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
|
|
* 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 "Vibed.h"
|
|
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <QDomElement>
|
|
|
|
#include "AudioEngine.h"
|
|
#include "Engine.h"
|
|
#include "InstrumentTrack.h"
|
|
#include "NotePlayHandle.h"
|
|
#include "VibratingString.h"
|
|
#include "MemoryManager.h"
|
|
#include "base64.h"
|
|
#include "CaptionMenu.h"
|
|
#include "volume.h"
|
|
#include "Song.h"
|
|
|
|
#include "embed.h"
|
|
#include "plugin_export.h"
|
|
|
|
namespace lmms
|
|
{
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
Plugin::Descriptor PLUGIN_EXPORT vibedstrings_plugin_descriptor =
|
|
{
|
|
LMMS_STRINGIFY(PLUGIN_NAME),
|
|
"Vibed",
|
|
QT_TRANSLATE_NOOP("PluginBrowser", "Vibrating string modeler"),
|
|
"Danny McRae <khjklujn/at/yahoo/com>",
|
|
0x0100,
|
|
Plugin::Type::Instrument,
|
|
new PluginPixmapLoader("logo"),
|
|
nullptr,
|
|
nullptr
|
|
};
|
|
|
|
}
|
|
|
|
|
|
class Vibed::StringContainer
|
|
{
|
|
MM_OPERATORS
|
|
public:
|
|
StringContainer(float pitch, sample_rate_t sampleRate, int bufferLength) :
|
|
m_pitch(pitch), m_sampleRate(sampleRate), m_bufferLength(bufferLength) {}
|
|
|
|
~StringContainer() = default;
|
|
|
|
void addString(int harm, float pick, float pickup, const float* impulse, float randomize,
|
|
float stringLoss, float detune, int oversample, bool state, int id)
|
|
{
|
|
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());
|
|
|
|
m_strings[id] = VibratingString{m_pitch * octave[harm], pick, pickup, impulse, m_bufferLength,
|
|
m_sampleRate, oversample, randomize, stringLoss, detune, state};
|
|
|
|
m_exists[id] = true;
|
|
}
|
|
|
|
bool exists(int id) const { return m_exists[id]; }
|
|
|
|
sample_t getStringSample(int id) { return m_strings[id].nextSample(); }
|
|
|
|
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{};
|
|
};
|
|
|
|
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& elem)
|
|
{
|
|
// Save plugin version
|
|
elem.setAttribute("version", "0.2");
|
|
|
|
for (int i = 0; i < s_stringCount; ++i)
|
|
{
|
|
const auto is = QString::number(i);
|
|
|
|
elem.setAttribute("active" + is, QString::number(m_powerModels[i]->value()));
|
|
|
|
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);
|
|
|
|
QString sampleString;
|
|
base64::encode((const char*)m_graphModels[i]->samples(), s_sampleLength * sizeof(float), sampleString);
|
|
|
|
elem.setAttribute("graph" + is, sampleString);
|
|
}
|
|
}
|
|
|
|
void Vibed::loadSettings(const QDomElement& elem)
|
|
{
|
|
// Load plugin version
|
|
bool newVersion = false;
|
|
if (elem.hasAttribute("version"))
|
|
{
|
|
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))
|
|
{
|
|
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 = nullptr;
|
|
base64::decode(elem.attribute("graph" + is), &shp, &size);
|
|
|
|
assert(size == 128 * sizeof(float));
|
|
m_graphModels[i]->setSamples(shp);
|
|
delete[] shp;
|
|
}
|
|
}
|
|
}
|
|
|
|
QString Vibed::nodeName() const
|
|
{
|
|
return vibedstrings_plugin_descriptor.name;
|
|
}
|
|
|
|
void Vibed::playNote(NotePlayHandle* n, sampleFrame* workingBuffer)
|
|
{
|
|
if (!n->m_pluginData)
|
|
{
|
|
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_powerModels[i]->value())
|
|
{
|
|
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);
|
|
|
|
for (fpp_t i = offset; i < frames + offset; ++i)
|
|
{
|
|
workingBuffer[i][0] = 0.0f;
|
|
workingBuffer[i][1] = 0.0f;
|
|
for (int str = 0; str < s_stringCount; ++str)
|
|
{
|
|
if (ps->exists(str))
|
|
{
|
|
// pan: 0 -> left, 1 -> right
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Vibed::deleteNotePluginData(NotePlayHandle* n)
|
|
{
|
|
delete static_cast<StringContainer*>(n->m_pluginData);
|
|
}
|
|
|
|
gui::PluginView* Vibed::instantiateView(QWidget* parent)
|
|
{
|
|
return new gui::VibedView(this, parent);
|
|
}
|
|
|
|
|
|
namespace gui
|
|
{
|
|
|
|
|
|
VibedView::VibedView(Instrument* instrument, QWidget* parent) :
|
|
InstrumentViewFixedSize(instrument, parent),
|
|
m_volumeKnob(KnobType::Bright26, this),
|
|
m_stiffnessKnob(KnobType::Bright26, this),
|
|
m_pickKnob(KnobType::Bright26, this),
|
|
m_pickupKnob(KnobType::Bright26, this),
|
|
m_panKnob(KnobType::Bright26, this),
|
|
m_detuneKnob(KnobType::Bright26, this),
|
|
m_randomKnob(KnobType::Bright26, this),
|
|
m_lengthKnob(KnobType::Bright26, 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);
|
|
QPalette pal;
|
|
pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("artwork"));
|
|
setPalette(pal);
|
|
|
|
m_volumeKnob.setVolumeKnob(true);
|
|
m_volumeKnob.move(103, 142);
|
|
m_volumeKnob.setHintText(tr("String volume:"), "");
|
|
|
|
m_stiffnessKnob.move(129, 142);
|
|
m_stiffnessKnob.setHintText(tr("String stiffness:"), "");
|
|
|
|
m_pickKnob.move(153, 142);
|
|
m_pickKnob.setHintText(tr("Pick position:"), "");
|
|
|
|
m_pickupKnob.move(177, 142);
|
|
m_pickupKnob.setHintText(tr("Pickup position:"), "");
|
|
|
|
m_panKnob.move(105, 187);
|
|
m_panKnob.setHintText(tr("String panning:"), "");
|
|
|
|
m_detuneKnob.move(150, 187);
|
|
m_detuneKnob.setHintText(tr("String detune:"), "");
|
|
|
|
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);
|
|
|
|
m_harmonic->setWindowTitle(tr("Octave"));
|
|
|
|
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);
|
|
|
|
// String selector is not a part of the model
|
|
m_stringSelector->setWindowTitle(tr("String"));
|
|
|
|
connect(m_stringSelector.get(), SIGNAL(NineButtonSelection(int)), this, SLOT(showString(int)));
|
|
|
|
showString(0);
|
|
|
|
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.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_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_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_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_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_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);
|
|
}
|
|
|
|
void VibedView::showString(int str)
|
|
{
|
|
auto v = castModel<Vibed>();
|
|
|
|
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();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::triangleWaveClicked()
|
|
{
|
|
m_graph.model()->setWaveToTriangle();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::sawWaveClicked()
|
|
{
|
|
m_graph.model()->setWaveToSaw();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::sqrWaveClicked()
|
|
{
|
|
m_graph.model()->setWaveToSquare();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::noiseWaveClicked()
|
|
{
|
|
m_graph.model()->setWaveToNoise();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::usrWaveClicked()
|
|
{
|
|
QString fileName = m_graph.model()->setWaveToUser();
|
|
m_usrWaveBtn.setToolTip(fileName);
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::smoothClicked()
|
|
{
|
|
m_graph.model()->smooth();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::normalizeClicked()
|
|
{
|
|
m_graph.model()->normalize();
|
|
Engine::getSong()->setModified();
|
|
}
|
|
|
|
void VibedView::contextMenuEvent(QContextMenuEvent*)
|
|
{
|
|
CaptionMenu contextMenu(model()->displayName(), this);
|
|
contextMenu.exec(QCursor::pos());
|
|
}
|
|
|
|
|
|
} // namespace gui
|
|
|
|
extern "C"
|
|
{
|
|
|
|
// necessary for getting instance out of shared lib
|
|
PLUGIN_EXPORT Plugin* lmms_plugin_main(Model* m, void*)
|
|
{
|
|
return new Vibed(static_cast<InstrumentTrack*>(m));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} // namespace lmms
|