@@ -42,7 +42,7 @@ extern void carla_register_native_plugin_nekobi(); | |||||
extern void carla_register_native_plugin_pingpongpan(); | extern void carla_register_native_plugin_pingpongpan(); | ||||
extern void carla_register_native_plugin_stereoenhancer(); | extern void carla_register_native_plugin_stereoenhancer(); | ||||
//extern void carla_register_native_plugin_powerjuice(); | |||||
extern void carla_register_native_plugin_powerjuice(); | |||||
extern void carla_register_native_plugin_segmentjuice(); | extern void carla_register_native_plugin_segmentjuice(); | ||||
extern void carla_register_native_plugin_vectorjuice(); | extern void carla_register_native_plugin_vectorjuice(); | ||||
extern void carla_register_native_plugin_wobblejuice(); | extern void carla_register_native_plugin_wobblejuice(); | ||||
@@ -105,7 +105,7 @@ void carla_register_all_plugins() | |||||
carla_register_native_plugin_pingpongpan(); | carla_register_native_plugin_pingpongpan(); | ||||
//carla_register_native_plugin_stereoenhancer(); | //carla_register_native_plugin_stereoenhancer(); | ||||
//carla_register_native_plugin_powerjuice(); | |||||
carla_register_native_plugin_powerjuice(); | |||||
carla_register_native_plugin_segmentjuice(); | carla_register_native_plugin_segmentjuice(); | ||||
carla_register_native_plugin_vectorjuice(); | carla_register_native_plugin_vectorjuice(); | ||||
carla_register_native_plugin_wobblejuice(); | carla_register_native_plugin_wobblejuice(); | ||||
@@ -28,9 +28,12 @@ | |||||
#define DISTRHO_PLUGIN_WANT_LATENCY 0 | #define DISTRHO_PLUGIN_WANT_LATENCY 0 | ||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | ||||
#define DISTRHO_PLUGIN_WANT_STATE 1 | |||||
#define DISTRHO_PLUGIN_WANT_STATE 0 | |||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 0 | #define DISTRHO_PLUGIN_WANT_TIMEPOS 0 | ||||
// needed for spectrum | |||||
#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | |||||
#define DISTRHO_PLUGIN_URI "urn:distrho:PowerJuice" | #define DISTRHO_PLUGIN_URI "urn:distrho:PowerJuice" | ||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED | #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -29,17 +29,14 @@ PowerJuicePlugin::PowerJuicePlugin() | |||||
// set default values | // set default values | ||||
d_setProgram(0); | d_setProgram(0); | ||||
// init shm vars | |||||
carla_shm_init(shm); | |||||
shmData = nullptr; | |||||
// reset | // reset | ||||
d_deactivate(); | d_deactivate(); | ||||
} | } | ||||
PowerJuicePlugin::~PowerJuicePlugin() | PowerJuicePlugin::~PowerJuicePlugin() | ||||
{ | { | ||||
closeShm(); | |||||
free(lookaheadStack.data); | |||||
free(RMSStack.data); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -115,16 +112,6 @@ void PowerJuicePlugin::d_initProgramName(uint32_t index, d_string& programName) | |||||
programName = "Default"; | programName = "Default"; | ||||
} | } | ||||
void PowerJuicePlugin::d_initStateKey(uint32_t /*index*/, d_string& /*key*/) | |||||
{ | |||||
/* | |||||
if (index != 0) | |||||
return; | |||||
key = "shmKey"; | |||||
*/ | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Internal data | // Internal data | ||||
@@ -155,9 +142,11 @@ void PowerJuicePlugin::d_setParameterValue(uint32_t index, float value) | |||||
{ | { | ||||
case paramAttack: | case paramAttack: | ||||
attack = value; | attack = value; | ||||
attackSamples = d_getSampleRate()*(attack/1000.0f); | |||||
break; | break; | ||||
case paramRelease: | case paramRelease: | ||||
release = value; | release = value; | ||||
releaseSamples = d_getSampleRate()*(release/1000.0f); | |||||
break; | break; | ||||
case paramThreshold: | case paramThreshold: | ||||
threshold = value; | threshold = value; | ||||
@@ -167,6 +156,7 @@ void PowerJuicePlugin::d_setParameterValue(uint32_t index, float value) | |||||
break; | break; | ||||
case paramMakeup: | case paramMakeup: | ||||
makeup = value; | makeup = value; | ||||
makeupFloat = fromDB(makeup); | |||||
break; | break; | ||||
case paramMix: | case paramMix: | ||||
mix = value; | mix = value; | ||||
@@ -187,34 +177,72 @@ void PowerJuicePlugin::d_setProgram(uint32_t index) | |||||
makeup = 0.0f; | makeup = 0.0f; | ||||
mix = 1.0f; | mix = 1.0f; | ||||
makeupFloat = fromDB(makeup); | |||||
attackSamples = d_getSampleRate()*(attack/1000.0f); | |||||
releaseSamples = d_getSampleRate()*(release/1000.0f); | |||||
w = 563; //waveform plane size, size of the plane in pixels; | |||||
w2 = 1126; //wavefowm array | |||||
h = 121; //waveform plane height | |||||
x = 27; //waveform plane positions | |||||
y = 53; | |||||
dc = 113; //0DC line y position | |||||
/* Default variable values */ | /* Default variable values */ | ||||
averageCounter = 0; | averageCounter = 0; | ||||
inputMin = 0.0f; | |||||
inputMax = 0.0f; | inputMax = 0.0f; | ||||
balancer = 1.0f; | |||||
GR = 1.0f; | |||||
newRepaint = false; | |||||
input.start = 0; | input.start = 0; | ||||
output.start = 0; | |||||
rms.start = 0; | |||||
gainReduction.start = 0; | gainReduction.start = 0; | ||||
std::memset(input.data, 0, sizeof(float)*kFloatStackCount); | |||||
std::memset(output.data, 0, sizeof(float)*kFloatStackCount); | |||||
RMSStack.start = 0; | |||||
lookaheadStack.start = 0; | |||||
repaintSkip = 0; | |||||
kFloatRMSStackCount = 400.0f/44100.0f*d_getSampleRate(); | |||||
RMSStack.data = (float*) calloc(kFloatRMSStackCount, sizeof(float)); | |||||
kFloatLookaheadStackCount = 800.0f/44100.0f*d_getSampleRate(); | |||||
lookaheadStack.data = (float*) calloc(kFloatLookaheadStackCount, sizeof(float)); | |||||
refreshSkip= 300.0f/44100.0f*d_getSampleRate(); | |||||
std::memset(rms.data, 0, sizeof(float)*kFloatStackCount); | |||||
std::memset(gainReduction.data, 0, sizeof(float)*kFloatStackCount); | std::memset(gainReduction.data, 0, sizeof(float)*kFloatStackCount); | ||||
std::memset(RMSStack.data, 0, sizeof(float)*kFloatRMSStackCount); | |||||
std::memset(lookaheadStack.data, 0, sizeof(float)*kFloatLookaheadStackCount); | |||||
for (int j=0; j < kFloatStackCount; ++j) | |||||
history.rms[j] = h +y; | |||||
for (int j=0; j < kFloatStackCount; ++j) | |||||
history.gainReduction[j] = h +y; | |||||
d_activate(); | d_activate(); | ||||
} | } | ||||
void PowerJuicePlugin::d_setState(const char* key, const char* value) | |||||
{ | |||||
if (std::strcmp(key, "shmKey") != 0) | |||||
return; | |||||
float PowerJuicePlugin::getRMSHistory(int n) { | |||||
return history.rms[n]; | |||||
} | |||||
if (value[0] == '\0') | |||||
{ | |||||
carla_stdout("Shm closed"); | |||||
return closeShm(); | |||||
} | |||||
bool PowerJuicePlugin::repaintNeeded() { | |||||
return newRepaint; | |||||
} | |||||
carla_stdout("Got shmKey => %s", value); | |||||
initShm(value); | |||||
float PowerJuicePlugin::getGainReductionHistory(int n) { | |||||
if (n == kFloatStackCount-1) { | |||||
newRepaint = false; | |||||
//printf("falsing!\n"); | |||||
} | |||||
return history.gainReduction[n]; | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -229,71 +257,114 @@ void PowerJuicePlugin::d_deactivate() | |||||
// all values to zero | // all values to zero | ||||
} | } | ||||
void PowerJuicePlugin::d_run(float** inputs, float** /*outputs*/, uint32_t frames) | |||||
void PowerJuicePlugin::d_run(float** inputs, float** outputs, uint32_t frames) | |||||
{ | { | ||||
float* in = inputs[0]; | float* in = inputs[0]; | ||||
//float* out = outputs[0]; | |||||
float* out = outputs[0]; | |||||
float sum; | |||||
float data; | |||||
float difference; | |||||
for (uint32_t i=0; i < frames; i++) { | for (uint32_t i=0; i < frames; i++) { | ||||
//for every sample | |||||
//printf("av"); | |||||
//averageInputs[averageCounter] = in[i]; | |||||
if (in[i]<inputMin) { | |||||
inputMin = in[i]; | |||||
} | |||||
if (in[i]>inputMax) { | |||||
inputMax = in[i]; | |||||
sum = 0.0f; | |||||
data = 0.0f; | |||||
difference = 0; | |||||
sanitizeDenormal(in[i]); | |||||
/* compute last RMS */ | |||||
//store audio samples in an RMS buffer line | |||||
RMSStack.data[RMSStack.start++] = in[i]; | |||||
if (RMSStack.start == kFloatRMSStackCount) | |||||
RMSStack.start = 0; | |||||
//compute RMS over last kFloatRMSStackCount samples | |||||
for (int j=0; j < kFloatRMSStackCount; ++j) { | |||||
data = RMSStack.data[(RMSStack.start+j) % kFloatRMSStackCount]; | |||||
sum += data * data; | |||||
} | } | ||||
if (++averageCounter == 300) { | |||||
//output waveform parameter | |||||
input.data[input.start++] = inputMin; | |||||
input.data[input.start++] = inputMax; | |||||
if (input.start == kFloatStackCount) | |||||
input.start = 0; | |||||
if (shmData != nullptr) | |||||
{ | |||||
for (int j=0; j < kFloatStackCount; ++j) | |||||
shmData->input[j] = input.data[(input.start+j) % kFloatStackCount]; | |||||
//root mean SQUARE | |||||
float RMS = sqrt(sum / kFloatRMSStackCount); | |||||
sanitizeDenormal(RMS); | |||||
/* compute gain reduction if needed */ | |||||
float RMSDB = toDB(RMS); | |||||
if (RMSDB>threshold) { | |||||
//attack stage | |||||
float difference = (RMSDB-threshold); | |||||
//sanitizeDenormal(difference); | |||||
targetGR = difference - difference/ratio; | |||||
if (targetGR>difference/(ratio/4.0f)) { | |||||
targetGR = difference - difference/(ratio*1.5f); | |||||
//more power! | |||||
} | } | ||||
// | |||||
if (GR<targetGR) { | |||||
//approach targetGR at attackSamples rate | |||||
GR -= (GR-targetGR)/(attackSamples); | |||||
} else { | |||||
//approach targetGR at releaseSamples rate | |||||
GR -= (GR-targetGR)/releaseSamples; | |||||
} | |||||
sanitizeDenormal(GR); | |||||
} else { | |||||
//release stage | |||||
//approach targetGR at releaseSamples rate, targetGR = 0.0f | |||||
GR -= GR/releaseSamples; | |||||
} | |||||
//store audio in lookahead buffer | |||||
lookaheadStack.data[lookaheadStack.start++] = in[i]; | |||||
//printf("rms\n"); | |||||
if (lookaheadStack.start == kFloatLookaheadStackCount) | |||||
lookaheadStack.start = 0; | |||||
if (++averageCounter >= refreshSkip) { | |||||
//add relevant values to the shared memory | |||||
rms.data[rms.start++] = RMSDB; | |||||
gainReduction.data[gainReduction.start++] = GR; | |||||
//rewind stack reading heads if needed | |||||
if (rms.start == kFloatStackCount) | |||||
rms.start = 0; | |||||
if (gainReduction.start == kFloatStackCount) | |||||
gainReduction.start = 0; | |||||
//saving in gfx format, for speed | |||||
//share memory | |||||
for (int j=0; j < kFloatStackCount; ++j) | |||||
history.rms[j] = -toIEC(rms.data[(rms.start+j) % kFloatStackCount])/200*h +h +y; | |||||
for (int j=0; j < kFloatStackCount; ++j) { | |||||
history.gainReduction[j] = -toIEC(-gainReduction.data[(gainReduction.start+j) % kFloatStackCount])/200*h +h +y; | |||||
} | |||||
repaintSkip++; | |||||
if (repaintSkip>5) { | |||||
repaintSkip = 0; | |||||
newRepaint = true; | |||||
} | |||||
averageCounter = 0; | averageCounter = 0; | ||||
inputMin = 0.0f; | |||||
inputMax = 0.0f; | inputMax = 0.0f; | ||||
} | } | ||||
} | |||||
} | |||||
void PowerJuicePlugin::initShm(const char* shmKey) | |||||
{ | |||||
shm = carla_shm_attach(shmKey); | |||||
if (! carla_is_shm_valid(shm)) | |||||
{ | |||||
carla_stderr2("Failed to created shared memory!"); | |||||
return; | |||||
/* compress, mix, done. */ | |||||
float compressedSignal = in[i]*fromDB(-GR); | |||||
out[i] = (compressedSignal*makeupFloat*mix)+in[i]*(1-mix); | |||||
} | } | ||||
if (! carla_shm_map<SharedMemData>(shm, shmData)) | |||||
{ | |||||
carla_stderr2("Failed to map shared memory!"); | |||||
return; | |||||
} | |||||
} | |||||
void PowerJuicePlugin::closeShm() | |||||
{ | |||||
if (! carla_is_shm_valid(shm)) | |||||
return; | |||||
if (shmData != nullptr) | |||||
{ | |||||
carla_shm_unmap<SharedMemData>(shm, shmData); | |||||
shmData = nullptr; | |||||
} | |||||
carla_shm_close(shm); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -19,18 +19,29 @@ | |||||
#define POWERJUICEPLUGIN_HPP_INCLUDED | #define POWERJUICEPLUGIN_HPP_INCLUDED | ||||
#include "DistrhoPlugin.hpp" | #include "DistrhoPlugin.hpp" | ||||
#include "CarlaShmUtils.hpp" | |||||
static const int kFloatStackCount = 1126; | |||||
#include <cmath> | |||||
struct FloatStack { | |||||
static const int kFloatStackCount = 563; | |||||
struct FloatStack { //history for GUI! | |||||
int32_t start; | int32_t start; | ||||
float data[kFloatStackCount]; | float data[kFloatStackCount]; | ||||
}; | }; | ||||
struct SharedMemData { | |||||
float input[kFloatStackCount]; | |||||
float output[kFloatStackCount]; | |||||
struct FloatRMSStack { //rms, sr-dependent | |||||
int32_t start; | |||||
float* data; | |||||
}; | |||||
struct LookaheadStack { //lookahead buffer, sr-dependent | |||||
int32_t start; | |||||
float* data; | |||||
}; | |||||
struct SharedMemData { //history for the GUI ! | |||||
float rms[kFloatStackCount]; | |||||
float gainReduction[kFloatStackCount]; | float gainReduction[kFloatStackCount]; | ||||
}; | }; | ||||
@@ -49,9 +60,6 @@ public: | |||||
paramRatio, | paramRatio, | ||||
paramMakeup, | paramMakeup, | ||||
paramMix, | paramMix, | ||||
paramInput, | |||||
paramOutput, | |||||
paramGainReduction, | |||||
paramCount | paramCount | ||||
}; | }; | ||||
@@ -92,7 +100,6 @@ protected: | |||||
void d_initParameter(uint32_t index, Parameter& parameter) override; | void d_initParameter(uint32_t index, Parameter& parameter) override; | ||||
void d_initProgramName(uint32_t index, d_string& programName) override; | void d_initProgramName(uint32_t index, d_string& programName) override; | ||||
void d_initStateKey(uint32_t, d_string&) override; | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Internal data | // Internal data | ||||
@@ -100,7 +107,6 @@ protected: | |||||
float d_getParameterValue(uint32_t index) const override; | float d_getParameterValue(uint32_t index) const override; | ||||
void d_setParameterValue(uint32_t index, float value) override; | void d_setParameterValue(uint32_t index, float value) override; | ||||
void d_setProgram(uint32_t index) override; | void d_setProgram(uint32_t index) override; | ||||
void d_setState(const char* key, const char* value) override; | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Process | // Process | ||||
@@ -114,20 +120,89 @@ protected: | |||||
private: | private: | ||||
// params | // params | ||||
float attack, release, threshold, ratio, makeup, mix; | float attack, release, threshold, ratio, makeup, mix; | ||||
float attackSamples, releaseSamples, makeupFloat; | |||||
float balancer; | |||||
float targetGR; | |||||
float GR; | |||||
SharedMemData history; | |||||
float sum; | |||||
float data; | |||||
float difference; | |||||
int w; //waveform plane size, size of the plane in pixels; | |||||
int w2; //wavefowm array | |||||
int h; //waveform plane height | |||||
int x; //waveform plane positions | |||||
int y; | |||||
int dc; //0DC line y position | |||||
int kFloatRMSStackCount; | |||||
int kFloatLookaheadStackCount; | |||||
float refreshSkip; | |||||
int averageCounter; | int averageCounter; | ||||
float inputMin, inputMax; | |||||
float inputMax; | |||||
FloatStack input, rms, gainReduction; | |||||
struct FloatRMSStack RMSStack; | |||||
struct LookaheadStack lookaheadStack; | |||||
bool newRepaint; | |||||
int repaintSkip; | |||||
float fromDB(float gdb) { | |||||
return (std::exp(gdb/20.f*std::log(10.f))); | |||||
}; | |||||
// this was unused | |||||
// float averageInputs[150]; | |||||
float toDB(float g) { | |||||
return (20.f*std::log10(g)); | |||||
} | |||||
FloatStack input, output, gainReduction; | |||||
float toIEC(float db) { | |||||
float def = 0.0f; /* Meter deflection %age */ | |||||
if (db < -70.0f) { | |||||
def = 0.0f; | |||||
} else if (db < -60.0f) { | |||||
def = (db + 70.0f) * 0.25f; | |||||
} else if (db < -50.0f) { | |||||
def = (db + 60.0f) * 0.5f + 5.0f; | |||||
} else if (db < -40.0f) { | |||||
def = (db + 50.0f) * 0.75f + 7.5; | |||||
} else if (db < -30.0f) { | |||||
def = (db + 40.0f) * 1.5f + 15.0f; | |||||
} else if (db < -20.0f) { | |||||
def = (db + 30.0f) * 2.0f + 30.0f; | |||||
} else if (db < 0.0f) { | |||||
def = (db + 20.0f) * 2.5f + 50.0f; | |||||
} else { | |||||
def = 100.0f; | |||||
} | |||||
return (def * 2.0f); | |||||
} | |||||
shm_t shm; | |||||
SharedMemData* shmData; | |||||
bool isNan(float& value ) { | |||||
if (((*(uint32_t *) &value) & 0x7fffffff) > 0x7f800000) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void initShm(const char* shmKey); | |||||
void closeShm(); | |||||
void sanitizeDenormal(float& value) { | |||||
if (isNan(value)) { | |||||
//std::printf("Booo!\n"); | |||||
value = 0.f; | |||||
} | |||||
} | |||||
public: | |||||
//methods | |||||
float getRMSHistory(int n); | |||||
float getGainReductionHistory(int n); | |||||
bool repaintNeeded(); | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -28,8 +28,7 @@ START_NAMESPACE_DISTRHO | |||||
PowerJuiceUI::PowerJuiceUI() | PowerJuiceUI::PowerJuiceUI() | ||||
: UI(), | : UI(), | ||||
fAboutWindow(this), | |||||
shmData(nullptr) | |||||
fAboutWindow(this) | |||||
{ | { | ||||
// background | // background | ||||
fImgBackground = Image(PowerJuiceArtwork::backgroundData, PowerJuiceArtwork::backgroundWidth, PowerJuiceArtwork::backgroundHeight, GL_BGR); | fImgBackground = Image(PowerJuiceArtwork::backgroundData, PowerJuiceArtwork::backgroundWidth, PowerJuiceArtwork::backgroundHeight, GL_BGR); | ||||
@@ -97,11 +96,7 @@ PowerJuiceUI::PowerJuiceUI() | |||||
fButtonAbout->setPos(502, 17); | fButtonAbout->setPos(502, 17); | ||||
fButtonAbout->setCallback(this); | fButtonAbout->setCallback(this); | ||||
// init shm vars | |||||
carla_shm_init(shm); | |||||
shmData = nullptr; | |||||
fFirstDisplay = true; | |||||
} | } | ||||
PowerJuiceUI::~PowerJuiceUI() | PowerJuiceUI::~PowerJuiceUI() | ||||
@@ -113,8 +108,6 @@ PowerJuiceUI::~PowerJuiceUI() | |||||
delete fKnobMakeup; | delete fKnobMakeup; | ||||
delete fKnobMix; | delete fKnobMix; | ||||
delete fButtonAbout; | delete fButtonAbout; | ||||
closeShm(); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -159,10 +152,6 @@ void PowerJuiceUI::d_programChanged(uint32_t index) | |||||
fKnobMix->setValue(1.0f); | fKnobMix->setValue(1.0f); | ||||
} | } | ||||
void PowerJuiceUI::d_stateChanged(const char*, const char*) | |||||
{ | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Widget Callbacks | // Widget Callbacks | ||||
@@ -208,7 +197,7 @@ void PowerJuiceUI::imageKnobDragFinished(ImageKnob* knob) | |||||
void PowerJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | void PowerJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | ||||
{ | { | ||||
if (knob == fKnobAttack) | |||||
if (knob == fKnobAttack) | |||||
d_setParameterValue(PowerJuicePlugin::paramAttack, value); | d_setParameterValue(PowerJuicePlugin::paramAttack, value); | ||||
else if (knob == fKnobRelease) | else if (knob == fKnobRelease) | ||||
d_setParameterValue(PowerJuicePlugin::paramRelease, value); | d_setParameterValue(PowerJuicePlugin::paramRelease, value); | ||||
@@ -224,106 +213,97 @@ void PowerJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
} | } | ||||
void PowerJuiceUI::d_uiIdle() { | void PowerJuiceUI::d_uiIdle() { | ||||
repaint(); | |||||
dsp = (PowerJuicePlugin*)d_getPluginInstancePointer(); | |||||
if (dsp -> repaintNeeded()) { | |||||
repaint(); | |||||
} else { | |||||
} | |||||
} | } | ||||
void PowerJuiceUI::onDisplay() | void PowerJuiceUI::onDisplay() | ||||
{ | { | ||||
if (fFirstDisplay) | |||||
{ | |||||
initShm(); | |||||
fFirstDisplay = false; | |||||
} | |||||
fImgBackground.draw(); | fImgBackground.draw(); | ||||
if (shmData == nullptr) | |||||
//dsp side connection | |||||
dsp = (PowerJuicePlugin*)d_getPluginInstancePointer(); | |||||
if (dsp == nullptr) | |||||
return; | return; | ||||
int w = 563; //waveform plane size, size of the plane in pixels; | int w = 563; //waveform plane size, size of the plane in pixels; | ||||
int w2 = 1126; //wavefowm array | int w2 = 1126; //wavefowm array | ||||
int h = 60; //waveform plane height | |||||
int x = 28; //waveform plane positions | |||||
int y = 51; | |||||
int h = 121; //waveform plane height | |||||
int x = 27; //waveform plane positions | |||||
int y = 53; | |||||
int dc = 113; //0DC line y position | int dc = 113; //0DC line y position | ||||
//draw waveform | |||||
for (int i=0; i<w2; i+=2) { | |||||
//glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
//glEnable(GL_LINE_SMOOTH); | |||||
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | |||||
glColor4f(0.0f, 1.0f, 0.0f, 1.0f); | |||||
glLineWidth(1.0f); | |||||
glBegin(GL_LINES); | |||||
glVertex2i(x+(i/2), shmData->input[i]*h+dc); | |||||
glVertex2i(x+(i/2), shmData->input[i+1]*h+dc); | |||||
glEnd(); | |||||
// reset color | |||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
} | |||||
//draw shits | |||||
} | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glEnable(GL_LINE_SMOOTH); | |||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | |||||
void PowerJuiceUI::onClose() | |||||
{ | |||||
// tell DSP to stop sending SHM data | |||||
d_setState("shmKey", ""); | |||||
} | |||||
void PowerJuiceUI::initShm() | |||||
{ | |||||
// generate a random key | |||||
static const char charSet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |||||
static const int charSetLen = sizeof(charSet) - 1; // -1 to avoid trailing '\0' | |||||
char shmKey[24+1]; | |||||
shmKey[24] = '\0'; | |||||
std::srand(std::time(nullptr)); | |||||
float thresholdPosition = (-toIEC(fKnobThreshold->getValue()))/200*h+h+y; | |||||
for (int i=0; i<24; ++i) | |||||
shmKey[i] = charSet[std::rand() % charSetLen]; | |||||
// create shared memory | |||||
shm = carla_shm_create(shmKey); | |||||
//draw waveform | |||||
/* | |||||
glColor4f(0.0f, 1.0f, 0.0f, 0.4f); | |||||
glLineWidth(1.2f); | |||||
for (int i=0; i<w; i++) { | |||||
if (! carla_is_shm_valid(shm)) | |||||
{ | |||||
carla_stderr2("Failed to created shared memory!"); | |||||
return; | |||||
glBegin(GL_LINES); | |||||
glVertex2i(x+i, -toIEC(shmData->input[i])/200*h+h+y); | |||||
glVertex2i(x+i, y+h); | |||||
glEnd(); | |||||
} | } | ||||
if (! carla_shm_map<SharedMemData>(shm, shmData)) | |||||
{ | |||||
carla_stderr2("Failed to map shared memory!"); | |||||
return; | |||||
*/ | |||||
//draw RMS | |||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f); | |||||
glLineWidth(2.0f); | |||||
glBegin(GL_LINE_STRIP); | |||||
for (int i=2; i<w; i++) { | |||||
float value = dsp->getRMSHistory(i); | |||||
if (value<thresholdPosition) { | |||||
glColor4f(0.0f, 0.5f, 0.0f, 1.0f); | |||||
} else { | |||||
glColor4f(0.0f, 0.5f, 0.2f, 1.0f); | |||||
} | |||||
glVertex2i(x+i, value); | |||||
} | } | ||||
std::memset(shmData, 0, sizeof(SharedMemData)); | |||||
// tell DSP to use this key for SHM | |||||
carla_stdout("Sending shmKey %s", shmKey); | |||||
d_setState("shmKey", shmKey); | |||||
} | |||||
void PowerJuiceUI::closeShm() | |||||
{ | |||||
fFirstDisplay = true; | |||||
if (! carla_is_shm_valid(shm)) | |||||
return; | |||||
if (shmData != nullptr) | |||||
{ | |||||
carla_shm_unmap<SharedMemData>(shm, shmData); | |||||
shmData = nullptr; | |||||
glEnd(); | |||||
//draw gain reduction | |||||
glColor4f(1.0f, 1.0f, 1.0f, 0.3f); | |||||
glLineWidth(3.0f); | |||||
glBegin(GL_LINES); | |||||
for (int i=2; i<w; i++) { | |||||
glColor4f(1.0f, 1.0f, 1.0f, 0.3f); | |||||
float value = dsp->getGainReductionHistory(i); | |||||
glVertex2i(x+i, value); | |||||
glVertex2i(x+i, y); | |||||
value = dsp->getRMSHistory(i); | |||||
glColor4f(0.0f, 0.5f, 0.2f, 0.1f); | |||||
glVertex2i(x+i, value); | |||||
glVertex2i(x+i, y+h); | |||||
} | } | ||||
carla_shm_close(shm); | |||||
glEnd(); | |||||
//draw Threshold | |||||
glLineWidth(2.0f); | |||||
glColor4f(0.4f, 0.4f, 1.0f, 0.8f); | |||||
//float thresholdPosition = ((60-fKnobThreshold->getValue())/60); | |||||
glBegin(GL_LINES); | |||||
glVertex2i(x, thresholdPosition); | |||||
glVertex2i(x+w, thresholdPosition); | |||||
glEnd(); | |||||
// reset color | |||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -28,6 +28,8 @@ | |||||
#include "PowerJuiceArtwork.hpp" | #include "PowerJuiceArtwork.hpp" | ||||
#include "PowerJuicePlugin.hpp" | #include "PowerJuicePlugin.hpp" | ||||
#include <cmath> | |||||
using DGL::Image; | using DGL::Image; | ||||
using DGL::ImageAboutWindow; | using DGL::ImageAboutWindow; | ||||
using DGL::ImageButton; | using DGL::ImageButton; | ||||
@@ -64,7 +66,6 @@ protected: | |||||
void d_parameterChanged(uint32_t index, float value) override; | void d_parameterChanged(uint32_t index, float value) override; | ||||
void d_programChanged(uint32_t index) override; | void d_programChanged(uint32_t index) override; | ||||
void d_stateChanged(const char*, const char*) override; | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// UI Callbacks | // UI Callbacks | ||||
@@ -79,7 +80,6 @@ protected: | |||||
void imageKnobDragFinished(ImageKnob* knob) override; | void imageKnobDragFinished(ImageKnob* knob) override; | ||||
void imageKnobValueChanged(ImageKnob* knob, float value) override; | void imageKnobValueChanged(ImageKnob* knob, float value) override; | ||||
void onDisplay() override; | void onDisplay() override; | ||||
void onClose() override; | |||||
private: | private: | ||||
Image fImgBackground; | Image fImgBackground; | ||||
@@ -93,12 +93,39 @@ private: | |||||
ImageKnob* fKnobMix; | ImageKnob* fKnobMix; | ||||
ImageButton* fButtonAbout; | ImageButton* fButtonAbout; | ||||
shm_t shm; | |||||
SharedMemData* shmData; | |||||
PowerJuicePlugin* dsp; | |||||
float fromDB(float gdb) { | |||||
return (std::exp(gdb/20.f*std::log(10.f))); | |||||
}; | |||||
bool fFirstDisplay; | |||||
void initShm(); | |||||
void closeShm(); | |||||
float toDB(float g) { | |||||
return (20.f*std::log10(g)); | |||||
} | |||||
float toIEC(float db) { | |||||
float def = 0.0f; /* Meter deflection %age */ | |||||
if (db < -70.0f) { | |||||
def = 0.0f; | |||||
} else if (db < -60.0f) { | |||||
def = (db + 70.0f) * 0.25f; | |||||
} else if (db < -50.0f) { | |||||
def = (db + 60.0f) * 0.5f + 5.0f; | |||||
} else if (db < -40.0f) { | |||||
def = (db + 50.0f) * 0.75f + 7.5; | |||||
} else if (db < -30.0f) { | |||||
def = (db + 40.0f) * 1.5f + 15.0f; | |||||
} else if (db < -20.0f) { | |||||
def = (db + 30.0f) * 2.0f + 30.0f; | |||||
} else if (db < 0.0f) { | |||||
def = (db + 20.0f) * 2.5f + 50.0f; | |||||
} else { | |||||
def = 100.0f; | |||||
} | |||||
return (def * 2.0f); | |||||
} | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||