granary - a hybrid granulation engine

Built using vanilla MaxMSP and Gen objects.
(see latest post of mine below, for the newerist version)
Great work, Brendan! Thanks for sharing!
Brendan, this patch means a lot to me! I've been using grainstretch~ and absolutely loving it, and have been hoping to create a tangible 'instrument' for live-looping with access to any portion of the buffer, with time and pitch shifting available to the extreme. However, grainstretch~ was a somewhat mysterious external that I could not easily learn from nor add to, and I was concerned about it remaining compatible with my system.
My professor at university advised I try and build a grainstretch~ equivalent from vanilla max objects, in gen~, but this project had been difficult for me for quite some time. Finding your patch was like discovering a pot of gold. So elegant, so simple, so powerful! I plan to do quite a bit of hacking with it, and hope to create something really cool for live performances with this excellent tool to help get me started.
Thank you! Thank you!
Brendan I've really been enjoying your patch! After some study, I have a few questions:
Could you explain the meaning and characteristics of "de-correlated grain pitch and grain size"?
What are the blur and interonset parameters for? Blur seems to have a similar effect to "range". I have not come across those in other granular synthesis patches. You mention in the patch that "In true granulation synthesis, interonset duration and even shape is user-defined." This patch sure sounds like "true granulation synthesis", why do you say it's not?
Also, I have experimented with adding variable grainsize to the patch--I am hoping to produce highly rhythmic loops the length of the grain size (a la grainstretch~), but your instrument is exceptionally smooth no matter what I try. Is it possible to create very rhythmic grains without re-working the heart of the patch?
Hallo Jaren
interesting and pertinent questions; I'll try to address them in point form:
- de-correlated grain pitch and grain size: in many other granular playback/synthesis engines I have tried by other authors, changing the SIZE of the grain (by altering the phasor frequency) also changes its pitch, and vice-versa. I have simply made the grain size fixed, and a function of the pitch scalar. Effectively, changing grain pitch does not alter the size of the grain.
- the 'blur' parameter operates at around 0. ~ 5ms; you're right, it is a 'range' control, but I wanted really precise control at the sub-millisecond level in this domain, hence the two variables. This is because spectral artefacts are unavoidable if playback speed and pitch are anything other than 1. Now, I haven't done enough research to know WHY this is the case, it is a subjective observation from many years of tweaking this algorithm. Effectively, I use the 'blur' control to vary normal playback, and also for some cool comb-filter/AM type resonances when re-pitching or changing playback speed (when blur = 0.); the 'range' control is for more cloud-like textures, which leads me to . . .
- the difference between granular playback and granulation synthesis: "granary" is a hybrid engine - it allows relatively artefact-free repitching and speed control (manual scrubbing), but it also aspires to granulation synthesis textures, through the interonset, spread and range controls. If this was a true granulation synthesis engine, then we would expect control over grain size, window shape, interonset TIME, etc etc. These are the control parameters (amongst several others) fundamental to granulation synthesis (see Robert Henke's Monolake for example). Therefore, 'granary' reveals a hybrid approach. I wanted smooth playback/scrubbing AND some re-synthesis possibilities.
- yes, the fixed grain size is the blue [sig~ 80] inside my [jj.pitchSize] abstraction; mess with this if you like, for variable grain size, but you will lose the buttery goodness of smooth manula scrubbing; as for rhythmic grains, you will have to hack the interonset section of the gen~ abstraction, which I don't have time to do sadly. Try lowering the voice count of the poly~ (to 4 or 2), see how that sounds.
ps
Andreas Wetterberg recently asked about the blur/range thing too, so I hacked a cleaner version for him; here it is attached:
pps
please do point me to any artistic uses (performance audio/video) featuring 'granary'
Best regards
Brendan
And besides Henke's Monolake, here's another example of a highly sophisticated granulation synthesis engine, by Tom Maisey:
This one is particularly sexy.
And to anyone else watching: NO, I am not being typically humble; there are other really good grain engines out there, these are facts.
;)
Fantastic explanation, thank you Brendan that clears a lot up (and for an already exceptionally clean patch to begin with!)
Thanks for pointing me in the right direction for some tinkering, I've already learned a lot from this instrument
Hi Brendan,
Really love this. Especially the interonset.
One question. When turning scrubbing on and off, autoplay always begins where you left off. Where do I send a zero message so when I turn manual scrubbing off autoplay starts at zero?
I tried sending zero to the scrub between the r and s loc_GUI2 but if I add a multi slider set to continuous data output to track the position I can see that the position jumps back to wherever I left off. So it is being stored somewhere and I cannot find it.
Sorry if this is a simple question that I should have been able to figure out on my own.
edit: its the phasor. starts and stops where it left off. what message do I send to make it start at zero?
edit: ahhh, the second inlet of phasor resets the phase. (finger > flick > head)
Wil
Hi Wil
glad you like it; and also happy that you sussed out where to make your own changes - exactly! Resetting the phase of the scrub/playback phasor (it's inside [jj.scrub] I think) will force playback from 0ms. Here's a more refined and more functional version, which I think sounds even better (attached)
Best
Brendan
awesome brendan!
thanks for this. question: is this the newest version? jj.panning is in the folder (and different than the last version), but not in the actual patch.
wil
Well-spotted again. Yes, this is the latest version; I forgot to delete jj.panning. I found that panning inside the granulator was introducing additional and unwanted artefacts through low frequency amplitude modulation, so I removed it. You could reinstate it, outside the granulator if you need it.
Brendan
Nah I dont need it. Using a different type of panning anyway. Was just wondering cause it was different than the older version. Definitely don't want art (e) facts, those are for historians. We need fact free art!!
Thanks again.
And here's a further update (for the users above, I just increased the voice count to 24; hits my CPU for about 30 ~ 50%)
B
Final update as of 08/11/15, purely cosmetic with some simple GUI enhancements. Zip attached, and video demo here; as always patch is fully annotated for your learning/hacking pleasure.
https://www.youtube.com/watch?v=Ou5x9d5_Bts
Enjoy
Brendan
A very handsome piece of work, Brendan. Nicely done.
I can't even seem to find where to download the patch to be honest....? HALP
Read up two postings from yours - the bit that says "Final update...."
Right below Brendan's name, there's a .zip file. Click on it.
struggling to find the patch also, would love to have a look! can anyone point me in the right direction? Apologies if it's really obvious!
Hello!
Can you post the zip again? I can not find it.
thank you
Let's try this again. In your browser window, search for the string "Final update as of 08/11/15." See that .zip file listed under Brendan's name? Click on it.
hahah now I feel silly but to my simple mind it wasn't that easy! Thanks for getting back guys. Gotta love the C74 community.
Now time to tweak!
Peace.
Kev
Awesome Brendan, thanks a lot!
@Max
; )
Brendan
@Brendan
hi Brendan, some things...
1. anything I need to be aware of if I replace my existing granary objects? They're actually called "granny" (top level ) and subFin (gen patch), so I'm guessing that they are a few generations back!
2. Also - I use between 4 & 6 instances of granny in my patches, and at the moment I have to create separate instances of each of the elements (granny1, granny2 etc, subFin1, subFin2 etc) to allow for reach instance to have its own named buffer...
granny1 (top level patcher) contains named buffer & poly~ subFin_1, which contains the gen~ object & a few other bits & pieces. The gen object has been edited to refer to the specific buffer (in this case sampill_1 ).
If this was a patch using an external I would expect to be able to specify the buffer to use either using an argument or by sending a message to the object (e.g. set buffer ...). I can't see any way to do this with a gen~ - is it not possible? (i.e. do I have to keep creating multiple instances of the gen & surrounding patch?)
3. You mentioned you'd like to hear examples of pieces using granary . The sounds in this piece were created entirely using your object...
https://soundcloud.com/davidestevens/all-remains
(earlier pieces on my page will have been created using either granary or elasticx~. I know for sure that All Remains & Last Day used granary)
David
Hi David
thanks for continuing to use Granary, and thanks for your questions:
1. I can't recall if the version you currently have (subFin etc) uses my own abstractions (jj.pitchsize, etc.). Can I suggest that you download the zip, extract it and point Max at it. The user controls are now: pitch, pitch rand, grain shape, blur, interonset; playback speed, freeze, loop length and loop start. If these parameter controls are vastly different from the version of granary you have I can only apologise - I haven't been tracking changes and I am constantly improving it (I'm working on new elements as we speak !).
2. Addressing different buffers, for different audio file sources (which is what I guess you're doing) shouldn't be too much of a challenge, I'd need to look at the helpfile for buffer~ in a little more detail; maybe polybuffer~, or dynamic name changes to buffers.
3. Thank you so much for these, very intriguing to see how others use Granary.
Gimme a day or two
Best
Brendan
Mmm, yes. I will give that a try with my existing setup before I replace the older modules. As long as max doesn't complain about multiple modules with the same named buffer (before the pairing is changed by the message).
Any looplength setting other than 0 generates no sound. Is that normal behavior ?
Hi Stephane
this is not expected behaviour; looplength (0.0 ~ 1.0) determines how much of the audio is looped: at 1.0 the whole file is read, at 0.0 one 'grain' is read, effectively freezing playback and allowing loopstart to act as an alternative 'scrub' control. So be aware of any silences in your source audio.
I'll upload a short demo video asap.
https://www.youtube.com/watch?v=VgdEaJB9V0M
Brendan
Does this problem persist
"Any looplength setting other than 0 generates no sound. Is that normal behavior ?"
It seems to be a bug, after a few selection of loop length of 0, the patch stops generating sound for any other length except 0. After restarting the patch everything works for a while, then again the same problem occurs. The problem persist from the first time I played around with granary patch. I did an attempt to find and fix the problem, 'till now no success.
.r.
-
Hi
I just spent 20 minutes messing around with loop-length and loop-start parameters and have to confirm that I can indeed recreate this bug. Sorry guys; I strongly suspect it has something to do with the [jj.scrub] abstraction, which uses a separate single phasor to control playback speed/direction/length; the ramp often overruns the end of the buffer size, when loop start is anything other than 0ms into the file. Hmmm. No time tmoro to fix, but I will solve this over the weekend
Thanks for flagging this
Brendan
FYI
anecdotally, it seems the playback phasor is getting a freq value of zero from somewhere, and then refusing to accept further freq values. Should be simple to repair. I'm contemplating translating the 2 abstractions (for playback and grain size etc) into gen~ patches, maybe wrap as much as I can up into one single gen grain.
(Check me out, tracking bug fixes! Can I add the title Developer to my CV now hehe?)
Brendan
thanks for the fast replay! indeed when You reinitiate the phasor~ object in the jj.scrub abstraction everything works fine. very strange bug!
curious of the gen versions of the abstractions and yes you can add Developer to your CV. :)
.r.
-
Glad you like it, and solved your issue. I currently use only PD and Supercollider as I've abandoned commercial software for a while, so I can't maintain and update Granary. But I'll be back soon ;)
Hey Brendan,
Your patch was working fine (brilliantly actually, i absolutely LOVE it) and suddenly I'm not seeing any waveforms in the visualiser, not hearing any audio when I add files. It feels like there is a disconnect somewhere and I'm not smart enough to work it out as I'm a pretty newbie max user/coder. Any chance you know what's the problem?
Hi Brendan, I use Granary as my sample player of choice in a Max For Live audio effect found here
http://maxforlive.com/library/device/5024/grain-convolvor
It does Spectral Convolution of the Input audio with a Sample loaded into Granary.
I had to add a bypassable limiter because the results really can be preposterously loud and other times way too quiet. It depends on the Input and the Sample.

Hi Eric
I'm glad this 'older' work is still of value! The interface looks very neat. I did notice an issue with variable amplitude: when playback is normal, with no blurring, the amplitude is 'normal', but it then drops whenever blur is engaged. I considered using some sort of compensatory algorithm that boosted grains. Maybe have a look inside the poly~ or gen~ blocks.
I'd love to see a demo video of how you're using this ;)
(I have ported this to PurrData and I'm in the process of re-writing it for Supercollider, but I really miss gen~ as my licence has expired)
Brendan
@uresses
Sorry to have missed your comment; does this problem persist, and have you recently updated Max or your OS?
Brendan
It might be older, but at least it works in 64bit. I used to use Grainstretch~ and FFtease but I can't get either of those to work on Win10. I suspect they only work on macs now.
Unfortunately, Live10 Suite doesn't let you edit gen~. Also, I don't really have the DSP wherewithal to hack that kind of thing.
Also, here is a picture of my fix for the buffer overun problem mentioned back in Dec 10 2015
Basically, when the scrub counter becomes larger than the filesize, it resets the phasor to 0.
Nice!
re amplitude, could do something to boost/limit amplitude inside the poly~ ? I could send you my own voice subpatch, via PM if you need/want.
Brendan
[sent]