Zipper/Gritty distortion when writing with poke/ipoke backwards (groove sync)?

Rodrigo's icon

I'm making a looper/sampler based on poke(ipoke) and groove for playback. I'm using the sync output of groove multiplied by the total number of samples in my buffer (sample rate * duration in ms) and then adding +0.5 (as I've seen in a couple of examples on here).

I'm assuming the 0.5 offsets the sync forward one sample so that you write a sample before reading it (so your record head is 1sample ahead of the read head).

Now when recording (or overdubbing) in reverse, I get a zipper/gritty type distortion on the sample. I thought this might have to do with the fact that when going backwards, I'm recording one sample AFTER I'm reading (or the same sample) so I'm adjusting the offset to -1 (to presumably write the sample before I read it (but going backwards).

Still getting the noise.

This seems to happen with poke and ipoke, so I don't think it's an interpolation problem, but a sync problem.

Here's the patch (annotated).

Max Patch
Copy patch and select New From Clipboard in Max.

Rodrigo's icon

I'm also noticing that I hear the zipper/glitchy sounds AS I'm recording, even though I don't normally hear them when going forwards, so I think there's some 'write before read' or 'read before write' type issues here.

Can you drive (i)poke with groove's sync output with sample accuracy? (Seems to work fine going forwards...)

christripledot's icon

I've just got in to work, so I can't open your patch (no Max here) :(

But, the [+~ 0.5] is just a trick to round the index up to a whole number (it's explained in one of the audio-rate-looping example patches). You could try replacing it with a [trunc~] (which is the 'correct' object to do this anyway, but it's CPU-heavy) to see if that alleviates the glitching.

Another thought - you may be losing sample-accuracy at the moment you trigger [groove~] (therefore offsetting its sync outlet's phasor~ by a tiny amount). Perhaps you could re-structure the patch around a master phasor? Sorry for being vague; I just can't see what your patch is doing so I'm stabbing in the dark!

Rodrigo's icon

I've got a trunc~ after the 0.5 as well (the examples I found on the forum had both).

I would imagine the resetting and jumping around groove (by ms) isn't the more accurate thing in the world, as far as placement, but wouldn't the sync output be sample accurate in terms of how poke/groove work together?

Unless grooves 'ms' input doesn't stay in time with it's sync output, which would obviously be a bummer...

christripledot's icon

If you've got a [trunc~] in there as well, scrap the [+~ 0.5].

[groove~]'s 'ms' input might not be totally reliable; I'm sure there is some precision lost during the ms to samps conversion.

Rodrigo's icon

Ill try dropping the 0.5 when I get home. (I'm at work too).

I can live with it being a bit off in terms of input, but the output is the important one as it's driving poke.

Rodrigo's icon

Removing 0.5 still creates the zipper sound. On top of that, I noticed (since the zipper noise is pretty high frequency) that playing backwards, without overdubbing or doing anything, is messed up completely (using groove to drive poke).

If I start playing a loop while reversed it starts rolling off the highs, similar to an analog delay. It takes 3-4 passes before you start noticing it, but it's definitely there. When playing forward, there is no degradation at all.

..........

Ok did some more thorough tests, trying with and without trunc, with and without the +0.5, and then multiple variations of variables for the +~ object.

Going reverse, I managed to reduce the zipper stuff by changing the +~0.5 to +~1.

Now when recording (forward or reverse) at a slow clock level (set the 'speed' knob to 0.1) you hear artifacts being recorded forward and backwards, and the signal degrades very quickly, very much like an analog delay. So something is awry!

I then decided to get more thorough and poking(pun?!) around.

First of all I noticed there's clock jitter..... Multiplying the sync out by anything above 5 gives some jitter in the output value (tested by using delta~). Now, unless I'm doing something wrong in my testing here, the results after multiplying by the samples in my buffer is outrageous....

Trunc~ is outputing with a possible difference between the multiplied output of -0.1 to 0.9, so a +/- of 1 sample.

Now before it even gets to there there's a ludicrous range coming out of the delta~ of the post multiplication signal. (-5733 to 0.1) (+/- of 5700?!?!)

So this is getting to hair pulling territory now. Especially since if from groove to *~ to *+ produces such wide jitter in delta~, that this would be the case if I used a phasor~ to drive everything (say poke and index or something).

I dread having to rebuild my whole patch again around a different playback object (setting min/max loop points as well as jumping to arbitrary points of the loop are central to my patch).

Here is the patch from above but with all the testing stuff in place (annotated).

Max Patch
Copy patch and select New From Clipboard in Max.

christripledot's icon

Don't panic! Look after your hair; lather, rinse, and repeat.

I'll take a look in a couple of hours.

Rodrigo's icon

Lol, thanks!

I just thought I had it cracked open and done (the rest of my patch is working/looking great!) to find out that the core of the whole thing (the sampler/looper) is effed....

christripledot's icon

Hmmmmm.... the size of your record buffer is pretty damn big. I need some dinner before dissecting your patch properly, but I think you might be running into a floating-point representation problem.

A 32-bit float can't represent every single integer exactly. Once you get over around a million (2^31 - 1), the gap between numbers that can be represented becomes greater than 1. You could try simplifying your patch and using a shorter buffer to see if that helps.

Rodrigo's icon

Yeah it's pretty big. I rarely use that much of it but I do want the option to get longer(ish).

From what I've been told, you can trust 32-bit floats up to 5min though, but that could be in a different context (it was referring to buffer length, but maybe not using this (sync*samples) method.

The main body of the patch is working well, logistically, and I've isolated that the multiplication/trunc/sync section is what's causing the gritiness/glitchiness.

As far as I can understand, this method of overdubbing/recording is based around the idea that I record to a sample while playing back the next one in line, in a perfect little line. When reversing those things must change direction. And any jitter in that clock is making audio come through when recording (as the zipper noise) and temporaly glitching the sample.

I tidied the patch up a (little) bit here:

Max Patch
Copy patch and select New From Clipboard in Max.

christripledot's icon

Hmmm... I still reckon you can't trust a 32-bit float for that long. In any case, I've never implemented an overdubber using [groove~]. Unless you switch off interpolation I imagine you'll get weird artefacts anyway, because it tries to interpolate samples that haven't been recorded yet (following me on this? hard to explain...)

Take a look at Andrew Benson's looper from an old thread. It uses [index~] and works in reverse just fine (just set the [phasor~] speed to negative).

Max Patch
Copy patch and select New From Clipboard in Max.

In the meantime I'll cobble together a looper with the same controls as yours...

Rodrigo's icon

Hmm, I didn't know groove interpolated. I did see that looper a while back but it didn't do the dynamic sizing thing, which was the first thing I had to figure out how to implement, so I didn't look at it further.

What makes things more complicated for me in terms of replacing groove/poke is that I use the min/max points of groove a lot (in the rest of the patch), as well as jumping around to different starting points. I suppose scaling wouldn't be too bad, in terms of 'faking' the min/max stuff with a phasor, but I don't know how you would 'jump' to a point in a phasor without offsetting it.

I'll try to tweak that patch (Andrew's) a bit to see if I can dynamically size a loop.

christripledot's icon

I've struggled with dynamic resizing of a loop using a [phasor~]. You need a feedback loop to make it work, and it'll never quite do what you want. I have a home-brew external for that sort of thing - what platform are you on?

In the meantime I'm trying a workaround; I'll get back to you with any progress.

christripledot's icon

I think I've got it... my patch is too ugly to post just yet, but I suspect it IS to do with [groove~]'s interpolation.

When you record forwards, bung a [sig~ -4] into poke's index (to make sure you're recording 4 samples behind the playback head). When you record backwards, stuff [sig~ +4] into poke's index. No grittyness here!

christripledot's icon

Ack, my eyes are going funny, I can't be arsed to tidy this up.

Be warned, it's a mess!!!

Once you tidy up the patch cords it's a bit simpler than your patch, although I haven't incorporated any logic to handle what happens if you start recording with reverse enabled. It shouldn't be too hard to hack it.

Max Patch
Copy patch and select New From Clipboard in Max.

Lemme know if this works for you...

Rodrigo's icon

On OS X here.

Man, that sounds like the kind of thing that never would have occurred to me in a million years!

If this works well you'll have to send me your email address and I'll send you some CDs and stuff, or something!

christripledot's icon

Hahah! Not at all, dear chap. Intel Mac, by any chance? If so I have a few things for the toolbox page in the next few days that might interest you.

Rodrigo's icon

Yup, Intel (Lion).

So is that sig~ -1 going to poke's index making it not......jitter all the time?

Out of curiosity how did you figure this out? (the +/- 4samples thing) Does it matter than it's 4 samples off, or is that just far enough that the read/write heads never 'cross streams' ?

christripledot's icon

The [sig~ -1] leading to the [selector~] is to ensure that when record is off, nothing new gets written to the buffer.

Don't confuse it with the other [sig~]... the one that's hooked up to the [t 1 -4] and [t 1 4]... that's the one that fixes the grit. Oh, I just realised that the [+~ 0.5] really isn't necessary, just the [trunc~].

I'm just tidying up a new buffer playback object, so I've got interpolation on the brain at the moment. IIRC, [groove~] uses cubic interpolation, which requires 2 points either side of the 2 points being interpolated. So in fact, you only need to offset +/- 3 samples to avoid the grit. That way the playhead doesn't ever take into account any of the new samples you've just recorded.

It's not sample-accurate like this, but it shouldn't really matter - your patch suggests to me a live improv sort of approach anyway, especially with the autosizing feature. Let it drift, it's funkier that way ;)

I think to do this completely in the audio domain, you'll need to use [index~] instead, unless you want to go down some sort of horrible twin-buffer approach. I'm sure there are other solutions but they would definitely take some working out, and probably use up more CPU cycles.

Sorry for the lazy patching, there are lots of bits to improve, but it seems good enough for now.

I should be thanking you anyway, you've given me some interesting new ideas for a resampling machine!

Rodrigo's icon

That makes total sense about the interpolation, I hadn't thought of that. I'll trim those bits out and adjust it accordingly.

Once it's tidied up I'll post it here in this thread so it shows up in the searches. Super handy stuff!

Yeah it's for an improv/performance based situation. I'm not a fan of tempo and/or synchronized sampling/looping. It'd be like playing through quantize/autotune all the time..... not for me.

Though it wasn't incorporated in the version of the patch I posted on this thread, the minmax~ (instead of a banged snapshot~) was there so I could reverse while recording the initial loop and let that wrap back in on itself. So minmax~ would store the highest I've been to, not the highest I currently am (like snapshot does). Rather esoteric, but it sounds amazing (once you wrap your brain/mental performance time around the 'non-linear' aspect of that).

christripledot's icon
Max Patch
Copy patch and select New From Clipboard in Max.

Ah, clever. Here's a tidier version of the patch I posted - I leave the minmax~ modification as an exercise for the reader ;)

Just don't do any f***ing beatboxing with it.

Rodrigo's icon

Here's your logic incorporated to the patch I posted before. Yours is definitely tidier that's for sure!

I added a couple frilly bits. Like the selector~ closing after 5ms so the line~ has time to fade out. Also there's a click in your patch when you overdub across the wrap around.

Mine had it too when I incorporated the changes. I added some declicking (only when not recording the original loop) to remove it. There's the smallest of audio dips, but there's no click now. If it was going all of the time, if you're making sound when you start the first loop the fade in is to severe (line~ fading in AND trapezoid fading in).

Mine uses minmax as the object, but doesn't have the 'reverse while you record' code in there at the moment.

Max Patch
Copy patch and select New From Clipboard in Max.

Rodrigo's icon

Lol, possibly the furthest thing possible from beatboxing! (though I guess there are drums involved)

christripledot's icon

Phew, that's a relief. Too many Beardyman wannabes out there these days. Man, there's some beautiful haunting sounds in that set of yours; I particularly like it around the 16-18m mark. Not to mention egg whisk steez! Nice one! My live sets are a bit noisier and haphazard than yours:

Rodrigo's icon

I agree there. That linear looping is a real snore, particularly when it takes a songs length of time, to build up one section of a songs worth of material....

Glad you dig it!

Shifting back to Max/MSP is a big change for me. I've been doing max stuff on/off for many years, but I'm primarily a hardware/diy/instrumental kind of guy.

Prior to this max stuff, this is the last thing I 'made':
http://www.rodrigoconstanzo.com/2011/08/sidrassi-tom-v3-finished/

Pierre Alexandre Tremblay's icon

hey this patch is cool but does not allow faster than real time overdub... hence the ipoke~ object I coded.

Alex and I are improving it in our hobby times (he is on his way to the Max Expo where he will showcase the non-hobby stuff - Impulse Response stuff ;-)

p

christripledot's icon

Nice one Pierre! I haven't tried [ipoke~] yet; definitely something to check out.

Rodrigo's icon

Hey PA.

Yeah you can't go faster than 1. for speed with poke, but in my patch I was never doing that. More to the point I was jumping around arbitrary points while recording, which you can imagine/picture what ipoke(r) did with the buffer in those cases. (Filled the whole buffer with massive DC offset/noise) So for when writing arbitrary points I had to use poke anyways.

I also ran into some weird stuff with ipoke erasing parts of the buffer when I stopped recording after the halfway point. (I'll explain further in an email).

Rodrigo's icon

Yeah ipoke~ is great! Even when underclocking as it averages samples received and writes that, so that sounds slightly better than poke writing capturing every nth sample.

The original version of this looper was using a slightly modified version if ipoke to allow for dynamic sample length but all of it broke when I could jump around the buffer while writing (another part of the code omitted for trouble shooting purposes).

8888's icon

I've been looking around the forum for some live sampling patches, and this one seems very useful, although I always get distortion whenever using it. No matter how I set the level for my [adc~], there is always a distorted sound. Has anyone else had this problem, or know of a solution?

Here's the patch, the last one posted in this thread:

Max Patch
Copy patch and select New From Clipboard in Max.

Rodrigo's icon

Maybe raise your I/O vector settings? And/or restart Max. I sometimes get a bit of noise when the CPU is getting hit to hard, and a restart clears it.

Also maybe try recording a file playing back, rather than live audio, to rule out noise there.

8888's icon

Interesting, it worked fine when I used a file playing back. The live input was still giving me this distorted accompaniment to what I was recording, but then I did a PRAM reset on my Mac and the live input works fine now. I'm not sure exactly what the problem was, since other patches weren't giving me this problem with the live input, but it seems to be fixed now.

Thanks for your response, and thanks for making this patch!

Rodrigo's icon

Glad that worked out. I always try to troubleshoot that way (even things that doesn't seem like it would matter).

This is what this patch eventually turned into:

8888's icon

Wow, that is a great project! I love the demo with the snare drum, too!

zangpa's icon

Hi and thanks for a great looping patch Rodrigo (and christripledot) . I've been working on a looper myself and used your patch as the starting point. But now i've run into some trouble. When i jump around in the patch and overdub, i get these clicking sounds at the start and end of the part i just recorded. Do you have any idea how to fix this? Your patch smooth out the start and end of the loop (with the declicker subpatch), but how do i smooth out random start- and endpoints (not loop start/end, but recording start/end)

Rodrigo's icon

You have to apply a fade in/out each time you jump.

Max Patch
Copy patch and select New From Clipboard in Max.

There's probably better ways to do this, but I made this abstraction for dealing with that:

Basically you send the new position into the left inlet, and it ducks the audio coming into the right inlet (so you run the groove audio through it).

I use line~ driving a wave~ to have a smooth hanning style bell curve.
In order for the abstraction to work you need the attached audio file in a buffer named "declicker"

4638.declicker.wav
wav
zangpa's icon

Thanks very much Rodrigo! A simple but nice way to solve the problem. I will try it in my patch at once. I also got an advice from a max friend of mine from norway. He'd made his looper with groove/xrecord, so i'll try that too!

Rodrigo's icon

What's the advice you got?

My version works well, but isn't ideal as it's mixing the max scheduler and the MSP one, so potentially things won't line up as they should.

zangpa's icon

Hm, i just looked at the other patch. It eliminated all the clicks in the begining/end, but it doesn't yet make it possible to jump around in the loop. So i got to do some modifications.
The patch is using xsample instead of poke (since xsample have built in overdub) and it uses two buffers and four grooves, and crossfades between the grooves. I'll take a closer look, and will post the result later.

Rodrigo's icon

Yeah that's a separate problem. Declicking the end/start is easy using trapezoid, but declicking jumps requires something else.
Curious to see what you've come up with.

zangpa's icon

No luck yet coming up with a solution on this problem, and no luck with the xrecord object. But i'm not giving up yet....