[MSP Extern:] rez~ - a sample-accurate looper - (update for apple sili)
Hiello!
This is a sample-accurate looper i'm feeling a nice ease-and-flow in coding and using, that stems from a good amount of simplicity/minimalism in the design. So I think this might be good to eventually release to the wild as officially and functionally as possible(eventually submitted as a 'package' to the max ecosystem with nice helpfile/refpage/docs etc.).
So I could use some beta-testing! And also help on bettering the helpfile/docs :)
Attached are the externals for Mac(.mxo), Win(.mxe64), along with helpfile.
Source-code available here.
And here's a bit of a description to start with:
1) For playback, the signal-inlet controls are 'starting-phase', and 'speed':
'speed' of '0' turns the object off, any other speed turns it on(w/ de-click fade-ins/outs)
'starting-phase' is the position at which playback starts, and can be changed on the fly while playing with crossfade-declicking(not while in 'oneshot' mode, though)
2) For recording, the signal-inlets are for 'starting-phase', 'speed'(-1., 0., or 1.; reverse/stop/forward only), overdub, and recording-inputs for left and right
3) For outlets: there are playback outputs(left and right), a playback-phase outlet, and a recording-phase outlet
4) The only messages are "in", "aus"(for playback-loop 'in' and 'out' points),
"rin"/"raus"(for recording-loop 'in' and 'out' points),
and "set"(to change buffer~s referred to)
5) Just two attributes:
"fade" is an attribute you can set for all fade-times
(in samples; interesting effects can be achieved by changing this in real-time)
"oneshot" is an attribute you can set (as a flag - 0/1) to put the object in one-shot mode where, only a speed-change from 0 to non-zero will set the object playing starting from the 'starting-phase' inlet's control, and ending at the furthest loop-boundary
(if playing forward, it will play til the end(aus/raus) point, if playing backward, will play 'til the start(in/rin))
5) while playing, de-clicking is handled by crossfades
(sine-based crossfade: fades out of the previous-position, in-tandem with a fade-in to the current/changed-position) for playback and recording (in recording, the crossfade accounts for overdub amount)
6) 'initialization-modes' allow you to setup the object more efficiently:
the object takes 3 arguments -> buffer~ name(mandatory), channel-number(optional... although mandatory if you want to enter up to three arguments), and initialization-mode(optional)
the initialization-modes allow you to access "play"-only functions, "rec"ording-only functions, or all functions at once, just give a 3rd argument of either nothing(for all functions available), "play", or "rec". accordingly, the object will initialize to cut-out any unnecessary inlets/outlets, and internal variables/functions, etc. to give you the most efficient possible object for whatever usage you choose
(for example, creating an object like so: [rez~ bufname 1 play],
gives you a 1-channel playback-only object, where only two signal-inlets are provided(the two for playback-control only), and 1 signal-outlet for single-channel output, plus 1 signal-outlet for playback-phase..
..or creating an object like so: [rez~ bufname 1 rec],
gives you a 1-channel recording-only object, where 4 signal-inlets are given(starting-phase, rec-speed(-1/0/1), overdub, rec-inputLeft), and 1 signal-outlet for recording-phase signal..
..whereas, creating an object like so: [rez~ bufname],
gives you all signal-inlets/signal-outlets/functions(and 2-channel by default))
Known issues: so far, i do run into clicks/pops here and there(mainly when using the object(in the default initialization with recording/playback all-in-one) to cause the playback and record heads to cross each other, but with very small loop-sizes or performing very fast cuts yet very close to each other continually... the first tab in the helpfile runs into this issue). also, i've not de-clicked transition from 'oneshot' mode to regular, so for now, that attribute is better changed whenever the object is not running. and also, in 'oneshot', sometimes the recording performs something inaccurate about the fade-outs near buffer~ boundaries. Basically, i need to look more closely at 'oneshot' in general, plus default initialization, and some recording-fade/declick details
but no crashes so far! :D
The de-clicking for recording-over-play crossover is probably as good as i can get it for now(i tried other sharper fade-curves and they don't necessarily work better at higher speeds, i've found this simple-cosine-based fader is the best trade-off for more widespread contexts).
But feel free to report any bugs/issues you find, do try to focus more on those which you can reproduce to some extent: even 2-out-of-every-7 tries is a good reproducible frequency(if you get something even closely reproducible, list me the steps to repro and i'll do my best to fix).
...and(in case any of you saw the edit earlier where i had to make a last minute change before attaching), beta-test is now officially launched!
in beta until January, 20, 2021. i forgot to add presets to finish up the 'oneshot' tab in the helpfile(if you mouse-over the 'oneshot' buttons in that patch, it'll perform oneshot play/recording)... that could use more explanation along with other things... anyways, hope you like and have fun :)
Sounds good!
Thanks, Matt! Much Appreciated 🍻
thanks! love rezer~ and looking forward to taking this on a test drive tonight :-)
@LILSKULLYMANE Thank YOU!
Hope this works just as well if not better for ya, let me know how it goes 🤘
thanks for rez~!
@Alfonso
My pleasure! Let me know if you run into issues or any other feedback you have about it, i'll do my best 🍻
Yes! This comes just at the right moment!
I will let you know if i discover anything buggy..
@MartinMartin
Excellent, glad you'll find it useful! Ya, please let me know whatever you find, i'll appreciate it 👍
@RAJA yeah!
So I have built a patch that records a one-shot and then immediately plays it back in reverse. I am getting some inconsistent playback though. Sometimes the playhead just does not trigger
My solution may not be the most elegant at the end of the day lol.
I am definitely enjoying the external though! I am planning to use it on upcoming performance. Really just this effect alongside your gen stutter (hoping to modify an speed envelope into it in the next few days) with some live drumming
@Davis Polito
looking more closely at your patch, i see i can rework it to get a reliable trigger like this without having to add any fixes/updates to the rez~ object itself:
(the very first time i trigger it, it doesn't playback, but after that, it always works... the way i have set it up now, it resizes the buffer before every new recording... this ends up tricking the object into thinking the positioning relative to loop-points is reset everytime, and i think this is why it ends up being a reliable one-shot reverse trigger... but that's not to say this is how i'll leave the design of rez~... i'll keep trying to refine the object's interface, but in the meantime, this can be a solution for your performance if i don't get the object interface redesigned simpler before then)
here's a vid to show it in action, just to make sure we see/hear the same thing with this version of your patch(i'm just brushing my hand across the mic on my laptop):
hope that works for ya for now 🍻
😭😭😭😭
i don't like this object anymore... back to the drawing-board... i feel maybe it needs to be simpler:
just 2 signal inlets: one to trigger playback-based functions, and another to trigger recording-based functions(using something like click~ or basically by detection of an upward-edge in those inlets)..
the rest of the time, the user will send event messages to instruct the object what to do the next time it receives a sample-accurate trigger in the appropriate inlet... and the user will need to time it so the event-message gets to the left-inlet before triggering either signal-inlet to carry out that message...
i dunno... looking for a simplistic interface for one single external that will serve as both a looper and a one-shot, but will have independent recording and playback positioning/controls... and no clicks...
@anyone feel free to make suggestions...
(i might also extend the beta-test to 2/22/2022... just because of all the '2's in that date... that and i'm distracted by my Norns... '2's, i'm distracted by my Norns... and also it's the holidays so i'm feeling lazy 😜)
apologies for being a continuous failure 😭
(norns is more fun than max, tho.. it's like supercollider but simplified with a lua layer for event/dataflow... y'all should try one😜)
i will get it together soon, and finish this object off at some point... let's make a finite deadline... NO LATER THAN 5/5/5055!! 😜 (just kidding, no later than cinco de mayo of next year)
hopefully no one cares too much( 🤣 ) but in case anyone is depending on something like this: go for the karma~ object(see package manager)... or else there's also the softcut~ external: https://github.com/catfact/softcut-msp ..softcut was originally on norns(why i'm distracted now..) although it doesn't have independent record/playback positioning on the norns, i think the msp external linked there might... not sure..anyways...
i will persevere! 💪 (just not right away 😂)
I really like that idea! Internalize all the LFO and scrubbing structure etc. would definitely make it a powerhouse in terms of usability. I think it would be cool to allow things like doing a one shot that loops for x repetitions at x speed (could even allow for changing x speed at some repetition rate).
I have messed around with karma~ (I actually found you through finding rodRick then karma~). Excited to see what you come up with next and I will keep playing with this little object in its current state to see if I can’t come up with other ideas.
Also OMG I am in love with this Norns thing
loops for x repetitions at x speed (could even allow for changing x speed at some repetition rate)
this might complicate things, but i like the suggestion alot, thank you!
... it'll cut down on having to sample-accurately trigger things after each message if the messages can instruct further into the future(something about the messaging can instruct on how to 'iterate' in simplified ways after each repetition... this can be for @oneshot mode, whereas in @loop mode, the number of repetitions could also apply, as something that happens before it resets to a certain user-defined default behavior... or something...)... might take me longer, but ya, i think this'll prove more powerful and diverse... thanks again!
Hello,
I was just wondering about the development status of rez~. I found it while searching for an alternative to xgroove~ from xsample. In particular, I'm looking for a sample player that can crossfade the loop edges, not only for de-clicking but also capable of longer crossfades for sound effect purpose (xgroove~ was great for this but there's no Windows 64 bit version of it that is easily accessible). I've tried rez~ and it seems to do all that I need, but before I build performance systems around it I wanted to get an idea of what the near/far future of rez~ is looking like now. Is it your plan to open source it or to sell it? Is it still being developed?
Thanks for your great work and for sharing it!
I've tried rez~ and it seems to do all that I need, but before I build performance systems around it I wanted to get an idea of what the near/far future of rez~ is looking like now. Is it your plan to open source it or to sell it? Is it still being developed?
Hi! Thanks for the interest, this is up in the air right now but to develop rez~ any further, i would first move it to a C++ version(using the 'min dev kit'). this was my next plan, but Cycling74 also recently released some interesting additions to help make groove~ more sample-accurate, namely "phasegroove~"(and there are also new objects like ramp~ and twist~ that can help with amp-envelopes and waveshaping, etc.)... i was curious to see if people might just go back to using groove~ for things like this now that some of this newer sample-accurate stuff exists(groove~ has that built-in DIRAC timestretch, too... which i'd probably never be able to build with the same awesome/hi-tech quality into rez~)... but basically as specific answers to your questions:
-plans to open source or sell it: i never plan to sell this in its max external form(it'll remain free - though if i ever learn to build VST and AU plugins, there might be a different version that gets sold in that form while this max-external version will always remain free), and it is open-source, the source-code available here: https://github.com/ItWasAlienz/rez
you're free to use it however you like and even sell your creation/variation based off of it - i'd be honored if it gives you any benefit as such(if the license on there is any issue, let me know, i can change or remove it, i'm not too attached, i just picked the standard MIT one github offers...)
-plans to develop: possibly moving this to C++ in the near future, but 'near future' could mean anywhere between 6months to 2years(looking to get back with serious intent on this around October of this year, and anticipate it might take me about 2-4 months from there to release the C++ version, but that's just a ballpark guess... leaving my schedule/options open for fun :D...)
Thanks again! Hopefully i'll get back on this later this year, in the meantime, hope it works great as is for you :)
Thanks RAJA! It's great to see that the code is available. Building a sample player with loop crossfade, variable speed and reversible direction using vanilla objects like groove~ and phasegroove~ seems doable but it's a bit cumbersome to get it to work properly and fault free for interactive performance. I've also considered using Gen and codebox instead.
Cheers!
Something like Rosa 2 or LiSa would be nice. I tried Karma~ but the re-pitching is grainy.
Hi again, apologies for floundering so long on this(was trying to get the min-devkit to work on my machine but...), i've now moved back to the C based SDK, and finally got an Apple Silicon version(no other changes here):
the .C code is still on the github so anyone's welcome to rebuild themselves ongoing to keep developing however they'd like.
sorry for the lack of progress.
I downloaded and tested this - it works with excellence, it is basically everything I ever thought I'd want for a live looping setup.
I noticed that sometimes when changing loop points, the play head 'leaves' the loop and goes back either to the beginning, or a previous loop start point - it always returns to the loop afterwards though.
Not sure if this is something I'm missing regarding functionality, but thought I'd report it just in case.
Thank you for this object, and here's some encouragement for future development!
Thank You! (will take a look at that bug when i return to it, i think i've found that when i combine a very small duration loop-window with a fade-time that is larger or equal in size to half that loop's duration, the fade-in-and-out which needs to complete first causes a loss of loop tracking and returns the play-head to the previous starting point... i thought i built in some automatic-constraint-of-loop-duration based on the fade-time, but will take a further look...)
I've no set plans at the moment, but this is something i definitely want to get back to improving on eventually(they added the 'array' object, with possibility of explaining more about how to use it in the SDK soon: https://cycling74.com/forums/arraystring-sdk-and-documentation-follow-up, but also Jeremy was gracious enough to post some examples already: https://cycling74.com/forums/accessing-and-processing-arrays ), so i'll be looking into adding some internal sequencing whereby it would be possible to process parameter-lists using the array and dict objects/utilities... but not sure of the exact details and specs yet, and definitely unsure of any timing.
(i've also decluttered in my mind and decided not to pursue learning c++ through min-devkit as it's difficult to ensure i've a correct understanding of using more esoteric and newer concepts/functionalities, such as 'dict' and 'array' in the most-efficient/intended ways.. this is just to say that, for a noob-to-programming-languages such as myself, it doesn't feel like a very friendly way to learn and will cause me to spread too thin, which is a problem for me as is (😅😂))
but, will keep at it as soon as i can, and Thank You Again!