ctford / leipzig

A music composition library for Clojure and Clojurescript.
Other
454 stars 26 forks source link

[Feature Request] Velocity support #10

Closed kureta closed 5 years ago

kureta commented 8 years ago

Velocity is also an important part of music. It would be great if notes were represented like this:

{:time 0
:pitch 67
:velocity 127
:duration 2
:part :melody}
ctford commented 8 years ago

Thanks for the feedback. As it happens, I had a very similar idea myself. phrase currently supports an optional third argument, which sets :velocity keys. It's still up to you to make use of it in your play-note definitions.

What unit are you using for velocity? When I implemented the feature, I imagined that it would be centred around 1 i.e. 1/2 implies a soft note and 3/2 a stressed not.

kureta commented 8 years ago

A floating point between 0 and 1 would be more general I guess. Currently I am trying to use leipzig to play midi instruments so my units are between 0-127. I am trying to converge my setup into Clojure, from Common Music/Open Music (for classical notation, composing for physical instruments and human players) + Clojure.(as a more sane alternative to directly using SuperCollider).

Oh! I just got what you meant by "centered around 1". It is an interesting idea. However basically everything that can accept a note event expects a velocity from nothing to full-force. Also assuming a "normal" velocity as 1.0 would be useless in many situations. For example if you write a Debussy inspired delicate piano prelude your normal would be below 1.0. So there are no advantages to a normal velocity. But I might be wrong.

Thanks for the quick response.

ctford commented 8 years ago

I'm interested to hear how you use the velocity in the instrument definition. So far, I generally multiply the volume of the instrument by the velocity, which is why 1 being neutral works for me.

As an aside, it's interesting to use wherever and testing whether the time is a multiple of four to add metre.

On 29 February 2016 at 21:47, kureta notifications@github.com wrote:

A floating point between 0 and 1 would be more general I guess. Currently I am trying to use leipzig to play midi instruments so my units are between 0-127. I am trying to converge my setup into Clojure, from Common Music/Open Music (for classical notation, composing for physical instruments and human players) + Clojure.(as a more sane alternative to directly using SuperCollider).

Oh! I just got what you meant by "centered around 1". It is an interesting idea. However basically everything that can accept a note event expects a velocity from nothing to full-force. Also assuming a "normal" velocity as 1.0 would be useless in many situations. For example if you write a Debussy inspired delicate piano prelude your normal would be below 1.0. So there are no advantages to a normal velocity. But I might be wrong.

Thanks for the quick response.

— Reply to this email directly or view it on GitHub https://github.com/ctford/leipzig/issues/10#issuecomment-190410829.

Bohrbug commented 8 years ago

Yes, velocity is an very good idea. Are you guys familiar with Symbolic Composer ? http://symboliccomposer.com/ I used it for more than a decade, it's super, but it is not open source and not suitable for live coding. But it is worth to check, for inspiration, as it has a lot of similarities with what Leipzig wants to accomplish i guess. I love the idea of community supported, free software, so I don't use it as often anymore.

Chris, as I susggested on Gitter, would it be possible to implement a negavtive rational for a rest in rhythms ? The nil before pitches for a rest isn't very helpful when constructing rhythms, though i find it very interesting for constructing melodies for sure. Something like that would be very helpful.

Thanks for all the good stuff you are doing already with this library.

Best,

Dago

On Mon, Feb 29, 2016 at 10:52 PM, Chris Ford notifications@github.com wrote:

I'm interested to hear how you use the velocity in the instrument definition. So far, I generally multiply the volume of the instrument by the velocity, which is why 1 being neutral works for me.

As an aside, it's interesting to use wherever and testing whether the time is a multiple of four to add metre.

On 29 February 2016 at 21:47, kureta notifications@github.com wrote:

A floating point between 0 and 1 would be more general I guess. Currently I am trying to use leipzig to play midi instruments so my units are between 0-127. I am trying to converge my setup into Clojure, from Common Music/Open Music (for classical notation, composing for physical instruments and human players) + Clojure.(as a more sane alternative to directly using SuperCollider).

Oh! I just got what you meant by "centered around 1". It is an interesting idea. However basically everything that can accept a note event expects a velocity from nothing to full-force. Also assuming a "normal" velocity as 1.0 would be useless in many situations. For example if you write a Debussy inspired delicate piano prelude your normal would be below 1.0. So there are no advantages to a normal velocity. But I might be wrong.

Thanks for the quick response.

— Reply to this email directly or view it on GitHub https://github.com/ctford/leipzig/issues/10#issuecomment-190410829.

— Reply to this email directly or view it on GitHub https://github.com/ctford/leipzig/issues/10#issuecomment-190413182.

ctford commented 8 years ago

I'll take a look at Symbolic Composer. Thanks for the tip.

The negative numbers coding rests is a really interesting idea. I see your point about rhythms - so far I've used atonal rhythms exclusively with percussion, so I've been able to encode a rest by extending the previous note. I can see that's not a general solution.

By the way, the way Leipzig is designed, you should be able to experiment with your own functions and mix them in at will. So long as a function outputs notes in the right format, then it should just work. So we could (experimentally) create phrase2 that used the negative-rest technique, and it wouldn't have to immediately be in Leipzig itself.

Having said that, I'll take a look at implementing it. I think I'd want to try it out myself a couple of times before documenting/announcing that behaviour, just because punning on negatives like that could some people.

Thanks again.

Bohrbug commented 8 years ago

Super, Chris. thanks for the reply ! I'll try to experiment with mixing some functions in and see if I can come up with something. btw : a spin-off of Symbolic Composer , named OpusModus, uses this negative rationals as well. http://opusmodus.com/omn.html This one is usable for live coding. But not open source as well.

Cheers

On Tue, Mar 1, 2016 at 9:57 AM, Chris Ford notifications@github.com wrote:

I'll take a look at Symbolic Composer. Thanks for the tip.

The negative numbers coding rests is a really interesting idea. I see your point about rhythms - so far I've used atonal rhythms exclusively with percussion, so I've been able to encode a rest by extending the previous note. I can see that's not a general solution.

By the way, the way Leipzig is designed, you should be able to experiment with your own functions and mix them in at will. So long as a function outputs notes in the right format, then it should just work. So we could (experimentally) create phrase2 that used the negative-rest technique, and it wouldn't have to immediately be in Leipzig itself.

Having said that, I'll take a look at implementing it. I think I'd want to try it out myself a couple of times before documenting/announcing that behaviour, just because punning on negatives like that could some people.

Thanks again.

— Reply to this email directly or view it on GitHub https://github.com/ctford/leipzig/issues/10#issuecomment-190619334.

kureta commented 8 years ago

Since the synths have a maximum amplitude of 1.0 I send a velocity between 0.0-1.0 directly to my synths as amp. Inside the synth amp is probably transformed into an exponential though. As I said I also use 0-127 for playing midi.

About rests: I have just started playing around with leipzig and didn't have time to look at it during the last couple of days. I just realized that (phrase) function accepts duration, pitches, and velocities but not time.

I usually represent music using time and duration for a single note. That way I can play more than one note at the same time, I can play a second note without stopping the first note, and I don't need a different symbol for a rest. For example I just write [time:0, pitch: 60, duration: 1, velocity: 90], [time: 3, pitch 63, duration: 1, velocity: 90] so there is a 2-unit rest between these two notes. (I did this when I used python for this stuff)

ctford commented 8 years ago

@kureta, Leipzig also has both :time and :duration, so you can play chords etc. The tricky part is when rests occur at the end of a melody. If I want to play twice a four beat melody with a one beat rest at the end, how would times know when to start the second time around? That was an issue with the first version of Leipzig.

At the moment, Leipzig represents rests as notes with a :time and :duration, but no :pitch. play-note implementations are responsible for ignoring them.

This is a bit annoying, and also makes it impossible to represent rests in rhythms, which is why I haven't been able to do something nice along the lines of @Bohrbug's suggestion. I'm considering a special :rest? field that I can set to true and therefore filter those notes before play-note is called.

ctford commented 5 years ago

I've now implemented ignoring :rest?-marked notes in master.