|
- /*
- * DISTRHO Kars Plugin, based on karplong by Chris Cannam.
- * Copyright (C) 2015-2019 Filipe Coelho <falktx@falktx.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any purpose with
- * or without fee is hereby granted, provided that the above copyright notice and this
- * permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
- #include "DistrhoPluginKars.hpp"
- #include "DistrhoPluginUtils.hpp"
-
- START_NAMESPACE_DISTRHO
-
- // -----------------------------------------------------------------------
-
- DistrhoPluginKars::DistrhoPluginKars()
- : Plugin(paramCount, 0, 0), // 0 programs, 0 states
- fSustain(false),
- fRelease(0.01),
- fVolume(75.0f),
- fSampleRate(getSampleRate()),
- fBlockStart(0)
- {
- for (int i=kMaxNotes; --i >= 0;)
- {
- fNotes[i].voice = i;
- fNotes[i].setSampleRate(fSampleRate);
- }
- }
-
- // -----------------------------------------------------------------------
- // Init
-
- void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter)
- {
- switch (index)
- {
- case paramSustain:
- parameter.hints = kParameterIsAutomatable|kParameterIsBoolean;
- parameter.name = "Sustain";
- parameter.symbol = "sustain";
- parameter.ranges.def = 0.0f;
- parameter.ranges.min = 0.0f;
- parameter.ranges.max = 1.0f;
- break;
- case paramRelease:
- parameter.hints = kParameterIsAutomatable;
- parameter.name = "Release";
- parameter.symbol = "release";
- parameter.unit = "s";
- parameter.ranges.def = 0.01f;
- parameter.ranges.min = 0.0f;
- parameter.ranges.max = 5.0f;
- break;
- case paramVolume:
- parameter.hints = kParameterIsAutomatable;
- parameter.name = "Volume";
- parameter.symbol = "volume";
- parameter.unit = "%";
- parameter.ranges.def = 75.0f;
- parameter.ranges.min = 0.0f;
- parameter.ranges.max = 100.0f;
- break;
- }
- }
-
- // -----------------------------------------------------------------------
- // Internal data
-
- float DistrhoPluginKars::getParameterValue(uint32_t index) const
- {
- switch (index)
- {
- case paramSustain: return fSustain ? 1.0f : 0.0f;
- case paramRelease: return fRelease;
- case paramVolume: return fVolume;
- }
-
- return 0.0f;
- }
-
- void DistrhoPluginKars::setParameterValue(uint32_t index, float value)
- {
- switch (index)
- {
- case paramSustain:
- fSustain = value > 0.5f;
- break;
- case paramRelease:
- fRelease = value;
- break;
- case paramVolume:
- fVolume = value;
- break;
- }
- }
-
- // -----------------------------------------------------------------------
- // Process
-
- void DistrhoPluginKars::activate()
- {
- fBlockStart = 0;
-
- for (int i=kMaxNotes; --i >= 0;)
- {
- fNotes[i].on = kNoteNull;
- fNotes[i].off = kNoteNull;
- fNotes[i].velocity = 0;
- }
- }
-
- void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
- {
- uint8_t note, velo;
- std::memset(outputs[0], 0, sizeof(float)*frames);
-
- for (AudioMidiSyncHelper amsh(outputs, frames, midiEvents, midiEventCount); amsh.nextEvent();)
- {
- for (uint32_t i=0; i<amsh.midiEventCount; ++i)
- {
- if (amsh.midiEvents[i].size > MidiEvent::kDataSize)
- continue;
-
- const uint8_t* data = amsh.midiEvents[i].data;
- const uint8_t status = data[0] & 0xF0;
-
- switch (status)
- {
- case 0x90:
- note = data[1];
- velo = data[2];
- DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
- if (velo > 0)
- {
- fNotes[note].on = fBlockStart;
- fNotes[note].off = kNoteNull;
- fNotes[note].velocity = velo;
- break;
- }
- // fall through
- case 0x80:
- note = data[1];
- DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
- fNotes[note].off = fBlockStart;
- break;
- }
- }
-
- float* const out = amsh.outputs[0];
-
- for (int i=kMaxNotes; --i >= 0;)
- {
- if (fNotes[i].on != kNoteNull)
- addSamples(out, i, amsh.frames);
- }
-
- fBlockStart += amsh.frames;
- }
- }
-
- void DistrhoPluginKars::addSamples(float* out, int voice, uint32_t frames)
- {
- const uint32_t start = fBlockStart;
-
- Note& note(fNotes[voice]);
-
- if (start < note.on)
- return;
-
- if (start == note.on)
- {
- for (int i=note.sizei; --i >= 0;)
- note.wavetable[i] = (float(rand()) / float(RAND_MAX)) * 2.0f - 1.0f;
- }
-
- const float vgain = float(note.velocity) / 127.0f;
-
- bool decay;
- float gain, sample;
- uint32_t index, size;
-
- for (uint32_t i=0, s=start-note.on; i<frames; ++i, ++s)
- {
- gain = vgain;
-
- if ((! fSustain) && note.off != kNoteNull && note.off < i+start)
- {
- // reuse index and size to save some performance.
- // actual values are release and dist
- index = 1 + uint32_t(fRelease * fSampleRate); // release, not index
- size = i + start - note.off; // dist, not size
-
- if (size > index)
- {
- note.on = kNoteNull;
- break;
- }
-
- gain = gain * float(index - size) / float(index);
- }
-
- size = uint32_t(note.sizei);
- decay = s > size;
- index = s % size;
-
- sample = note.wavetable[index];
-
- if (decay)
- {
- if (index == 0)
- sample += note.wavetable[size-1];
- else
- sample += note.wavetable[index-1];
-
- note.wavetable[index] = sample/2;
- }
-
- out[i] += gain * sample * (fVolume / 100.0f);
- }
- }
-
- // -----------------------------------------------------------------------
-
- Plugin* createPlugin()
- {
- return new DistrhoPluginKars();
- }
-
- // -----------------------------------------------------------------------
-
- END_NAMESPACE_DISTRHO
|