tmhglnd / mercury-playground

The Mercury live coding environment running in the browser
GNU General Public License v3.0
62 stars 6 forks source link

Allow setting duration relative to note event spacing #43

Open totalgee opened 9 months ago

totalgee commented 9 months ago

I'd like a duration/length setting (especially for MIDI notes, but applies to synths/samples too) that is relative to the note event spacing -- like legato in SuperCollider Events. The default legato is 0.8 in SC, which means the Event "gate" is held for 80% of their duration. In MIDI terms, this would be the time between a noteOn and its corresponding noteOff. You can set it to a small fraction (e.g. 0.1) for very short staccato notes, or > 1 for legato notes that overlap and last longer than the space between notes.

With Mercury and a mono MIDI synth, I'm getting issues where I have to figure out what length/duration to set, based on time, but the actual duration (or maybe better to say inter-onset spacing) can be affected by other things, like timediv.

tmhglnd commented 9 months ago

Yes, I like this feature so will have a look if it is possible to implement. In terms of the code I see 2 options:

  1. Specify the duration as a floating point number 0-0.999, just like in SC. This could lead to some confusion tho because a 1 would then mean 1ms (since that's how it currently works), and not 100%

  2. Specify the duration as a percentage string "0%" - "100%". This is probably the most clear, but a bit more typing.

totalgee commented 9 months ago

I see, yes, good old backward compatibility. (-;

The number should also be settable longer than 100%, if that's technically possible within Mercury, so the next note can start before the current one has ended (legato). If the decimal thing won't work then the % notation seems reasonable. Maybe you wouldn't even be a new function/keyword in that case, you could just make duration/length support relative values using % suffix on numbers.

totalgee commented 9 months ago

The more I think about it, I think it could be better to have the % sign to specify relative duration, if you can. Because a fractional value still has meaning in other cases, like length(5.5) would mean 5.5 ms and length(0.9/8) means 90% of an eighth note. With the new/proposed notation, if I had specified time(1/8) then I could just set length(90%), and if I change to time(1/16) I wouldn't have to adjust the length as well, as I do now.

The only "weird" thing is whether you could put them (% durations) in lists, like for example if I want to mix portamento with non-portamento, I'd want to be able to do this:

// Every second note has portamento (length > 100%)
// Can you allow percentages in lists?
new midi default time(1/16) note([2 4 6 8]) play(random(16 2)) length([90% 110%])

// Right now, it works if I do this, but is clunky to have to write /16 on everything in length()!
new midi default time(1/16) note([2 4 6 8]) play(random(16 2)) length([0.9/16 1.1/16])
tmhglnd commented 9 months ago

So something to reduce typing right now is for example to apply an add() list function to the parameters. If add has a string as argument it will actually concatenate the number and string into a new string. If both values were a number it would add normaly of course. For example:

list durs [0.9 1.1]
print durs
//=> [0.9 1.1]

// adding a string to every item in the list will concatenate the number to the string
list fracs add(durs '/16')
print fracs
//=> [0.9/16 1.1/16]

With the same logic in the future, if % would be possible to use then you could easily do:

// generate 8 random percentages between 0-100
list durs random(8 0 100) 
print durs
//=> [89 66 86 76 39 9 67 75]

list percentages add(durs '%')
print percentages
//=> [89% 66% 86% 76% 39% 9% 67% 75%]

In some cases it is possible to omit the ' in the code, for example add(durs %) also works because % can not be anything else than a string. add(durs /16) is not possible because the parser thinks you write a division/fraction for a timing and is therefore looking for a number in front of the /

totalgee commented 9 months ago

Nice! I love the way numbers with / are special, they're actually strings and not calculated as numeric expressions. It's not really obvious (to me, at first) but it works well, as soon as you understand you can't just write "inline" math operations directly in Mercury, you need to use functions like add().