|
|
@@ -686,7 +686,6 @@ public: |
|
|
|
|
|
|
|
// always available if needed |
|
|
|
kData->availOptions |= PLUGIN_OPTION_FIXED_BUFFER; |
|
|
|
kData->availOptions |= PLUGIN_OPTION_SELF_AUTOMATION; |
|
|
|
|
|
|
|
// check latency |
|
|
|
if (fHints & PLUGIN_CAN_DRYWET) |
|
|
@@ -779,7 +778,7 @@ public: |
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Check if not active before |
|
|
|
|
|
|
|
if (! kData->activeBefore) |
|
|
|
if (kData->needsReset || ! kData->activeBefore) |
|
|
|
{ |
|
|
|
if (kData->latency > 0) |
|
|
|
{ |
|
|
@@ -787,6 +786,17 @@ public: |
|
|
|
carla_zeroFloat(kData->latencyBuffers[i], kData->latency); |
|
|
|
} |
|
|
|
|
|
|
|
if (kData->activeBefore) |
|
|
|
{ |
|
|
|
if (fDescriptor->deactivate != nullptr) |
|
|
|
{ |
|
|
|
fDescriptor->deactivate(fHandle); |
|
|
|
|
|
|
|
if (fHandle2 != nullptr) |
|
|
|
fDescriptor->deactivate(fHandle2); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (fDescriptor->activate != nullptr) |
|
|
|
{ |
|
|
|
fDescriptor->activate(fHandle); |
|
|
@@ -794,6 +804,8 @@ public: |
|
|
|
if (fHandle2 != nullptr) |
|
|
|
fDescriptor->activate(fHandle2); |
|
|
|
} |
|
|
|
|
|
|
|
kData->needsReset = false; |
|
|
|
} |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
@@ -822,8 +834,8 @@ public: |
|
|
|
|
|
|
|
if (time > timeOffset && sampleAccurate) |
|
|
|
{ |
|
|
|
processSingle(inBuffer, outBuffer, time - timeOffset, timeOffset); |
|
|
|
timeOffset = time; |
|
|
|
if (processSingle(inBuffer, outBuffer, time - timeOffset, timeOffset)) |
|
|
|
timeOffset = time; |
|
|
|
} |
|
|
|
|
|
|
|
// Control change |
|
|
@@ -1003,12 +1015,73 @@ public: |
|
|
|
|
|
|
|
CARLA_PROCESS_CONTINUE_CHECK; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Control Output |
|
|
|
|
|
|
|
if (kData->event.portOut != nullptr) |
|
|
|
{ |
|
|
|
float value; |
|
|
|
|
|
|
|
for (k=0; k < kData->param.count; k++) |
|
|
|
{ |
|
|
|
if (kData->param.data[k].type != PARAMETER_OUTPUT) |
|
|
|
continue; |
|
|
|
|
|
|
|
kData->param.ranges[k].fixValue(fParamBuffers[k]); |
|
|
|
|
|
|
|
if (kData->param.data[k].midiCC > 0) |
|
|
|
{ |
|
|
|
value = kData->param.ranges[k].normalizeValue(fParamBuffers[k]); |
|
|
|
kData->event.portOut->writeControlEvent(0, kData->param.data[k].midiChannel, kEngineControlEventTypeParameter, kData->param.data[k].midiCC, value); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} // End of Control Output |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
kData->activeBefore = kData->active; |
|
|
|
} |
|
|
|
|
|
|
|
bool processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) |
|
|
|
{ |
|
|
|
uint32_t i, k; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Try lock, silence otherwise |
|
|
|
|
|
|
|
if (! kData->mutex.tryLock()) |
|
|
|
{ |
|
|
|
for (i=0; i < kData->audioOut.count; i++) |
|
|
|
{ |
|
|
|
for (k=0; k < frames; k++) |
|
|
|
outBuffer[i][k+timeOffset] = 0.0f; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Fill plugin buffers |
|
|
|
|
|
|
|
for (i=0; i < kData->audioIn.count; i++) |
|
|
|
carla_copyFloat(fAudioInBuffers[i], inBuffer[i]+timeOffset, frames); |
|
|
|
for (i=0; i < kData->audioOut.count; i++) |
|
|
|
carla_zeroFloat(fAudioOutBuffers[i], frames); |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Run plugin |
|
|
|
|
|
|
|
fDescriptor->run(fHandle, frames); |
|
|
|
|
|
|
|
if (fHandle2 != nullptr) |
|
|
|
fDescriptor->run(fHandle2, frames); |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Post-processing (dry/wet, volume and balance) |
|
|
|
|
|
|
|
{ |
|
|
|
const bool doDryWet = (fHints & PLUGIN_CAN_DRYWET) > 0 && kData->postProc.dryWet != 1.0f; |
|
|
|
const bool doVolume = (fHints & PLUGIN_CAN_VOLUME) > 0 && kData->postProc.volume != 1.0f; |
|
|
|
const bool doBalance = (fHints & PLUGIN_CAN_BALANCE) > 0 && (kData->postProc.balanceLeft != -1.0f || kData->postProc.balanceRight != 1.0f); |
|
|
|
|
|
|
|
float bufValue, oldBufLeft[doBalance ? frames : 1]; |
|
|
@@ -1026,9 +1099,8 @@ public: |
|
|
|
//else |
|
|
|
// bufValue = (kData->audioIn.count == 1) ? inBuffer[0][k-m_latency] : inBuffer[i][k-m_latency]; |
|
|
|
|
|
|
|
bufValue = inBuffer[ (kData->audioIn.count == 1) ? 0 : i ][k]; |
|
|
|
|
|
|
|
outBuffer[i][k] = (outBuffer[i][k] * kData->postProc.dryWet) + (bufValue * (1.0f - kData->postProc.dryWet)); |
|
|
|
bufValue = fAudioInBuffers[(kData->audioIn.count == 1) ? 0 : i][k]; |
|
|
|
fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * kData->postProc.dryWet) + (bufValue * (1.0f - kData->postProc.dryWet)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -1036,7 +1108,7 @@ public: |
|
|
|
if (doBalance) |
|
|
|
{ |
|
|
|
if (i % 2 == 0) |
|
|
|
carla_copyFloat(oldBufLeft, outBuffer[i], frames); |
|
|
|
carla_copyFloat(oldBufLeft, fAudioOutBuffers[i], frames); |
|
|
|
|
|
|
|
float balRangeL = (kData->postProc.balanceLeft + 1.0f)/2.0f; |
|
|
|
float balRangeR = (kData->postProc.balanceRight + 1.0f)/2.0f; |
|
|
@@ -1046,23 +1118,22 @@ public: |
|
|
|
if (i % 2 == 0) |
|
|
|
{ |
|
|
|
// left |
|
|
|
outBuffer[i][k] = oldBufLeft[k] * (1.0f - balRangeL); |
|
|
|
outBuffer[i][k] += outBuffer[i+1][k] * (1.0f - balRangeR); |
|
|
|
fAudioOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL); |
|
|
|
fAudioOutBuffers[i][k] += fAudioOutBuffers[i+1][k] * (1.0f - balRangeR); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// right |
|
|
|
outBuffer[i][k] = outBuffer[i][k] * balRangeR; |
|
|
|
outBuffer[i][k] += oldBufLeft[k] * balRangeL; |
|
|
|
fAudioOutBuffers[i][k] = fAudioOutBuffers[i][k] * balRangeR; |
|
|
|
fAudioOutBuffers[i][k] += oldBufLeft[k] * balRangeL; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Volume |
|
|
|
if (doVolume) |
|
|
|
// Volume (and buffer copy) |
|
|
|
{ |
|
|
|
for (k=0; k < frames; k++) |
|
|
|
outBuffer[i][k] *= kData->postProc.volume; |
|
|
|
outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k] * kData->postProc.volume; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -1076,53 +1147,10 @@ public: |
|
|
|
#endif |
|
|
|
} // End of Post-processing |
|
|
|
|
|
|
|
CARLA_PROCESS_CONTINUE_CHECK; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
// Control Output |
|
|
|
|
|
|
|
if (kData->event.portOut != nullptr) |
|
|
|
{ |
|
|
|
float value; |
|
|
|
|
|
|
|
for (k=0; k < kData->param.count; k++) |
|
|
|
{ |
|
|
|
if (kData->param.data[k].type != PARAMETER_OUTPUT) |
|
|
|
continue; |
|
|
|
|
|
|
|
kData->param.ranges[k].fixValue(fParamBuffers[k]); |
|
|
|
|
|
|
|
if (kData->param.data[k].midiCC > 0) |
|
|
|
{ |
|
|
|
value = kData->param.ranges[k].normalizeValue(fParamBuffers[k]); |
|
|
|
kData->event.portOut->writeControlEvent(0, kData->param.data[k].midiChannel, kEngineControlEventTypeParameter, kData->param.data[k].midiCC, value); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} // End of Control Output |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
kData->activeBefore = kData->active; |
|
|
|
} |
|
|
|
|
|
|
|
void processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) |
|
|
|
{ |
|
|
|
for (uint32_t i=0; i < kData->audioIn.count; i++) |
|
|
|
carla_copyFloat(fAudioInBuffers[i], inBuffer[i]+timeOffset, frames); |
|
|
|
for (uint32_t i=0; i < kData->audioOut.count; i++) |
|
|
|
carla_zeroFloat(fAudioOutBuffers[i], frames); |
|
|
|
|
|
|
|
fDescriptor->run(fHandle, frames); |
|
|
|
|
|
|
|
if (fHandle2 != nullptr) |
|
|
|
fDescriptor->run(fHandle2, frames); |
|
|
|
|
|
|
|
for (uint32_t i=0, k; i < kData->audioOut.count; i++) |
|
|
|
{ |
|
|
|
for (k=0; k < frames; k++) |
|
|
|
outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k]; |
|
|
|
} |
|
|
|
kData->mutex.unlock(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
void bufferSizeChanged(const uint32_t newBufferSize) |
|
|
|