Found some other clicks
There are no real crossfades when using undo, redo, undo all, and redo all. Only fade-ins of the new loop. Depending on what you're playing this causes heavy clicks.. Here's a solution for real crossfades (fade out of the old loop while fading in the new one):
Added some new states for the sampler:
Code: Select all
/* States of the sampler */
#define STATE_OFF 0
#define STATE_TRIG_START 1
#define STATE_RECORD 2
#define STATE_TRIG_STOP 3
#define STATE_PLAY 4
#define STATE_OVERDUB 5
#define STATE_MULTIPLY 6
#define STATE_INSERT 7
#define STATE_REPLACE 8
#define STATE_DELAY 9
#define STATE_MUTE 10
#define STATE_SCRATCH 11
#define STATE_ONESHOT 12
#define STATE_SUBSTITUTE 13
#define STATE_PAUSED 14
#define STATE_UNDO_ALL 15//Uebe new
#define STATE_TRIGGER_PLAY 16
#define STATE_UNDO 17//Uebe new
#define STATE_REDO 18//Uebe new
#define STATE_REDO_ALL 19//Uebe new
All following changes are in the function runSooperLooper in plugin.cc
Some new variables and pointers...
Code: Select all
unsigned int xCurrPos = 0;
unsigned int lpCurrPos = 0;
LADSPA_Data *pLoopSample, *spLoopSample, *rLoopSample, *rpLoopSample, *xLoopSample;
LoopChunk *lastloop, *prevloop, *nextloop;
More ore less rewriten part in switch(lMultiCtrl)
Code: Select all
case MULTI_UNDO:
case MULTI_UNDO_TWICE:
{
switch(pLS->state) {
case STATE_PLAY:
case STATE_RECORD:
case STATE_OVERDUB:
case STATE_MULTIPLY:
case STATE_INSERT:
case STATE_TRIG_START:
case STATE_TRIG_STOP:
case STATE_REPLACE:
case STATE_SUBSTITUTE:
case STATE_DELAY:
case STATE_MUTE:
case STATE_PAUSED:
// cancel whatever mode, back to play mode (or mute)
pLS->state = pLS->wasMuted ? STATE_MUTE : STATE_PLAY;
if (pLS->waitingForSync) {
// don't undo loop
// just return to play (or mute)
pLS->waitingForSync = 0;
pLS->nextState = -1;
}
else if (pLS->fNextCurrRate != 0.0f) {
// undo pending reverse
pLS->fNextCurrRate = 0.0f;
}
if (pLS->state == STATE_MUTE) {
// undo ONE)
undoLoop(pLS, false);;
} else {
if (loop->prev) {
pLS->state = STATE_UNDO;
pLS->nextState = STATE_PLAY;
} else {
pLS->state = STATE_UNDO_ALL;
}
}
pLS->fLoopFadeDelta = -1.0f / xfadeSamples;
pLS->fFeedFadeDelta = 1.0f / xfadeSamples;
pLS->fPlayFadeAtten = 0.0f;
pLS->fPlayFadeDelta = 1.0f / xfadeSamples;
if (pLS->state == STATE_MUTE) {
pLS->fPlayFadeDelta = 0.0f;
} else if (pLS->state == STATE_UNDO_ALL) {
pLS->fPlayFadeAtten = 1.0f;
pLS->fPlayFadeDelta = -1.0f / xfadeSamples;
}
DBG(fprintf(stderr,"%u:%u Undoing and reentering PLAY state from UNDO\n", pLS->lLoopIndex, pLS->lChannelIndex));
break;
}
} break;
case MULTI_UNDO_ALL:
{
if (pLS->state != STATE_OFF) {
DBG(fprintf(stderr,"%u:%u UNDO all loops\n", pLS->lLoopIndex, pLS->lChannelIndex));
pLS->fPlayFadeDelta = -1.0f / xfadeSamples;
pLS->fLoopFadeDelta = -1.0f / xfadeSamples;
pLS->fFeedFadeDelta = 1.0f / xfadeSamples;
pLS->state = pLS->wasMuted ? STATE_MUTE : STATE_PLAY;
if (loop && loop->lLoopLength) {
pLS->state = STATE_UNDO_ALL;
pLS->fLoopFadeDelta = -1.0f / (xfadeSamples);
pLS->fPlayFadeDelta = -1.0f / xfadeSamples;// fade out for undo all
pLS->wasMuted = true;
}
}
} break;
case MULTI_REDO_ALL:
{
if (pLS->state == STATE_OFF) {
pLS->state = STATE_PLAY;
pLS->wasMuted = false;
} else {
pLS->state = pLS->wasMuted ? STATE_MUTE : STATE_PLAY;
}
if (!loop || pLS->state == STATE_MUTE) {
// redo ALL)
lastloop = pLS->headLoopChunk;
redoLoop(pLS);
while (pLS->headLoopChunk != lastloop) {
lastloop = pLS->headLoopChunk;
redoLoop(pLS);
}
if (!pLS->headLoopChunk) {
pLS->state = STATE_OFF;
}
} else {
if (loop->next) {
pLS->state = STATE_REDO_ALL;
pLS->nextState = STATE_PLAY;
}
}
pLS->fLoopFadeDelta = -1.0f / xfadeSamples;
pLS->fFeedFadeDelta = 1.0f / xfadeSamples;
pLS->fPlayFadeAtten = 0.0f;
pLS->fPlayFadeDelta = 1.0f / xfadeSamples;
if (pLS->state == STATE_MUTE) {
pLS->fPlayFadeDelta = 0.0f;
}
DBG(fprintf(stderr,"REDO all loops\n"));
} break;
case MULTI_REDO:
{
switch (pLS->state) {
case STATE_PLAY:
case STATE_RECORD:
case STATE_TRIG_START:
case STATE_TRIG_STOP:
case STATE_OVERDUB:
case STATE_MULTIPLY:
case STATE_INSERT:
case STATE_REPLACE:
case STATE_SUBSTITUTE:
case STATE_MUTE:
case STATE_PAUSED:
case STATE_OFF:
if (pLS->state == STATE_OFF) {
pLS->state = STATE_PLAY;
pLS->wasMuted = false;
} else {
pLS->state = pLS->wasMuted ? STATE_MUTE : STATE_PLAY;
}
if (!loop || pLS->state == STATE_MUTE) {
// we don't need a fadeout
redoLoop(pLS);
if (!pLS->headLoopChunk) {
pLS->state = STATE_OFF;
}
} else {
// we need a x-fade
if (loop->next) {
pLS->state = STATE_REDO;
pLS->nextState = STATE_PLAY;
pLS->fPlayFadeAtten = 0.0f;
}
}
pLS->fLoopFadeDelta = -1.0f / xfadeSamples;
pLS->fFeedFadeDelta = 1.0f / xfadeSamples;
if (pLS->state == STATE_MUTE) {
// we don't need a fade in
pLS->fPlayFadeDelta = 0.0f;
} else {
pLS->fPlayFadeDelta = 1.0f / xfadeSamples;
}
break;
}
} break;
Added the new states to the STATE_PLAY in switch(pLS->state)
Code: Select all
case STATE_UNDO_ALL:
case STATE_REDO_ALL:
case STATE_UNDO:
case STATE_REDO:
case STATE_PLAY:
case STATE_ONESHOT:
case STATE_SCRATCH:
case STATE_MUTE:
case STATE_PAUSED:
{
//fprintf(stderr,"in play begin\n");
// play the input out mixed with the recorded loop.
Changes in the for loop (;lSampleIndex < SampleCount;
lSampleIndex++)
Code: Select all
lCurrPos =(unsigned int) fmod(loop->dCurrPos, loop->lLoopLength);
//fprintf(stderr, "curr = %u\n", lCurrPos);
pLoopSample = & pLS->pSampleBuf[(loop->lLoopStart + lCurrPos) & pLS->lBufferSizeMask];
if (pLS->state == STATE_UNDO){
prevloop = pLS->headLoopChunk->prev;
xCurrPos = (unsigned int) fmod(loop->dCurrPos, prevloop->lLoopLength);
xLoopSample = & pLS->pSampleBuf[(prevloop->lLoopStart + xCurrPos) & pLS->lBufferSizeMask];
}
if (pLS->state == STATE_REDO) {
nextloop = pLS->headLoopChunk->next;
xCurrPos = (unsigned int) fmod(loop->dCurrPos, nextloop->lLoopLength);
xLoopSample = & pLS->pSampleBuf[(nextloop->lLoopStart + xCurrPos) & pLS->lBufferSizeMask];
}
if (pLS->state == STATE_REDO_ALL) {
nextloop = pLS->headLoopChunk;
while (nextloop->next) {
nextloop = nextloop->next;
}
xCurrPos = (unsigned int) fmod(loop->dCurrPos, nextloop->lLoopLength);
xLoopSample = & pLS->pSampleBuf[(nextloop->lLoopStart + xCurrPos) & pLS->lBufferSizeMask];
}
rCurrPos = fmod (loop->dCurrPos - (fRate * (lOutputLatency + lInputLatency)), loop->lLoopLength);
if (rCurrPos < 0) {
rCurrPos += loop->lLoopLength;
}
Code: Select all
fOutputSample = tmpWet * (*pLoopSample)
+ fDry * fInputSample;
if (pLS->state == STATE_UNDO || pLS->state == STATE_REDO || pLS->state == STATE_REDO_ALL) {
//fprintf(stderr, "fading.. :%g\n", tmpWet);
fOutputSample = tmpWet * (*xLoopSample)
+ fDry * fInputSample + (fWet-tmpWet) * (*pLoopSample);
}
// jlc play
and after the for loop
Code: Select all
if (pLS->state == STATE_UNDO && pLS->fPlayFadeAtten == 1.0f) {
// play some of the old loop first and switch later
undoLoop(pLS, false);
fprintf(stderr, "finished UNDO...\n");
pLS->state = pLS->nextState;
}
if (pLS->state == STATE_REDO && pLS->fPlayFadeAtten == 1.0f) {
// play some of the old loop first and switch later
redoLoop(pLS);
fprintf(stderr, "finished REDO...\n");
pLS->state = pLS->nextState;
}
if (pLS->state == STATE_UNDO_ALL && pLS->fPlayFadeAtten == 0.0f) {
// fade out the old loop and goto sate_off
clearLoopChunks(pLS);
fprintf(stderr, "finished UNDO ALL...\n");
pLS->state = STATE_OFF;
}
if (pLS->state == STATE_REDO_ALL && pLS->fPlayFadeAtten == 1.0f) {
// play some of the old loop first and switch later
lastloop = pLS->headLoopChunk;
redoLoop(pLS);
while (pLS->headLoopChunk != lastloop) {
lastloop = pLS->headLoopChunk;
redoLoop(pLS);
}
fprintf(stderr, "finished REDO ALL...\n");
pLS->state = pLS->nextState;
}
// recenter around the mod
if (loop) {
lCurrPos = (unsigned int) fabs(fmod(loop->dCurrPos, loop->lLoopLength));
if (recenter) {
loop->dCurrPos = lCurrPos + modf(loop->dCurrPos, &dDummy);
}
}
Hope you can check this and merge it into the dev repo.
Greetings, Uebe