[Latest News: MAJOR UPDATE! - v.008 - released May 15th, 2019 ]
Hello and a beautiful day to you all! 🤗 (after stepping away from Max for 2 years due to life stuff a few years back, didn't think i'd get my chops back, but lately seems perhaps improving... so this is quite a lucky thing that i created this... hope you'll all be patient with me as this work was very unexpected and flowed out of me as though from somewhere else...)
Unfortunately, this is not easy to explain in a short and concise manner, so let's start right off with a feature list(and possible explanations as to why i went with these features):
it's free 😋
built-in de-clicking fades at all starts, stops, loop-points, and retriggers(as well as when play and record positions cross; at loop-points and retriggers, the de-clicking is actually a tight crossfade from where the playback was into where the playback skips to), plus the same on the recording end(with a clever bit added to incorporate fading/crossfading previously-recorded material around an overdub amount)
different modes for styles of sequencing(things can be triggered right away, or they can wait til a loop-point is crossed before responding to signal changes/triggers at inlets)
can only do 1x or -1x recording speed - this leaves the object much easier to use efficiently CPU-wise as well as manage ongoing development(but years down the line, if you're still craving this object with varispeed recording, let me know, i'll think about it then...)
playback employs 'hermetic bicubic'(also just known as a form of 'cubic') interpolation at all times for high-quality varispeed playback, and the interface allows you to control the record-head separately from the playhead(each has their own independent start/stop, loop-start/end signal-inlets for specific control).... (this also means there is an additional de-clicking to take care of whenever the playhead crosses the recordhead; it will duck out the playhead smoothly momentarily until they are safely apart from each other(at a distance of 'fade' * 2))
additional 'virtual' playback boundaries - so you can limit playback controls to one part of a buffer~ while recording can go all over.... i didn't want to lose the 'append' functionality of karma~ altogether here, so this can help substitute for that(but you still need to sequence the signal-control very sample-accurately if you really want to replicate an 'append'-like functionality...); these can also be a quick way to create rolls, stutters, zipper-noise from a decreasing/increasing loop-window duration, etc.
'overdub' amount(for recording) is controlled by signal - allows for side-chain driven modulation or precise mixing
helpfile shows how to make it MC-compatible - so you can have as many playheads and recordheads all independently controlled as you'd like 😃 (the 'mc' tab in the helpfile contains an example with 64 channels playing back slightly offset in phases from the same buffer~)
currently only 'mono' and 'stereo' modes available - the way mono/stereo works is you have to instantiate the object with a 2nd argument for the type you want and then the object will always only play/record in that channel-setup.. for example, a rezer~ instantiated as "rezer~ bufname 1" is only capable of addressing mono-buffer~s, and you can't send a message to it to suddenly change it to address stereo buffer~s; if you want to switch between stereo and mono buffer~s, use a stereo form of rezer~(no 2nd argument defaults to stereo, so just instantiate like so: "rezer~ bufname") and then create your own switching mechanism at the output of rezer~ to send the left channel out to both channels when the buffer~ is mono and otherwise work as normal stereo.... (i haven't tried this, pretty sure that can work, though)
Everything you need(both pc and mac) is attached here, the helpfile will tell you much more... however, it's not the best help-file 😂 ...it's actually the patches i used for testing(when testing for de-clicking, writing low/bassy sine tones really fast into a buffer~ is a very good test 😁), so feel free to make patches which you think could demonstrate things better and maybe we can add them as tabs to the helpfile. If you want a quick demo, go to the 'xtra' tab and just turn on audio, click the toggle on near the top-left, and then listen and watch(it will fill the buffer~, mix with overdub from 3 different sources, and playback with sample-accurate rhythmic accuracy in mode 1(changes aren't registered til end of loops)). Sounds like a perpetual remix machine 😄
Some notes on possible areas of confusion:
The first most likely area of confusion for people: to retrigger, you simply send a different 'Starting Phase/Index', the difference in signal value at that inlet causes the object to jump to the new position... with this object, jumping is different than with karma~: it's a bit like when you jump you carry a loop window with you.... (the control is complex, but if you can do it outside the object i'd prefer to try to avoid coding it within... so just try things out and let me know what's possible). In addition, alternating positive and negative values of the same number is the way to retrigger the object quickly from the same starting point(example: say i want to quickly repeat-retrigger from the point exactly halfway in the buffer~, i need to set up the patch so that each alternate hit will send the opposite sign of that value in a signal like so: 0.5..... -0.5.....0.5 etc.), to retrigger the starting point of 0. you can alternate between 0. and 1.(in the opening tab of the help-file, the toggle labelled "RetriggerNumBox" does this, there are probably better ways to setup that interface but that's one easy way)
there is no speed inlet for recording(use the recording's on/off inlet, 1 for forward record, -1 for reverse record, and 0 for off.... that reminds me, there may be a possible click if you suddenly go from 1 to -1 for recording direction, keep me informed on what you find and i might look into trying to de-click that further for you)
in karma~, you could start a recording, and it would determine the loop's duration based on when you stopped.. try to do similar here if you can, and just keep me informed on how it goes(you might be able to set the loop duration to the whole buffer~ at first, start recording, then when you hit stop, sample-and-hold the value coming out of rezer~'s phase outlet and send it back to the duration inlet(you'll need to convert from signal-to-event and back to do this, but the duration inlet does not change things right away, so this might be doable).... in the future, i'm thinking i'll add stuff like this into additional 'modes' beyond 2('mode 3' might allow you to do this, also thinking of a 'mode 4' to make one-shot playback easier, etc... feel free to suggest other modes and things you think of...)
"what's happening with karma~?" - karma~ is Rodrigo's baby(his design) and so he's leading that into deeper territory, will leave it to him to inform you further about that, but rest assured it's still around and very much alive(i was having too much trouble returning to that level of complexity in terms of coding/development, i didn't expect to even get this much done on 'rezer~' but because this all flowed out of me in 2 weeks i am able to put it out now and it's likely i'll take a step back from all this for a bit now again too...).... rezer~ and karma~ can coexist nicely in the same ecosystem(each shines at different things)
TRULY SORRY FOR THE ULTRA-LONG POST! I'm not sure how to explain all this. There's likely so much more i need to explain(oh just remembered: there are extra messages for snooping internal states(to help me dev this), if you run into any problems especially where the record or playback position gets stuck or can't be turned off, hit the 'snoop' message and give me the info. it tells you in the Max window(when things get stuck, this message will help me know where things were internally... if the object does get stuck, generally you'll probably just want to quickly reload the patch, but sometimes i've actually gotten it to recover by slowing the playback speed really far down and then attempting to retrigger, start/stop, etc...).
Also, if you run into a crash, i don't need your full crash report, i just need the thread that crashed; you'll see a line like this at the top of your report...:
from there, scroll down in the report to the thread that crashed according to that information, and send me the information only related to that thread which crashed, the only part you need to send me will look something like this:
In particular, the most important thing i need from the crash report is just that line "rezer~.c:840", it tells me which line number the code failed at((in this report's case, it was the line '840', ...i've since fixed this crash, your line number will be different)...since i'm not a professional developer, nor do i develop Max from the OS-level, there's not much i can do with the other info. in the report or with your system specs so it can save us both time this way).
I'm just going to keep development here a bit more informal(but will ask for more specifics whenever i think i could use them), hope that's understandable. The most important thing I need from you when something goes wrong is your steps to reproduce(please try and remember exactly what you did, and let me know as many specifics as you can there).
Ok, that's all for now. Let me know any questions you have here on this thread, I'll do my best to keep up and keep trying to fix and improve things here, and I hope you all enjoy it immensely. Thanks for reading or checking this out 🙏
ALL ATTACHED HERE(.mxo file is for mac, .mxe64 file is for windows... both are 64-bit only):
USE THIS ONE, THE MOST CURRENT VERSION - V.008 - released May 14th, 2019:
Also, i started a github just for the C code(anyone trying to create similar in gen~ can use this) here.
MAJOR UPDATE! - v.008 - released May 15th, 2019
(it's the 2nd/last attachment to the top/original post, you'll see it labelled 'v008'
- again, the .mxo for Mac, the .mxe64 for PC, plus a new helpfile - all attached there)
For a more easy experience getting it to work like karma~ where you can use the recording length to set the window duration, i've added a "Mode 3"! The helpfile tab 'mode3' will show you how this is done(in addition will show you how to append using mode 0).
Added mode3 for setting playback duration by recording length
optimized interpolation(whole number speeds don't need interpolation so it's skipped in such cases)
forced inline functions(a small compiler-specific consideration, not a huge difference, but just in case it helps optimize further)
removed some unnecessary constraints
extra code for varying buffer~ sample-rates
removed unnecessary things like unused messages, etc.
added safer checks for reworking buffer~-access boundaries whenever 't_max_err' notifications are received/requested upon buffer~-modifications made by sources outside the external
created another tab to explain mode 3 in the helpfile
some known issues:
there's a possible crash if you leave rezer~ with playback or recording on while rapidly resizing the buffer~ it's referring to(i generally get this crash if i attempt to constantly switch the files in the buffer~ at a constant rate and more rapidly than once every 100ms, while i am recording/playing in a later part of a bigger buffer~ and suddenly replace the buffer~'s file with a shorter file thus resizing it much smaller, leaving playback/recording in a dangerous area), this crash is not easy to get if you are using the object normally and don't try to resize the buffer~ at a ridiculously constant and fast rate, but it's there, so to avoid it altogether, you can turn off playback and recording temporarily for a short instant before you resize-buffer~/load-another-file, and then turn it back on after the resizing/loading is completed(use buffer~'s right-outlet for this type of thing... it's what it's meant for and i wouldn't be able to de-click instant changes in buffer~ content from loading different files like that for you, so you probably want to turn it off and on around file-loading like this to avoid clicks anyways)... this issue is a bit out of my hands, but i'll keep looking for a solution to it.
in mode 3, or while attempting to append as in the helpfile with mode 0, when you finally wrap around the buffer~'s end, it will register the wraparound position at which the recording stops as the 'vend' point(which might not be what you want)... while this is not the intended behavior i don't believe it needs a fix(you can switch immediately into another mode upon wraparound or whenever, and set the 'vend' message back to wherever you want)
This will be the last major push for awhile, and because there is so much here now, i can't say i've thoroughly tested it all, so have a go, and enjoy. 👊
Thanks, All! I truly appreciate everyone checking it out so far🙏
[Edit: @Alfonso - karma~ is still alive, these two objects will serve different purposes in different ways and exist nicely in the same ecosystem... rezer~, in particular, is something i needed for my own music(sample-accuracy, plus 1x recording(for greatest fidelity in recording and original-pitch capture) combined with varispeed playback over it), so rezer~ will be my own individual project(limited to the work of one person: me), while karma~ will likely grow in the hands of different people... i was having difficulty returning to the complexity of karma~ in coding, i'm lucky to get this much on rezer~ done now so i can turn to focus on other things... therefore, karma~ requires a change in developer(from my point of view), while i am being pulled away by other things i need to focus on... i am still very proud and honored to have helped Rodrigo with karma~ and am excited to see where it goes(and from what i've heard Rodrigo is also really happy with how it turned out and will continue supporting its growth), and while i turn to focus on growing my own artistic output, rezer~ is a nice side-effect offering i have to give the community since it just happened to get finished so quickly.]