DigiScore / neoscore

A python library for notating music in a graphics-first paradigm
https://neoscore.org
BSD 3-Clause "New" or "Revised" License
108 stars 9 forks source link

Support tremolos #87

Closed ajyoon closed 1 year ago

ajyoon commented 1 year ago

The API needs some thought, but it would be reasonable to include automatic tremolo support in Chordrest. The tremolo marking positioning logic can be subtle and tricky to get right, so we should save users the trouble. Ideally the solution should also support custom tremolo marking glyphs, like the penderecki tremolo.

See also https://w3c.github.io/smufl/latest/tables/tremolos.html

This feature gap was raised by @charlesneimog in #86

craigvear commented 1 year ago

Is your thinking here that Chordrest has a bool param for a trem (e.g. has_trem: bool = False), or we create a trem object that is given a Chordrest as its parent?

craigvear commented 1 year ago

But we would need to pass trem the rhythmic sub-division such 3, as this dictates the rhythmic result. E.g. tremelo1 over a semi-breve would result in a series of 8th notes over the bar. Perhaps has_trem: int = 0. Any number > 0 would indicate the rhythmic type of the assigned trem. Should it be a separate object? They can be drawn between 2 notes to signify trem of both events.

ajyoon commented 1 year ago

good points, I think you're probably right it makes more sense to make tremolo supported with a separate class. Optionally it could take a chordrest (or 2 for 2-chord tremolos) and intelligently work out a positioning.

craigvear commented 1 year ago

I'm happy to tinker with this one. Is a good additional class to have and its quite a creative music function. Agreed about making either single Chordrest (start parent?) or 2 Chordrests (start and end?). The intelligent positioning AND slant angle looks a lot similar to the tuplet class I worked on last. Any others spring to mind as a staring point?

ajyoon commented 1 year ago

It feels a bit weird to me for Tremolo to inherit Spanner, since the more common case by far is single-chordrest trems, but maybe it's alright as long as the Tremolo init function abstracts away the spanner-ness so it's elegant to simply provide a chordrest and let the magic happen.

btw, you'll probably want to use Beam for drawing the actual paths.

charlesneimog commented 1 year ago

One more request, maybe, not just add the tremolo option, but make it possible do replace the tremolo symbol with something else, like the pendereckiTremolo, etc...

craigvear commented 1 year ago

Quick Question. Should the parent of Tremolo be a type Chordrest (so I can extract info about highest_notehead), or a PositionedObject (and adjust positioning from that)? I guess we are setting up a new type of class that could set the design for many other types of note ornamentation.

ajyoon commented 1 year ago

I think the best approach is to make Tremolo by default just take a general parent(s), position, and styling info, then provide it with a convenience constructor like Tremolo.for_chordrest(cr: Chordrest) -> Tremolo which automatically works out a sensible layout for this common use-case.

I'm actually not sure it is best to have it also support glyph-based appearances, since that's quite a different (and more narrow) functionality than tremolos, whose layout is more involved. For something like penderecki trems, I think it would be better if Chordrest had its own method like Chordrest.mid_stem_attachment_point(self) -> Point, which conveniently works out where such glyphs would be placed, similar to Chordrest.extra_attachment_point. Users wanting penderecki trems would then simply do something like MusicText(cr.mid_stem_attachment_point(), cr, 'pendereckiTremolo'). I think Tremolo should be broadly limited to standard beam-like slashes.

ajyoon commented 1 year ago

This is released now in 0.1.12. See Tremolo

ajyoon commented 1 year ago

@craigvear want to take a crack at adding a section on tremolos in the doc guide? I'm not sure the best place for it. Maybe a new subsection at the end of "Advanced Chordrests"?