Karya, built on Mon Jul 24 11:39:07 PDT 2017 (patch 33511aca01257b76b88de7c7a2763b7a965c084e)

Safe HaskellNone

Cmd.Ruler.Meter

Contents

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

make_measures Source #

Arguments

:: MeterConfig 
-> ScoreTime.TrackTime

duration of one measure

-> AbstractMeter 
-> Int

sections

-> Int

measures per section

-> Ruler.Ruler 

fit_ruler :: MeterConfig -> ScoreTime.ScoreTime -> [AbstractMeter] -> Ruler.Ruler Source #

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.

type Duration = ScoreTime.TrackTime 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.

clip :: Duration -> Duration -> LabeledMeter -> LabeledMeter Source #

Extract the inclusive range from start to end.

delete :: Duration -> Duration -> LabeledMeter -> LabeledMeter Source #

Remove the half-open range.

meter constants

color1 :: Double -> Double -> Double -> Color.Color Source #

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

color2 :: Double -> Double -> Double -> Color.Color Source #

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

meter_ranks :: [(Color.Color, MarkWidth, Int)] Source #

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.

r_section :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_1 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_2 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_4 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_8 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_16 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_32 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_64 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_128 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

r_256 :: Ruler.Rank Source #

These are the conventional meanings for the ranks.

default_labeled_ranks :: Set RankName Source #

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.

construct meters

data AbstractMeter Source #

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] 

subdivide :: Int -> AbstractMeter -> AbstractMeter Source #

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

repeat :: Int -> AbstractMeter -> AbstractMeter Source #

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

regular_subdivision :: [Int] -> AbstractMeter Source #

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

replace_t :: AbstractMeter -> AbstractMeter -> AbstractMeter Source #

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

meter implementation

make_meter :: Duration -> [AbstractMeter] -> Meter Source #

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

fit_meter :: Duration -> [AbstractMeter] -> Meter Source #

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

marklist conversion

data MeterConfig Source #

Constructors

MeterConfig 

Fields

meter_marklist :: MeterConfig -> Meter -> Ruler.Marklist Source #

Convert a Meter into a Marklist using the default labels.

labeled_marklist :: LabeledMeter -> Ruler.Marklist Source #

Create a Marklist from a labeled Meter.

marklist_labeled :: Ruler.Marklist -> LabeledMeter Source #

The last mark gets a 0 duration.

implementation

big_number_components :: Int -> Int -> LabelComponents Source #

Like number_components, but the first two are bigger.

rank_durs :: Meter -> [Duration] Source #

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

pixels_to_zoom :: Duration -> Int -> Double Source #

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

labels

mtype :: Ruler.MeterType Source #

Standard numbered meter, starting from 1.

renumber_meter :: MeterConfig -> Renumber Source #

Strip all labels and renumber. I can do this for default_config because I can regenerate the labels from the rank. TODO can't I do it for tala too? I would need to put meter_types into another module that can import both Cmd.Meter and Cmd.Tala

renumber_topmost :: Renumber Source #

Renumber only the topmost count. The number is increased at ranks 0 and 1, based on unlabeled_ranks.

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]] 

convert_labels Source #

Arguments

:: Int

Labels have at least this many sections. Otherwise, trailing sections are omitted.

-> LabelComponents 
-> [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.