I often find it easier to understand what I'm hearing when I can see a visual representation of the music. This has become more important as I've been experimenting with generative music. I'm starting to give up full control over the composition process and it's not always clear what the results are without a lot of repeated listens.
Unfortunately, Max/MSP doesn't have much support for standard music notation. So I've been experimenting with generating notation inside Max/MSP using LilyPond, my ajm.ruby object, and the jweb object from Max 5. This isn't a great solution: it's slow and it can only display notation. You can't interact with the notation in any way, which is what I'd really want. But if you don't want to pay money or spend a ton of time writing your own notation software, this is potentially a viable solution for getting notation inside Max.
If you want to try this out, first you need to install:
Then:
I'm not going to give a tutorial on LilyPond, so check out the documentation on their site if you want to play around with notating different things.
There's a bonus on OS X (maybe Leopard only?): jweb uses webkit, which has some nice controls for viewing pdf. If you click on the notation, controls will appear that allow you to zoom in or out, and open the pdf in Preview (where you can print).
So what's going on under the hood? The maxlily.rb file is Ruby code that does most of the work. Ruby is certainly not the only solution here, I just find it very easy to work with. This code could be ported to C or Java or whatever without much difficulty. If you are interested in doing that, let's take a look at the code in detail and see what it's doing:
Comments
escaping backslashes
The method that you are using works well for a piece that I am doing for generative music, but I wanted to note that because of the way the Ruby notate def, it errors on any \ that are in the lilypond syntax. For example:
\relative c' {
c d e f
g a b c
}
Doesn't compile correctly. if you add another backslash:
\\relative c' {
c d e f
g a b c
}
it then works. I don't know Ruby well at all, so I don't know the proper way to Regex the string for the slashes, or I would provide code to fix the bug.
As a side note, it would seem like you could do this with simple scripting executing terminal commands to lilypond, but I won't argue with something that works.
RE: escaping backslashes
Good catch. I don't think there is actually anything wrong with the Ruby script. There are some confusing interactions between Max, Java (ajm.ruby is Java), and Ruby. By the time we get to the Ruby script, the "\r" in "\relative" is being interpreted as a "return feed" character rather than a separate "\" and an "r". So this is a much deeper problem.
A potential workaround is to add this line to the top of the notate def:
str.gsub!("\r", "\\r")
But this will only fix the specific problem you mentioned. I think you will run into further issues if you need to use a backslash for other LilyPond commands. Probably the best solution for now is to use the extra backslash like you are doing.
Perhaps a regexp object could be used in the Max patch to replace "\" with "\\" but I can't seem to get that to work. I'll investigate if I can make some adjustments to ajm.ruby to prevent this, but the obvious solution (replace "\" with "\\" before passing things to Ruby) does not work either! Argh! The problem may ultimately lie with how textedit/Max handles backslashes.
And you are right, there's no particular reason to use Ruby for this, I was just testing out my ajm objects when I made this patch. Terminal scripting could work too.
Re: escaping backslashes
I have been further modifying your work because I myself am doing research for a Chance Music Piece to generate original readable notation in real-time for perfomance based off of things the computer has "learned" by analysis of people whom have previously played the "Mother" instrument. I have a Disklavier Upright Player Piano that has midi capabilities that will be used to "teach" it(This is the Mother instrument). I have accomplished Key Signature Modification and Time Signature, all of which were a real pain, so I am starting to second guess the process. Max Objects like coll and sprintf, possibly text though I have not tested yet, all use backslashes to indicate either escaping or "insertions", similar to the whole \r issue. Past that, the comma also has significance to max also, so when dealing with lilypond syntax(\relative c,,) it becomes cumbersome. I will keep investigating also, and try some your suggestions. I have been meaning to pick up Ruby, but never had a use for it in the stuff I do, but with this awesome little object you made, I now have an excuse. I will keep you up to date with my progress, maybe we can work out something fun and useful. This has lots of potential, and is a big hole in max IMHO, that needs to be filled.
Quick Update
After some testing, it seems that using the Text Object is the best way to go in terms of storing the generation of the lilypond syntax either to compile together for use with your object/script, or as a "dictionary" of sorts to translate midi->lilypond. It seems to not have "programming" traits like coll and sprintf, and treats backslash and comma normally. You can also send it commands for carriage returns and have it spit out specific lines, and write to file with a .ly extension, eliminating the need to pass the str into Ruby at all, just call the file from the script. I will let you know how further tests go.
PS sorry for the back-to-back comments... just thought I would pass along that tidbit, because it makes this whole approach feasible again.
RE: Quick Update
No problem on the back-to-back comments. Actually, thanks for giving updates on your progress. It sounds like you have a pretty good solution now and hopefully this discussion can benefit anyone else who stumbles on this article.
I meant to reply sooner... I was going to play around with the text object over the weekend and I didn't get around to it. In any case, it seems the text object is much better than textedit when it's important to process the text exactly as entered. Maybe I should update the ajm.ruby help file with some examples, or at least post a follow up article here.