Tutorials

    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


    by Les Stuck on
    May 5, 2011 9:05 PM

    • Stephen Taylor
      May 09 2011 | 7:32 am
      This is a fantastic tutorial - I had never thought of using swap and edge~ within poly~, thanks a lot!
      Share
    • tommy's icon
      tommy's icon
      tommy
      May 09 2011 | 12:19 pm
      great! more tutorials please! thx
    • saturnin79's icon
      saturnin79's icon
      saturnin79
      May 11 2011 | 3:28 am
      Great tutorial, but what about making the final patch downloadable so that we can study it further ?
    • Ben Bracken's icon
      Ben Bracken's icon
      Ben Bracken
      May 12 2011 | 1:01 pm
      Hi Jeepee,
      Here is a link to these two patches:
      Enjoy! -Ben
    • fleeger's icon
      fleeger's icon
      fleeger
      May 14 2011 | 2:22 pm
      Very clear! Excellent tutorial. Thanks tons!
    • PapyLives's icon
      PapyLives's icon
      PapyLives
      May 21 2011 | 8:57 am
      Thanks for this tutorial ! When an another one ???
    • lauweo1989's icon
      lauweo1989's icon
      lauweo1989
      May 25 2011 | 6:25 am
      Thanks you!!!
    • Richard's icon
      Richard's icon
      Richard
      Jun 10 2011 | 11:24 am
      Hey! Very excellant tutorial. Professional and clear. You should definitely do more! Thanks.
    • jhaysonn's icon
      jhaysonn's icon
      jhaysonn
      Jul 30 2011 | 2:42 pm
      great tutorial man. bravo
    • lucycle's icon
      lucycle's icon
      lucycle
      Sep 02 2011 | 2:58 am
      I'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!
    • irvn's icon
      irvn's icon
      irvn
      Jan 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?
    • irvn's icon
      irvn's icon
      irvn
      Jan 30 2012 | 8:40 pm
      the 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?
    • UncleChubb's icon
      UncleChubb's icon
      UncleChubb
      Feb 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 Stuck's icon
      Les Stuck's icon
      Les Stuck
      Feb 02 2012 | 4:14 pm
      Thanks 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!
    • Rokwatnou's icon
      Rokwatnou's icon
      Rokwatnou
      Feb 25 2012 | 11:58 pm
      guys, 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 Stuck's icon
      Les Stuck's icon
      Les Stuck
      Feb 27 2012 | 1:15 pm
      It 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.
    • R's icon
      R's icon
      R
      Mar 05 2012 | 2:33 am
      thanks 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
    • Logan's icon
      Logan's icon
      Logan
      Jul 13 2013 | 6:55 pm
      R: 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 Shute's icon
      Dan Shute's icon
      Dan Shute
      Apr 13 2015 | 3:45 am
      Hey 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.
    • Morgan Rodabaugh's icon
      Morgan Rodabaugh's icon
      Morgan Rodabaugh
      Jul 18 2015 | 8:19 pm
      Why does this patch not work using a Novation Launchpad?
    • brendan mccloskey's icon
      brendan mccloskey's icon
      brendan mccloskey
      Jul 18 2015 | 10:03 pm
      I predict that this question will fall off the end of the interwebz
    • luvulongtime's icon
      luvulongtime's icon
      luvulongtime
      Jul 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 kassem's icon
      mohamad kassem's icon
      mohamad kassem
      Aug 15 2015 | 11:57 pm
      i have used your method but changed the saw~ object to a wavetable with an oscillator but cant get any polyphony and ideas ?
      Screen-Shot-2015-08-16-at-00.31.58.png
      png
    • Ullstein's icon
      Ullstein's icon
      Ullstein
      Sep 16 2015 | 3:45 pm
      thanks 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? Thanks
      Hans Peter
    • Ben Bracken's icon
      Ben Bracken's icon
      Ben Bracken
      Sep 16 2015 | 7:40 pm
      Hi 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
    • JD95's icon
      JD95's icon
      JD95
      Oct 09 2015 | 2:16 pm
      I'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 Bracken's icon
      Ben Bracken's icon
      Ben Bracken
      Oct 10 2015 | 3:56 am
      Hi 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 Shanov's icon
      Alexander Shanov's icon
      Alexander Shanov
      Oct 31 2016 | 9:31 pm
      Hey 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 Shanov's icon
      Alexander Shanov's icon
      Alexander Shanov
      Oct 31 2016 | 9:36 pm
      Hey 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 Laming's icon
      Matt Laming's icon
      Matt Laming
      Dec 01 2016 | 8:25 pm
      Hi, 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 Laming's icon
      Matt Laming's icon
      Matt Laming
      Dec 01 2016 | 8:27 pm
      Hi, 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.
      poly.maxpat
      maxpat
    • vichug's icon
      vichug's icon
      vichug
      Dec 02 2016 | 4:14 am
      what 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
    • Ernest's icon
      Ernest's icon
      Ernest
      Dec 02 2016 | 5:29 am
      voice 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:
    • vichug's icon
      vichug's icon
      vichug
      Dec 02 2016 | 10:24 am
      Hey Ernest, your page displays an error 403 (forbidden) for me
    • Sonia Beckwith's icon
      Sonia Beckwith's icon
      Sonia Beckwith
      Jun 06 2017 | 11:38 pm
      Hello,
      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 Grouse's icon
      Matthew Grouse's icon
      Matthew Grouse
      Feb 21 2018 | 7:43 pm
      Thanks 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 Mcrobbie's icon
      Noah Mcrobbie's icon
      Noah Mcrobbie
      Oct 25 2018 | 10:51 pm
      I'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.
    • Andrew Yatsuhashi's icon
      Andrew Yatsuhashi's icon
      Andrew Yatsuhashi
      Sep 29 2019 | 10:52 pm
      How can you change the adsr parameters from the main patch?
    • PSG's icon
      PSG's icon
      PSG
      Jan 31 2021 | 3:14 pm
      Can 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 Thilenius's icon
      Roman Thilenius's icon
      Roman Thilenius
      Jan 31 2021 | 6:39 pm
      nobody said thispoly~ would have to do anything with polyphony.
    • 👽It W∆s ∆lienz👽's icon
      👽It W∆s ∆lienz👽's icon
      👽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)
    • PSG's icon
      PSG's icon
      PSG
      Feb 01 2021 | 8:36 am
      As 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...