@@ -0,0 +1,36 @@ | |||
/* | |||
* Grain Juice Plugin | |||
* Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
* | |||
* 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 doc/GPL.txt file. | |||
*/ | |||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
#define DISTRHO_PLUGIN_NAME "GrainJuice" | |||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||
#define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
#define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
#define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
#define DISTRHO_PLUGIN_WANT_STATE 0 | |||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 0 | |||
#define DISTRHO_PLUGIN_URI "urn:distrho:GrainJuice" | |||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,35 @@ | |||
/* (Auto-generated binary data file). */ | |||
#ifndef BINARY_GRAINJUICEARTWORK_HPP | |||
#define BINARY_GRAINJUICEARTWORK_HPP | |||
namespace GrainJuiceArtwork | |||
{ | |||
extern const char* aboutData; | |||
const unsigned int aboutDataSize = 180000; | |||
const unsigned int aboutWidth = 300; | |||
const unsigned int aboutHeight = 200; | |||
extern const char* aboutButtonHoverData; | |||
const unsigned int aboutButtonHoverDataSize = 5888; | |||
const unsigned int aboutButtonHoverWidth = 92; | |||
const unsigned int aboutButtonHoverHeight = 16; | |||
extern const char* aboutButtonNormalData; | |||
const unsigned int aboutButtonNormalDataSize = 5888; | |||
const unsigned int aboutButtonNormalWidth = 92; | |||
const unsigned int aboutButtonNormalHeight = 16; | |||
extern const char* backgroundData; | |||
const unsigned int backgroundDataSize = 450000; | |||
const unsigned int backgroundWidth = 500; | |||
const unsigned int backgroundHeight = 300; | |||
extern const char* knobData; | |||
const unsigned int knobDataSize = 6084; | |||
const unsigned int knobWidth = 39; | |||
const unsigned int knobHeight = 39; | |||
} | |||
#endif // BINARY_GRAINJUICEARTWORK_HPP | |||
@@ -0,0 +1,520 @@ | |||
/* | |||
* Grain Juice Plugin | |||
* Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
* | |||
* 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 doc/GPL.txt file. | |||
*/ | |||
#include "GrainJuicePlugin.hpp" | |||
#include <iostream> | |||
#include <math.h> | |||
#include <cmath> | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
GrainJuicePlugin::GrainJuicePlugin() | |||
: Plugin(paramCount, 1, 0) { // 1 program, 0 states | |||
// set default values | |||
d_setProgram(0); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Init | |||
void GrainJuicePlugin::d_initParameter(uint32_t index, Parameter& parameter) { | |||
switch (index) { | |||
case paramSize: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramScatter: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Scatter"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramGain: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Gain"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramDensity: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Density"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramLPF: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "LPF"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramHPF: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "HPF"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramSizeR: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramScatterR: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramGainR: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramDensityR: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramLPFR: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
case paramHPFR: | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Size"; | |||
parameter.symbol = "siz"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = 0.5f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 1.0f; | |||
break; | |||
} | |||
} | |||
void GrainJuicePlugin::d_initProgramName(uint32_t index, d_string& programName) { | |||
if (index != 0) | |||
return; | |||
programName = "Default"; | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Internal data | |||
float GrainJuicePlugin::d_getParameterValue(uint32_t index) const { | |||
switch (index) { | |||
case paramSize: | |||
return size; | |||
case paramScatter: | |||
return scatter; | |||
case paramGain: | |||
return gain; | |||
case paramDensity: | |||
return density; | |||
case paramLPF: | |||
return LPF; | |||
case paramHPF: | |||
return HPF; | |||
case paramSizeR: | |||
return sizeR; | |||
case paramScatterR: | |||
return scatterR; | |||
case paramGainR: | |||
return gainR; | |||
case paramDensityR: | |||
return densityR; | |||
case paramLPFR: | |||
return LPFR; | |||
case paramHPFR: | |||
return HPFR; | |||
default: | |||
return 0.0f; | |||
} | |||
} | |||
void GrainJuicePlugin::d_setParameterValue(uint32_t index, float value) { | |||
switch (index) { | |||
case paramSize: | |||
size = value; | |||
break; | |||
case paramScatter: | |||
scatter = value; | |||
break; | |||
case paramGain: | |||
gain = value; | |||
break; | |||
case paramDensity: | |||
density = value; | |||
break; | |||
case paramLPF: | |||
LPF = value; | |||
break; | |||
case paramHPF: | |||
HPF = value; | |||
break; | |||
case paramSizeR: | |||
sizeR = value; | |||
break; | |||
case paramScatterR: | |||
scatterR = value; | |||
break; | |||
case paramGainR: | |||
gainR = value; | |||
break; | |||
case paramDensityR: | |||
densityR = value; | |||
break; | |||
case paramLPFR: | |||
LPFR = value; | |||
break; | |||
case paramHPFR: | |||
HPFR = value; | |||
break; | |||
} | |||
} | |||
void GrainJuicePlugin::d_setProgram(uint32_t index) { | |||
if (index != 0) | |||
return; | |||
/* Default parameter values */ | |||
size=scatter=gain=density=HPF=LPF=1.f; | |||
sizeR=scatterR=gainR=densityR=HPFR=LPFR=1.f; | |||
prevTotalGrains = 0; | |||
/* Default variable values */ | |||
srand (time(NULL)); | |||
nSample = new float[2]; | |||
prevSample = new float[2]; | |||
std::cout << "Starting." << std::endl; | |||
for (int i=0; i<1000; i++) { | |||
logTable[i] = expf((logf(0.999f)-logf(0.001f))*(i/1000.0f)+logf(0.999f)); | |||
} | |||
logTable[0] = 0.0f; | |||
concurrentFilling = 0; | |||
d_activate(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// GRAINS | |||
GrainJuicePlugin::CGrain::CGrain(uint32_t nLength, uint32_t nDelay, float lpf, float hpf, float nGain) { | |||
length = nLength; | |||
readyForPlayback = false; | |||
delay = nDelay; | |||
playhead = 0; | |||
gain = nGain; | |||
//highPass = new HPF[2]; | |||
//lowPass = new LPF[2]; | |||
highPass[0].setSampleRate(48000); | |||
highPass[1].setSampleRate(48000); | |||
highPass[0].setReso(0.1f); | |||
highPass[1].setReso(0.1f); | |||
highPass[0].setFreq(hpf); | |||
highPass[1].setFreq(hpf); | |||
highPass[0].compute(); | |||
highPass[1].compute(); | |||
lowPass[0].setSampleRate(48000); | |||
lowPass[1].setSampleRate(48000); | |||
lowPass[0].setReso(1.4f); | |||
lowPass[1].setReso(1.4f); | |||
lowPass[0].setFreq(lpf); | |||
lowPass[1].setFreq(lpf); | |||
lowPass[0].compute(); | |||
lowPass[1].compute(); | |||
} | |||
bool GrainJuicePlugin::CGrain::wantsSample() { | |||
if (playhead<length && !readyForPlayback) { | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
void GrainJuicePlugin::CGrain::fillSample(float *nSample) { | |||
//std::cout << "omnom" << std::endl; | |||
//std::cout << "playhead: " << playhead << std::endl; | |||
//std::cout << "length: " << length << std::endl; | |||
samples[playhead][0] = nSample[0]; | |||
samples[playhead][1] = nSample[1]; | |||
playhead++; | |||
if (playhead==length-5) { | |||
readyForPlayback = true; | |||
applyEnvelope(); | |||
playhead = length-5; | |||
} | |||
} | |||
float *GrainJuicePlugin::CGrain::getSample() { | |||
playhead--; | |||
float coeff = 0.5f * (1 - cosf((2.f * M_PI * playhead)/(length-1))); | |||
float newSample[2]; | |||
for (int i = 0; i < 2; i++) { | |||
newSample[i] = samples[playhead][i]; | |||
newSample[i] *= coeff*gain; | |||
newSample[i] = lowPass[i].process(newSample[i]); | |||
//newSample[i] = highPass[i].process(newSample[i]); | |||
} | |||
samples[playhead][0] = newSample[0]; | |||
samples[playhead][1] = newSample[1]; | |||
return samples[playhead]; | |||
} | |||
bool GrainJuicePlugin::CGrain::inDelay() { | |||
if (delay>0) { | |||
playhead = length; | |||
delay--; | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
uint32_t GrainJuicePlugin::CGrain::getLength() { | |||
return length; | |||
} | |||
bool GrainJuicePlugin::CGrain::donePlaying() { | |||
if (playhead<1) { //TODO: fix so all the samples get played/recorded | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
void GrainJuicePlugin::CGrain::applyEnvelope() { | |||
} | |||
void GrainJuicePlugin::CGrain::updateParams(float nDensity, float nScatter, uint32_t nSRT) { | |||
density = nDensity; | |||
scatter = nScatter; | |||
SRT = nSRT; | |||
} | |||
void GrainJuicePlugin::CGrain::setDelay(uint32_t nDelay) { | |||
delay = nDelay; | |||
} | |||
float GrainJuicePlugin::CGrain::inspectSample(uint32_t index, int channel) { | |||
return samples[index][channel]; | |||
} | |||
void GrainJuicePlugin::newGrain(bool first) { | |||
// create a new grain | |||
concurrentFilling = 0; | |||
bool create = false; | |||
if (first) { | |||
create = true; | |||
} else if (grains.size()+1 <= density*MAXGRAINS) { | |||
create = true; | |||
} | |||
if (create) { | |||
uint32_t newGrainSize =(int) size*d_getSampleRate()*MAXGRAINSIZE; | |||
newGrainSize = rand() % newGrainSize-1000; | |||
newGrainSize += 1000; | |||
uint32_t delayChance = (1000 - (rand() % (int) (density*1000.f)))/25+1; | |||
//std::cout << "grain fill!" << std::endl; | |||
//std::cout << "chance: " << delayChance << std::endl;; | |||
//delayChance = 2; | |||
for (int d=0; d<delayChance; d++) { | |||
if (grains.size()+1 > density*MAXGRAINS) { | |||
break; | |||
} | |||
int newDelayTime = rand() % (int) (MAXSCATTER*scatter*d_getSampleRate()); | |||
newDelayTime += 100; | |||
int newLPF = LPF*998; | |||
int random = (rand() % (int) (LPFR*1000+1))-(rand() % (int) (LPFR*500+1)); | |||
newLPF = limit(newLPF-random); | |||
int LPFLimit = newLPF; | |||
newLPF = logTable[newLPF]*20+100; | |||
if (newLPF>20000) newLPF = 20000; | |||
if (newLPF<100) newLPF = 100; | |||
int newHPF = HPF*998; | |||
random = (rand() % (int) (HPFR*1000+1))-(rand() % (int) (HPFR*500+1)); | |||
newHPF = limit(newHPF-random); | |||
newHPF = logTable[newHPF]*20+20; | |||
if (newHPF>20000) newHPF = 20000; | |||
newHPF *= newLPF/20000.f; | |||
if (newHPF<50) newHPF = 50; | |||
std::cout << newHPF << std::endl; | |||
//int newHPF = rand() % (int) (LPF); | |||
int newGain = rand() % (int) (1000); | |||
grains.push_back(new CGrain(newGrainSize, newDelayTime, newLPF, newHPF, newGain/1000.f)); | |||
//grains.push_back(new CGrain(newGrainSize, newDelayTime)); | |||
concurrentFilling++; | |||
} | |||
} | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Process | |||
void GrainJuicePlugin::d_activate() { | |||
} | |||
void GrainJuicePlugin::d_run(const float** inputs, float** outputs, uint32_t frames) { | |||
static int k = 0; | |||
for (uint32_t i = 0; i < frames; i++) { | |||
// RUNTIME CODE HERE | |||
//std::cout << "..record" << std::endl; | |||
//------------------------------------- | |||
// RECORD | |||
//std::cout << "total grains:" << grains.size() << std::endl; | |||
//std::cout << "max grains:" << density*MAXGRAINS << std::endl; | |||
if (grains.size() <= density*MAXGRAINS) { | |||
//std::cout << "not enough full grains" << std::endl; | |||
if (grains.size() == 0) { | |||
newGrain(true); | |||
} | |||
if (grains.back() -> wantsSample()) { | |||
nSample[0] = inputs[0][i]; | |||
nSample[1] = inputs[1][i]; | |||
for (int q=0; q<concurrentFilling; q++) { | |||
grains[grains.size()-1-q] -> fillSample(nSample); | |||
} | |||
} else { | |||
newGrain(false); | |||
} | |||
} | |||
//std::cout << "..playback" << std::endl; | |||
//------------------------------------- | |||
// PLAYBACK | |||
outputs[0][i] = 0.0f; | |||
outputs[1][i] = 0.0f; | |||
eraseIndex = 0; | |||
int grainsPlaying = 0; | |||
int l = 0; | |||
for (uint32_t j = 0; j < grains.size(); j++) { | |||
if (!grains[j]->wantsSample()) { | |||
grainsPlaying++; | |||
if (!grains[j]->inDelay()) { | |||
//play this sample back | |||
grains[j]->updateParams(density, scatter, d_getSampleRate()); | |||
if (grains[j]->donePlaying()) { | |||
// mark grains for erase | |||
eraseGrains[eraseIndex] = j; | |||
eraseIndex++; | |||
//grains.erase(grains.begin()+j); | |||
//j--; // COME ON BABY LIGHT MY FIRE | |||
} else { | |||
nSample = grains[j]->getSample(); | |||
outputs[0][i] += nSample[0]; | |||
outputs[1][i] += nSample[1]; | |||
} | |||
} | |||
} | |||
} | |||
for (int j=0; j<eraseIndex; j++) { | |||
grains.erase(grains.begin()+eraseGrains[j]); | |||
} | |||
if (grains.size() != prevTotalGrains) { | |||
//std::cout << "total grains: " << grainsPlaying << " conc: " << concurrentFilling << " size: " << grains.size() << std::endl; | |||
//std::cout << "total grains playing: " << grainsPlaying << std::endl; | |||
prevTotalGrains = grainsPlaying; | |||
} | |||
if (k==9) k=0; | |||
} | |||
} | |||
// ----------------------------------------------------------------------- | |||
Plugin* createPlugin() { | |||
return new GrainJuicePlugin(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,307 @@ | |||
/* | |||
* Grain Juice Plugin | |||
* Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
* | |||
* 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 doc/GPL.txt file. | |||
*/ | |||
#ifndef GrainJUICEPLUGIN_HPP_INCLUDED | |||
#define GrainJUICEPLUGIN_HPP_INCLUDED | |||
#include "DistrhoPlugin.hpp" | |||
#include <cstdlib> | |||
#include <time.h> | |||
#include <vector> | |||
#define MAXGRAINSIZE 0.5f // in seconds | |||
#define MAXSCATTER 3.f // in seconds | |||
#define MAXGRAINS 300 // in grains | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
class GrainJuicePlugin : public Plugin { | |||
public: | |||
enum Parameters { | |||
paramSize = 0, | |||
paramScatter, | |||
paramGain, | |||
paramDensity, | |||
paramLPF, | |||
paramHPF, | |||
paramSizeR, | |||
paramScatterR, | |||
paramGainR, | |||
paramDensityR, | |||
paramLPFR, | |||
paramHPFR, | |||
paramCount | |||
}; | |||
GrainJuicePlugin(); | |||
protected: | |||
// ------------------------------------------------------------------- | |||
// Information | |||
const char* d_getLabel() const noexcept override { | |||
return "GrainJuice"; | |||
} | |||
const char* d_getMaker() const noexcept override { | |||
return "Andre Sklenar"; | |||
} | |||
const char* d_getLicense() const noexcept override { | |||
return "GPL v2+"; | |||
} | |||
uint32_t d_getVersion() const noexcept override { | |||
return 0x1000; | |||
} | |||
long d_getUniqueId() const noexcept override { | |||
return d_cconst('G', 'r', 'n', 'J'); | |||
} | |||
// ------------------------------------------------------------------- | |||
// Init | |||
void d_initParameter(uint32_t index, Parameter& parameter) override; | |||
void d_initProgramName(uint32_t index, d_string& programName) override; | |||
// ------------------------------------------------------------------- | |||
// Internal data | |||
float d_getParameterValue(uint32_t index) const override; | |||
void d_setParameterValue(uint32_t index, float value) override; | |||
void d_setProgram(uint32_t index) override; | |||
// ------------------------------------------------------------------- | |||
// Process | |||
void d_activate() override; | |||
void d_run(const float** inputs, float** outputs, uint32_t frames) override; | |||
// ------------------------------------------------------------------- | |||
private: | |||
float size, scatter, gain, density, LPF, HPF; | |||
float sizeR, scatterR, gainR, densityR, LPFR, HPFR; | |||
float *nSample; | |||
float *prevSample; | |||
int concurrentFilling; | |||
int eraseIndex; | |||
int eraseGrains[100]; | |||
float logTable[1000]; | |||
int limit(int what) { | |||
if (what>1000) | |||
return 999; | |||
if (what<0) | |||
return 0; | |||
return what; | |||
} | |||
void newGrain(bool first); | |||
//float *nSample; | |||
bool isNan(float& value ) { | |||
if (((*(uint32_t *) &value) & 0x7fffffff) > 0x7f800000) { | |||
return true; | |||
} | |||
return false; | |||
} | |||
uint32_t prevTotalGrains; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(GrainJuicePlugin) | |||
class CGrain { | |||
public: | |||
CGrain(uint32_t nLength, uint32_t nDelay, float lpf, float hpf, float nGain); | |||
uint32_t getLength(); | |||
void fillSample(float *nSample); | |||
bool wantsSample(); | |||
float *getSample(); | |||
bool donePlaying(); | |||
void cleanUp(); | |||
bool inDelay(); | |||
uint32_t length; | |||
bool repeat(); | |||
void setDelay(uint32_t nDelay); | |||
void updateParams(float nDensity, float nScatter, uint32_t nSRT); | |||
float inspectSample(uint32_t index, int channel); | |||
private: | |||
void applyEnvelope(); | |||
float samples[(int)(48000*MAXGRAINSIZE)][2]; | |||
uint32_t playhead; | |||
bool readyForPlayback; | |||
uint32_t delay; | |||
float *emptySamples; | |||
float density; | |||
float scatter; | |||
float gain; | |||
uint32_t SRT; | |||
class CLPF | |||
{ | |||
private: | |||
float r; // reso - 0.1 - 1.4 | |||
float f; // freq in Hz | |||
float a1, a2, a3, b1, b2; | |||
float in, in1, in2; | |||
float out, out1, out2; | |||
float c; | |||
float sampleRate; | |||
public: | |||
CLPF() { | |||
r = 1.0f; | |||
f = 0.0f; | |||
a1=a2=a3=b1=b2=0.0f; | |||
in=in1=in2=out=out1=out2=0.0f; | |||
} | |||
void compute() { | |||
c = 1.0 / tan(M_PI * f / sampleRate); | |||
a1 = 1.0 / (1.0 + r*c + c*c); | |||
a2 = 2 * a1; | |||
a3 = a1; | |||
b1 = 2.0 * (1.0 - c*c) * a1; | |||
b2 = (1.0 - r*c + c*c) * a1; | |||
} | |||
void setFreq(float nFreq) { | |||
f = nFreq; | |||
if (f==0) { | |||
f=20; | |||
} | |||
} | |||
void setReso(float nReso) { | |||
r = nReso; | |||
if (r==0) { | |||
r = 0.1f; | |||
} | |||
r = 1.0f; | |||
f = 0.0f; | |||
a1=a2=a3=b1=b2=0.0f; | |||
in=in1=in2=out=out1=out2=0.0f; | |||
} | |||
void setSampleRate(float nSampleRate) { | |||
sampleRate = nSampleRate; | |||
} | |||
float process(float sample) { | |||
in = sample; | |||
out = a1 * in + a2 * in1 + a3 * in2 - b1*out1 - b2*out2; | |||
in2=in1; | |||
in1=in; | |||
out2=out1; | |||
out1 = out; | |||
return out; | |||
} | |||
}; | |||
class CHPF | |||
{ | |||
private: | |||
float r; // reso - 0.1 - 1.4 | |||
float f; // freq in Hz | |||
float a1, a2, a3, b1, b2; | |||
float in, in1, in2; | |||
float out, out1, out2; | |||
float c; | |||
float sampleRate; | |||
public: | |||
CHPF() { | |||
r = 1.0f; | |||
f = 0.0f; | |||
a1=a2=a3=b1=b2=0.0f; | |||
in=in1=in2=out=out1=out2=0.0f; | |||
} | |||
void compute() { | |||
c = tan(M_PI * f / sampleRate); | |||
a1 = 1.0 / (1.0 + r*c + c*c); | |||
a2 = -2*a1; | |||
a3 = a1; | |||
b1 = 2.0 * (c*c - 1.0) * a1; | |||
b2 = (1.0 - r*c + c*c) * a1; | |||
} | |||
void setFreq(float nFreq) { | |||
f = nFreq; | |||
if (f==0) { | |||
f=20; | |||
} | |||
} | |||
void setReso(float nReso) { | |||
r = nReso; | |||
if (r==0) { | |||
r = 0.1f; | |||
} | |||
} | |||
void setSampleRate(float nSampleRate) { | |||
sampleRate = nSampleRate; | |||
} | |||
float process(float sample) { | |||
//compute(); | |||
in = sample; | |||
out = a1 * in + a2 * in1 + a3 * in2 - b1*out1 - b2*out2; | |||
in2=in1; | |||
in1=in; | |||
out2=out1; | |||
out1 = out; | |||
return out; | |||
} | |||
}; | |||
CHPF highPass[2]; | |||
CLPF lowPass[2]; | |||
}; | |||
std::vector<CGrain*> grains; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
#endif // GrainJUICE_HPP_INCLUDED |
@@ -0,0 +1,283 @@ | |||
/* | |||
* Grain Juice Plugin | |||
* Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
* | |||
* 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 doc/GPL.txt file. | |||
*/ | |||
#include "GrainJuicePlugin.hpp" | |||
#include "GrainJuiceUI.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
GrainJuiceUI::GrainJuiceUI() | |||
: UI(), | |||
fAboutWindow(this) { | |||
setSize(GrainJuiceArtwork::backgroundWidth, GrainJuiceArtwork::backgroundHeight); | |||
// background | |||
fImgBackground = Image(GrainJuiceArtwork::backgroundData, GrainJuiceArtwork::backgroundWidth, GrainJuiceArtwork::backgroundHeight, GL_BGR); | |||
// about | |||
Image aboutImage(GrainJuiceArtwork::aboutData, GrainJuiceArtwork::aboutWidth, GrainJuiceArtwork::aboutHeight, GL_BGR); | |||
fAboutWindow.setImage(aboutImage); | |||
// knobs | |||
Image knobImage(GrainJuiceArtwork::knobData, GrainJuiceArtwork::knobWidth, GrainJuiceArtwork::knobHeight); | |||
#define PX 56 //position top X | |||
#define PY 98 //position top Y | |||
#define SX 70 //spacing X | |||
#define SY 86 //spacing Y | |||
// knob Size | |||
fKnobSize = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobSize->setId(GrainJuicePlugin::paramSize); | |||
fKnobSize->setAbsolutePos(PX, PY); | |||
fKnobSize->setRotationAngle(270); | |||
fKnobSize->setRange(0.0f, 1.0f); | |||
fKnobSize->setDefault(0.5f); | |||
fKnobSize->setStep(0.01f); | |||
fKnobSize->setCallback(this); | |||
// knob Scatter | |||
fKnobScatter = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobScatter->setId(GrainJuicePlugin::paramScatter); | |||
fKnobScatter->setAbsolutePos(PX+SX, PY); | |||
fKnobScatter->setRotationAngle(270); | |||
fKnobScatter->setRange(0.0f, 1.0f); | |||
fKnobScatter->setDefault(0.5f); | |||
fKnobScatter->setStep(0.01f); | |||
fKnobScatter->setCallback(this); | |||
// knob Gain | |||
fKnobGain = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobGain->setId(GrainJuicePlugin::paramGain); | |||
fKnobGain->setAbsolutePos(PX+SX*2, PY); | |||
fKnobGain->setRotationAngle(270); | |||
fKnobGain->setRange(0.0f, 1.0f); | |||
fKnobGain->setDefault(0.5f); | |||
fKnobGain->setStep(0.01f); | |||
fKnobGain->setCallback(this); | |||
// knob Density | |||
fKnobDensity = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobDensity->setId(GrainJuicePlugin::paramDensity); | |||
fKnobDensity->setAbsolutePos(PX+SX*3, PY); | |||
fKnobDensity->setRotationAngle(270); | |||
fKnobDensity->setRange(0.0f, 1.0f); | |||
fKnobDensity->setDefault(0.5f); | |||
fKnobDensity->setStep(0.01f); | |||
fKnobDensity->setCallback(this); | |||
// knob LPF | |||
fKnobLPF = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobLPF->setId(GrainJuicePlugin::paramLPF); | |||
fKnobLPF->setAbsolutePos(PX+SX*4, PY); | |||
fKnobLPF->setRotationAngle(270); | |||
fKnobLPF->setRange(0.0f, 1.0f); | |||
fKnobLPF->setDefault(0.5f); | |||
fKnobLPF->setStep(0.01f); | |||
fKnobLPF->setCallback(this); | |||
// knob HPF | |||
fKnobHPF = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobHPF->setId(GrainJuicePlugin::paramHPF); | |||
fKnobHPF->setAbsolutePos(PX+SX*5, PY); | |||
fKnobHPF->setRotationAngle(270); | |||
fKnobHPF->setRange(0.0f, 1.0f); | |||
fKnobHPF->setDefault(0.5f); | |||
fKnobHPF->setStep(0.01f); | |||
fKnobHPF->setCallback(this); | |||
//////////// RANDOMIZE KNOBS | |||
// knob Size | |||
fKnobSizeR = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobSizeR->setId(GrainJuicePlugin::paramSizeR); | |||
fKnobSizeR->setAbsolutePos(PX, PY+SY); | |||
fKnobSizeR->setRotationAngle(270); | |||
fKnobSizeR->setRange(0.0f, 1.0f); | |||
fKnobSizeR->setDefault(0.5f); | |||
fKnobSizeR->setStep(0.01f); | |||
fKnobSizeR->setCallback(this); | |||
// knob Scatter | |||
fKnobScatterR = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobScatterR->setId(GrainJuicePlugin::paramScatterR); | |||
fKnobScatterR->setAbsolutePos(PX+SX, PY+SY); | |||
fKnobScatterR->setRotationAngle(270); | |||
fKnobScatterR->setRange(0.0f, 1.0f); | |||
fKnobScatterR->setDefault(0.5f); | |||
fKnobScatterR->setStep(0.01f); | |||
fKnobScatterR->setCallback(this); | |||
// knob Gain | |||
fKnobGainR = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobGainR->setId(GrainJuicePlugin::paramGainR); | |||
fKnobGainR->setAbsolutePos(PX+SX*2, PY+SY); | |||
fKnobGainR->setRotationAngle(270); | |||
fKnobGainR->setRange(0.0f, 1.0f); | |||
fKnobGainR->setDefault(0.5f); | |||
fKnobGainR->setStep(0.01f); | |||
fKnobGainR->setCallback(this); | |||
// knob Density | |||
fKnobDensityR = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobDensityR->setId(GrainJuicePlugin::paramDensityR); | |||
fKnobDensityR->setAbsolutePos(PX+SX*3, PY+SY); | |||
fKnobDensityR->setRotationAngle(270); | |||
fKnobDensityR->setRange(0.0f, 1.0f); | |||
fKnobDensityR->setDefault(0.5f); | |||
fKnobDensityR->setStep(0.01f); | |||
fKnobDensityR->setCallback(this); | |||
// knob LPF | |||
fKnobLPFR = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobLPFR->setId(GrainJuicePlugin::paramLPFR); | |||
fKnobLPFR->setAbsolutePos(PX+SX*4, PY+SY); | |||
fKnobLPFR->setRotationAngle(270); | |||
fKnobLPFR->setRange(0.0f, 1.0f); | |||
fKnobLPFR->setDefault(0.5f); | |||
fKnobLPFR->setStep(0.01f); | |||
fKnobLPFR->setCallback(this); | |||
// knob HPF | |||
fKnobHPFR = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||
fKnobHPFR->setId(GrainJuicePlugin::paramHPFR); | |||
fKnobHPFR->setAbsolutePos(PX+SX*5, PY+SY); | |||
fKnobHPFR->setRotationAngle(270); | |||
fKnobHPFR->setRange(0.0f, 1.0f); | |||
fKnobHPFR->setDefault(0.5f); | |||
fKnobHPFR->setStep(0.01f); | |||
fKnobHPFR->setCallback(this); | |||
// about button | |||
Image aboutImageNormal(GrainJuiceArtwork::aboutButtonNormalData, GrainJuiceArtwork::aboutButtonNormalWidth, GrainJuiceArtwork::aboutButtonNormalHeight); | |||
Image aboutImageHover(GrainJuiceArtwork::aboutButtonHoverData, GrainJuiceArtwork::aboutButtonHoverWidth, GrainJuiceArtwork::aboutButtonHoverHeight); | |||
fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||
fButtonAbout->setAbsolutePos(390, 20); | |||
fButtonAbout->setCallback(this); | |||
// set default values | |||
d_programChanged(0); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// DSP Callbacks | |||
void GrainJuiceUI::d_parameterChanged(uint32_t index, float value) { | |||
switch (index) { | |||
case GrainJuicePlugin::paramSize: | |||
fKnobSize->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramScatter: | |||
fKnobScatter->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramGain: | |||
fKnobGain->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramDensity: | |||
fKnobDensity->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramLPF: | |||
fKnobLPF->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramHPF: | |||
fKnobHPF->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramSizeR: | |||
fKnobSizeR->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramScatterR: | |||
fKnobScatterR->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramGainR: | |||
fKnobGainR->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramDensityR: | |||
fKnobDensityR->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramLPFR: | |||
fKnobLPFR->setValue(value); | |||
break; | |||
case GrainJuicePlugin::paramHPFR: | |||
fKnobHPFR->setValue(value); | |||
break; | |||
} | |||
} | |||
void GrainJuiceUI::d_programChanged(uint32_t index) { | |||
if (index != 0) | |||
return; | |||
// Default values | |||
fKnobSize->setValue(0.5f); | |||
fKnobScatter->setValue(0.5f); | |||
fKnobGain->setValue(0.5f); | |||
fKnobDensity->setValue(0.5f); | |||
fKnobLPF->setValue(0.5f); | |||
fKnobHPF->setValue(0.5f); | |||
fKnobSizeR->setValue(0.5f); | |||
fKnobScatterR->setValue(0.5f); | |||
fKnobGainR->setValue(0.5f); | |||
fKnobDensityR->setValue(0.5f); | |||
fKnobLPFR->setValue(0.5f); | |||
fKnobHPFR->setValue(0.5f); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Widget Callbacks | |||
void GrainJuiceUI::imageButtonClicked(ImageButton* button, int) { | |||
if (button != fButtonAbout) | |||
return; | |||
fAboutWindow.exec(); | |||
} | |||
void GrainJuiceUI::imageKnobDragStarted(ImageKnob* knob) { | |||
d_editParameter(knob->getId(), true); | |||
} | |||
void GrainJuiceUI::imageKnobDragFinished(ImageKnob* knob) { | |||
d_editParameter(knob->getId(), false); | |||
} | |||
void GrainJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) { | |||
d_setParameterValue(knob->getId(), value); | |||
} | |||
void GrainJuiceUI::onDisplay() { | |||
fImgBackground.draw(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
UI* createUI() { | |||
return new GrainJuiceUI(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,80 @@ | |||
/* | |||
* Grain Juice Plugin | |||
* Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
* | |||
* 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 doc/GPL.txt file. | |||
*/ | |||
#ifndef GrainJUICEUI_HPP_INCLUDED | |||
#define GrainJUICEUI_HPP_INCLUDED | |||
#include "DistrhoUI.hpp" | |||
#include "ImageAboutWindow.hpp" | |||
#include "ImageButton.hpp" | |||
#include "ImageKnob.hpp" | |||
#include "GrainJuiceArtwork.hpp" | |||
using DGL::Image; | |||
using DGL::ImageAboutWindow; | |||
using DGL::ImageButton; | |||
using DGL::ImageKnob; | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
class GrainJuiceUI : public UI, | |||
public ImageButton::Callback, | |||
public ImageKnob::Callback { | |||
public: | |||
GrainJuiceUI(); | |||
protected: | |||
// ------------------------------------------------------------------- | |||
// DSP Callbacks | |||
void d_parameterChanged(uint32_t index, float value) override; | |||
void d_programChanged(uint32_t index) override; | |||
// ------------------------------------------------------------------- | |||
// Widget Callbacks | |||
void imageButtonClicked(ImageButton* button, int) override; | |||
void imageKnobDragStarted(ImageKnob* knob) override; | |||
void imageKnobDragFinished(ImageKnob* knob) override; | |||
void imageKnobValueChanged(ImageKnob* knob, float value) override; | |||
void onDisplay() override; | |||
private: | |||
Image fImgBackground; | |||
ImageAboutWindow fAboutWindow; | |||
ScopedPointer<ImageButton> fButtonAbout; | |||
ScopedPointer<ImageKnob> fKnobSize, fKnobScatter, fKnobGain; | |||
ScopedPointer<ImageKnob> fKnobDensity, fKnobLPF, fKnobHPF; | |||
ScopedPointer<ImageKnob> fKnobSizeR, fKnobScatterR, fKnobGainR; | |||
ScopedPointer<ImageKnob> fKnobDensityR, fKnobLPFR, fKnobHPFR; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(GrainJuiceUI) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
#endif // GrainJUICEUI_HPP_INCLUDED |
@@ -0,0 +1,37 @@ | |||
#!/usr/bin/make -f | |||
# Makefile for DISTRHO Plugins # | |||
# ---------------------------- # | |||
# Created by falkTX | |||
# | |||
# -------------------------------------------------------------- | |||
# Project name, used for binaries | |||
NAME = GrainJuice | |||
# -------------------------------------------------------------- | |||
# Files to build | |||
OBJS_DSP = \ | |||
GrainJuicePlugin.cpp.o | |||
OBJS_UI = \ | |||
GrainJuiceArtwork.cpp.o \ | |||
GrainJuiceUI.cpp.o | |||
# -------------------------------------------------------------- | |||
# Do some magic | |||
include ../Makefile.mk | |||
# -------------------------------------------------------------- | |||
# Enable all possible plugin types | |||
ifeq ($(LINUX),true) | |||
all: jack | |||
#lv2_sep vst | |||
else | |||
all: lv2_sep vst | |||
endif | |||
# -------------------------------------------------------------- |