alda-lang / alda

A music programming language for musicians. :notes:
https://alda.io
Eclipse Public License 2.0
5.6k stars 288 forks source link

Can't use ms durations inside CRAM #322

Closed aengelberg closed 2 years ago

aengelberg commented 7 years ago
piano> {c500ms}1
java.lang.ArithmeticException: Divide by zero
elydpg commented 7 years ago

imo it doesn't make sense to have millisecond durations inside crams, since ratios inside crams are relative. This should at least throw a dedicated error though...

aengelberg commented 7 years ago

I was hoping I could use milliseconds to more explicitly specify the ratios I'm expecting between note durations. e.g. for a 4:3:2 ratio:

{c4ms d3ms e2ms}1

as opposed to something like

{c4 d8. e8}1

which is less intuitive.

elydpg commented 7 years ago

Remember that {ax by} means that whenever a plays x times, b should play y times, within the cram. So for your 4:3:2 ratio example, {c2 d3 e4} should work.

aengelberg commented 7 years ago

{c2 d3 e4} would be a 6:4:3 ratio.

elydpg commented 7 years ago

Ah, you're thinking in terms of counts, whereas I'm thinking in terms of the "for every" system I described above. Such are the confusions when the notelength notation is reciprocal...

Personally I think there needs to be a formal way to notate durations in terms of fractions of a bar, however you can try the set-duration attribute and see if that works. set-duration works in terms of fractions of a quarter note, so (set-duration 5) sets a note to 5 quarter notes long. {(set-duration 4) c (set-duration 3) d (set-duration 2) e} should work, although it's not exactly intuitive.

daveyarwood commented 7 years ago

I was hoping I could use milliseconds to more explicitly specify the ratios I'm expecting between note durations. e.g. for a 4:3:2 ratio:

{c4ms d3ms e2ms}1

I like that idea, but it's interesting to consider how that would interact with standard note lengths. For example, how would the ratios be assigned here?

{c4ms d8 e2ms}

The duration of an 8th note varies depending on the tempo at that moment. In most cases, this is not difficult to calculate -- e.g. if the tempo is 120 bpm, then an 8th note takes 250ms, so the ratio would be 4:250:2.

But, it gets more complicated than that because in Alda, different instruments can be playing at different tempos at the same time. Consider this score:

cello: (tempo 120)
bassoon: (tempo 60)

cello/bassoon: {c4ms d8 e2ms}

Now, the cello's ratio is 4:250:2 and the bassoon's ratio is 4:500:2.

To further complicate things, we're also concerned with the number outside the brackets, i.e. the length of the entire CRAM expression. This can be explicit, e.g. {c d e}2 or implicit, e.g. {c d e}. When it's implicit, the length is determined just like for notes and rests, where if the length is left out, we use the last declared note length.

This can lead to situations where multiple instruments play at different speeds, depending on their respective implicit note lengths, as shown in this example score:

piano: (set-duration 4)
harp:  (set-duration 2) (octave 3)

piano/harp:
  {e f g} {a b > c}

harp:
 {d e f} {g a b}

Having said all that, I don't think it's necessarily a problem that Alda allows you to get yourself into situations like the ones above. I actually consider it a feature.

As far as I can tell, it should be possible to allow millisecond durations inside of a CRAM, even alongside standard note lengths. It's not an easy to change to make, because the code is currently oriented around counting beats to determine the ratio, but I am on board with making the change.

I probably won't get to this for quite a while -- PR welcome, if someone is willing to tackle it. :)

elydpg commented 7 years ago

As far as I can tell, it should be possible to allow millisecond durations inside of a CRAM, even alongside standard note lengths.

I'm curious as to how that would work from a logic perspective. Would millisecond durations inside the cram just override the length of the cram itself? And then only the notes within the cram with relative length would be counted for the ratio and length system? Not sure tbh...

Also @aengelberg in terms of better notation I suggested fractional notelength notation awhile back which you can check out in alda-lang/alda-core#16

daveyarwood commented 7 years ago

Instead of tallying beats, we would tally milliseconds, as I described above.

There are 2 relevant numbers, when it comes to CRAM:

That ratio (e.g. 792 / 2000) is then used to speed up or slow down the notes inside the brackets so that they sum up to the outer duration.

The issue right now is that we don't support ms durations inside a CRAM -- we ignore them and consider them to be 0-length.

daveyarwood commented 2 years ago

@aengelberg I just realized that I totally fixed this in the process of porting Alda to Go. I think this has been fixed since I released Alda 2.0.0 last summer. :tada: