Skip to content

Commit 6605ead

Browse files
committed
sampler again try remove click
1 parent 4188d70 commit 6605ead

2 files changed

Lines changed: 84 additions & 87 deletions

File tree

‎Source/Node/nodes/sampler/SamplerNode.cpp‎

Lines changed: 82 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,9 @@ void SamplerNode::handleNoteOn(MidiKeyboardState* source, int midiChannel, int m
510510
if (hm == HIT_RESET)
511511
{
512512
sn->jumpGhostSample = sn->playingSample;
513-
sn->jumpGhostGain = sn->adsr.getOutput();
513+
sn->jumpGhostGain = sn->adsr.getOutput() * sn->velocity;
514+
sn->jumpGhostFadeTotal = jmax(1, (int)(AudioManager::getInstance()->currentSampleRate * 0.02f));
515+
sn->jumpGhostFadeRemaining = sn->jumpGhostFadeTotal;
514516
sn->adsr.reset();
515517
sn->playingSample = 0;
516518
sn->rtPitchReadSample = 0;
@@ -521,7 +523,7 @@ void SamplerNode::handleNoteOn(MidiKeyboardState* source, int midiChannel, int m
521523
double shift = MidiMessage::getMidiNoteInHertz(midiNoteNumber) / MidiMessage::getMidiNoteInHertz(closestNote);
522524
samplerNotes[midiNoteNumber]->setAutoKey(samplerNotes[closestNote], shift);
523525

524-
sn->jumpGhostGain = sn->adsr.getOutput();
526+
sn->jumpGhostGain = sn->adsr.getOutput() * sn->velocity;
525527
sn->adsr.reset();
526528
sn->velocity = velocity;
527529
sn->adsr.gate(1);
@@ -548,7 +550,9 @@ void SamplerNode::handleNoteOn(MidiKeyboardState* source, int midiChannel, int m
548550
if (hm == HIT_RESET)
549551
{
550552
sn->jumpGhostSample = sn->playingSample;
551-
sn->jumpGhostGain = sn->adsr.getOutput();
553+
sn->jumpGhostGain = sn->adsr.getOutput() * sn->velocity;
554+
sn->jumpGhostFadeTotal = jmax(1, (int)(AudioManager::getInstance()->currentSampleRate * 0.02f));
555+
sn->jumpGhostFadeRemaining = sn->jumpGhostFadeTotal;
552556
sn->adsr.reset();
553557
sn->playingSample = 0;
554558
}
@@ -560,7 +564,9 @@ void SamplerNode::handleNoteOn(MidiKeyboardState* source, int midiChannel, int m
560564
if (sn->adsr.getState() != CurvedADSR::env_idle)
561565
{
562566
sn->jumpGhostSample = sn->playingSample;
563-
sn->jumpGhostGain = sn->adsr.getOutput();
567+
sn->jumpGhostGain = sn->adsr.getOutput() * sn->velocity;
568+
sn->jumpGhostFadeTotal = jmax(1, (int)(AudioManager::getInstance()->currentSampleRate * 0.02f));
569+
sn->jumpGhostFadeRemaining = sn->jumpGhostFadeTotal;
564570
}
565571
sn->adsr.reset();
566572
sn->playingSample = 0;
@@ -868,20 +874,13 @@ void SamplerNode::processBlockInternal(AudioBuffer<float>& buffer, MidiBuffer& m
868874
}
869875

870876

871-
if (pm == HIT_ONESHOT && s->oneShotted)
872-
{
873-
s->adsr.applyEnvelopeToBuffer(tmpNoteBuffer, 0, blockSize);
874-
continue;
875-
}
876-
877877
if (pm != HIT_ONESHOT || !s->oneShotted)
878878
{
879879
AudioSampleBuffer* targetBuffer = &s->buffer;
880880
int targetReadSample = s->playingSample;
881881

882882
if (s->isProxyNote())
883883
{
884-
885884
AudioBuffer<float> tmpBuffer(s->autoKeyFromNote->buffer.getNumChannels(), blockSize);
886885
auto readPointers = tmpBuffer.getArrayOfReadPointers();
887886

@@ -905,7 +904,6 @@ void SamplerNode::processBlockInternal(AudioBuffer<float>& buffer, MidiBuffer& m
905904
if (pm == HIT_ONESHOT && s->playingSample + blockSize >= sourceNumSamples)
906905
{
907906
s->oneShotted = true;
908-
s->jumpGhostSample = -1;
909907
s->playingSample = 0;
910908
s->state->setValueWithData(s->hasContent() ? NoteState::FILLED : NoteState::EMPTY);
911909
break;
@@ -918,106 +916,101 @@ void SamplerNode::processBlockInternal(AudioBuffer<float>& buffer, MidiBuffer& m
918916
targetReadSample = 0;
919917
}
920918

921-
if (s->jumpGhostSample != -1 && s->jumpGhostSample != s->playingSample && s->jumpGhostSample < s->buffer.getNumSamples())
919+
// --- 1. NORMAL PROCESSING ---
920+
if (pm == HIT_ONESHOT && s->oneShotted)
921+
{
922+
// Process release tail silently so the ADSR finishes correctly
923+
tmpNoteBuffer.clear();
924+
s->adsr.applyEnvelopeToBuffer(tmpNoteBuffer, 0, blockSize);
925+
}
926+
else
922927
{
923928
const int bufNumSamples = targetBuffer->getNumSamples();
924-
const int ghostFirstPart = jmax(0, jmin(blockSize, bufNumSamples - s->jumpGhostSample));
925-
const int playFirstPart = jmax(0, jmin(blockSize, bufNumSamples - s->playingSample));
926-
927-
float ghostGainStart = s->jumpGhostGain;
928-
929+
const int firstPart = jmax(0, jmin(blockSize, bufNumSamples - targetReadSample));
930+
const int secondPart = blockSize - firstPart;
931+
929932
for (int j = 0; j < buffer.getNumChannels(); j++)
930933
{
931934
tmpNoteBuffer.clear(j, 0, blockSize);
932935

933-
if (playFirstPart > 0)
934-
{
935-
tmpNoteBuffer.copyFromWithRamp(j, 0, targetBuffer->getReadPointer(j, s->playingSample), playFirstPart, 0, (float)playFirstPart / blockSize);
936-
}
937-
938-
if (playFirstPart < blockSize)
936+
if (pm == HIT_ONESHOT || s->isProxyNote())
939937
{
940-
const int playSecondPart = blockSize - playFirstPart;
941-
if (pm != HIT_ONESHOT && !s->isProxyNote())
938+
if (firstPart > 0)
939+
tmpNoteBuffer.copyFrom(j, 0, *targetBuffer, j, targetReadSample, firstPart);
940+
941+
if (secondPart > 0 && firstPart > 0)
942942
{
943-
tmpNoteBuffer.addFromWithRamp(j, playFirstPart, targetBuffer->getReadPointer(j, 0), playSecondPart, (float)playFirstPart / blockSize, 1);
943+
const int fadeLen = jmin(64, firstPart);
944+
tmpNoteBuffer.applyGainRamp(j, firstPart - fadeLen, fadeLen, 1.0f, 0.0f);
944945
}
945946
}
947+
else
948+
{
949+
if (firstPart > 0)
950+
tmpNoteBuffer.copyFrom(j, 0, *targetBuffer, j, targetReadSample, firstPart);
951+
952+
if (secondPart > 0)
953+
tmpNoteBuffer.copyFrom(j, firstPart, *targetBuffer, j, 0, secondPart);
954+
}
946955
}
947-
948-
s->adsr.applyEnvelopeToBuffer(tmpNoteBuffer, 0, blockSize);
949956

957+
s->adsr.applyEnvelopeToBuffer(tmpNoteBuffer, 0, blockSize);
950958
for (int j = 0; j < buffer.getNumChannels(); j++)
951959
{
952-
if (ghostFirstPart > 0)
960+
buffer.addFromWithRamp(j, 0, tmpNoteBuffer.getReadPointer(j), blockSize, s->prevVelocity, s->velocity);
961+
}
962+
963+
s->prevVelocity = s->velocity;
964+
s->playingSample += blockSize;
965+
966+
int numSamplesToCheck = s->isProxyNote() ? s->autoKeyFromNote->buffer.getNumSamples()
967+
: targetBuffer->getNumSamples();
968+
969+
if (s->playingSample >= numSamplesToCheck)
970+
{
971+
if (pm == HIT_ONESHOT || s->isProxyNote())
972+
{
973+
s->oneShotted = true;
974+
s->adsr.gate(0);
975+
s->playingSample = 0;
976+
}
977+
else
953978
{
954-
tmpNoteBuffer.addFromWithRamp(j, 0, targetBuffer->getReadPointer(j, s->jumpGhostSample), ghostFirstPart, ghostGainStart, ghostGainStart * (1.0f - ((float)ghostFirstPart / blockSize)));
979+
s->playingSample %= numSamplesToCheck;
955980
}
956981
}
957-
958-
s->jumpGhostSample = -1;
959-
}
960-
else
961-
{
962-
const int bufNumSamples = targetBuffer->getNumSamples();
963-
const int firstPart = jmax(0, jmin(blockSize, bufNumSamples - targetReadSample));
964-
const int secondPart = blockSize - firstPart;
965-
966-
967-
for (int j = 0; j < buffer.getNumChannels(); j++)
968-
{
969-
tmpNoteBuffer.clear(j, 0, blockSize);
970-
971-
972-
if (pm == HIT_ONESHOT || s->isProxyNote())
973-
{
974-
if (firstPart > 0)
975-
tmpNoteBuffer.copyFrom(j, 0, *targetBuffer, j, targetReadSample, firstPart);
976-
977-
978-
if (secondPart > 0 && firstPart > 0)
979-
{
980-
const int fadeLen = jmin(64, firstPart);
981-
tmpNoteBuffer.applyGainRamp(j, firstPart - fadeLen, fadeLen, 1.0f, 0.0f);
982-
}
983-
}
984-
else
985-
{
986-
if (firstPart > 0)
987-
tmpNoteBuffer.copyFrom(j, 0, *targetBuffer, j, targetReadSample, firstPart);
988-
989-
990-
if (secondPart > 0)
991-
tmpNoteBuffer.copyFrom(j, firstPart, *targetBuffer, j, 0, secondPart);
992-
}
993-
}
994982
}
995983

996-
s->adsr.applyEnvelopeToBuffer(tmpNoteBuffer, 0, blockSize);
997-
for (int j = 0; j < buffer.getNumChannels(); j++)
984+
// --- 2. INDEPENDENT GHOST FADE LOGIC ---
985+
// Process the fading tail directly into the main buffer (bypassing the new velocity ramp)
986+
if (!s->isProxyNote() && s->jumpGhostSample != -1 && s->jumpGhostFadeRemaining > 0)
998987
{
999-
buffer.addFromWithRamp(j, 0, tmpNoteBuffer.getReadPointer(j), blockSize, s->prevVelocity, s->velocity);
1000-
}
988+
const int bufNumSamples = s->buffer.getNumSamples();
989+
const int ghostFirstPart = jmax(0, jmin(blockSize, bufNumSamples - s->jumpGhostSample));
990+
int processSamples = jmin(ghostFirstPart, s->jumpGhostFadeRemaining);
1001991

1002-
s->prevVelocity = s->velocity;
992+
if (processSamples > 0)
993+
{
994+
float gainStart = s->jumpGhostGain * ((float)s->jumpGhostFadeRemaining / s->jumpGhostFadeTotal);
995+
float gainEnd = s->jumpGhostGain * ((float)(s->jumpGhostFadeRemaining - processSamples) / s->jumpGhostFadeTotal);
1003996

1004-
s->playingSample += blockSize;
997+
// Prevent click if the sample intrinsically ends before the 20ms fade finishes
998+
if (s->jumpGhostSample + processSamples >= bufNumSamples)
999+
gainEnd = 0.0f;
10051000

1006-
int numSamplesToCheck = s->isProxyNote() ? s->autoKeyFromNote->buffer.getNumSamples()
1007-
: targetBuffer->getNumSamples();
1008-
1009-
if (s->playingSample >= numSamplesToCheck)
1010-
{
1011-
if (pm == HIT_ONESHOT || s->isProxyNote())
1012-
{
1013-
s->oneShotted = true;
1014-
s->jumpGhostSample = -1;
1015-
s->adsr.gate(0);
1016-
s->playingSample = 0;
1001+
for (int j = 0; j < buffer.getNumChannels(); j++)
1002+
{
1003+
buffer.addFromWithRamp(j, 0, s->buffer.getReadPointer(j, s->jumpGhostSample), processSamples, gainStart, gainEnd);
1004+
}
1005+
1006+
s->jumpGhostSample += processSamples;
1007+
s->jumpGhostFadeRemaining -= processSamples;
10171008
}
1018-
else
1009+
1010+
// Clean up ghost when fade completes or sample ends
1011+
if (s->jumpGhostFadeRemaining <= 0 || s->jumpGhostSample >= bufNumSamples)
10191012
{
1020-
s->playingSample %= numSamplesToCheck;
1013+
s->jumpGhostSample = -1;
10211014
}
10221015
}
10231016
}
@@ -1241,6 +1234,8 @@ void SamplerNode::SamplerNote::reset()
12411234
setAutoKey(nullptr);
12421235
jumpGhostSample = -1;
12431236
jumpGhostGain = 0.0f;
1237+
jumpGhostFadeTotal = 0;
1238+
jumpGhostFadeRemaining = 0;
12441239
playingSample = 0;
12451240
oneShotted = false;
12461241
state->setValueWithData(hasContent() ? NoteState::FILLED : NoteState::EMPTY);

‎Source/Node/nodes/sampler/SamplerNode.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class SamplerNode :
115115
int playingSample = 0;
116116
int jumpGhostSample = -1;
117117
float jumpGhostGain = 0.0f;
118+
int jumpGhostFadeTotal = 0; // ADD THIS
119+
int jumpGhostFadeRemaining = 0; // ADD THIS
118120
float prevVelocity = 0;
119121
float velocity = 0;
120122
CurvedADSR adsr;

0 commit comments

Comments
 (0)