fixing width
This commit is contained in:
parent
787f084b74
commit
ed79c8e3b9
1 changed files with 25 additions and 27 deletions
52
src/Gate.cpp
52
src/Gate.cpp
|
|
@ -294,59 +294,58 @@ void Gate::update() {
|
||||||
// 1. EXIT EARLY IF OFF
|
// 1. EXIT EARLY IF OFF
|
||||||
if (!state && !sticky) {
|
if (!state && !sticky) {
|
||||||
lastOutVal = 0.0f;
|
lastOutVal = 0.0f;
|
||||||
// Make sure we actually write 0 if we aren't sticky
|
|
||||||
writeAnalog(0);
|
writeAnalog(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. LIVE WIDTH MODULATION
|
// 2. LIVE WIDTH MODULATION
|
||||||
// We calculate the 'stopTick' every frame.
|
|
||||||
// IMPORTANT: Cap at 98% to ensure the gate has a "low" period before next beat.
|
|
||||||
float effectiveWidth = (float)width + (widthMod * 100.0f);
|
float effectiveWidth = (float)width + (widthMod * 100.0f);
|
||||||
if (effectiveWidth > 98.0f) effectiveWidth = 98.0f;
|
if (effectiveWidth > 100.0f) effectiveWidth = 100.0f;
|
||||||
if (effectiveWidth < 1.0f) effectiveWidth = 1.0f;
|
if (effectiveWidth < 0.0f) effectiveWidth = 0.0f;
|
||||||
|
|
||||||
uint32_t modulatedTicks = (uint32_t)((float)this->tickInterval * (effectiveWidth / 100.0f));
|
uint32_t modulatedTicks = (uint32_t)((float)this->tickInterval * (effectiveWidth / 100.0f));
|
||||||
if (modulatedTicks < 1) modulatedTicks = 1;
|
|
||||||
|
|
||||||
// This is our "Target" end point
|
|
||||||
this->stopTick = startTick + modulatedTicks;
|
this->stopTick = startTick + modulatedTicks;
|
||||||
|
|
||||||
// 3. THE HARD SYNC (THE FIX)
|
// 3. THE HARD SYNC
|
||||||
// If the Master Tick reached stopTick, kill the gate.
|
// Only kill the gate if width is strictly less than 100%
|
||||||
if (MASTER_TICK >= stopTick) {
|
if (effectiveWidth < 100.0f) {
|
||||||
state = 0;
|
if (MASTER_TICK >= stopTick) {
|
||||||
// Don't reset lastTriggerTick here, otherwise turnOn() might re-fire
|
state = 0;
|
||||||
// on the same tick that we just finished.
|
if (!sticky) {
|
||||||
if (!sticky) {
|
lastOutVal = 0.0f;
|
||||||
lastOutVal = 0.0f;
|
writeAnalog(0);
|
||||||
writeAnalog(0);
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. HYBRID SMOOTHNESS MATH
|
// 4. HYBRID SMOOTHNESS MATH
|
||||||
uint64_t now = time_us_64();
|
uint64_t now = time_us_64();
|
||||||
// Ensure we don't underflow if now < last_clk_us (jitter)
|
|
||||||
uint64_t usSinceLastTick = (now > last_clk_us) ? (now - last_clk_us) : 0;
|
uint64_t usSinceLastTick = (now > last_clk_us) ? (now - last_clk_us) : 0;
|
||||||
|
|
||||||
double current_BPM_for_math = (double)filteredBPM;
|
double current_BPM_for_math = (double)filteredBPM;
|
||||||
if (current_BPM_for_math < 1.0) current_BPM_for_math = 1.0;
|
if (current_BPM_for_math < 1.0) current_BPM_for_math = 1.0;
|
||||||
|
|
||||||
double us_per_tick = 60000000.0 / (current_BPM_for_math * (double)PPQN);
|
double us_per_tick = 60000000.0 / (current_BPM_for_math * (double)PPQN);
|
||||||
|
|
||||||
float subTick = (float)usSinceLastTick / (float)us_per_tick;
|
float subTick = (float)usSinceLastTick / (float)us_per_tick;
|
||||||
if (subTick > 0.98f) subTick = 0.98f;
|
if (subTick > 0.99f) subTick = 0.99f;
|
||||||
|
|
||||||
// Calculate phase (0.0 to 1.0)
|
// --- THE SINE WAVE FIX ---
|
||||||
|
// If width is 100%, we calculate phase based on the WHOLE interval.
|
||||||
|
// If width < 100%, we calculate phase based on the PULSE duration.
|
||||||
float elapsedTicks = (float)(MASTER_TICK - startTick) + subTick;
|
float elapsedTicks = (float)(MASTER_TICK - startTick) + subTick;
|
||||||
float totalDurationTicks = (float)(stopTick - startTick);
|
float totalDurationTicks = (effectiveWidth >= 100.0f) ? (float)tickInterval : (float)(stopTick - startTick);
|
||||||
|
|
||||||
// Safety check for division by zero
|
|
||||||
if (totalDurationTicks < 1.0f) totalDurationTicks = 1.0f;
|
if (totalDurationTicks < 1.0f) totalDurationTicks = 1.0f;
|
||||||
|
|
||||||
float phase = elapsedTicks / totalDurationTicks;
|
float phase = elapsedTicks / totalDurationTicks;
|
||||||
if (phase > 1.0f) phase = 1.0f;
|
|
||||||
|
// Keep phase looping if we are at 100% width (so LFOs/Sines keep moving)
|
||||||
|
if (effectiveWidth >= 100.0f) {
|
||||||
|
while (phase >= 1.0f) phase -= 1.0f;
|
||||||
|
} else {
|
||||||
|
if (phase > 1.0f) phase = 1.0f;
|
||||||
|
}
|
||||||
if (phase < 0.0f) phase = 0.0f;
|
if (phase < 0.0f) phase = 0.0f;
|
||||||
|
|
||||||
// 5. WAVEFORM GENERATION
|
// 5. WAVEFORM GENERATION
|
||||||
|
|
@ -360,7 +359,7 @@ void Gate::update() {
|
||||||
case EXP: outVal = expf(-5.0f * phase); break;
|
case EXP: outVal = expf(-5.0f * phase); break;
|
||||||
case REXP: outVal = expf(5.0f * (phase - 1.0f)); break;
|
case REXP: outVal = expf(5.0f * (phase - 1.0f)); break;
|
||||||
case LOG: outVal = 1.0f - expf(-5.0f * phase); break;
|
case LOG: outVal = 1.0f - expf(-5.0f * phase); break;
|
||||||
case SQUARE: outVal = 1.0f; break; // Square is simple ON
|
case SQUARE: outVal = 1.0f; break;
|
||||||
case BOUNCE: outVal = fabsf(sinf(phase * 3.14159265f * 2.0f)); break;
|
case BOUNCE: outVal = fabsf(sinf(phase * 3.14159265f * 2.0f)); break;
|
||||||
case SIGMO: outVal = phase * phase * (3.0f - 2.0f * phase); break;
|
case SIGMO: outVal = phase * phase * (3.0f - 2.0f * phase); break;
|
||||||
case WOBBLE: outVal = expf(-3.0f * phase) * cosf(phase * 3.14159265f * 4.0f);
|
case WOBBLE: outVal = expf(-3.0f * phase) * cosf(phase * 3.14159265f * 4.0f);
|
||||||
|
|
@ -378,7 +377,6 @@ void Gate::update() {
|
||||||
if (finalLevel > 1.0f) finalLevel = 1.0f;
|
if (finalLevel > 1.0f) finalLevel = 1.0f;
|
||||||
if (finalLevel < 0.0f) finalLevel = 0.0f;
|
if (finalLevel < 0.0f) finalLevel = 0.0f;
|
||||||
|
|
||||||
// Use (uint16_t) cast to ensure the PWM driver gets a clean integer
|
|
||||||
writeAnalog((uint16_t)(outVal * 1023.0f * finalLevel));
|
writeAnalog((uint16_t)(outVal * 1023.0f * finalLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue