Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve instance/group assignment + "." group-member operator #249

Closed
elydpg opened this issue Jul 20, 2016 · 60 comments
Closed

Improve instance/group assignment + "." group-member operator #249

elydpg opened this issue Jul 20, 2016 · 60 comments
Assignees
Milestone

Comments

@elydpg
Copy link
Contributor

elydpg commented Jul 20, 2016

Consider the following code:

piano:
piano "piano1":

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

When played, it plays normally. However, if I switch the declaration of the instruments at the top

piano "piano1":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

piano1 does not start playing until piano has finished its melody. The order of the melodies at the bottom does not matter, so

piano "piano1":
piano:

piano1: o4 e f g a b > c d e
piano: o4 c d e f g a b > c

will play piano1 first and then play piano.

And if they're both named, there is no problem. both of the scores below play normally.

piano "piano1":
piano "piano2":

piano1: o4 c d e f g a b > c
piano2: o4 e f g a b > c d e
piano "piano2":
piano "piano1":

piano1: o4 c d e f g a b > c
piano2: o4 e f g a b > c d e
@daveyarwood
Copy link
Member

daveyarwood commented Jul 20, 2016

This is working as expected. The rules of instance and group assignment are a bit complicated, but I feel like they should hopefully work the way one might expect. The question is, what do/should one expect?

To explain what's happening in each of the above scenarios:


Example 1:

piano:
piano "piano1":

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

piano: registers "piano A." Then piano "piano1" contains a nickname, so it is forced to be a new instrument, "piano B."


Example 2:

piano "piano1":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

piano "piano 1" registers "piano A," then piano: does not contain a nickname, so it is interpreted to be the first instance it finds that is a piano, so it ends up also being piano A.


Example 3:

piano "piano1":
piano "piano2":

piano1: o4 c d e f g a b > c
piano2: o4 e f g a b > c d e

Now both piano instances are named, so they are both forced to be new instances.


This makes perfect sense to me, but I admit that it's complicated, and might not make perfect sense to other people who use Alda. I can understand how in Example 2, one might expect "piano" to be available again as a new instrument instance after you named another piano, but the question is, is that the way it should work?

@elydpg
Copy link
Contributor Author

elydpg commented Jul 20, 2016

The way I expected it was that an unnamed instrument was treated as its own instrument instance that was just called by the name of the instrument itself. so in the case of the code

piano "piano1":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

what I expected was that piano was its own instrument (simply called "piano") and that piano1 was a separate piano called "piano1".

But what happens when we modify the code slightly?

piano "piano1":
piano "piano2":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e
piano2: o4 g a b > c d e f g

According to my expectations, all these instruments would play together. However, with the way things are now there's ambiguity as to which piano piano refers to, and if you actually run this, it plays piano and piano2 together, followed by piano1. To me, this makes no sense, and I think it's better to treat instruments without nicknames as if they're named what they are.

EDIT: oh, and also

piano "piano1":
piano "piano1":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

this plays normally for some reason...

@daveyarwood
Copy link
Member

Yeah, that does make a lot of sense. I think we should change it to make it
work the way you're describing before the release of 1.0.0. The more
intuitive / less confusing we can make it, the better!

On Jul 20, 2016 10:25 AM, "elyisgreat" [email protected] wrote:

The way I expected it was that an unnamed instrument was treated as its
own instrument instance that was just called by the name of the instrument
itself. so in the case of the code

piano "piano1":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e

what I expected was that piano was its own instrument (simply called
"piano") and that piano1 was a separate piano called "piano1".

But what happens when we modify the code slightly?

piano "piano1":
piano "piano2":
piano:

piano: o4 c d e f g a b > c
piano1: o4 e f g a b > c d e
piano2: o4 g a b > c d e f g

According to my expectations, all these instruments would play together.
However, with the way things are now there's ambiguity as to which piano
piano refers to, and if you actually run this, it plays piano and piano2
together, followed by piano1. To me, this makes no sense, and I think
it's better to treat instruments without nicknames as if they're named what
they are.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#249 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AEroF9mPjISR9K7a7zlMjg0eGwPOnIXsks5qXln0gaJpZM4JQ93G
.

@elydpg elydpg changed the title Time continuity bug Time continuity bug (refining instrument instance calling) Jul 20, 2016
@elydpg
Copy link
Contributor Author

elydpg commented Jul 20, 2016

I am going to refine my expectations into the following logic. I think it should be pretty intuitive, although I'd love to hear your thoughts on it

an instrument call takes the form $type "$name": or the form $argument:

If the call has two arguments then

If it is the first call with the arguments $type and $name then

If there is an existing instrument with name $name then

throw a syntax error

else create a new instrument instance of type $type with name $name

else treat the call as a continuation of the instrument with name $name

If the call has one argument then

If it is the first call of an instrument with the name $argument then

create a new instrument instance of type $argument (will throw an error if type $argument is not a valid type) with name $argument

else treat the call as a continuation of the instrument with name $argument

@daveyarwood
Copy link
Member

Makes sense to me! 👍

On Jul 20, 2016 11:20 AM, "elyisgreat" [email protected] wrote:

I am going to refine my expectations into the following logic. I think it
should be pretty intuitive, although I'd love to hear your thoughts on it

an instrument call takes the form $type "$name": or the form $argument:

If the call has two arguments then
If it is the first call with the arguments $type and $name then
If there is an existing instrument with name $name then throw a syntax
error
else create a new instrument instance of type $type with name $name
else treat the call as a continuation of the instrument with name $name

If the call has one argument then
If it is the first call of an instrument with the name $argument then
create a new instrument instance of type $argument (will throw an error
if type $argument is not a valid type) with name $argument
else treat the call as a continuation of the instrument with name $name


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#249 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AEroF3YJ3rdBLChoiEiVNZpOS5VBlYqNks5qXmbpgaJpZM4JQ93G
.

@elydpg
Copy link
Contributor Author

elydpg commented Jul 20, 2016

Ok. I changed the blocking a bit to make it more readable.

@daveyarwood
Copy link
Member

OK, so, after re-familiarizing myself with the code... One wrinkle about doing it the way you're proposing is that it would make it cumbersome to define new named instrument groups using all new instrument instances.

The way it works currently:

  • Let's say we already have a clarinet and a flute in a score. Let's call them clarinet-1 and flute-1:

    clarinet "clarinet-1": c8 d e f
    flute "flute-1": c8 d e f
    
  • Now let's say we want to create a new clarinet and a new flute, and let's say a (new) oboe too, and we want them to be in a group together, and we don't care about ever using them separately. Let's call this group "winds":

    clarinet/flute/oboe "winds": c1/e/g
    

    Because an alias is being assigned to the group, a new instance is created for every stock instrument. So we end up with essentially clarinet-2, flute-2 and oboe-1, all new, anonymous instances in a named group.

If we made this change:

  • Trying to create a new, named group with new, anonymous instrument instances, does not work. Following the example above, if we tried to instantiate the group with clarinet/flute/oboe "winds":, we would end up re-using the existing clarinet and flute, which is not the behavior I would expect.

  • Instead, we would be forced to explicitly create a new clarinet and a new flute, resulting in this rather awkward-looking code:

    clarinet "clarinet-2":
    flute "flute-2":
    clarinet-2/flute-2/oboe "winds": c1/e/g
    

It's been a long time (years!) since I designed this system of instance assignment, but I believe this may have been my reasoning for making it work the way it does. Basically, the idea is that a "stock instrument" like clarinet is always reusable as a way to initialize a new instance of that instrument in a group.

@elydpg
Copy link
Contributor Author

elydpg commented Jul 21, 2016

Oh. I must admit I completely forgot about grouped instruments. I think for ungrouped instruments the logic I'm proposing makes the most sense.

This, however is the problem:

A new instance of an instrument is created whenever a stock instrument is called with any nickname, either as part of a group or not.

This makes it very easy to make new instances of stock instruments within groups. There are problems with this, though, besides having a less intuitive instrument system.

1: You can't separate new instances of stock instruments created in groups. Consider:

clarinet "clarinet-1": c8 d e f
flute "flute-1": c8 d e f
clarinet/flute/oboe "winds": c1/e/g

Currently creates a new clarinet and flute, but what if you want to extract just the clarinet somewhere else? There's no way to refer to it unambiguously.

2: Recall that you can name instruments after other stock instruments. I'd imagine this is highly recommended against, however my proposed system would have no problem handling it. This creates a problem, though, because if one were to do something like this...

piano "violin": c d e f g
piano "clarinet": c d e f g
violin/clarinet "pianos": c/e/g

They would expect that no new instrument instances are created. But they would end up with a violin and a clarinet that they did not want.

Personally, I think it's more intuitive that instrument grouping does not create new instances, as I see it more as bringing instruments together. However I can see why it may be desirable to do so.

@jimcheetham
Copy link

jimcheetham commented Jul 21, 2016

Separating instruments from a group could be achieved, if the implicit instrument name were a mix of the group name plus the instrument.

e.g. clarinet/flute/oboe "winds": creates

  • clarinet "winds-clarinet":
  • flute "winds-flute":
  • oboe "winds-oboe":

The second issue, where explicit names are created that might match implicit names, is a matter for the score writer. If you declare any instrument called "piano", any declaration of a new instrument with the same name should throw an error - whether that new declaration were implicit or explicit. The error helps the score writer discover what they've done wrong :-)

piano "violin": a b c
violin: a b c 
** Error, cannot create "violin:", an instrument with the name "violin" has already been declared

violin: a b c
piano "violin": a b c
** Error, cannot create "piano "violin":", an instrument with the name "violin" has already been declared

piano "winds-piano": a b c 
piano/clarinet "winds": a b c
** Error, cannot create "piano/clarinet "winds":", an instrument with the name "winds-piano" has already been declared

@elydpg
Copy link
Contributor Author

elydpg commented Jul 21, 2016

Hm. I'm not a huge fan of either of those ideas; the first one because many stock instruments have a - character in their name, making it an ambiguous character in instrument calling.

The second one is a problem because I don't believe we should disallow users from naming instruments after other instruments, mainly because in the future plugins will allow more instruments and this could break alda scores when played in a separate alda client that has those plugins.

I don't actually think it makes sense to ever create new instrument instances when grouping. when I think of grouping I think of bringing instruments together, not creating new ones. Unfortunately, this leads to some awkward code:

piano: c d e f g
piano/violin: c d e f g
#throws an error because violin is a new instance

I don't know if most people would expect this. But it seems like the most intuitive behaviour to me.

@daveyarwood
Copy link
Member

daveyarwood commented Jul 21, 2016

@jimcheetham said:

Separating instruments from a group could be achieved, if the implicit instrument name were a mix of the group name plus the instrument.

e.g. clarinet/flute/oboe "winds": creates

  • clarinet "winds-clarinet":
  • flute "winds-flute":
  • oboe "winds-oboe":

I like this idea. As @elyisgreat mentioned, there is some potential for naming conflicts, so I think what we would do is add a special operator for accessing members of a group. I think . might be a nice choice:

clarinet/flute/oboe "winds": c d e f

winds.clarinet: d  e f  g
winds.flute:    g  a b >c
winds.oboe:     b >c d  e

I like this because it provides the new ability of accessing (previously "anonymous") members of a named group, but still keeps the syntax concise and elegant.


I'm not sure yet what we should do (if anything) about the possibility of naming instrument instances after stock instruments and other instance names, but my gut feeling is that we should throw an informative error in both cases, like @jimcheetham said. I think that stock instrument names should always be available for creating new instances of that instrument, and if a score writer gives a name to an instance (or group of instances), then that name should always refer to that instance or group.


@elyisgreat: One important thing to remember is that when you use a group, e.g. piano/violin: it will reuse instances if they already exist. Looking at your last example:

piano: c d e f g
piano/violin: c d e f g

This creates one piano and one violin. The piano plays c d e f g c d e f g and the violin plays c d e f g.

On the other hand, if you give a name to the group, the semantics are different; it will create new instances for any stock instruments described in the group. Consider this score:

piano: c d e f g
piano/violin "piano-and-violin": c d e f g

This creates two pianos and one violin. The second piano was created in order to be a part of this new group, piano-and-violin.

Basically the idea is that if you're giving a name to a group, it's going to be its own entity with its own instrument instances, so as not to conflict with other instances that are doing their own thing.

This is my fault for not making it clearer in the documentation / examples, but my general recommendation is that you can't go wrong if you name every instrument and instrument group that you use, the first time you use it, and then use the names from then onward. Mixing and matching named and unnamed things is a recipe for confusion. So, continuing with the same example, take a look at this score:

piano "piano1": c d e f g
piano/violin: "piano2-and-violin": c d e f g

Like the last example, this also creates two pianos and one violin, but now it's extra clear that the first piano is a separate piano. Now from this point onward in the score, you are working with two separate entities, "piano1" and "piano2-and-violin," and it's easy to keep them separate in your mind as you're writing the score.

So then, what if you wanted to break the violin out of the "piano2-and-violin" group and have it play something by itself? If we added an operator, you would have an operator like piano2-and-violin.violin that you could use. Or, you could do something like this:

piano "piano1":
piano "piano2":
violin "violin1":

piano1: c d e f g
piano2/violin1 "piano2-and-violin1": c d e f g

violin1: a b > c

I know this is a little awkward-looking, but maybe this is a good example of a situation where a "member of group" operator could help make the code cleaner and more concise:

piano "piano1": c d e f g
piano/violin: "piano2-and-violin": c d e f g

piano2-and-violin.violin: a b > c

I'm still open to altering the way this works, it's just difficult to adjust such a complicated system without unexpected consequences. It might end up being easier to fix this issue with a combination of better documentation and useful error-throwing when score writers attempt to do things that aren't recommended.

@elydpg
Copy link
Contributor Author

elydpg commented Jul 22, 2016

All this is just making the system even more complicated than it already is. I think we should use my system, and just disallow any new instances to be created as part of groups. Otherwise I think we need a new, simpler system.

@elydpg
Copy link
Contributor Author

elydpg commented Jul 24, 2016

Now that I think about it, instrument instance calling needs to be not only refined, but completely overhauled. Alda will eventually support waveforms, non-MIDI instruments, and plugins that may add even more instruments, and piling that on top of an already confusing instrument instance system will just add more confusion.

@elydpg elydpg changed the title Time continuity bug (refining instrument instance calling) overhauling instrument instance calling Jul 24, 2016
@daveyarwood
Copy link
Member

I'm not opposed to radically changing the instrument assignment/reference
syntax if someone has an idea that would be an improvement over what we
have now.

I've played around with a syntax that was more explicit about creating a
new instrument/group vs. using as existing one, but I found it difficult to
do this while also keeping the syntax simple and user-friendly. I think one
of the major selling points of Alda is its concise syntax. I like that an
Alda score can be as simple as "piano: c d e f g a b > c".

On Jul 23, 2016 10:26 PM, "elyisgreat" [email protected] wrote:

Now that I think about it, instrument instance calling needs to be not
only refined, but completely overhauled. Alda will eventually support
waveforms, non-MIDI instruments, and plugins that may add even more
instruments, and piling that on top of an already confusing instrument
instance system will just add more confusion.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#249 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AEroF9Xh57-en76i9Rcfr4xCh536kCxbks5qYs1xgaJpZM4JQ93G
.

@daveyarwood
Copy link
Member

I think the way it works currently is intuitive, we just need to explain it better in the documentation.

The first key thing that perhaps isn't clear enough in the docs is that assigning an alias is something you do when you create an instance or group. After that, you always use the alias to refer to the instrument.

The second key thing is that you should not use a combination of named and unnamed things; if you name one thing, you should name all of them.

Does that make sense? I'd like to talk about this and figure out where exactly the confusion lies, and improve our documentation so that it doesn't confuse other people.

@elydpg
Copy link
Contributor Author

elydpg commented Jul 24, 2016

not sure. there's still the problem of plugin instruments though...

@daveyarwood
Copy link
Member

I'm not sure what you mean by "plugin instruments" -- can you elaborate on that?

@elydpg
Copy link
Contributor Author

elydpg commented Jul 24, 2016

Alda will eventually have plugins, which may add more instruments. so for example:

piano "8bit": c d e f g
violin: c d e f g
8bit/violin "group": f e d c

If a plugin is added that adds a stock instrument 8bit, there could be some problems...

@daveyarwood
Copy link
Member

daveyarwood commented Jul 24, 2016

Oh, I see what you're saying. I don't think that will be problematic, though. Take the following score, for example:

piano "violin": c d e
violin: f g a

The first line creates a piano and names it "violin" -- now violin doesn't refer to the stock instrument violin anymore, it refers to that piano instance. In fact, it is now impossible to create a violin instance using violin as the stock instrument:

piano "violin": c d e
violin: f g a
violin "violin-2": b
violin-2: >c

In this score, a piano called "violin" is instantiated on the first line, and continued on the second line. On the third line, the same instrument is continued again and nicknamed "violin-2". On the fourth line, it is continued again. piano, violin, and violin-2 all refer to the same piano instrument in this case, and there is no way to create a violin instance*. Is this a problem? Only if you name your piano "violin"! 😛

*unless you use the stock instrument's full name midi-violin -- but let's not get into that!

The same logic will apply to any new stock instruments that get added as available instruments in Alda scores. For example, if we add a square-osc instrument, and you have an old score where you have a midi-square-lead instance nicknamed "square-osc", your score will still sound the same, using the midi-square-lead instrument, because that's the stock instrument you used when you instantiated it. The nickname doesn't play any role in determining what stock instrument is used.

@elydpg
Copy link
Contributor Author

elydpg commented Jul 24, 2016

That doesn't make sense... In fact I would imagine that violin "violin-2" would call a new violin because its name is explicitly stated along with type.

@daveyarwood
Copy link
Member

violin "violin-2" refers to the piano instance called "violin" in order to be consistent with the way new groups are instantiated from existing instances by referring to them by name. For example:

piano "violin": c d e
violin/guitar "piano-and-guitar": c

Here, on the first line, a piano is created and named "violin". On the second line, the same instance is reused along with a new guitar instance, to form the group named "piano-and-guitar."

So, if the violin in violin/guitar is the piano named "violin", then shouldn't the violin in violin "violin-2" also refer to the piano named "violin"?

@elydpg
Copy link
Contributor Author

elydpg commented Jul 24, 2016

No, as it seems to violate this part of the instances doc:

A new instance of an instrument is created whenever a stock instrument is called with any nickname, either as part of a group or not.

Also, it seems confusing that two names can refer to the same instrument instance.

@jimcheetham
Copy link

Here's your problem:

violin "violin-2" refers to the piano instance called "violin" in order
to be consistent with the way new groups are instantiated from existing
instances by referring to them by name.

You have the same problem with variable naming too - by insisting on an
implicit syntax, you're creating uncertainty. Things that are normally
thought to have been "reserved words" are being overwritten by the user.
You could introduce reserved words to prevent someone calling a piano
"violin", but you might not be able to track future plugin-generated
instruments.

Madness:
violin = a b c
violin "violin": violin

What would happen to instance names if you always required the "double
quotes" to refer to a user's reference?

piano "violin": c d e
violin: c d e
"violin": e d c

If you wanted the mix you suggested earlier, you'd do
piano "violin": c d e
"violin"/guitar "piano-and-guitar": c

If you also signalled user's variable names with a marker, you wouldn't
have to have rules like "has to be two characters at least, and not
starting with a number" :-)

$hook = a b >c<
piano: $hook b b

As a programmer, I'm used to seeing that sort of syntax.

-jim

@elydpg
Copy link
Contributor Author

elydpg commented Aug 1, 2016

Ok; I think I have a pretty good compromise that should be pretty intuitive.

  • Any call of the form <type> <name>: must create a new instrument instance of type <type> with name <name>. Duplicate names will always throw errors here.
  • If a call is of the form <type>:, then the following happens:
    • If there exists an instrument with the name <type>, refer to that instrument.
    • Else if it is the first call of a stock instrument, a new stock instrument instance of type <type> is created with a name to refer to it unambiguously.
    • Else if it refers to a stock instrument, refer to the most recently called instrument of type <type>
  • If a call is a group call, then it is treated exactly like multiple individual calls with no <name> argument (See: If a call is of the form <type>:).
  • However, if the group call has its own <name> argument, then it will reserve <name> to refer to that particular grouping. Duplicate names will always throw errors here.

@daveyarwood
Copy link
Member

It seems like that's fairly close to what we have now, but with a couple of differences:

  • After initializing a particular type of instrument with a name (like trumpet "foo"), the name of the stock instrument (trumpet) now refers to the most recently called instance of that type.

    (Currently, we don't have any defined behavior for which instrument the name of the stock instrument will select in this scenario. I think it just grabs the first instance it finds of that type.)

  • Instrument instances in a named group are not automatically new instances.

    (Currently, if you already have a named piano instance, and then you initialize a grouping called piano/cello, then both piano and cello will be new instances of those stock instruments; piano will not select the existing piano instance.)


Re: the first point, I do like the idea of defining a behavior for that scenario, but I'm not sure if "most recently used instance of that stock instrument" is the behavior we want. That would mean that, in a score where you have multiple named piano instances, if you choose to use piano: then the instance it selects will vary depending on which one was most recently called.

What if, instead of referring to the instance most recently called, the call would create (and then refer back to) a new instance? That would allow for one "anonymous" piano instance, alongside the named ones. For example:

piano "foo": c8 d e f g2
piano "bar": e8 f g a b2

# happens at the same time as foo and bar
piano: o3 c2 g

That behavior seems it might be easier for newcomers to understand, and could possibly be more useful. Although, I would still recommend NOT mixing and matching named vs. unnamed instances; if you find yourself naming one instance, you should name them all.


As for the second point, we would still have the problem of being forced to use an awkward syntax in order to create a named group of new instances:

piano "foo":
harpsichord "bar":
foo/bar "keyboards": c

Whereas currently you can just do:

piano/harpsichord: c

@daveyarwood
Copy link
Member

I think the current system is intuitive as long as you don't mix and match named and unnamed things. What if we threw a descriptive error whenever you tried to do that? That way, newcomers to Alda would learn early how this works.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 2, 2016

Making mixing named and unnamed stock instruments of the same type illegal is probably the most intuitive and least ambiguous solution. One thing I would add is that I like the idea of calls of the form <type> <name>: should always create a new instance of <type> with name <name>, even if there is already an instrument with the name <type>. I also think having a . syntax to refer to anonymous instruments in groups is necessary to make all instruments unambiguous.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 2, 2016

Here's the latest system more formalized:

Two important points:

  1. Every name must have a one-to-one relationship with an instrument instance or group.
  2. Every call is one of exactly four forms, which I am labelling here for convenience: 0–<type> <name>: 1–<argument>: 2–<grouping>: 3–<grouping> <name>:
  • If the call is of form 0, it must create a new instrument instance of type <type> with name <name>. Duplicate names will always throw errors here.
  • If a call is of form 1, then the following happens:
    • If there exists an instrument with the name <argument>, refer to that instrument.
    • Else if there exists a stock instrument of type <argument> , and there is no named stock instrument instance of type <argument>, it refers to an unambiguous instrument instance of type <argument>
    • Else an ambiguity error is thrown
  • If a call is of form 2, then it is treated exactly like multiple individual calls of form 1.
  • If a call is of form 3, then it is treated exactly like multiple individual calls of form 1. As with calls of form 0, duplicate naming will throw errors here. However there is one exception:
    • If one of the component calls refers to a stock instrument that is not one of the named instruments, it is possible to create a new instrument instance unambiguously, aliased to the new group using the reference <groupname>.<instrument>

@elydpg
Copy link
Contributor Author

elydpg commented Aug 2, 2016

Include the rules in the docs. (Replace or update this page?)

I think I would include the rules above somewhere in the documentation, and replace this page with a more user-friendly explanation of how the new rules work.

@daveyarwood daveyarwood added this to the 1.0.0 milestone Aug 3, 2016
@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

Another thing to mention; I'm assuming nested group operators would work; if you had code of the form

piano/guitar "foo":
clarinet "bob":
bob/foo.piano "bar":
bar.foo.piano: 

I would assume that bar.foo.piano would refer to the piano that is in foo and also in bar, though you may as well call it foo.piano. However would it also be called bar.piano?

And what happens if the stock instruments in a new group are the same? piano/piano "foo": would cause problems under the new rules...

@daveyarwood
Copy link
Member

Nested group operators seems like an obscure use case, but I see no reason not to allow it.

Seems like piano/piano "foo": ought to create a new group consisting of two new piano instances, no?

@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

Yes, however consider this:

  1. How do you distinguish between the pianos? does foo.piano refer to the first piano or the second piano?
  2. What about if the duplicate reference is to a named instrument, like foo/foo "bar":?

I reckon the second case should be made illegal, as it doesn't make sense to have the same instrument in a group twice. However the case of piano/piano I think should be allowed. The only question is how to refer to the different instruments?

@daveyarwood
Copy link
Member

Sure, I could see it being useful to define a group of the same instrument playing in unison, for example if you wanted to emulate a chorus effect.

I'm not sure how we should handle the foo.piano case if foo is two pianos... maybe we should throw an error there too? The moral of the story being that if you want to define a group consisting of two of the same instrument, and then access them individually, then you're better off giving the two instances names? e.g.

# not OK
piano/piano "foobar": c d e
foobar.piano: f

# OK
piano "foo":
piano "bar":
foo/bar "foobar": c d e
foo: f

Now we're back to the awkward syntax where you have to define and name instances without giving them any notes to play, but maybe this situation is rare enough that it's acceptable.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

Agreed. Probably could update the ruleset for group calling stating that group calls to the same stock instrument or named instrument are not allowed.

@daveyarwood
Copy link
Member

Sounds good to me. Updated.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

I should also note that in the case of unnamed groups, it is still possible to encounter a case where only some instruments are being created anew:

piano: c d e f
piano/clarinet: g a b >c<

Should this throw an ambiguity error?

@daveyarwood
Copy link
Member

No, that should re-use the same piano instance.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

rules look good then! I'm interested in how the progress is going on the implementation...

@daveyarwood
Copy link
Member

I've been very busy lately, and this issue is not a priority. A PR would be much appreciated, otherwise I'll get to it when I can. I think it will be a while.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

A PR would be much appreciated

How would that work?

@daveyarwood
Copy link
Member

The logic for determining which instrument instances to use/create when calling a part is all in the alda.lisp.score.part namespace -- determine-current-instruments is the most relevant part.

@daveyarwood
Copy link
Member

If you're wanting general info about how to create a PR to a project on GitHub: https://help.github.com/articles/creating-a-pull-request/

@elydpg
Copy link
Contributor Author

elydpg commented Aug 9, 2016

Thanks! If I can figure out the clojure, I'll take a look.

@daveyarwood
Copy link
Member

Awesome, sounds good! I realize it's a lot to ask of anybody to learn a new language just to contribute to an OSS project, and I feel bad that I don't have more time to tackle all of these Alda issues, but I'm basically working on Alda by myself, and there's only so much one person can do :)

@elydpg
Copy link
Contributor Author

elydpg commented Aug 12, 2016

The clojure still goes over my head for me (although even if I knew the language it would probably be faster to write it yourself than me ask about all the contextual information). I could, if you'd like, write some java pseudocode to simulate calling instruments to a score. You might want to assign this to a contributor with some time who actually knows the language :P

@daveyarwood
Copy link
Member

No worries! This shouldn't be hard for myself or another Clojure-savvy contributor to knock out -- the only obstacle for me is finding a pocket of free time :)

@elydpg
Copy link
Contributor Author

elydpg commented Aug 12, 2016

Still interested in the pseudocode?

@daveyarwood
Copy link
Member

Sure, that could be helpful -- I would just put it in a gist or pastebin or something so this issue doesn't get too noisy.

@elydpg
Copy link
Contributor Author

elydpg commented Aug 12, 2016

The code started turning into a mess rather quickly, so I think I'm going to leave it up to you. sorry about that.

@daveyarwood
Copy link
Member

daveyarwood commented Aug 12, 2016 via email

@daveyarwood
Copy link
Member

1.0.0-rc46 is out, incorporating the changes described above.

I've updated the docs as well, summarizing the rules in what I hope is an intuitive way, with examples.

I'm pleased with the state of part and group assignment in Alda now, but I'm happy to discuss further if anyone has any questions or points of confusion going forward!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants