• ### Creating a counterpoint object

Hi,
I have an idea for an object, and I was wondering if anyone might be able to suggest a way to realize my concept.

I want to make an object that will take as it's input a midi note number. It will output another number that will be a musical interval. Then I input another note, and based on the previous resulting interval it will create a counterpoint melody based on rules and probability that I create.

For example, if a previous interval was a perfect 5th, and the note I play (let's say the top note) goes up a step, I want there to be a high probability that the counterpoint note will go down a step and it will result in a 7th by contrary motion. If I have a 3rd there might be a high probability that the next interval will be a parallel 3rd. I have all the rules and probabilities kind of figured out in my head.

But I don't really know the best way to approach this. I would think some kind of text based coding might be a way to go. Maybe I could do this in C++. But i can also use regular vanilla objects like select objects and, based on the interval, choose a different outcome.

Eventually, based on if I can actually make this and it sounds decent, I would want to expand this into a 4 voice counterpoint generator.

Anyway, any suggestions would be welcome.

EDIT: ok I am looking at the expr if statements. I'll see if I can say if it's this interval, do this, else if it's this other interval do this, and try and list every interval. That seems to be a place to start.

thank you

• Posts 11 | Views 1284
• Ok now I have a more specific question

How would I express an else if statement in the expr object? I don't see it in the help file.

For example, if the incoming interval is 1 ( a 2nd) bang out of output 2,
else if the incoming interval is 2 bang out of output 3,
else if the incoming interval is 3 bang out of output 4, etc.

thank you

• @nicnut [expr] outputs ints and floats, not bangs.
Also [expr] is tedious with complicated if-else statements, you have to nest them:
[expr if (\$f1==1, 1, if (\$f1 ==2, 2, 0) )]
or
[expr if(\$i1==1, 1, 0;
if (\$i1==2, 2, 0) ]

But the object you are describing is [select] or [sel] in short.

Also right click in Vanilla on the blank canvas > help
to see all Vanilla objects
(this is the vocabulary)
and look closer at operators [==] [>] [&&] ect. also [moses]

To read some 'previous' data I usually do

[t f b]
X
[f]

this first outputs the previous float, then stores the new one in [f].
But if you may want to look further past, and make up more complicated rules, building lists or writing into [text] or [array] will be more flexible.

For probabilities, there are [array random] or [random] for example.

• @nicnut I think you're describing a markov chain. there's an example of one in the help files: 2.control.examples/21.markov.chain.pd

• @nicnut For doing this sort of stuff I generally create little purpose designed programming languages since the patch interface of pd can get tedious when you decide to change a rule or the like with all the patching and repatching. For example here is a very simplified Forth style stack based language with four commands which you can see at the bottom of screenshot, +, ==, dup (duplicate) and print, top right is the stack and top left we see the program in the message and the parser bellow. Really it is just a fancy programmable route with a memory. pd is surprisingly good for this sort of stuff as long as you stick the lower level language styles.

4th.pd
So if we click the message to send the program it is dripped by [list-drip] into the [route symbol], any floats go out the right outlet and are pushed onto the stack, any symbols go out the left outlet packed with a \$0 to create the send symbol for the command in the format of \$0-COMMAND, this symbol is sent to the stack's output [send] and the parser's [send] which is then banged to run the command. 1 and 2 get pushed to the stack, + being a symbol is packed and the symbol \$0-+ is made and sent to the right inlet of the parser and stack output [send]s, we then send a bang to the parser send. This bang gets sent to [r \$0-+] which sends the message [2( to \$0pop, two items are popped off the stack, 2 then 1 which are added and 3 is then pushed, and so on. With this setup we can make any block of pd code into a command so a very simple and reasonably efficient language can be very complex and infinitely expandable. The one catch is you really need to remember to keep the language purpose specific or you end up like me and have a handful of very large, complicated and difficult to maintain languages which while being really useful I have forgotten half the features of and : the idea of going through them to figure out and document them causes me to whither.

Edit: Sort of sidetracked myself there and lost my direction. Short of it is if you use pd in a more functional way instead of the dataflow way it makes it quick and simple to rewrite your rules or create whole new sets of rules without having to create entire new patches/abstractions every time.

• Hi,

thank you everyone for all these suggestions. Thank you @lacuna for the clarification on the [expr] object.

I think I am going to try and pursue using the [expr] object with if statements. This is because, once I get a handle on 2 voice counterpoint I want to expand it to 3 voice and maybe even 4 voice.

So I might do something like this to incorporate 2 intervals:
[expr if(\$f1==1 && \$f2==1, 1, if(\$f1==2 && \$f2==2, 2, 0 ))]

Otherwise, the select object would be easier to use.
Thank you @oid for your code examples. I need to really examine what you have there. At first glance I am having a hard time understanding you patches.

@seb-harmonik.ar I have been using Markov Chain methods for awhile and i really love doing that, but thats not what I am looking for here. I see Markov Chains as a way to imitate something, where what I want to do is have hard coded rules as to what the out comes will be. There will be some weighted probabilities, but everything will be predetermined.

I will post some examples once I have something working. Thank you all.

• @nicnut think twice @oid's patch is pure gold!!!

• @nicnut It is no where near as difficult to understand as I made it seem, you said you considered doing this in C++ so I did the patch in the C style. Forth may have not been the best example language but it is very transparent in how it functions in pd, but lets explain it in C terms.

Across the bottom we have our function definitions, the name of the function is the receive symbol, I defined addition, equals, duplicate and print. Top left is the parser which is just a while loop and an if statement, while true read input, if input is a symbol it is a function so run the function, if it is a float store it and push it on the stack. The only major difference from the C way is that we don't call a function with its arguments (add 3 9) we just run 'add' by sending it a bang and it takes its arguments off the stack. So you define the functions required to mark out the rules of counterpoint then you can either run it by just running the functions, compound commands as I did in the example or writing out entire programs in a [text], you can even change the rules while it runs or have it change the rules and alter its own programming.

PureData is a full programming language, not just a fancy modular synth like thing, we can use it to implement programming languages or create new ones of most any paradigm, with dynamic patching it would not be terribly difficult to implement object oriented programming complete with C like grammar (I think?), you could even write a compiler which compiles your language into a native pd patch instead of just interpreting it. Pd is surprisingly good at doing this sort of stuff which is a great thing since it has a few areas where it is awkward to say the least, defining the rules of music systems being one of them and what should be a minor change can result in hours of the worst sorts of patching. So we make a language with just the handful of features we need designed around the data we need to work with and the result we need to achieve and now we can make radical changes to our rules in minutes instead of hours.

This weekend I can go into this all a bit more and provide some examples more directly suited to your needs if you want to pursue this.

• Hi @oid. After reading your most recent post I think I am starting to get it and I can see the advantages to how you are approaching this. It seems you are modularizing parts of the patch. That's why it would be easier for me to envision this in C++ because i can have a different block of code for different situations. And of course you can get as detailed as you want in each section.

I am going to post what I have so far, even though it doesn't really work very well yet. In folder there is a patch called counterpointtest, and other necessary elements.

For now I am trying out the expr object with two variables. f1 is an incoming scale step, and f2 is an interval between the last two notes.

The patch should generate two notes. The one on the left would be a scale step a musician would input into the patch, and the one on the right would be generated based on some counterpoint rules that will be in the expr object (for now I only have a few to see how everything will work).

The inputs Into the expr are intervals based on a 7 note scale, starting with 0. So 0 = unison, 1 = a 2nd, 2 = a 3rd, 3 = a 4th, 4 = a 5th and 7 = an Octave.

In the f2 inlet of the expr should be the interval between the last 2 notes tested.
What should happen is when a new note is played it’s state of change is tested against the last note played

Ideally what would happen is I would play a note that would be f1, that note would be tested against the previous f1. For example, is the new f1 a scale step higher, or lower, etc. Whatever that difference in the past f1 to the current f1 would go into the expr object f1 inlet.

In the other inlet of the expr object, f2 would be the last interval between the two notes, so a 5th, 4th, 3rd etc.

A new interval should be generated by the expr object and added to the f1 scale step that was played. This new note will be played out of the right side of the patch., and the note selected to be played by the musician will be played on the left side of the patch, generating a two note interval (dyad).

This patch doesn't work so well yet. One reason is that I need to put in every possible combination of intervals and scale steps into the expr. Maybe this is crazy as there are probably a hundred possible ways 2 notes can interact. And on top of that I want some interval combinations to have several possible weighted outcomes. Maybe this is too much work, but If I could do it it might be cool to use.

Anyway, if anyone has time to take a look and let me know if I am approaching this in a way that might work and be practical.

thank you. Nick

counterpointtest.zip

• @nicnut said:

One reason is that I need to put in every possible combination of intervals and scale steps into the expr. Maybe this is crazy as there are probably a hundred possible ways 2 notes can interact.

Now you see where I am getting at about this being tedious in native pd, imagine if you patched all that up and wanted to make a change, you could end having to a great deal of repatching because of a simple oversight. But I finally realized how to go about executing a general purpose language in pd that can be allowed to grow and adapt to the need and not just turn into a massive beast so I will throw together a more proper pd Forth which works well with the pd way this weekend. It will be Forth syntax so takes some learning for most but it is a very simple language to learn, only trick is learning to think like a stack. But this could be done for other paradigms, simple stack based language is just the most efficient in pd and easily can be made to be self adapting/modifying on both the language and program level which offers a great deal of power so worth learning its quirks.

And on top of that I want some interval combinations to have several possible weighted outcomes.

This is what @seb-harmonik.ar was getting at with the markov chain, not a big deal and we can even use the previous notes to calculate the weights.

Maybe this is too much work, but If I could do it it might be cool to use.

It is doable but the first time going at it is daunting, but designing a language just for executing that rule set makes things much easier and even easier than using something like the python or lua externals because it is designed around the task. Catch is you need to put in the work to develop that language but once you get the basics down you realize most music systems can be realized without too much effort.

• @nicnut one thing that would make it simpler is to use a 2-dimensional array. Pd doesn't have them natively but you can just multiply the 1st index by the size of the 2nd dimension and add
Instead of your giant 'if 1st thing = x and 2nd thing = y output z' you can just look up z using x and y as indices.

Posts 11 | Views 1284
Internal error.

Oops! Looks like something went wrong!