Granular Synth Problem (poly~)
I have a question concerning a polyphonic granular synthesizer I am trying to build.
The architecture of the instrument is quite simple and it is basically driven by a grain generator, which is packed into a poly~ object in order to obtain multiple grain streams. In essence it is very similar and based on to the granular tutorial patcher which can be found here: http://cycling74.com/wiki/index.php?title=MSP_Polyphony_Tutorial_3:_Granular_Synthesis
Now, I have tried to nest this polyphonic grain generator into another poly~ abstraction in order to obtain an individual pitches per key that is pressed on the midi keyboard.
However, whatever I try it remains monophonic and fails to deliver the desired results.
I have uploaded the patch with all necessary externals and abstractions. On the top level, you can find the poly~ object, which hosts the "tr_notepoly_0.6" abstraction, which in turn hosts the "tr_grains_0.6" (the grain generator) abstraction.
When I replace the "tr_grains_0.6" poly~ object inside the "tr_notepoly_0.6" poly~ object with a normal saw~ oscillator, the patch behaves as expected. Whenever I hook up the "tr_grains_0.6" poly~ object, the patch is monophonic.
Is there anything I have overlooked? Does anything go wrong with muting and unmuting the poly~ instances in the embedded abstraction?
I would call myself an intermediate user of Max, but I think I am stuck here and can’t find the solution to this problem. Maybe someone of you may find the time to look at my patch and tell me what’s going on?
I am aware of the discussion in this thread http://cycling74.com/forums/topic/poly-within-poly-for-polyphonic-granular-synth/, where it is the overall opinion to avoid poly~ inside poly~. However, this is just for complex control reasons, which I seem to have control over.
Some help would be much appreciated!
Thanks in advance,
Nesting poly~’s in poly’s may indeed introduce problems. But I have used it quite a bit.
I’m not sure what’s causing your problem. It’s a pretty big patch. But you should take note that the send object sends data globally. So the data going through your "send pitch.min" and "send pitch.max" are sent to all poly patches. Maybe this is your problem..
Thank you very much for your hint, and sorry for the late reply. I had kind of a busy weekend.
I suspected something along these lines. I now had some time to play around with getting discreet pitch information into the nested poly~ and, tadaaaa, it works.
I now have some other issues with voice allocation in the top poly~ object. But this is peanuts.
If anyone’s interested, I’ll post and share again as soon as I have something worth showing.
Best and thanks again!
I think there’s another problem with your patch. When you send a note-off to your notepoly patch the nested poly patch with the grains is muted automatically. This way you have a grain that is turned off mid-ramp. When you unmute that notepoly patch it finishes that grain first. The problem is that this particular grain is pitched to the previous note.
I have had this problem before. But it may be that this is not an issue in your case.
Anyway to solve this you’d have to stop sending triggers for the grainramps at a note-off message. Then you wait for the last grain to finish and mute your notepoly patch.
That’s exactly what I’m dealing with at the moment. I am experiencing the exact symptoms you are describing (the nested poly patch finishes the last grains with the previous pitch as soon as I unmute the notepoly).
Your idea seems to make good sense to me. However, stopping the triggers for the grain ramps at the moment of the note-off message would prevent me from having slow releases from the ADSR envelope. I was more thinking of stopping the triggers for the grain ramps as soon as the ADSR finishes (detectable from the mute outlet) and only then muting the notepoly.
The only problem then would be how to detect the moment when the nested poly finishes the last grain, which would be the trigger for muting the notepoly. Would you have any idea how to achive this?
Thanks for your input, Dave, you were a great help with this!
I’ve used a silence detector for this before. You may need to tweak some parameters to make the silence detector work properly.
----------begin_max5_patcher---------- 1193.3oc0Y18iZaDD.+Y3uhsV8oJBc+veQkhTSSnmNonjJt6kppJzBdiOm3O P1KWuznve606t1bFXA7AXi6Cm47501y7amY1YF+s98Llk7DKy.7Kf+Bzq225 2qmbHw.8JNumQD8o4gzL4zLlmDEwh4FCTWiydhKG+Mu6tIkCF3IGJY1mekqc 4feJIlGSiXpYmFPCA+VRn25Km5OSbI3PXwHwKiBhCYb46EU4ojE7uxmBZi4l rjWN4xQWP4yeHH1eZJaNWojnQV42Df3n9Yj3HxcHD72ha4686KNLnlrHl8O4 53NnHWRVAP5fgYMgQSp5lVP4OvmU8h6Ii9HyaZtfleKSobdZvrkbk0Qu0Dnm g3JSKMCDxug7BR1cgH3OsRG8HmB8vuD5UhZ0P7utfoPmQVfeLMzXMpN.dgJK K7PqKuk0hjvutBHNZ5mRChyzgITGvHifcE5+H6lv+JLg5MiF6qS4gMtxuWaD oHcHKDSWzPWBgfHC.VXImrrZB.EId2fnbmW.TCjbbudP5f.xBBeFPJz3bd.J hkkQ8Y6RHAazEh1w45Ej4vFOl6vFShjM1mHa12N4+wGe+eB98ONAbyj2b6Gt SGjr5lapiTFKP7YYyjuoGOIVmZCOniwkJLQg1fUKxXX4wK5h76Fe+32dO3ta e+3O71wZTVa2t0Zrok4PRg8eQ1aibNq048gFoYO39I2dyMimny72taZ9irUT wsI1R4Gdk1vkVtWuvkAhzOOtez5LRZhDx7oblNrzU2EoL1BtAYRDimljK3Pv uRmyCdT+FslWQKmiFBtH1aoEDzoQRB4GwZ3Bwtql.RdwxkAfQpZHKrerur1O +L.gcFpAM3QWOz7o7hNNb3FxHISTGImWgOeIKLvikpiAqcaVPSyI.mkNkESm ExptIQThGaqTS1EHap4kitHkkkuqHkGjDWQ6jZkR0T5lEoRmCzFadvwCQ6nx f0Zmm6kyZh+PPlrrYcvjz3EBgOSBsQZ+tMXMiTurzU45A.BP4oaB0U3H5jb. sdI7x7HcfYP0+S9WM7IQpjnGQZBvsmT.Pv+OTHYSlGPd3oEYQII7GVkaT45h 0YRgOEJQZqd5UsnCShxuCAaD2uYY5hPgPWuV07R4SQiOMaB7v77YZ4C95EAW 0Bx5z2upTprKwMAkd8qWosgeHyNcmy2fOphXOy7mVPiYg5ZOL9EzAmREcFc9 W7SSVF6Uct5JtxEV4aKUVpkI7BqDNj1PIPUUBSqKrNXa2j5P0RUZ5UC61X0n n0Nk0iR11uP5cYDFDu82xU9HEiuolkkrLcdoGZ42VC7b97drLdPrrFfpSxbi I8PfmGKtpZ4EjIpDQpTPsLttxiHSyiKOBgF0NxCpFxCt0vCtFRCp8VsDe0si JOhurRKIOhOv0wWsHsq0L9X7ws83iSGiOcL6mZsdIZTWa4tWmngaExrIkGq5 X+3.aM4wrN96Rgtc1sXKSi8HOsm+tUs4Cr6vGT6Y+HZpZESi8DOr87u1Zq68 vm1KcCDttqWmh+kJ4U5hEOxRyJdlRQIOA7OmjJN0df7zfX0oxDlMRYOFTNeY OFMno44OyySddYppB2mbsM5KdOeu++YO+ZkO -----------end_max5_patcher-----------
Thanks a million for that! I’ll have a look at it as soon as I get the chance. Might be another two days until then, though.
I looked at your silence detector and played around with it for a little while. Brilliant idea and I wouldn’t have come up with it ;-)
I now finally got the polyphony to work properly. The only tradeoff I had to find is between the rampsmooth value (the 8820 samples you suggested works quite well) and the grain density. When the density parameter is quite low and the grains short, the interval between grains becomes larger, possibly larger than the rampsmooth value and, as a consequence, the voice is muted. I now found a sweet spot between minimum grain density and grain length value so that the voice won’t be muted even at the lowest settings.
Thanks again for the inspiring input, Dave! Without you I’d still be stuck.
If anyone’s interested, I’ve uploaded the final result (I have started to rebuild the surrounding patch to make it a bit tidier, so the lfo feature for scrubbing through the sample is still missing).
Maybe you don’t need the silence detection. You can also try to send the bangs from the right outlet of the line~ object through the gate to thispoly~. The same line~ object that mutes the grain poly~ patch.
I’m glad I have been of some help to you.
Yes you have indeed, thanks again!
I now had some time to experiment around with the patch over the weekend. And I’ve had the same idea before. However, the silence detector is actually the better solution to solve the problem when the interval between successive grains becomes larger.
When there is a larger interval (no grain playing, but the next is supposed to be fired) the parent poly~ patch is muted immediatly. With the silence detector I am able to introduce a slight delay (rampsmooth rampdown value) before the bang is sent.
I am now up and running with quite a solid polyphonic granular patch. I am just working out minor details (e.g. to prevent sending additional bangs into the nested poly~ patch at the moment of the note-off message). I’ll post and share as soon as it is done.
One more thing, just out of interest: I turned the instrument into a Max For Live patch and noticed that at lower settings (5 – 10 Hz) of the density parameter (a phasor~ object triggering a series of bangs), the bangs triggering the individual grains is much more regular in the Max For Live device than in Max6 standalone. Any idea as to what is the cause for this? Is it the max scheduler (I read some stuff about it but haven’t actually fiddled around with it at all) versus the handling of timing in Live? Or is it something else?
I’m not sure but I understood that the scheduler is automatically in overdrive in M4L. In Max standalone you can set it to overdrive manually. You can check the box in the audio status window.
OK, thanks Dave. And sorry for the late reply, I didn’t have a chance to check back lately.
I have the patch up and running now, but it’s a huge CPU hog with high density settings and more than 2 voices playing ;-)
It works and makes beautiful sound textures, but it’s not easy to balance playability and CPU usage. My idea is now to build myself an external that then replaces the innermost grain poly~. I have looked around for ready made externals (Nathan Wolek’s Granular Toolkit and others), but none seem to do what my lowest level poly~ does and with all of them I would need to have 2 levels of poly~.
I’ll be off learning C, then ;-)
Thanks again for your help, dave!
You may also want to check out the Robert Henke Granulator 2 which (I think) uses gen~ inside poly~ and is very efficient.
I have looked at Robert’s Granulator (version I and II) closely and it doesn’t granulate the way I wish. I also checked for other externals and none of them do what I want them to do.
I am really learning to code in C right now, I wanted to do this for a long time. I’ll post back as soon as I have something useful, could be a while though ;-) I know exactly what it should do, I just need to know how to build it.
Thanks for all the input in this topic. I’m not sure if I should post the synth discussed here until I have something more efficient, it’s really a CPU hog at the moment.