desc: NEONFORGE Duo-Path Pedalboard (Dual Input) options:maxmem=16777216 // ============================================================ // NEONFORGE :: DUO-PATH // Dual-input virtual pedalboard for REAPER JSFX // Vocal side: Low-Cut Filter -> Tap Delay -> Room Reverb // Guitar side: OctaBass -> DL4 Delay -> Reggie Looper // ============================================================ // --- INPUT ROUTING --- slider1:0<0,1,1{Input 1,Input 2}>Vocal Side Input slider2:1<0,1,1{Input 1,Input 2}>Guitar Side Input // --- VOCAL LOW-CUT FILTER --- slider3:1<0,1,1{On,Off}>Vocal Low-Cut (On/Off) slider4:120<20,500,1>Vocal Low-Cut Freq (Hz) slider5:1<0,2,1{12dB,24dB,48dB}>Vocal Low-Cut Slope // --- VOCAL TAP DELAY --- slider6:1<0,1,1{On,Off}>Vocal Delay (On/Off) slider7:400<20,2000,1>Vocal Delay Time (ms) slider8:0.3<0,1,0.01>Vocal Delay Repeats slider9:0.3<0,1,0.01>Vocal Delay Mix // --- VOCAL ROOM REVERB --- slider10:1<0,1,1{On,Off}>Vocal Reverb (On/Off) slider11:0.5<0,1,0.01>Vocal Reverb Size slider12:0.5<0,1,0.01>Vocal Reverb Decay slider13:0.25<0,1,0.01>Vocal Reverb Mix // --- GUITAR OCTABASS --- slider14:1<0,1,1{On,Off}>OctaBass (On/Off) slider15:0.5<0,1,0.01>OctaBass Blend slider16:0.5<0,1,0.01>OctaBass Tone // --- GUITAR DL4 DELAY --- slider17:1<0,1,1{On,Off}>DL4 Delay (On/Off) slider18:450<20,2000,1>DL4 Delay Time (ms) slider19:0.4<0,1,0.01>DL4 Repeats slider20:1<0,4,1{Digital,Analog,Tape,LoRes,Sweep}>DL4 Model slider21:0.5<0,1,0.01>DL4 Tweak (Mod Rate) slider22:0.5<0,1,0.01>DL4 Tweez (Mod Depth) slider23:0.35<0,1,0.01>DL4 Mix // --- GUITAR LOOPER --- slider24:1<0,1,1{On,Off}>Looper (On/Off) slider25:0<0,2,1{Play,Record,Overdub}>Looper State slider26:1<0,1,1{Stop,Play}>Looper Playback in_pin:Input 1 in_pin:Input 2 out_pin:Vocal Output out_pin:Guitar Output @init // ============================================================ // MEMORY ALLOCATION // ============================================================ // Vocal delay buffer: 200000 samples (~4.1 sec at 48k) vocal_delay_buf = 0; vocal_delay_size = 200000; // Guitar delay buffer: 200000 samples guitar_delay_buf = 200000; guitar_delay_size = 200000; // Looper buffer: 960000 samples (~20 sec at 48k) looper_buf = 400000; looper_size = 960000; // Reverb comb filter buffers (classic Freeverb-ish sizes) rev_comb1 = 1360000; rev_comb1_size = 1557; rev_comb2 = 1361557; rev_comb2_size = 1617; rev_comb3 = 1363174; rev_comb3_size = 1491; rev_comb4 = 1364665; rev_comb4_size = 1422; // Reverb allpass filter buffers rev_ap1 = 1366087; rev_ap1_size = 225; rev_ap2 = 1366312; rev_ap2_size = 556; rev_ap3 = 1366868; rev_ap3_size = 441; rev_ap4 = 1367309; rev_ap4_size = 341; // ============================================================ // STATE VARIABLES // ============================================================ // Vocal HPF biquad state v_x1 = v_x2 = v_y1 = v_y2 = 0; // Delay write positions v_delay_wpos = 0; g_delay_wpos = 0; looper_wpos = 0; looper_rpos = 0; // Reverb write positions rev_comb1_w = 0; rev_comb2_w = 0; rev_comb3_w = 0; rev_comb4_w = 0; rev_ap1_w = 0; rev_ap2_w = 0; rev_ap3_w = 0; rev_ap4_w = 0; // OctaBass state oct_last_in = 0; oct_count = 0; oct_state = -1; oct_filter = 0; // LFO phase for DL4 modulation lfo_phase = 0; // Looper state tracking last_looper_state = 0; loop_length = 0; is_recording_first = 1; @slider // ============================================================ // PARAMETER PARSING // ============================================================ // Input routing vocal_input_select = slider1; guitar_input_select = slider2; // Vocal low-cut coefficients v_cutoff = slider4; v_slope_mode = slider5; v_cutoff_on = slider3; w0 = 2 * $pi * v_cutoff / srate; cos_w0 = cos(w0); sin_w0 = sin(w0); q = 0.707; alpha = sin_w0 / (2 * q); // High-pass biquad coefficients (normalized) hp_a0 = 1 + alpha; hp_b0 = (1 + cos_w0) / 2; hp_b1 = -(1 + cos_w0); hp_b2 = (1 + cos_w0) / 2; hp_a1 = -2 * cos_w0; hp_a2 = 1 - alpha; hp_b0 /= hp_a0; hp_b1 /= hp_a0; hp_b2 /= hp_a0; hp_a1 /= hp_a0; hp_a2 /= hp_a0; // Delay times in samples v_delay_samples = (slider7 / 1000) * srate; g_delay_samples = (slider18 / 1000) * srate; // Reverb parameters rev_size = slider11; rev_decay = slider12; rev_mix = slider13; // Comb feedback based on decay comb_fb1 = 0.2 + rev_decay * 0.6; comb_fb2 = 0.2 + rev_decay * 0.65; comb_fb3 = 0.2 + rev_decay * 0.7; comb_fb4 = 0.2 + rev_decay * 0.75; // OctaBass oct_blend = slider15; oct_tone = slider16 * 0.95 + 0.04; // keep stable // DL4 model = slider20; mod_rate = slider21 * 10 + 0.1; // 0.1 to 10 Hz mod_depth = slider22 * 20; // up to 20 samples modulation g_feedback = slider19; g_mix = slider23; // Looper looper_on = slider24; looper_state = slider25; looper_play = slider26; @sample // ============================================================ // INPUT ROUTING // ============================================================ input1 = spl0; input2 = spl1; vocal_in = vocal_input_select == 0 ? input1 : input2; guitar_in = guitar_input_select == 0 ? input1 : input2; // ============================================================ // VOCAL PATH PROCESSING // ============================================================ vocal_out = vocal_in; // --- 1. Low-Cut Filter --- v_cutoff_on == 1 ? ( // Apply biquad HPF once per slope mode v_hpf = hp_b0 * vocal_out + hp_b1 * v_x1 + hp_b2 * v_x2 - hp_a1 * v_y1 - hp_a2 * v_y2; v_x2 = v_x1; v_x1 = vocal_out; v_y2 = v_y1; v_y1 = v_hpf; vocal_out = v_hpf; v_slope_mode >= 1 ? ( v_hpf2 = hp_b0 * vocal_out + hp_b1 * v_x1b + hp_b2 * v_x2b - hp_a1 * v_y1b - hp_a2 * v_y2b; v_x2b = v_x1b; v_x1b = vocal_out; v_y2b = v_y1b; v_y1b = v_hpf2; vocal_out = v_hpf2; ); v_slope_mode >= 2 ? ( v_hpf3 = hp_b0 * vocal_out + hp_b1 * v_x1c + hp_b2 * v_x2c - hp_a1 * v_y1c - hp_a2 * v_y2c; v_x2c = v_x1c; v_x1c = vocal_out; v_y2c = v_y1c; v_y1c = v_hpf3; vocal_out = v_hpf3; ); ); // --- 2. Vocal Tap Delay --- slider6 == 1 ? ( v_read = v_delay_wpos - v_delay_samples; v_read < 0 ? v_read += vocal_delay_size; v_delayed = vocal_delay_buf[v_read]; vocal_delay_buf[v_delay_wpos] = vocal_out + (v_delayed * slider8); v_delay_wpos += 1; v_delay_wpos >= vocal_delay_size ? v_delay_wpos = 0; vocal_out = vocal_out * (1 - slider9) + v_delayed * slider9; ); // --- 3. Room Reverb --- slider10 == 1 ? ( // 4 parallel comb filters comb1_read = rev_comb1_w - floor(rev_comb1_size * (0.8 + rev_size * 0.2)); comb1_read < 0 ? comb1_read += rev_comb1_size; comb1_out = rev_comb1[comb1_read]; rev_comb1[rev_comb1_w] = vocal_out + comb1_out * comb_fb1; rev_comb1_w += 1; rev_comb1_w >= rev_comb1_size ? rev_comb1_w = 0; comb2_read = rev_comb2_w - floor(rev_comb2_size * (0.8 + rev_size * 0.2)); comb2_read < 0 ? comb2_read += rev_comb2_size; comb2_out = rev_comb2[comb2_read]; rev_comb2[rev_comb2_w] = vocal_out + comb2_out * comb_fb2; rev_comb2_w += 1; rev_comb2_w >= rev_comb2_size ? rev_comb2_w = 0; comb3_read = rev_comb3_w - floor(rev_comb3_size * (0.8 + rev_size * 0.2)); comb3_read < 0 ? comb3_read += rev_comb3_size; comb3_out = rev_comb3[comb3_read]; rev_comb3[rev_comb3_w] = vocal_out + comb3_out * comb_fb3; rev_comb3_w += 1; rev_comb3_w >= rev_comb3_size ? rev_comb3_w = 0; comb4_read = rev_comb4_w - floor(rev_comb4_size * (0.8 + rev_size * 0.2)); comb4_read < 0 ? comb4_read += rev_comb4_size; comb4_out = rev_comb4[comb4_read]; rev_comb4[rev_comb4_w] = vocal_out + comb4_out * comb_fb4; rev_comb4_w += 1; rev_comb4_w >= rev_comb4_size ? rev_comb4_w = 0; reverb_sum = (comb1_out + comb2_out + comb3_out + comb4_out) * 0.25; // 4 allpass filters in series ap1_in = reverb_sum; ap1_read = rev_ap1_w - rev_ap1_size + 1; ap1_read < 0 ? ap1_read += rev_ap1_size; ap1_out = rev_ap1[ap1_read]; rev_ap1[rev_ap1_w] = ap1_in + ap1_out * 0.5; rev_ap1_w += 1; rev_ap1_w >= rev_ap1_size ? rev_ap1_w = 0; ap1_final = ap1_out - ap1_in * 0.5; ap2_read = rev_ap2_w - rev_ap2_size + 1; ap2_read < 0 ? ap2_read += rev_ap2_size; ap2_out = rev_ap2[ap2_read]; rev_ap2[rev_ap2_w] = ap1_final + ap2_out * 0.5; rev_ap2_w += 1; rev_ap2_w >= rev_ap2_size ? rev_ap2_w = 0; ap2_final = ap2_out - ap1_final * 0.5; ap3_read = rev_ap3_w - rev_ap3_size + 1; ap3_read < 0 ? ap3_read += rev_ap3_size; ap3_out = rev_ap3[ap3_read]; rev_ap3[rev_ap3_w] = ap2_final + ap3_out * 0.5; rev_ap3_w += 1; rev_ap3_w >= rev_ap3_size ? rev_ap3_w = 0; ap3_final = ap3_out - ap2_final * 0.5; ap4_read = rev_ap4_w - rev_ap4_size + 1; ap4_read < 0 ? ap4_read += rev_ap4_size; ap4_out = rev_ap4[ap4_read]; rev_ap4[rev_ap4_w] = ap3_final + ap4_out * 0.5; rev_ap4_w += 1; rev_ap4_w >= rev_ap4_size ? rev_ap4_w = 0; ap4_final = ap4_out - ap3_final * 0.5; vocal_out = vocal_out * (1 - rev_mix) + ap4_final * rev_mix; ); // ============================================================ // GUITAR PATH PROCESSING // ============================================================ guitar_out = guitar_in; // --- 1. OctaBass --- slider14 == 1 ? ( // Zero-crossing flip-flop octave divider guitar_in >= 0 && oct_last_in < 0 ? ( oct_count += 1; oct_count >= 2 ? ( oct_state = -oct_state; oct_count = 0; ); ); oct_last_in = guitar_in; // Smooth with simple lowpass oct_filter = oct_filter * oct_tone + oct_state * (1 - oct_tone); guitar_out = guitar_out * (1 - oct_blend) + oct_filter * oct_blend * 0.7; ); // --- 2. DL4-Style Delay --- slider17 == 1 ? ( // Modulate delay time for analog/tape/lo-res/sweep models mod_amount = 0; model > 0 ? ( lfo_phase += mod_rate * 2 * $pi / srate; lfo_phase >= 2 * $pi ? lfo_phase -= 2 * $pi; mod_amount = sin(lfo_phase) * mod_depth; ); g_read = g_delay_wpos - g_delay_samples + mod_amount; g_read < 0 ? g_read += guitar_delay_size; g_read >= guitar_delay_size ? g_read -= guitar_delay_size; g_delayed = guitar_delay_buf[g_read]; guitar_delay_buf[g_delay_wpos] = guitar_out + (g_delayed * g_feedback); g_delay_wpos += 1; g_delay_wpos >= guitar_delay_size ? g_delay_wpos = 0; guitar_out = guitar_out * (1 - g_mix) + g_delayed * g_mix; ); // --- 3. Reggie Looper --- slider24 == 1 ? ( // Handle looper state transitions looper_state == 1 && last_looper_state != 1 ? ( // Start recording fresh looper_rpos = 0; looper_wpos = 0; is_recording_first = 1; ); looper_state == 2 && last_looper_state != 2 ? ( // Switch to overdub - keep playing from start looper_wpos = 0; ); // Record / Overdub looper_state == 1 || looper_state == 2 ? ( looper_state == 1 ? ( looper_buf[looper_wpos] = guitar_out; ) : ( // Overdub mixes with existing buffer looper_buf[looper_wpos] = looper_buf[looper_wpos] * 0.7 + guitar_out * 0.7; ); looper_wpos += 1; looper_wpos >= looper_size ? looper_wpos = 0; ); // Track loop length on first record looper_state == 1 && is_recording_first == 1 ? ( loop_length = looper_wpos; ); last_looper_state = looper_state; // Playback looper_play == 1 && loop_length > 0 ? ( loop_sample = looper_buf[looper_rpos]; looper_rpos += 1; looper_rpos >= loop_length ? looper_rpos = 0; // When recording, monitor dry; when playing only, mix looper in looper_state == 0 ? ( guitar_out = guitar_out * 0.5 + loop_sample * 0.5; ) : ( guitar_out = guitar_out + loop_sample * 0.5; ); ); ); // ============================================================ // OUTPUT ASSIGNMENT // ============================================================ spl0 = vocal_out; spl1 = guitar_out;