Delay-based Looper

I started this as an experiment in using a delay node for capturing and looping. I was going to add it in as another voice on my latest sequencer based patch, but instead I’ve built it up as a four channel loop recorder with solo and external audio supported.

Delay Looper 02.audulus (1.4 MB)

The little demo:

Another little demo (variation on a theme, I guess;):

Basic function

This patch plays loops of various lengths using the delay node built into Audulus. An external tempo source (in my case a drum machine) is analyzed to find the average period of that tempo (for human-powered tempo sources). The looper modules multiply or divide that period by an integer set by a knob, allowing each one to loop over an integer number of beats or to loop an integer number of times per beat, depending whether the setting is greater to or less than one. There’s nothing in the patch that’s actually “clocked.”

The loopers are selected for recording in “radio button” fashion, with only one looper active for recording at a time. Subsequent hits of the button for a channel will cycle it off then on again. A looper can either be erased with each new note played or manually. It can also be allowed to “pile on” notes.

An AGC (automatic gain control) module samples from the mixer the loudness of the loop channels (ch 3 thru 6) and boosts the gain of the solo and drums channel so they can be heard over the possibly ever building loops. Overall gain is maintained by taking that boost back out at the end, effectively lowering the volume of the loops (ch 3-6) while maintaining the solo and drums at their original levels.

Details

On this patch I’m using the white-key scale player module, which has new momentary black key outputs added to trigger the radio button loop record logic.


The button logic module (above) performs the radio button functionality and routes the midi triggers to the loopers as needed. The momentary inputs for selecting current recording channel have buttons in parallel, to allow selection when the white key module is in Chromatic mode (in which the black keys no longer function as switches.)

Solo channel (channel 1)–Tones are produced by my hybrid Osc/Res synth, made from a slightly modified SMOL and my tunable version of the ResDrum. Several params of each are brought out. The output of the synth is filtered by the peaky low pass filter (top item on the screenshot), its cutoff either set by knob or by a frequency (Hz) value presented at that input. Presenting that frequency value is the module, sitting between the looper below and the filter above, which latches the frequency of the last note that was hit and multiplies it by the knob setting. For my use, that knob is controlled in my little rig by the modulation wheel. Filtered output from the solo channel is fed to all loopers.

The in-scale bend module ahead of the synth module allows bends to be played solo or recorded into loops. In chromatic mode (a White-key scale player mode) the bends are chromatic as well.

Loop channels (3-6) Each looper channel is similar to the solo channel, with the exception of a looper module replacing the synth. The loop channels have a similar filter mechanism to the solo channel, with the cutoff above the latest latched tone set by knobs, each of which in the case of my setup is itself controlled by a physical knob.

Looper module. After some experimentation I found that the delay node can be erased by setting its delay and feedback to zero over the previously recorded period. I also found that the node could record an arbitrary length of audio even as it was being erased in the above fashion, playing back once a non-zero loop length was set at the delay knob.

The only hitch I found to this lovely situation was that the sudden change of the delay value on that knob, in the presence of an audio input to the looper, produced an audio burst at the beginning or the end of the loop, building endlessly with each pass. Guessing that this was some sort of “digital domain vs sampled audio domain” problem, and after much trial and error, the best fix I could find was to run the erasing pulse through an ADSR node, with A and R set to zero and D and S set to one. Attempts at filtering either the input signal or the erasing pulse (to cause some delay) failed to eliminate the burst. I don’t have any real idea why the ADSR fix works, apart from the above “hand-waving” guess-planation.

The use of the ADSR node did introduce its own problem into the mix. The main problem being that it introduces a slight error into the period value, effectively shortening the loop relative to the input clock. It’s small enough that for most applications it might not be noticeable, but for extended, Grateful Dead-esque, work you’ll probably hear some slippage.

If I understood the problem better I’d maybe have a cleaner fix. I hate patches like the one I’ve done here. It could break at any moment.

The AGC system is based on a running average calculator module, with rate and sample size set for a reasonable level of responsiveness. The averager I made using a state machine approach. It’s actually way simpler than it looks. Once you go the state machine way it’s hard to go back to crazy point-to-point logic!

5 Likes

Excellent work as usual! :cowboy_hat_face: I’ve dealt with similar audio issues trying to abruptly change the delay time value. AFAIK the delay is modeled on an analog unit so when the delay value is changed, the unit still attempts to render all the samples in the stream using interpolation rather than simply discarding the intermediate ones. This allows the delay to produce the pitch changes characteristic of an analog unit but results in the noise burst when the value is changed abruptly. Probably the result of trying to produce a whole frame’s worth of data at once. Interesting that the ADSR removes the glitch.

1 Like

I tried the ADSR because it translates a control signal into the “audio domain,” where we worry about digital audio things like aliasing, and that even set to “zero,” the ADSR wouldn’t be creating any appreciable output North of the Nyquist freq. I wish there were a node that just did that one job. I tried creating a simple digital filter to replace the ADSR, maybe an “all pass?”

1 Like

Interesting point. I don’t know if the ADSR has any slew limiting applied and what an attack or release value of 0 actually represents. I didn’t have much luck trying to suppress the noise by filtering the signal attached to the delay time.

2 Likes

Yeah. I tried that, too.

1 Like

@dcLargo :flushed: I am stunned, as I usually am when you reveal some new Wonka style contraption that makes everything I have ever made look like Playskool brand toys or building a tower out of LEGO Duplo blocks :rofl:

Great work! Keep the good vibes and fantastic work coming! :blush:

3 Likes

Thanks!

By the way, mr stschoen, I do believe I was talking outa my arse about the ADSR. I don’t know a thing about its internals. It was just a wordy rationalization for a hunch.

AND, speaking of hunches, another node that is made for audio signals is the mixer node! Nice thing about that thing is that you can put dc values in there, in my case the value 1 into one input, a or b, and zero into the other. Given its intended use as a simple audio mixer, I’m expecting that a step with slew rate above audio bandwidth, from 0 to 1 at input c whould create a step (or its inverse) at the mixer node output that’s correctly slew rate limited for audio. I’m trying that tonight and it seems at first glance to work. For smoothly switching audio off and back on.

Another audio issue that comes to mind is the old digital sound editing rule of making your cut at a zero crossing. Ideally you want to begin sampling at a point where the audio waveform is at or very near zero, since initiating or terminating capture at an arbitrary point in time when there’s signal will more likely than not place a step at the output, which as you know floods the signal at that moment with a high frequency “tic.”

Maybe delaying the initiation and termination of capture till the waveform is at or is reasonably close to zero. What do you think?

2 Likes

Switching at a zero crossing seems like a reasonable approach If you’re willing to run the circuit in single sample mode. AFAIK the crossfade node doesn’t do anything to limit the slew rate. I spoke to Taylor regarding the delay yesterday and other than a linear interpolation between samples, he’s not doing anything special with regard to the tap position. He was kind enough to share the code with me and it’s a straight random access tap into the buffer. I’ve been playing around with the delay the last couple of days and have come up with a design that is reasonably glitch free. It’s still in development at this point but I’m happy to share the WIP. At this point it’s a single channel non-quantized looper similar to the old looper pedals. Two switches, the first starts recording on the first tap and loops on the second. The looper is then in overdub mode. A third tap puts it in playback mode. Subsequent taps alternate between playback and overdub. The second button resets back to initial state. Because the Audulus trigger node isn’t MIDI channel specific I’m using an external MIDI trigger module so I can use a Korg NanoPad on channel 6 as my switch while I use an UltraNova on 3 as an audio source. My UltraNova happens to be on audio channel 5. I intend to perhaps incorporate some additional channels and quantization once I’m happy with the basic design.
The key features are that I’ve moved the feedback loop external to the delay node where I can manipulate it and I use a timer to advance the delay time while I’m in record mode. By using a bit of slew limiting on the switching I seem to have eliminated most of the glitches.
looper.audulus (78.2 KB)

2 Likes

Slightly updated version. I switch the order of the playback and overdub and grouped it into a module
looper.audulus (86.8 KB)

1 Like

Well, that looper module is great fun, and it sounds really clean! Great work, as usual!

Also, WHERE has the ADC module been all my life?? I am thrilled to have access to all of my interface!

1 Like

The looper version I posted in the modules category is a bit more complete as is the trigger module. No fundamental changes in the approach but more UI eye candy. The trigger module is an adaptation of an eight channel drum trigger I built a while back. The original supports velocity so if you have something like a Bop-pad or a velocity sensitive drum pad you can access the velocity values. In this case I only needed a trigger so I removed the velocity logic.
I’d still like to add something to quantize the looper based on an incoming clock. It’s pretty easy to deal with an early trigger by simply gating it with the clock but a late trigger is a bit trickier. Units like the current Boss stuff fill the buffer continuously and adjust the loop start and end either backwards or forwards depending on what’s closer, but to minimize glitching, I don’t start feeding the buffer until the recording is actually triggered. It’s difficult to go backwards in time. I have some ideas that are worth exploring but I don’t know if they’ll work out. In practice I usually use Ableton for my looping tasks since I’m not a big live performer. It only goes forward so if you are a bit late you miss a whole beat. I’ve gotten better with practice but still screw it up a lot. Probably just as well I’m not trying to do this live.

2 Likes

It has been in the same Utilities grouping of nodes where you find the speaker the whole time lol. There is also a DAC node that you can use for outbound stuff, as well. I’m glad to see that even the gifted musicians of the forum occasionally miss things too :wink:

3 Likes

It was hiding in plain sight!

3 Likes