Free Reverse Delay built in RNBO
-
Thank you so much mate.. A very nice Christmas Gift @HISEnberg
-
@HISEnberg Thank you))))))))
🤩
-
@HISEnberg
I just started a reverse delay idea myself. Since the post was looking for both RNBO and FAUST solutions, here is my implementation:import("stdfaust.lib"); MAX_DELAY = 192000; // Support up to 192kHz // Create phase-shifted phasor for reverse reading only the delayed signal phasor_phase(dtime, phase) = ((os.lf_rawsaw(dtime) + phase) % dtime) : int; phasor(dtime, phase) = phasor_phase(dtime*2, phase) <: <=(dtime), (*(-1) + dtime*2), _ : select2; // Main processing process = _ <: direct, delayed_and_reversed :> _ with { // Get current sample rate for scaling current_sr = ma.SR; // Controls - scale the delay time based on current sample rate delay_base = hslider("Delay Time[style:knob]", 0.5, 0.02, 1, 0.01); // 0-1 range delay_time = min(MAX_DELAY-1, delay_base * current_sr); // Scale to current sample rate dry_wet = hslider("Dry/Wet[style:knob]", 0.5, 0, 1, 0.01); // Direct path direct = *(1-dry_wet); // First delay the signal delayed = de.delay(MAX_DELAY, delay_time); // Then reverse the delayed signal reversed = rwtable(MAX_DELAY, 0.0, phasor(delay_time, 0) : int, // Write the delayed signal _, // Input from delay phasor(delay_time, delay_time/2) : int // Read reversed ); delayed_and_reversed = delayed : reversed : *(dry_wet); };
-
@Mighty23 you dont appear o be using cuurrent_sr anywhere..
-
@Lindon I edited the code in the previous comment.
The key is to make the delay time scale with the sample rate. -
@Mighty23 thank you! what's the process to get 2 channels tried to copy paste the process but it still says only 1 Channel
-
@treynterrio you can use this code if you have 2 inputs and 2 outputs or use the previous one if you have one input and one output.
The first code you can use in scriptnode in case you need to process, for example, mid and side separately.
import("stdfaust.lib"); MAX_DELAY = 192000; // Phase-shifted phasor for reverse reading // dtime: delay time in samples // phase: phase offset for reading position phasor_phase(dtime, phase) = ((os.lf_rawsaw(dtime) + phase) % dtime) : int; phasor(dtime, phase) = phasor_phase(dtime*2, phase) <: <=(dtime), (*(-1) + dtime*2), _ : select2; // Single channel reverse delay processing reverse_delay = _ <: direct, delayed_and_reversed :> _ with { // Get current sample rate for scaling controls current_sr = ma.SR; // User controls with sample rate scaling delay_base = hslider("Delay Time[style:knob]", 0.5, 0.02, 1, 0.01); delay_time = min(MAX_DELAY-1, delay_base * current_sr); dry_wet = hslider("Dry/Wet[style:knob]", 0.5, 0, 1, 0.01); // Direct path with gain direct = *(1-dry_wet); // Delay into reverse buffer implementation delayed = de.delay(MAX_DELAY, delay_time); // Reverse buffer using rwtable reversed = rwtable(MAX_DELAY, 0.0, phasor(delay_time, 0) : int, // Write index _, // Input signal phasor(delay_time, delay_time/2) : int // Read index ); // Process delayed signal through reverse buffer with gain delayed_and_reversed = delayed : reversed : *(dry_wet); }; // Main stereo processing - apply reverse_delay to each channel independently process = reverse_delay, reverse_delay;
-
@Mighty23 It works great, thanks!
The delay value is in 0 - 1 range. What is it referring to?
So what about time-based reverse? Like milliseconds, or 1/4, 1/8, 1/16? -
@JulesV
the delay value (0-1 range) refers to delay time as a fraction of one second.-
delay_base
ranges from 0.02 to 1.0 -
This gets multiplied by current_sr (sample rate), so:
at 44.1kHz: 0.5 = 22.050 samples = 500ms, 1.0 = 44.100 samples = 1 second
To do this in milliseconds, I can modify the implementation (I just need to remember). If I don't remember or am unmotivated to do it, feel free to message me and send a reminder :).
To switch from ms to tempo sync, there's a node for this:
https://docs.hise.dev/scriptnode/list/control/tempo_sync.html -
-
import("stdfaust.lib"); MAX_DELAY = 192000; // Phase-shifted phasor for reverse reading // dtime: delay time in samples // phase: phase offset for reading position phasor_phase(dtime, phase) = ((os.lf_rawsaw(dtime) + phase) % dtime) : int; phasor(dtime, phase) = phasor_phase(dtime*2, phase) <: <=(dtime), (*(-1) + dtime*2), _ : select2; // Single channel reverse delay processing reverse_delay = _ <: direct, delayed_and_reversed :> _ with { // Get current sample rate for scaling controls current_sr = ma.SR; // User controls in milliseconds delay_ms = hslider("Delay Time (ms)[style:knob]", 500, 20, 1000, 1); delay_time_raw = min(MAX_DELAY-1, delay_ms * current_sr / 1000); delay_time = si.smooth(ba.tau2pole(0.05), delay_time_raw); dry_wet = hslider("Dry/Wet[style:knob]", 0.5, 0, 1, 0.01); // Direct path with gain direct = *(1-dry_wet); // Delay into reverse buffer implementation delayed = de.delay(MAX_DELAY, delay_time); // Reverse buffer with windowing to reduce clicks // Use a single buffer with smoothed reading write_idx = phasor(delay_time, 0) : int; read_idx = phasor(delay_time, delay_time/2) : int; // Apply Hann window to reduce discontinuities window_pos = (phasor(delay_time, delay_time/2) / delay_time); hann_window = 0.5 * (1.0 - cos(2.0 * ma.PI * window_pos)); reversed = _ <: rwtable(MAX_DELAY, 0.0, write_idx, _, read_idx) * hann_window; // Process delayed signal through reverse buffer with filtering and gain // Add gentle low-pass filter to reduce aliasing artifacts delayed_and_reversed = delayed : reversed : fi.lowpass(2, current_sr * 0.45) : *(dry_wet); }; // Main stereo processing - apply reverse_delay to each channel independently process = reverse_delay, reverse_delay;
I tried a few additions because the previous version worked decently with mostly percussive sounds, but with instruments like vocals or pads, it tended to create too many clicks/pops and glitchy audio.
Test this new version (milliseconds > Delay time) included.