plugin cutoff range
This commit is contained in:
parent
f0bc568030
commit
bb5e064e1a
|
@ -1,387 +1,387 @@
|
|||
/*
|
||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others.
|
||||
* Copyright (C) 2004 Sean Bolton and others
|
||||
* Copyright (C) 2013-2022 Filipe Coelho <falktx@falktx.com>
|
||||
*
|
||||
* 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 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.
|
||||
*
|
||||
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "DistrhoPluginNekobi.hpp"
|
||||
|
||||
|
||||
#include "nekobee-src/nekobee_synth.c"
|
||||
#include "nekobee-src/nekobee_voice.c"
|
||||
#include "nekobee-src/nekobee_voice_render.c"
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// nekobee_handle_raw_event
|
||||
|
||||
void nekobee_handle_raw_event(nekobee_synth_t* const synth, const uint8_t size, const uint8_t* const data)
|
||||
{
|
||||
if (size != 3)
|
||||
return;
|
||||
|
||||
switch (data[0] & 0xf0)
|
||||
{
|
||||
case 0x80:
|
||||
nekobee_synth_note_off(synth, data[1], data[2]);
|
||||
break;
|
||||
case 0x90:
|
||||
if (data[2] > 0)
|
||||
nekobee_synth_note_on(synth, data[1], data[2]);
|
||||
else
|
||||
nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */
|
||||
break;
|
||||
case 0xB0:
|
||||
nekobee_synth_control_change(synth, data[1], data[2]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
DistrhoPluginNekobi::DistrhoPluginNekobi()
|
||||
: Plugin(paramCount, 0, 0) // 0 programs, 0 states
|
||||
{
|
||||
nekobee_init_tables();
|
||||
|
||||
// init synth
|
||||
fSynth.sample_rate = getSampleRate();
|
||||
fSynth.deltat = 1.0f / (float)getSampleRate();
|
||||
fSynth.nugget_remains = 0;
|
||||
|
||||
fSynth.note_id = 0;
|
||||
fSynth.monophonic = XSYNTH_MONO_MODE_ONCE;
|
||||
fSynth.glide = 0;
|
||||
fSynth.last_noteon_pitch = 0.0f;
|
||||
fSynth.vcf_accent = 0.0f;
|
||||
fSynth.vca_accent = 0.0f;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
fSynth.held_keys[i] = -1;
|
||||
|
||||
fSynth.voice = nekobee_voice_new();
|
||||
|
||||
fSynth.channel_pressure = 0;
|
||||
fSynth.pitch_wheel_sensitivity = 0;
|
||||
fSynth.pitch_wheel = 0;
|
||||
|
||||
for (int i=0; i<128; ++i)
|
||||
{
|
||||
fSynth.key_pressure[i] = 0;
|
||||
fSynth.cc[i] = 0;
|
||||
}
|
||||
fSynth.cc[7] = 127; // full volume
|
||||
|
||||
fSynth.mod_wheel = 1.0f;
|
||||
fSynth.pitch_bend = 1.0f;
|
||||
fSynth.cc_volume = 1.0f;
|
||||
|
||||
// Default values
|
||||
fParams.waveform = 0.0f;
|
||||
fParams.tuning = 0.0f;
|
||||
fParams.cutoff = 25.0f;
|
||||
fParams.resonance = 25.0f;
|
||||
fParams.envMod = 50.0f;
|
||||
fParams.decay = 75.0f;
|
||||
fParams.accent = 25.0f;
|
||||
fParams.volume = 75.0f;
|
||||
|
||||
// Internal stuff
|
||||
fSynth.waveform = 0.0f;
|
||||
fSynth.tuning = 1.0f;
|
||||
fSynth.cutoff = 5.0f;
|
||||
fSynth.resonance = 0.8f;
|
||||
fSynth.envmod = 0.3f;
|
||||
fSynth.decay = 0.0002f;
|
||||
fSynth.accent = 0.3f;
|
||||
fSynth.volume = 0.75f;
|
||||
|
||||
// reset
|
||||
deactivate();
|
||||
}
|
||||
|
||||
DistrhoPluginNekobi::~DistrhoPluginNekobi()
|
||||
{
|
||||
std::free(fSynth.voice);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Init
|
||||
|
||||
void DistrhoPluginNekobi::initAudioPort(bool input, uint32_t index, AudioPort& port)
|
||||
{
|
||||
port.groupId = kPortGroupMono;
|
||||
|
||||
Plugin::initAudioPort(input, index, port);
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case paramWaveform:
|
||||
parameter.hints = kParameterIsAutomatable|kParameterIsInteger;
|
||||
parameter.name = "Waveform";
|
||||
parameter.symbol = "waveform";
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.enumValues.count = 2;
|
||||
parameter.enumValues.restrictedMode = true;
|
||||
parameter.midiCC = 70; //Sound Variation
|
||||
{
|
||||
ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[2];
|
||||
enumValues[0].value = 0.0f;
|
||||
enumValues[0].label = "Square";
|
||||
enumValues[1].value = 1.0f;
|
||||
enumValues[1].label = "Triangle";
|
||||
parameter.enumValues.values = enumValues;
|
||||
}
|
||||
break;
|
||||
case paramTuning:
|
||||
parameter.hints = kParameterIsAutomatable; // was 0.5 <-> 2.0, log
|
||||
parameter.name = "Tuning";
|
||||
parameter.symbol = "tuning";
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.ranges.min = -12.0f;
|
||||
parameter.ranges.max = 12.0f;
|
||||
parameter.midiCC = 75;
|
||||
break;
|
||||
case paramCutoff:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x2.5
|
||||
parameter.name = "Cutoff";
|
||||
parameter.symbol = "cutoff";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 25.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 74;
|
||||
break;
|
||||
case paramResonance:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "VCF Resonance";
|
||||
parameter.symbol = "resonance";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 25.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 95.0f;
|
||||
parameter.midiCC = 71;
|
||||
break;
|
||||
case paramEnvMod:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "Env Mod";
|
||||
parameter.symbol = "env_mod";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 50.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 1; //Mod Wheel
|
||||
break;
|
||||
case paramDecay:
|
||||
parameter.hints = kParameterIsAutomatable; // was 0.000009 <-> 0.0005, log
|
||||
parameter.name = "Decay";
|
||||
parameter.symbol = "decay";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 75.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 72;
|
||||
break;
|
||||
case paramAccent:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "Accent";
|
||||
parameter.symbol = "accent";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 25.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 76;
|
||||
break;
|
||||
case paramVolume:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "Volume";
|
||||
parameter.symbol = "volume";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 75.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 7; //Volume
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Internal data
|
||||
|
||||
float DistrhoPluginNekobi::getParameterValue(uint32_t index) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case paramWaveform:
|
||||
return fParams.waveform;
|
||||
case paramTuning:
|
||||
return fParams.tuning;
|
||||
case paramCutoff:
|
||||
return fParams.cutoff;
|
||||
case paramResonance:
|
||||
return fParams.resonance;
|
||||
case paramEnvMod:
|
||||
return fParams.envMod;
|
||||
case paramDecay:
|
||||
return fParams.decay;
|
||||
case paramAccent:
|
||||
return fParams.accent;
|
||||
case paramVolume:
|
||||
return fParams.volume;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case paramWaveform:
|
||||
fParams.waveform = value;
|
||||
fSynth.waveform = value;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.waveform == 0.0f || fSynth.waveform == 1.0f);
|
||||
break;
|
||||
case paramTuning:
|
||||
fParams.tuning = value;
|
||||
fSynth.tuning = exp2f( value / 12.0f );
|
||||
DISTRHO_SAFE_ASSERT(fSynth.tuning >= 0.5f && fSynth.tuning <= 2.0f);
|
||||
break;
|
||||
case paramCutoff:
|
||||
fParams.cutoff = value;
|
||||
fSynth.cutoff = value/2.5f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.cutoff >= 0.0f && fSynth.cutoff <= 40.0f);
|
||||
break;
|
||||
case paramResonance:
|
||||
fParams.resonance = value;
|
||||
fSynth.resonance = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.resonance >= 0.0f && fSynth.resonance <= 0.95f);
|
||||
break;
|
||||
case paramEnvMod:
|
||||
fParams.envMod = value;
|
||||
fSynth.envmod = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.envmod >= 0.0f && fSynth.envmod <= 1.0f);
|
||||
break;
|
||||
case paramDecay:
|
||||
fParams.decay = value;
|
||||
fSynth.decay = value/100.0f * 0.000491f + 0.000009f; // FIXME: log?
|
||||
DISTRHO_SAFE_ASSERT(fSynth.decay >= 0.000009f && fSynth.decay <= 0.0005f);
|
||||
break;
|
||||
case paramAccent:
|
||||
fParams.accent = value;
|
||||
fSynth.accent = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.accent >= 0.0f && fSynth.accent <= 1.0f);
|
||||
break;
|
||||
case paramVolume:
|
||||
fParams.volume = value;
|
||||
fSynth.volume = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Process
|
||||
|
||||
void DistrhoPluginNekobi::activate()
|
||||
{
|
||||
fSynth.nugget_remains = 0;
|
||||
fSynth.note_id = 0;
|
||||
|
||||
if (fSynth.voice != nullptr)
|
||||
nekobee_synth_all_voices_off(&fSynth);
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::deactivate()
|
||||
{
|
||||
if (fSynth.voice != nullptr)
|
||||
nekobee_synth_all_voices_off(&fSynth);
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
|
||||
{
|
||||
uint32_t framesDone = 0;
|
||||
uint32_t curEventIndex = 0;
|
||||
uint32_t burstSize;
|
||||
|
||||
float* out = outputs[0];
|
||||
|
||||
if (fSynth.voice == nullptr)
|
||||
{
|
||||
std::memset(out, 0, sizeof(float)*frames);
|
||||
return;
|
||||
}
|
||||
|
||||
while (framesDone < frames)
|
||||
{
|
||||
if (fSynth.nugget_remains == 0)
|
||||
fSynth.nugget_remains = XSYNTH_NUGGET_SIZE;
|
||||
|
||||
/* process any ready events */
|
||||
for (; curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame; ++curEventIndex)
|
||||
{
|
||||
if (midiEvents[curEventIndex].size > MidiEvent::kDataSize)
|
||||
continue;
|
||||
|
||||
nekobee_handle_raw_event(&fSynth, midiEvents[curEventIndex].size, midiEvents[curEventIndex].data);
|
||||
}
|
||||
|
||||
/* calculate the sample count (burstSize) for the next nekobee_voice_render() call to be the smallest of:
|
||||
* - control calculation quantization size (XSYNTH_NUGGET_SIZE, in samples)
|
||||
* - the number of samples remaining in an already-begun nugget (synth->nugget_remains)
|
||||
* - the number of samples until the next event is ready
|
||||
* - the number of samples left in this run
|
||||
*/
|
||||
burstSize = XSYNTH_NUGGET_SIZE;
|
||||
|
||||
/* we're still in the middle of a nugget, so reduce the burst size
|
||||
* to end when the nugget ends */
|
||||
if (fSynth.nugget_remains < burstSize)
|
||||
burstSize = fSynth.nugget_remains;
|
||||
|
||||
/* reduce burst size to end when next event is ready */
|
||||
if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame - framesDone < burstSize)
|
||||
burstSize = midiEvents[curEventIndex].frame - framesDone;
|
||||
|
||||
/* reduce burst size to end at end of this run */
|
||||
if (frames - framesDone < burstSize)
|
||||
burstSize = frames - framesDone;
|
||||
|
||||
/* render the burst */
|
||||
nekobee_synth_render_voices(&fSynth, out + framesDone, burstSize, (burstSize == fSynth.nugget_remains));
|
||||
framesDone += burstSize;
|
||||
fSynth.nugget_remains -= burstSize;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Plugin* createPlugin()
|
||||
{
|
||||
return new DistrhoPluginNekobi();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
||||
/*
|
||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others.
|
||||
* Copyright (C) 2004 Sean Bolton and others
|
||||
* Copyright (C) 2013-2022 Filipe Coelho <falktx@falktx.com>
|
||||
*
|
||||
* 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 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.
|
||||
*
|
||||
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "DistrhoPluginNekobi.hpp"
|
||||
|
||||
|
||||
#include "nekobee-src/nekobee_synth.c"
|
||||
#include "nekobee-src/nekobee_voice.c"
|
||||
#include "nekobee-src/nekobee_voice_render.c"
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// nekobee_handle_raw_event
|
||||
|
||||
void nekobee_handle_raw_event(nekobee_synth_t* const synth, const uint8_t size, const uint8_t* const data)
|
||||
{
|
||||
if (size != 3)
|
||||
return;
|
||||
|
||||
switch (data[0] & 0xf0)
|
||||
{
|
||||
case 0x80:
|
||||
nekobee_synth_note_off(synth, data[1], data[2]);
|
||||
break;
|
||||
case 0x90:
|
||||
if (data[2] > 0)
|
||||
nekobee_synth_note_on(synth, data[1], data[2]);
|
||||
else
|
||||
nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */
|
||||
break;
|
||||
case 0xB0:
|
||||
nekobee_synth_control_change(synth, data[1], data[2]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
DistrhoPluginNekobi::DistrhoPluginNekobi()
|
||||
: Plugin(paramCount, 0, 0) // 0 programs, 0 states
|
||||
{
|
||||
nekobee_init_tables();
|
||||
|
||||
// init synth
|
||||
fSynth.sample_rate = getSampleRate();
|
||||
fSynth.deltat = 1.0f / (float)getSampleRate();
|
||||
fSynth.nugget_remains = 0;
|
||||
|
||||
fSynth.note_id = 0;
|
||||
fSynth.monophonic = XSYNTH_MONO_MODE_ONCE;
|
||||
fSynth.glide = 0;
|
||||
fSynth.last_noteon_pitch = 0.0f;
|
||||
fSynth.vcf_accent = 0.0f;
|
||||
fSynth.vca_accent = 0.0f;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
fSynth.held_keys[i] = -1;
|
||||
|
||||
fSynth.voice = nekobee_voice_new();
|
||||
|
||||
fSynth.channel_pressure = 0;
|
||||
fSynth.pitch_wheel_sensitivity = 0;
|
||||
fSynth.pitch_wheel = 0;
|
||||
|
||||
for (int i=0; i<128; ++i)
|
||||
{
|
||||
fSynth.key_pressure[i] = 0;
|
||||
fSynth.cc[i] = 0;
|
||||
}
|
||||
fSynth.cc[7] = 127; // full volume
|
||||
|
||||
fSynth.mod_wheel = 1.0f;
|
||||
fSynth.pitch_bend = 1.0f;
|
||||
fSynth.cc_volume = 1.0f;
|
||||
|
||||
// Default values
|
||||
fParams.waveform = 0.0f;
|
||||
fParams.tuning = 0.0f;
|
||||
fParams.cutoff = 25.0f;
|
||||
fParams.resonance = 25.0f;
|
||||
fParams.envMod = 50.0f;
|
||||
fParams.decay = 75.0f;
|
||||
fParams.accent = 25.0f;
|
||||
fParams.volume = 75.0f;
|
||||
|
||||
// Internal stuff
|
||||
fSynth.waveform = 0.0f;
|
||||
fSynth.tuning = 1.0f;
|
||||
fSynth.cutoff = 5.0f;
|
||||
fSynth.resonance = 0.8f;
|
||||
fSynth.envmod = 0.3f;
|
||||
fSynth.decay = 0.0002f;
|
||||
fSynth.accent = 0.3f;
|
||||
fSynth.volume = 0.75f;
|
||||
|
||||
// reset
|
||||
deactivate();
|
||||
}
|
||||
|
||||
DistrhoPluginNekobi::~DistrhoPluginNekobi()
|
||||
{
|
||||
std::free(fSynth.voice);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Init
|
||||
|
||||
void DistrhoPluginNekobi::initAudioPort(bool input, uint32_t index, AudioPort& port)
|
||||
{
|
||||
port.groupId = kPortGroupMono;
|
||||
|
||||
Plugin::initAudioPort(input, index, port);
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case paramWaveform:
|
||||
parameter.hints = kParameterIsAutomatable|kParameterIsInteger;
|
||||
parameter.name = "Waveform";
|
||||
parameter.symbol = "waveform";
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.enumValues.count = 2;
|
||||
parameter.enumValues.restrictedMode = true;
|
||||
parameter.midiCC = 70; //Sound Variation
|
||||
{
|
||||
ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[2];
|
||||
enumValues[0].value = 0.0f;
|
||||
enumValues[0].label = "Square";
|
||||
enumValues[1].value = 1.0f;
|
||||
enumValues[1].label = "Triangle";
|
||||
parameter.enumValues.values = enumValues;
|
||||
}
|
||||
break;
|
||||
case paramTuning:
|
||||
parameter.hints = kParameterIsAutomatable; // was 0.5 <-> 2.0, log
|
||||
parameter.name = "Tuning";
|
||||
parameter.symbol = "tuning";
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.ranges.min = -12.0f;
|
||||
parameter.ranges.max = 12.0f;
|
||||
parameter.midiCC = 75;
|
||||
break;
|
||||
case paramCutoff:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Cutoff";
|
||||
parameter.symbol = "cutoff";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 63.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.midiCC = 74;
|
||||
break;
|
||||
case paramResonance:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "VCF Resonance";
|
||||
parameter.symbol = "resonance";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 25.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 95.0f;
|
||||
parameter.midiCC = 71;
|
||||
break;
|
||||
case paramEnvMod:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "Env Mod";
|
||||
parameter.symbol = "env_mod";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 50.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 1; //Mod Wheel
|
||||
break;
|
||||
case paramDecay:
|
||||
parameter.hints = kParameterIsAutomatable; // was 0.000009 <-> 0.0005, log
|
||||
parameter.name = "Decay";
|
||||
parameter.symbol = "decay";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 75.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 72;
|
||||
break;
|
||||
case paramAccent:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "Accent";
|
||||
parameter.symbol = "accent";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 25.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 76;
|
||||
break;
|
||||
case paramVolume:
|
||||
parameter.hints = kParameterIsAutomatable; // modified x100
|
||||
parameter.name = "Volume";
|
||||
parameter.symbol = "volume";
|
||||
parameter.unit = "%";
|
||||
parameter.ranges.def = 75.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 100.0f;
|
||||
parameter.midiCC = 7; //Volume
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Internal data
|
||||
|
||||
float DistrhoPluginNekobi::getParameterValue(uint32_t index) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case paramWaveform:
|
||||
return fParams.waveform;
|
||||
case paramTuning:
|
||||
return fParams.tuning;
|
||||
case paramCutoff:
|
||||
return fParams.cutoff;
|
||||
case paramResonance:
|
||||
return fParams.resonance;
|
||||
case paramEnvMod:
|
||||
return fParams.envMod;
|
||||
case paramDecay:
|
||||
return fParams.decay;
|
||||
case paramAccent:
|
||||
return fParams.accent;
|
||||
case paramVolume:
|
||||
return fParams.volume;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case paramWaveform:
|
||||
fParams.waveform = value;
|
||||
fSynth.waveform = value;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.waveform == 0.0f || fSynth.waveform == 1.0f);
|
||||
break;
|
||||
case paramTuning:
|
||||
fParams.tuning = value;
|
||||
fSynth.tuning = exp2f( value / 12.0f );
|
||||
DISTRHO_SAFE_ASSERT(fSynth.tuning >= 0.5f && fSynth.tuning <= 2.0f);
|
||||
break;
|
||||
case paramCutoff:
|
||||
fParams.cutoff = value;
|
||||
fSynth.cutoff = value;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.cutoff >= 0.0f && fSynth.cutoff <= 127.0f);
|
||||
break;
|
||||
case paramResonance:
|
||||
fParams.resonance = value;
|
||||
fSynth.resonance = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.resonance >= 0.0f && fSynth.resonance <= 0.95f);
|
||||
break;
|
||||
case paramEnvMod:
|
||||
fParams.envMod = value;
|
||||
fSynth.envmod = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.envmod >= 0.0f && fSynth.envmod <= 1.0f);
|
||||
break;
|
||||
case paramDecay:
|
||||
fParams.decay = value;
|
||||
fSynth.decay = value/100.0f * 0.000491f + 0.000009f; // FIXME: log?
|
||||
DISTRHO_SAFE_ASSERT(fSynth.decay >= 0.000009f && fSynth.decay <= 0.0005f);
|
||||
break;
|
||||
case paramAccent:
|
||||
fParams.accent = value;
|
||||
fSynth.accent = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.accent >= 0.0f && fSynth.accent <= 1.0f);
|
||||
break;
|
||||
case paramVolume:
|
||||
fParams.volume = value;
|
||||
fSynth.volume = value/100.0f;
|
||||
DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Process
|
||||
|
||||
void DistrhoPluginNekobi::activate()
|
||||
{
|
||||
fSynth.nugget_remains = 0;
|
||||
fSynth.note_id = 0;
|
||||
|
||||
if (fSynth.voice != nullptr)
|
||||
nekobee_synth_all_voices_off(&fSynth);
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::deactivate()
|
||||
{
|
||||
if (fSynth.voice != nullptr)
|
||||
nekobee_synth_all_voices_off(&fSynth);
|
||||
}
|
||||
|
||||
void DistrhoPluginNekobi::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
|
||||
{
|
||||
uint32_t framesDone = 0;
|
||||
uint32_t curEventIndex = 0;
|
||||
uint32_t burstSize;
|
||||
|
||||
float* out = outputs[0];
|
||||
|
||||
if (fSynth.voice == nullptr)
|
||||
{
|
||||
std::memset(out, 0, sizeof(float)*frames);
|
||||
return;
|
||||
}
|
||||
|
||||
while (framesDone < frames)
|
||||
{
|
||||
if (fSynth.nugget_remains == 0)
|
||||
fSynth.nugget_remains = XSYNTH_NUGGET_SIZE;
|
||||
|
||||
/* process any ready events */
|
||||
for (; curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame; ++curEventIndex)
|
||||
{
|
||||
if (midiEvents[curEventIndex].size > MidiEvent::kDataSize)
|
||||
continue;
|
||||
|
||||
nekobee_handle_raw_event(&fSynth, midiEvents[curEventIndex].size, midiEvents[curEventIndex].data);
|
||||
}
|
||||
|
||||
/* calculate the sample count (burstSize) for the next nekobee_voice_render() call to be the smallest of:
|
||||
* - control calculation quantization size (XSYNTH_NUGGET_SIZE, in samples)
|
||||
* - the number of samples remaining in an already-begun nugget (synth->nugget_remains)
|
||||
* - the number of samples until the next event is ready
|
||||
* - the number of samples left in this run
|
||||
*/
|
||||
burstSize = XSYNTH_NUGGET_SIZE;
|
||||
|
||||
/* we're still in the middle of a nugget, so reduce the burst size
|
||||
* to end when the nugget ends */
|
||||
if (fSynth.nugget_remains < burstSize)
|
||||
burstSize = fSynth.nugget_remains;
|
||||
|
||||
/* reduce burst size to end when next event is ready */
|
||||
if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame - framesDone < burstSize)
|
||||
burstSize = midiEvents[curEventIndex].frame - framesDone;
|
||||
|
||||
/* reduce burst size to end at end of this run */
|
||||
if (frames - framesDone < burstSize)
|
||||
burstSize = frames - framesDone;
|
||||
|
||||
/* render the burst */
|
||||
nekobee_synth_render_voices(&fSynth, out + framesDone, burstSize, (burstSize == fSynth.nugget_remains));
|
||||
framesDone += burstSize;
|
||||
fSynth.nugget_remains -= burstSize;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Plugin* createPlugin()
|
||||
{
|
||||
return new DistrhoPluginNekobi();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
||||
|
|
|
@ -63,9 +63,9 @@ DistrhoUINekobi::DistrhoUINekobi()
|
|||
fKnobCutoff = new ImageKnob(this, knobImage, ImageKnob::Vertical);
|
||||
fKnobCutoff->setId(DistrhoPluginNekobi::paramCutoff);
|
||||
fKnobCutoff->setAbsolutePos(185, 43);
|
||||
fKnobCutoff->setRange(0.0f, 100.0f);
|
||||
fKnobCutoff->setDefault(25.0f);
|
||||
fKnobCutoff->setValue(25.0f);
|
||||
fKnobCutoff->setRange(0.0f, 127.0f);
|
||||
fKnobCutoff->setDefault(50.0f);
|
||||
fKnobCutoff->setValue(50.0f);
|
||||
fKnobCutoff->setRotationAngle(305);
|
||||
fKnobCutoff->setCallback(this);
|
||||
|
||||
|
|
|
@ -96,17 +96,30 @@ void vco(nekobee_synth_t *synth, uint32_t count) {
|
|||
osc->delay = delay;
|
||||
}
|
||||
|
||||
void vcf(nekobee_synth_t *synth, uint32_t count) {
|
||||
// run a 4-pole ladder filter over a block
|
||||
// this is a crude implementation that only approximates the complex
|
||||
// behaviour of the "real" ladder filter
|
||||
|
||||
nekobee_voice_t *voice = synth->voice;
|
||||
printf("cutoff set to %f\n", synth->cutoff);
|
||||
(void)voice;
|
||||
(void)count;
|
||||
|
||||
}
|
||||
|
||||
void nekobee_voice_render(nekobee_synth_t *synth, float *out, uint32_t count) {
|
||||
// generate "count" samples into the buffer at out
|
||||
|
||||
vco(synth, count);
|
||||
|
||||
vcf(synth, count);
|
||||
|
||||
for(uint32_t i=0; i<count; i++) {
|
||||
out[i] = synth->voice->osc_audio[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
return;
|
||||
(void)synth;
|
||||
(void)out;
|
||||
(void)count;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue