openlilylib / scholarly

ScholarLY, a library for annotating LilyPond scores
GNU General Public License v3.0
24 stars 6 forks source link

How to specify a set of variants at run time? #72

Open benjamingeer opened 4 years ago

benjamingeer commented 4 years ago

I would like to write a score that allows the user to choose a custom set of variants to be rendered at run time. In the scholarLY docs, it looks like \choice variants can be configured so that it always chooses the reading from one source, which is set globally. Instead, what I'd like is to give each reading a unique ID, and let the user specify at run time a set of reading IDs, as command-line arguments to lilypond. The specified readings could come from different sources. Then each \choice variants would check whether it has a reading with one of the specified IDs. If so, it would output that reading. If not, it would output the default reading given as lemma. Is there a way to do this already?

uliska commented 4 years ago

I see two approaches that you might check out. Ideally you'd test them, and if they work I'll either include them in the functionality or at least in the documentation.

Command line options

Have a look at http://lilypond.org/doc/v2.21/Documentation/usage/command_002dline-usage#advanced-command-line-options-for-lilypond. This shows how you can pass arbitrary options to LilyPond, for example

lilypond -dsourceID=lm14h

Within a LilyPond file you can access its value with

#(ly:get-option 'sourceID)

I think LIlyPond will print a warning about an unknown command line option, so while this has no negative impact I wouldn't consider it completely clean.

Please note that I haven't tested this, and you should properly check it out.

I'm not sure whether it's possible to register known command line options on the Scheme level (I don't recall to what conclusion I have once come with this topic). If that's possible I might add something to the scholarLY package itself because your use case seems generic enough.

Evaluate a Scheme Expression

Have a look at the --evaluate option in http://lilypond.org/doc/v2.21/Documentation/usage/command_002dline-usage#basic-command-line-options-for-lilypond and see if that's of your taste (or applicable to your use case).

benjamingeer commented 4 years ago

Thanks, that helps, but I’m mainly having trouble understanding how to get choice variants to choose an arbitrary reading, not according to the source. I guess I have to write a custom Scheme function, but I can’t figure out where I should put it. Inside the choice? Is there an example I could follow? The one in the docs puts the whole choice inside a function, but I don’t understand why that would be necessary just to select one reading instead of another. I know a bit about Lisp but haven’t written any Scheme in LilyPond. I’d be grateful for any hints.

uliska commented 4 years ago

Again, I can't currently test it and have to rely on the manual myself ;-)

What you will want to do is

\setOption scholarly.choice.preferences.variants "draft"

and replace "draft" with the value from your variable.

Given my example in the previous comment the following should work as desired:

 \setOption scholarly.choice.preferences.variants #(ly:get-option 'dsourceID)

Does that work?

benjamingeer commented 4 years ago

I’m wondering if there’s a way to write one centralised function that all the occurrences of choice variants will use to select a reading, instructions of writing a separate function for each one.

uliska commented 4 years ago

That's what the choice.preferences options are intended to do.

benjamingeer commented 4 years ago

I just saw your last comment. But isn’t draft the name of a source? I don’t want to specify a source, I want to specify a set of several readings, even if they all come from different sources. That’s why I want to give some kind of unique ID to each reading. Then the user could say, “Give me reading A in measure 10 and reading B in measure 15”.

uliska commented 4 years ago

Ah, that's something completely different. I'd have to think about how that can be matched on a conceptual level. The variants type essential is a way to encode readings from different sources. I think that's how it is handled in MEI, and that's how I understand the terminology in the general context of editing. I have the impression that you are looking for a different type of choice that may or may not interfere/overlap with variants.

To properly think about it I'd have to know a little more about the editorial concept you are after concretely.

benjamingeer commented 4 years ago

I’m using choice variants to encode readings from different sources, and I specify a lemma in each case. I think that’s an important part of the editor’s job. But there is sometimes a lot of uncertainty involved in choosing lemmas, and other readings might be valid. So I want to allow the musician to make their own choice in each case. I want them to be able to say, “I understand this editor’s methodology, but I want to choose different readings in some cases. The editor chose reading A from source X in measure 10, but in thar particular case I prefer reading B from source Y. And in measure 15, the editor chose reading C from source Y, but I want reading D from source X.” The idea is to allow the musician to disagree with the editor in some cases, and to generate a different score using their own choices. I would like to make a user interface that would enable a musician to select readings from menus, then run LilyPond to get a score with their chosen readings.

uliska commented 4 years ago

OK, I see, sounds good and reasonable.

Probably the current interface doesn't support this out-of-the-box, and I'll have to think about it.

"llemma" and "reading" are what they are I'd say, and when you want to override the editor's choice then you will have to add an ID to each choice instance where you will want to allow individual overrides. (It might be possible to write an external script to auto-generate such IDs for speciific or all types of choice, but that is something one would have to run on the input files externally.)

If I understand your use case correctly then your user (or the user interface) has to produce a potentially large list of IDs which will not fit nicely with the idea of passing to the command line. In that case I'd look for a solution where this list is written to an auxiliary file, and LilyPond reads that file to populate its list.

It seems this calls for an implementation within the package, not for a solution on the user-side. I'll have to consider this, not knowing really when I'll have the time ...

benjamingeer commented 4 years ago

You’re right, an auxiliary file would be better. For now it’s no problem, I can fake it using LilyPond tags for a demo, and we could talk about it some more whenever you have time to think about it.