Hi! I’ve been very slowly building a polysynth in Max. The goal is for me to learn more about working in Max and with digital audio signals in general, and also to make something that I’ll enjoy using in my own music. I finished a “version zero” a few months ago while working with @jasonw22 for LCRP, and I’ve been slowly working towards a version one.
I’m actually still a ways off from finishing, but since I do have something to share, I figured it might be fun to start a thread about it, and maybe if I’m lucky learn from your feedback about it, ala @billyhologram’s Nearness thread.
The high concept for the synth is to make something inspired by the sounds of early digital music like the Commodore64 or Yamaha FM chips in old cell phones, but without trying for fidelity.
The thing I have to share with you is a
gen~ patcher containing (among other things) a variable-slope triangle wave oscillator.
copy me into a Gen patcher!
----------begin_max5_patcher---------- 2107.3oc0ZszaiaCD9bxuBBeJwINgj5cebHIEs8xBDflKEaVrPQlNQExhpRz qR1E6+8RNjRVNwVRtVQEc2XYMiH4vuYFQ9QR+siOZxC7mYESP+.5iniN5aGe zQfJkhiLxGMYY3yQIgEPwlDwWtjkJlbt9YB1yBPeY3WXK34KQErDVT8ySWsL NMgIfJSLJimCUg+veMyBWUxrPQzSwoO94bU0gdD04B74H+.a0WDGr5Kp7J5S qac9JQUyiUJ+9wGqtb9ABmrUIELTY7bwS8EJT+VfhqkmFKiOT90OfhSmydt5 AIworH9pT3ozptbNqPV4PQLO8yasDcBe21hj1AW3bNRGIs.mfk0Xg9bEpPu2 v2pa3SFe3qvk.06TXZKffPs0ffrFEiTJ7hb1euhkF8B5je+qm1azPZAM9dJv PgqAj2ArjxJkch2.koUZzMu3kLltCMYRSiuFXz2BLhWa4Z3fK7f3jOfPHyiR 2I1HCG1hSQt6K7vaAdsNRhLLQUvCCSNP8gqiE7bFB3Y0QzSgNqwFbCQdYaS. RBfALrcAHMhIkCAvnNcfLHizKXrwVzKQIrciuy2IF21nk18.idvT.VtcjWRG zW5rFhW5ZalMWafbFQgn2o25h3yYpRXZvE7TQZ3R.GS9.KMg2CLppzhvHVSH tAts1BtIMMYQ7WgZST.c2AaOXzGGJ3U77gAZs872sCwnUARvxWdIJ6ovB184 2mlg9YI+SxOptuRuTQTNSMUuR6cXnHTnH2QkBzo2g0RVRIqJIY0KBWlkvJPY rb0mX9b0CtU0BjKMEq5ir32qIxe+DMUdk1RvXVPIuRYqKKg6uFt+jxYjSA4a jx3Kbld0zqA4eQofHUXrxsDo7MSu0Ho512RpEU86aoRwKIz5NU7BzIYneBUd pR5afZQkx6vmpUXzeuP5gU135oYnYxqxNvLDQ94VqoY5+qaYw20ewTKYot4n 8q4NS5rW2fpVmZt8L.sRLo0eCnRM46zap7A6vzV6ORjMcsgmgrWa3yPdSuAT ZIo0rCSucycETsqLlqYsfKUUzTsLUhgpBklR1H7T1V7QZlxJ6bF3QUvpr9ue DsCWUYagoW2pyLwo0sqwkUIMqNbYd3MZscFwJaKj0E3LILq6R1M6DyzAOk98 N5cstAt1X45poCdvG35jgatlyFBt4sQBxAlf4+.hBRG39hssPQfz1l0XAKhJ vUiM2QkVt8.vPvqaromPbLYkq2LMdNhtuHbKbAb5DgDr9aWxHtvi8GaaI0zt 625vXMprFOrIa00u304VgZ0i3iKj7Y4zAFv+OhhJEu+TT0gTJ0jsZqeuDOLL TWu0uuluXO4vtG7T6ftqHOLsHVsqjnLdxKo7kwgInHNawh3nXosKpIedxsXI cySujtl.pVEn0sY+OgWhVDmWH1IoTYgdf8nbj0xXwSnmhe7oYB9LU8V2ipKI zTFD2SNsyNAn5cpjRibx8xM4DnberHd57MZy9wtkNsQKK4LBhRApgNalzanr HPLx4M1U7Tbdal0pW3ogU0bYqsphGzasprQxjiTHcu6jTjrTQ7kYrzhPACsP NifjVDewhBl3UckxsR1csUTAysP+UC9Bj7OwSLz73BQXZjzT47kUZjwDQb5p XwKMoLOaSBy6NgnUVzmTwgrJm30vn67hV4SOSkYroIrLZLAJH8n7ee9wN4QW 9F3MaSaqYM2z116NKoJ90F24xsE+KDwIInTFaNRvQEQgILzCufnP1TDOWM5J RgrXwJ4njCJAM5.PPqscElnmamPvv9SgGuo3ubHVyPqLyLmcjdSYFyEMnSyy kC3LDa.WaLzrbgHl4nk7FwvmZpbd9.DCC5l.pFcti6IVPFhXWmXi5r2u2AEA NM1W86O.LhR+l3sfuJOppuWso7n0VZNSN.WJbBtMJjZ43HRcgVFOOiGmJJpN sEe3rxnXfAYf9UrlBDOPviVKf9zViO8sWqN6tN60.zHGpk5i6YydyqbOxkAp NcTXs7DeW856aHPr0DuIlC.w1tQjmmOmku674diB29BiC1eY0CK4ORAF+tiK t1MBEaHXqemDCG.rMcaAE5Ag.+9jCaqKzg4p5iuR8xBcW9JhOEl9DSz+.bZH cn8MZexLIs04bcbgti9mETf9D6Ao2FwvGTmsJZz8vNGpaoOiJaYM.FpOCjp1 wRznDnU6hQi.8PM5mSeyw14bbVNleoNP9uqm+akbz+bCbbgYwAogN+i32Wfz wndlYmq94G0PvfByK7uKnHnuLNNzTt9LoWv.LUjcOGd8PsCE2CCMHSX3222U w+m7tJXZxfa59DGICBoRbOyXvi.IofsGFsd+oM6z8.UDK32VnY3WPp8gizKH JLK6Kr7Bi8fdobod+EGJt+4fXbpVDVp1jb1WhqJOrO2SBykqRSHWh1pb8tc+ rqd02SVxkFNcUrIkS5ejlrP7RxqWDV8N+e0p4w7+PDJVU74OvRWoWJnzurHb UhXSe4COtHNIIhmn6dGU+D4RRMq6bh9omaTWW1OpNm5.aBwW5XuvR5tntvcx abbZ7JioNjpJY6XGfophZ6R8rcf67oVNVp6vupZz01BSBzV.G3is02IUQj1p Y0BSeLA54TXaILZyx4Y77prBYUCpK+JA+w7v4pMmuNBqCwZ2MjJlq15dkaG7 IFe5RoCMtpNMScqCF5k4ecxJV0Zx2dfHLJRZfMbtVDOWaOELcq8XAJUU.d.6 f+VNikt28PrpK4Xo9m5NhquLfN7ct+jkjvK26dmO0g.tOOehOAxsbBbT4aMR W13Dr9HbFVNAXr++F.nGN.1hGEBJxLGq1j4EYW7HKcxwe+3+AkO.Ch. -----------end_max5_patcher-----------
So, I’ve been shamelessly pulling apart the Max for Live Poli synthesizer to learn how to construct a robust Max for Live device.
Version zero of my synth created “8-bit” wavetables naïvely and attempted to eliminate most of the aliasing by filtering, so naturally I turned to Poli’s oscillator code to see how they do it. Peter McCulloch’s code uses the Polynomial Transition Region method to produce anti-aliased saw and pulse waves. I did find a paper that proposes an algorithm along these lines for the variable-slope triangle wave, but since they only compute the first-order case, I ended up having to rederive the algorithm.
Aurally, I think it sounds quite good, especially with “pulse width” near the middle. Testing it out in Max, there is still some aliasing, particularly as you sweep the frequency, but A/B comparison with the Poli square wave leads me to think we’re in “good enough” territory. I suspect that part of the missing link here is that Poli never lets you completely bypass the filter.
For my future purposes, the above patch contains both Peter’s code for the pulse wave and mine for the triangle wave but outputs only one of the two according to an input. I’ve also included options for two-operator linear FM. I took a nod here from @Galapagoose’s design for FM pairs on Just Friends, but arbitrary FM should be possible.
Questions I’m still working on that I would welcome input on
FM works very well, but PM creates bizarre clipping and volume-shift problems. Why is this? (In fact, since shifting the fundamental frequency involves forcing a recalculation of all the polynomial coefficients and so forth, it seems like PM should be easier, since we’re just changing the input of the polynomials.)
I tried to use
clampto constrain the pulse width, thus avoiding having to divide by zero at the extremes. However, not only did this not seem to have any effect on the output, division by zero seems to be “fine” in the sense that the code does not crash.
I’m not sure of the best way to implement hard sync; currently it seems like I would have to introduce some more state to keep track of whether we’re jumping to zero phase and how far our output is jumping.
I have very little idea of whether what I am doing could be improved performance-wise. E.g., does the selector tell Gen~ to turn on and off the parts of the DSP automatically, or is the idiom different.