Polyphonic Synthesizer Tutorial
Ever wanted to play multiple notes (voices) of your synthesizer or sampler at the same time? In Max, this is accomplished by using the poly~ object. In this video tutorial, we'll get you up to speed on how to use poly~, so you can start making your own polyphonic instruments.
Cycling74 Max/MSP/Jitter Tutorials: Polyphonic Synth
- Stephen TaylorMay 09 2011 | 7:32 amThis is a fantastic tutorial - I had never thought of using swap and edge~ within poly~, thanks a lot!
- saturnin79May 11 2011 | 3:28 amGreat tutorial, but what about making the final patch downloadable so that we can study it further ?
- Ben BrackenMay 12 2011 | 1:01 pmHi Jeepee,Here is a link to these two patches:Enjoy! -Ben
- RichardJun 10 2011 | 11:24 amHey! Very excellant tutorial. Professional and clear. You should definitely do more! Thanks.
- lucycleSep 02 2011 | 2:58 amI've learn many things through this tuto, which is great indeed! I have nonetheless several problems : 1Β° the changes in the saved subpatch weren't always taken into account immediately in the main patch. 2Β° It doesn't work with a cycle~ instead of the saw~: the synth clips when the keys are released. 3Β° When I use the synth with a live.step sequence and through a makenote, I have tone bends when notes are changed. I still find this tuto is great, but I have some further work to do to have my own synth module. Thank you!
- irvnJan 30 2012 | 8:23 pm@2:22 the divider /127 is not created.. or at the least it is not evident what the instructor is doing I am using MAX6 and there is no /1`27. object that i can find.. that works anyway Can not the lesson be just a little less arcane for idiots like me?
- irvnJan 30 2012 | 8:40 pmthe sub-patch does NOT open upon double click, nor does a separate window open after selecting and "encapsulating" is this a preference, am I an idiot, or can you at the least explain without the glaring gaps in this tutorial?
- UncleChubbFeb 02 2012 | 12:21 pm@1diot8ox; I had the same problems. Through extensive trial and error, I found the solution to our problems. @2:22, you need to create a new object, and simply type in "/ 127." (no quotes). to open the sub patch, right click and de-select "edit". then, you can double click the box that says p and the sub-patch will open in a new window.
- Les StuckFeb 02 2012 | 4:14 pmThanks everyone for the good feedback. It looks like UncleChubb figured out that I was making a "/ 127." object at 2:22. Yes, the space between the object's name (/) and its argument (127.) is important. UncleChubb also figured out that the patch needs to be taken out of Edit mode in order to double-click a patcher to open it. If you're in too much of a hurry to switch modes, you can just command-click (Mac) or control-click (Win) to operate a patcher when it's in Edit mode.Lucycle, keep in mind that the synth_voice patch must be saved to disk before the changes are loaded into poly~. I tried swapping a cycle~ for the saw~ and didn't hear any problems. Also I tried feeding MIDI notes from live.step to the synth and didn't hear any portamento happening. Hmmm...maybe there's something else going on?Sorry some things weren't clear. It's tough being really clear without making the tutorial ending up being an hour long. :) I'll definitely keep your comments in mind for the future. Happy patching!
- RokwatnouFeb 25 2012 | 11:58 pmguys, i am really frustrated... whenever i try to rename the patch p into the name synth_voice it does not seem to accept it. I saved it in one folder and checked the filenames. Furtheron, on one pc it works when i leave it as 'p synth_voice' and i can add the poly~ infront, however on the othermachine, as soon as i change it to poly~ it opens up an empty patch! It seems so easy but i am doing something wrong...
- Les StuckFeb 27 2012 | 1:15 pmIt sounds like your patch is having a hard time finding synth_voice.maxpat. In the tutorial, both the main synth_patch.maxpat and synth_voice.maxpat are on the Desktop, in other words, in the same folder. Here's something you can try: make sure both patches are in the same folder, then close them both and reopen synth_patch.maxpat. Does it find synth_voice.maxpat?Keep in mind also that "p synth_voice" is a subpatch; its contents are part of the main patch. Once you drop the p, both "synth_voice" and "poly~ synth_voice" load the file "synth_voice.maxpat" from disk. For that reason, it must be in a location that Max can find.If you're really frustrated, go to menu item Options > File Preferences⦠to add a new folder for Max to search.
- RMar 05 2012 | 2:33 amthanks a lot for you reply Les Stuck, now i am pretty sure it is a bug. I created a new folder into which i save all patches and sometimes it works and sometimes when i rename a new object to the patches name saved earlier it opens up a new patcher window. Then i copy paste the content of the patch but saving again gives me the obvious 'there is already a file with that name' dialogue. It is funny that once the containt is copied across it acts like the patcher is supposed to act ( i can see all the in and outs but once i create a new object again and copy the exact name of the patcher into the new object it opens up an empty patcher. Little note, i am using maxforlive but that would not be a problem right?Thanks in advance
- LoganJul 13 2013 | 6:55 pmR: Little note, i am using maxforlive but that would not be a problem right?Exactly the problem I had. I made sure i was putting the synth_voice file in the same folder as the patcher in live (I did Show in Finder), it did nothing. It worked fine when I open the same patcher without running ableton and do it with both files on the desktop. I guess theres another step to it when you are using m4l? i'm a little bit new to this, so I don't know what that might be.
- Dan ShuteApr 13 2015 | 3:45 amHey I know I'm probably doing something really stupid, but my outlet on the 'poly~ synth_voice 1 @steal 1' box refuses to show, even after I save the new sub patch with the new 'in 1' and 'out~ 1'. Any thoughts? Cheers.
- brendan mccloskeyJul 18 2015 | 10:03 pmI predict that this question will fall off the end of the interwebz
- luvulongtimeJul 19 2015 | 6:40 am"Why does this patch not work using a Novation Launchpad?"I can confirm here. Not working with 6.latest either...
- mohamad kassemAug 15 2015 | 11:57 pmi have used your method but changed the saw~ object to a wavetable with an oscillator but cant get any polyphony and ideas ?
- UllsteinSep 16 2015 | 3:45 pmthanks for the very helpful tutorial. Unfortunately I cannot open the original patch when option clicking the title bar of the instance in poly~ . Any idea what the reason for that could be? ThanksHans Peter
- Ben BrackenSep 16 2015 | 7:40 pmHi Hans Peter,In Max 7, I would recommend using the 'Patcher Windows' icon in the lower left patcher toolbar. This should show you the patcher hierarchy.-Ben
- JD95Oct 09 2015 | 2:16 pmI've copied this tutorial exactly and no outlet ever appears on the "poly~ synth_voice 16 @steal 1" patch. Any idea why this is? Thanks.
- Ben BrackenOct 10 2015 | 3:56 amHi James,Do you see any errors in the Max window?Is the synth_voice.maxpat patcher in Max's search path? It will have to be in order for poly~ to find it.What happens when you double-click on the poly~ in a locked patcher?-Ben
- Alexander ShanovOct 31 2016 | 9:31 pmHey James Dalgleish and Dan Shute,I encountered the same issue but managed to solve it in a very simple way.After saving the sub-patch, restart the main patch and they should appear. You could also add the file extension after sub-patch name, it might make it easier for Max to read/find the proper files, so for instance: [poly~ adsrsubpatch.maxpat 16 @steal 1].This should solve your problem but if it doesn't, check and see if you have saved both the main and sub-patches in the same directory (folder/location) on your computer.Also to whoever cant access the sub-patch, your patcher needs to be locked in order to do so!Cheers!
- Alexander ShanovOct 31 2016 | 9:36 pmHey James Dalgleish and Dan Shute,I encountered the same issue but I managed to solve it in a very simple way.After saving your sub-patch restart the main patch. That should make the inlets appear. Additionally you could add the file extension to "poly~", as it might help Max find/read the file.E.g. [poly~ adsrtest.maxpat 16 @steal 1] If this doesn't work, check if you have saved both the main and sub-patch in the same directory(location/folder) on your computer.Also, whoever can't open their sub-patches, the main patch needs to be locked in order to do so.Cheers!
- Matt LamingDec 01 2016 | 8:25 pmHi, I've tried this and it works fine when the cycle is inside the poly~ but not when its outside? How can I fix this because I require it to be outside. { "boxes" : [ { "box" : { "maxclass" : "number", "id" : "obj-6", "outlettype" : [ "", "bang" ], "patching_rect" : [ 302.0, 376.0, 50.0, 22.0 ], "style" : "", "numinlets" : 1, "parameter_enable" : 0, "numoutlets" : 2 }} , { "box" : { "maxclass" : "ezdac~", "id" : "obj-5", "patching_rect" : [ 485.5, 574.0, 45.0, 45.0 ], "style" : "", "numinlets" : 2, "numoutlets" : 0 }} , { "box" : { "maxclass" : "newobj", "text" : "*~", "id" : "obj-4", "outlettype" : [ "signal" ], "patching_rect" : [ 509.0, 339.0, 29.5, 22.0 ], "style" : "", "numinlets" : 2, "numoutlets" : 1 }} , { "box" : { "maxclass" : "gain~", "id" : "obj-2", "outlettype" : [ "signal", "int" ], "patching_rect" : [ 497.0, 407.0, 22.0, 140.0 ], "style" : "", "numinlets" : 1, "parameter_enable" : 0, "numoutlets" : 2 }} , { "box" : { "maxclass" : "newobj", "text" : "cycle~", "id" : "obj-1", "outlettype" : [ "signal" ], "patching_rect" : [ 397.0, 295.0, 45.0, 22.0 ], "style" : "", "numinlets" : 2, "numoutlets" : 1 }} , { "box" : { "maxclass" : "newobj", "text" : "poly~ PLYPHONIC 16 @steal", "fontname" : "Arial", "id" : "obj-152", "outlettype" : [ "signal", "" ], "patching_rect" : [ 447.75, 195.832977, 169.0, 22.0 ], "style" : "", "numinlets" : 5, "fontsize" : 12.0, "numoutlets" : 2 }} , { "box" : { "maxclass" : "message", "text" : "midinote 70 0", "linecount" : 2, "fontname" : "Arial", "id" : "obj-138", "outlettype" : [ "" ], "patching_rect" : [ 169.036987, 190.332977, 50.0, 36.0 ], "style" : "", "numinlets" : 2, "fontsize" : 12.0, "numoutlets" : 1 }} , { "box" : { "maxclass" : "dial", "varname" : "S[1]", "id" : "obj-129", "degrees" : 300, "outlettype" : [ "float" ], "patching_rect" : [ 628.120972, 78.795998, 40.0, 40.0 ], "size" : 1.0, "style" : "", "numinlets" : 1, "presentation" : 1, "parameter_enable" : 0, "presentation_rect" : [ 1144.333374, 528.0, 40.0, 40.0 ], "floatoutput" : 1, "numoutlets" : 1 }} , { "box" : { "maxclass" : "dial", "varname" : "R[1]", "id" : "obj-130", "degrees" : 300, "outlettype" : [ "float" ], "patching_rect" : [ 674.120972, 78.795998, 40.0, 40.0 ], "size" : 3000.0, "style" : "", "numinlets" : 1, "presentation" : 1, "parameter_enable" : 0, "presentation_rect" : [ 1188.333374, 528.0, 40.0, 40.0 ], "numoutlets" : 1 }} , { "box" : { "maxclass" : "dial", "varname" : "D[1]", "id" : "obj-131", "degrees" : 300, "outlettype" : [ "float" ], "patching_rect" : [ 579.120972, 78.795998, 40.0, 40.0 ], "size" : 1000.0, "style" : "", "numinlets" : 1, "presentation" : 1, "parameter_enable" : 0, "presentation_rect" : [ 1100.333374, 528.0, 40.0, 40.0 ], "numoutlets" : 1 }} , { "box" : { "maxclass" : "dial", "varname" : "A[1]", "id" : "obj-132", "degrees" : 300, "outlettype" : [ "float" ], "patching_rect" : [ 517.25, 65.486, 40.0, 40.0 ], "size" : 3000.0, "style" : "", "numinlets" : 1, "presentation" : 1, "parameter_enable" : 0, "presentation_rect" : [ 1056.333374, 528.0, 40.0, 40.0 ], "numoutlets" : 1 }} , { "box" : { "maxclass" : "newobj", "text" : "prepend midinote", "fontname" : "Arial", "id" : "obj-27", "outlettype" : [ "" ], "patching_rect" : [ 258.0, 115.000992, 134.0, 27.0 ], "style" : "", "numinlets" : 1, "fontsize" : 16.0, "numoutlets" : 1 }} , { "box" : { "maxclass" : "newobj", "text" : "pack", "fontname" : "Arial", "id" : "obj-107", "outlettype" : [ "" ], "patching_rect" : [ 40.549004, 86.795998, 44.0, 27.0 ], "style" : "", "numinlets" : 2, "fontsize" : 16.0, "numoutlets" : 1 }} , { "box" : { "maxclass" : "newobj", "text" : "notein", "fontname" : "Arial", "id" : "obj-110", "outlettype" : [ "int", "int", "int" ], "patching_rect" : [ 68.5, 20.5, 54.0, 27.0 ], "style" : "", "numinlets" : 1, "fontsize" : 16.0, "numoutlets" : 3 }} ], "lines" : [ { "patchline" : { "source" : [ "obj-4", 0 ], "destination" : [ "obj-2", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-27", 0 ], "destination" : [ "obj-152", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-27", 0 ], "destination" : [ "obj-138", 1 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-2", 0 ], "destination" : [ "obj-5", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-2", 0 ], "destination" : [ "obj-5", 1 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-152", 1 ], "destination" : [ "obj-6", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-152", 0 ], "destination" : [ "obj-4", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-152", 1 ], "destination" : [ "obj-1", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-132", 0 ], "destination" : [ "obj-152", 1 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-131", 0 ], "destination" : [ "obj-152", 2 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-130", 0 ], "destination" : [ "obj-152", 4 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-129", 0 ], "destination" : [ "obj-152", 3 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-110", 0 ], "destination" : [ "obj-107", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-110", 1 ], "destination" : [ "obj-107", 1 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-107", 0 ], "destination" : [ "obj-27", 0 ], "hidden" : 0, "disabled" : 0 }} , { "patchline" : { "source" : [ "obj-1", 0 ], "destination" : [ "obj-4", 1 ], "hidden" : 0, "disabled" : 0 }} ], "appversion" : { "major" : 7, "minor" : 2, "revision" : 4, "architecture" : "x64", "modernui" : 1 }}
- Matt LamingDec 01 2016 | 8:27 pmHi, Ive tried this and it works when the cycle is inside the poly~ but not when its outside. How can I fix this I need it outside.
- vichugDec 02 2016 | 4:14 amwhat are youtrying to achieve Matt ? the very essence of the poly~ is to multiply automatically the number of simultaneous voices of whatever you put inside the poly. So if you put something outside of it, you won't have polyphony. That said, if you want to share a patch using poly~, you need also to provide the abstraction that's inside the poly - remember it's a separate file
- ErnestDec 02 2016 | 5:29 amvoice clipping is actually very difficult to avoid. Another problem is that transpositions affect all the playing notes, rather than just new notes. I designed a patch to overcome these problems, which is part of my larger work Godel. You can find the simpler version here:
- Sonia BeckwithJun 06 2017 | 11:38 pmHello,I am trying to use [key] and [keyup] to trigger this patch instead of note in. I created a set of sine frequencies that relate to the keys on my computer keyboard.I am very new to max so please excuse my lack of know-how, any help is much appreciated!
- Matthew GrouseFeb 21 2018 | 7:43 pmThanks for this! I'm writing a piece that uses two keyboards (using cycle~ instead of saw~)Any ideas how I can have one of the keyboards at equal temperament and then keyboard 2 an exact replica but every pitch 'tuned down' a quartertone? e.g C1 on keyboard 1 is mirrored as C1/4b1 on keyboard 2.. Also, any ideas on getting rid of clicks? It's particularly bad when using cycle~ instead of saw~Cheers!
- Noah McrobbieOct 25 2018 | 10:51 pmI've been trying to do this with key and keyup objects to mapped to MIDI numbers and then sent through poly~ but it seems that once i try any sort of polyphony, at least one of the notes I've pressed never shuts off. This is also part of a microtonal synthesizer that I am building in Max and I have found that once i run it through poly~, even if I have pack and unpack set to send and receive floats (for the quatertones), it doesn't recognize the note values in between frequencies.(yes, i'm aware my key and keyup patching is a total mess to look at) If anyone could help me with this, it'd be greatly appreciated.
- PSGJan 31 2021 | 3:14 pmCan you think of any reason why thispoly~ won't create polyphony? I followed your tutorial and made your little poly synth work. But when I tried to apply the same method to an already complex mono synth I had created, the thispoly~ won't make it a polyphonic synth. I have loaded 6 instances of the synth patch. The thispoly~ outputs do confirm that. It is hooked up properly to an ADSR inside the synth voice. The ADSR works because I can hear it working. Still, thispoly~ will *not* make polyphony for me. I have many different ADSRs doing different things at different places within my original synth patch. Does that have anything to do with it? I tried recreating the thispoly~ many times and hooking it up to different ADSRs within the patch, all to no avail.
- Roman ThileniusJan 31 2021 | 6:39 pmnobody said thispoly~ would have to do anything with polyphony.
- π½It Wβs βlienzπ½Feb 01 2021 | 5:53 am(dang, sounds like they could've used some Izotope DeEsser back in 2011 0:57 - "sssssssssingle patch chord for note messsssssssagesssssssssssssss"ππππ) @PaulSanGregory thispoly~ is used to keep track of individual voice status, and change mute/busy status. yes, if you have many ADSRs, it might be the place to look, but mainly, if you're registering 'busy'-state with a signal from adsr~ as in the video, it might not be working if the particular ADSR you hook it up to does not release all the way back down to 0(another way to ensure everything works is to send "mute $1" and "busy $1" messages to thispoly~ explicitly, according to exact millisecond durations of notes)... you might want to go through the original documentation/reference tutorials on polyphony to complement what you learn from the video in order to have a more thorough grasp of how to accomplish polyphony in these different contexts: https://docs.cycling74.com/max8/tutorials/11_polychapter01 (or you could start another thread and post your patch there, people can take a look and give you specifics) @AndrewYatsuhashi you can attach 'receive' objects to the parameters of adsr~ within your poly~ patch, then in the main patch use 'send' objects of the same name to control those parameters(if you wanted to do this individually by voice, you could use the voice-specific 'target' messaging described in the poly~ helpfile under the 'voice messages' tab there)
- PSGFeb 01 2021 | 8:36 amAs you suspected, Raja, it was the "sssssssssingle patch chord for note messsssssssagesssssssssssssss" thing. Believe it or not, I had noticed that part already and tried wiring up with a single patch chord at one point, but something else must have been out of whack at the time because it still didn't work for me then. I tried it again just now, though, and it seems to work. Hopefully I'm not currently experiencing a fluke (!). Thanks for your reply...