I start to build a polyphonic synth that can play micro tonal scales using the else/scala object.
I created a clone object and saved it.
When I try to enter a list of data inside the clone (into inlet) I'm getting that error
-
help with polyphonic synth
-
@KMETE said:
so clone is not like poly~ in max msp?
Well, that's a good thing, because poly~ is clumsily engineered.
OK, in fairness to poly~, using an envelope to decide the instance's busy state is a good feature (which would be a bit tricky with clone).
But they really blew it by having 1 --> thispoly~ = "node is busy" and "mute 1" --> thispoly~ = "node is sleeping." So, when a node becomes active, you need to play opposites: nonzero for the busy state and zero for the muted state. Why did they do this? Would it not be simpler if it were nonzero = busy and "run 1" for active / non-muted? I mean... sorry... but Max is expensive. When they get the design wrong, it's irksome.
... which is why I laugh to myself whenever someone suggests that the Max way is the gold standard.
edit: perhaps one can share a small example of polyphonic synth in pd?
Assuming that you have note-on and note-off triggers:
... and with this design, the abstraction being cloned should accept a list "pitch velocity" in the leftmost inlet.
If you want note-on triggers, and an instance should remain busy as long as the envelope is nonzero, then I would just go round robin by prepending "next" onto the pitch:
next 60 64
hjh
-
What if I want to insert more data to my clone voice? such as in the attached picture.
I try to pass into it also a wave selector and duty cycle. in addition to frequency number and velocity and adsr -
@KMETE said:
What if I want to insert more data to my clone voice?
Hm, right, [poly] handles only note number and velocity.
I would pass the additional values into a [pack] -- note, not [pak]! In this case, it's absolutely critical to collect values using the cold inlets, before outputting the completed list only once. You've used pak throughout your screenshot but you should definitely not use pak right above clone.
Also you have another mistake -- you've provided only one value in the pak template for the adsr but then you're trying to stuff 5 values into it. I believe in that case only the first of the 5 values will pass through and the other 4 will be lost.
I'm not at the computer so I can't prepare a screenshot, but it would be something like:
step 2: note number and velocity *after* filling the pack | [poly 15] | | | [- 1] | | | step 1: put other data in here first | | | v [pack f f f f f f f ... as many as you need] | [clone ...]
You can use a trigger object to guarantee that step 1 happens before step 2.
hjh
-
I realized, after posting that, that there are two ways of thinking about the "extra parameters" going into the synth clone, which for lack of a better term I could call "global" vs "local" parameters.
Local parameters are "per-note" -- they are set at the time the note begins, and they hold their value for the duration of the note. The next note (which might overlap) could have completely different values.
Global parameters affect all notes simultaneously. This is the usual way that, for instance, filter frequency works. You twist the filter cutoff knob and all notes' cutoff changes simultaneously (even though each note could have its own filter cutoff envelope).
At minimum, pitch (note number or frequency) and velocity (on/off trigger) should be per-note. Other parameters could be global or local (and you can mix those styles).
As far as I can see, the best way is:
- All local parameters get packed into a list, along with the clone instance number (which is supplied by [poly]). The "local" list goes into the leftmost input, and only the leftmost.
- "Global" parameters add one or more inlets to the right. Note carefully in the [clone] help file that control inlets need to tag their values for specific instances. If we're using these as global parameters, then the tag should be
all
. Signal inlets are always global.
IMO it's best to be consistent about the handling of these input types, to avoid introducing bugs into your patch.
Example with filter cutoff and envelope parameters treated globally:
Example with filter cutoff and envelope parameters treated locally:
(Note: The example patches use the ELSE external library, and the global one uses cyclone.)
Hope this helps. IMO polysynth is a basic use case for any audio programming environment; if what I've posted here can't be easily figured out from the documentation, then it suggests a gap in the help. (One reason why I worked it out is that I teach a class in Pd; if the students ask "how do I make a poly synth?" then I'd better have an answer at the ready. So I tried a few ways and came up with this as a basic template that Just Works... then, just do it that way.)
hjh
-
@ddw_music Thank you so much! hope to find the time dive into your example this upcoming weekend!
-
is that type of adsr using the vline~ object could also have log curve?
-
@KMETE said:
is that type of adsr using the vline~ object could also have log curve?
You are, of course, free to implement whatever type of envelope curve you want. You don't need my permission or advice on that -- take the patch and do as you like with it.
A common and super-easy way to get a perceptually nicer envelope is to square it:
hjh
-
I have tried to insert into the clone object the frequency of the midi note after converted with the m2s object and the Scala object . I'm getting constant sound. How can I convert the midi note into frequency outside the clone object (as in the below picture)
clone:
my printing is the following (which looks wrong)
-
ok it seems I fixed: