Karya, built on 2020-11-26T21:03:17 (patch 23b5be2d53a9e8e7d6136cda5aae2849abe5cded)
Safe Haskell None

Cmd.Ruler.Meter

Description

Functions to construct meter rulers.

A meter ruler divides up a block analogous to a staff notation meter. It's actually more general, since the meter just says how to divide up a single measure, and only at one level, while the ruler has arbitrary divisions. However, in practice, it's convenient to use a similar organization to staff notation's meter. So by convention the ranks are for section, measure, half note, etc., and Cmd.TimeStep uses abbreviated mnemonics of these durations for the various ruler ranks it can snap to.

However, rank r_2, which corresponds to TimeStep's h, doesn't necessarily correspond to a half note. It actually corresponds to the division below the measure, which in 3+3/8 is a dotted quarter. In the case of 2/4 it would be a quarter note, but to keep the mnemonic names from getting too far from their staff notation counterparts, the 2/4 meter should skip a rank so that r_1 and r_2 both correspond to the same amount of time.

Synopsis

# Ruler.Ruler

Arguments

 :: Config -> ScoreTime.TrackTime duration of one measure -> AbstractMeter -> Int sections -> Int measures per section -> Ruler.Ruler

Make a ruler fit in the given duration.

# meter marklist

type Meter = [(Ruler.Rank, Duration)] Source #

Meter is for simple numeric meters, as in Cmd.Meters. The labels can be generated entirely from the Ruler.Ranks.

type LabeledMeter = [LabeledMark] Source #

LabeledMeter is for meters that have some structure in their labels, and can't be generated from the Ranks only, such as Cmd.Tala. After modification, they need a separate pass to renumber the labels, looked up in meter_types.

Constructors

 LabeledMark Fieldsm_rank :: !Ruler.Rank m_duration :: !Duration m_label :: !Label

#### Instances

Instances details
 # Instance detailsDefined in Cmd.Ruler.Meter Methods # Instance detailsDefined in Cmd.Ruler.Meter MethodsshowList :: [LabeledMark] -> ShowS # # Instance detailsDefined in Cmd.Ruler.Meter MethodsformatList :: [LabeledMark] -> Doc Source #

Duration between ruler marks. Since these are added together, there is a risk of accumulating innaccuracy. I could use rationals if I changed Ruler.PosMark to rational, but for the moment it's more convenient to stay as TrackTime, and convert to rationals before adding, assuming that TrackTime has enough resolution to figure out what the rational should be.

TODO If I get more inaccuracy problems I should probably just switch to rational, but it's a bit of a pain because Ruler.Marklist and its callers have to change. Also, I'm not even sure if it's a good idea, because TrackTime is still floating point, so there will still be rounding in there somewhere, and this would just put it in more places.

Extract an inclusive range.

Extract a half-open range.

Like extract, but also include the measure Start of the extracted bit.

Remove the half-open range.

## meter constants

The mark color defaults to mostly transparent so it looks nice on overlay rulers.

The mark color defaults to mostly transparent so it looks nice on overlay rulers.

Configs for marks in order of increasing rank. (color, width, zoom_pixels)

zoom_pixels is how many pixels of space a mark at this rank must have between its neighbors before it appears.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

These are the conventional meanings for the ranks.

By convention, ranks divide up the ruler by dividing it by two for each rank. This is convenient because that's how staff notation works. But then the labels wind up being all 0s and 1s, which is not that useful. The ranks in this list don't receive their own label.

rank_names :: [(Ruler.Rank, Text)] Source #

These are mnemonics for staff notation durations, though they may not correspond exactly, as documented in Cmd.Meter.

data RankName Source #

Constructors

 Section W H Q E S T32 T64 T128 T256

#### Instances

Instances details
 # Instance detailsDefined in Cmd.Ruler.Meter Methods # Instance detailsDefined in Cmd.Ruler.Meter MethodsenumFrom :: RankName -> [RankName] #enumFromTo :: RankName -> RankName -> [RankName] # # Instance detailsDefined in Cmd.Ruler.Meter Methods # Instance detailsDefined in Cmd.Ruler.Meter Methods(<) :: RankName -> RankName -> Bool #(>) :: RankName -> RankName -> Bool # # Instance detailsDefined in Cmd.Ruler.Meter MethodsshowList :: [RankName] -> ShowS # # Instance detailsDefined in Cmd.Ruler.Meter MethodsformatList :: [RankName] -> Doc Source # # Instance detailsDefined in Derive.Typecheck Methods # Instance detailsDefined in Derive.Typecheck Methods

## construct meters

An AbstractMeter is a structured description of how a unit of time is broken up into hiererchical sections. A T represents a mark with the unit duration, and a D is a group of Meters. The rank of each mark is determined by its nesting depth.

Previously a T could take a duration, but I didn't wind up using that feature, so I removed it. So meters have to be built of multiples of a unit duration multiplied by some stretch factor.

An AbstractMeter can be created either by declaring it outright, or by declaring a simpler AbstractMeter and subdividing or repeating it.

Constructors

 T D [AbstractMeter]

#### Instances

Instances details
 # Instance detailsDefined in Cmd.Ruler.Meter Methods # Instance detailsDefined in Cmd.Ruler.Meter MethodsshowList :: [AbstractMeter] -> ShowS #

Subdivide each mark into the given number Ds. This has the effect of putting one layer of subdivision under the current structure.

Create a layer that repeats the given meter a certain number of times.

Form a meter based on regular subdivision. E.g. [4, 4] is 4 groups of 4, [3, 3] is like 9/8, and [4, 3] is 4 groups of 3 (12/8).

### AbstractMeter utils

Map the given function over all Ts in the given AbstractMeter.

## meter implementation

Convert AbstractMeters into a Meter. The AbstractMeters are concatenated, and each one defines a rank 0.

Like make_meter, but stretch the meter to fit in the given duration.

## marklist conversion

data Config Source #

Constructors

 Config Fieldsconfig_labeled_ranks :: !(Set RankName)Skip labels for these ranks.config_label_components :: !LabelComponentsThe convention is that the first two ranks, section and measure, are universal. So this omits measure, which gets measure_labels, starting from config_start_measure.config_start_measure :: !StartStart measure_labels from this number.config_min_depth :: !IntLabels have at least this many sections. Otherwise, trailing sections are omitted.config_strip_depth :: !IntStrip leading prefixes to this depth, via strip_prefixes.config_name :: !TextKey to Ruler.config_name.

#### Instances

Instances details
 # Instance detailsDefined in Cmd.Ruler.Meter MethodsformatList :: [Config] -> Doc Source #

type Start = Int Source #

The ruler should start counting at this number. This could be measure number, or gong count, or avartanam count, whatever is the highest visual Label.

Get the rank that the measure count lives at, as used by renumber_measures. It assumes it's either Section or W.

Convert a Meter into a Marklist using the default labels.

Create a Marklist from a labeled Meter.

The last mark gets a 0 duration.

### implementation

Arguments

 :: Int each section starts its count here, presumably 0 or 1 -> LabelComponents

Like number_components, but the first two are bigger.

The rank duration is the duration until the next mark of equal or greater (lower) rank.

Given a mark duration and the number of pixels it needs to display, return the appropriate zoom factor.

# labels

Strip all labels and renumber. I can do this for a known Config because I can regenerate the labels from the rank.

Renumber the top level of the labels, which is assumed to be the measure number, which was presumably added by convert_labels.

newtype LabelComponents Source #

This is the prototype for how to draw labels. The outer list is indexed by rank, while the inner is has the sequence of labels at that rank. convert_labels will take from a given level each time it sees that rank, and reset back to the beginning when the rank becomes less than that level. The inner list should be infinite to so it won't run out of labels no matter how many consecutive ranks are at that level.

Constructors

 LabelComponents [[Label]]

#### Instances

Instances details
 # Instance detailsDefined in Cmd.Ruler.Meter MethodsshowList :: [LabelComponents] -> ShowS # # Instance detailsDefined in Cmd.Ruler.Meter Methods

Arguments

 :: Int Labels have at least this many sections. Otherwise, trailing sections are omitted. -> LabelComponents -> Start -> [Ruler.Rank] -> [[Label]]

Convert label components to label lists based on the given ranks.

collapse_ranks :: [Ruler.Rank] -> [Ruler.Rank] -> [Ruler.Rank] Source #

The ruler gets cluttered if I label every single rank, so combine the ones in the given list with the following rank.

strip_prefixes :: Text -> Int -> [[Label]] -> [[Label]] Source #

When labels are created, many of them have the same components as the previous label, e.g. 1.1.1, 1.1.2. Replace the identical components with a placeholder to make the difference more apparent: 1.1.1, -.-.2.

This doesn't actually look that nice on the UI because it does it for all labels, not just the visible ones.

apply_labels :: [[Label]] -> [Ruler.Rank] -> [[Label]] Source #

Apply the labels according to the ranks. Each Rank input has a corresponding [Label] output. Each rank advances the label at the rank's index in the labels, and resets all the labels beneath it. If a rank runs out of labels, "" is emitted.

The first rank doesn't matter since it always emits the initial state of the labels.