Karya, built on 2022-03-21T01:30:44 (patch 89d1651424c35e564138d93424a157ff87457245)
Safe HaskellSafe-Inferred



Work with rulers and meters. A meter is a marklist on a ruler named meter, and is used by Cmd.TimeStep to align things. By convention the meter has regular subdivisions, with Ranks that correspond roughly to timestep durations (e.g. whole, half, quarter notes). The ruler marks are numbered, and this module, with the support of Cmd.RulerUtil, lets you modify the meter in a higher level way and takes care of renumbering the labels so e.g. measure numbers always count up even if you double the length of the meter.

Ultimately this is necessary because I want to manipulate rulers as a high level Meter.Meter or LabeledMeter, but Marklist has lost the meter's structure. That in turn is because different kinds of meters, talams, gong cycles, etc. have different structures and I didn't think I could come up with a single high level data structure that fit them all and still allowed generic manipulation.

Many functions emit a Modify. If defaults to RulerUtil.Section scope, but you can change it to work on selected tracks with tracks or all rulers in the block with block. Then, the modify function will destructively modify selected rulers, while the local function will modify via copy-on-write, so that other blocks or tracks are unaffected.


  • Start at a different measure number:

    LRuler.modify $ LRuler.set_start_measure 4
  • Bali: 8 gongs with 4 jegogans per gong. Since counts are on calung, and there are 2 calung per jegogan, this is basically an 8 beat cycle:

    LRuler.modify $ LRuler.gongs 8 4
  • Give the current block 6 sections of standard 4/4 meter, with 4 measures per section, where each measure gets 1t:

    LRuler.modify $ LRuler.measures Meters.m44 6 4
  • TODO make a middle measure 5/4?
  • Set a block to 8 avartanams of adi talam:

    LRuler.local $ LRuler.ruler $ Tala.adi 8
  • Change the selected tracks to 8 avartanams of tisram:

    LRuler.local $ LRuler.tracks $ LRuler.ruler $
      Tala.simple Tala.adi_tala 3 8
  • Slow and fast rupaka, chatusra nadai:

    LRuler.local $ LRuler.ruler $ Tala.simple Tala.rupaka_tala 4 8
    LRuler.local $ LRuler.ruler $ Tala.simple Tala.rupaka_fast 4 8
  • Set a block to 8 avartanams of adi talam, then select tracks and set them to chatusram-tisram:

    LRuler.modify $ LRuler.ruler $ Tala.adi 8
    LRuler.local $ LRuler.tracks $ LRuler.ruler $ LTala.chatis 8 4

general purpose

listn :: Cmd.CmdL [(Id.RulerId, Int)] Source #

List all rulers, along with the number of blocks each one appears in.

gc :: Ui.M m => m [Id.RulerId] Source #

Destroy all unrefereced rulers, and return their now-invalid RulerIds.

unify :: Ui.M m => m [[Id.RulerId]] Source #

Group together rulers that are the same, replace all the duplicates with the first ruler in each group, then gc away the duplicates. Return the duplicates.

sync_ids :: Ui.M m => m Text Source #

After copying blocks around and fiddling with rulers, the RulerIds can wind up with names from other blocks. Synchronize RulerIds along with their owning BlockIds. A RulerId only on one BlockId is assumed to be local to that block, and will get its name.

blocks_of :: Ui.M m => Id.RulerId -> m [Id.BlockId] Source #

Blocks that contain the given ruler.

set_ruler_id :: Ui.M m => Id.RulerId -> Id.BlockId -> m () Source #

Set the rulers on a block to the given RulerId.

copy :: Cmd.M m => Id.BlockId -> m () Source #

Copy the ruler of the given block to the current one.

set :: Ui.M m => Id.RulerId -> Id.BlockId -> RulerUtil.Scope -> m () Source #

Set the ruler of the tracks in the given scope.

ruler :: Cmd.M m => Meter.Meter -> m Modify Source #

Replace the ruler.

modify_rulers :: Cmd.M m => (Ruler.Ruler -> Ruler.Ruler) -> m () Source #

Modify all rulers.

replace_ruler_id :: Ui.M m => Id.RulerId -> Id.RulerId -> m () Source #

Replace all occurrences of one RulerId with another.


selected_marks :: Cmd.M m => Meter.Rank -> m [(TrackTime, Mark.Mark)] Source #

Ruler under the selection having at least the given rank.

selected :: Cmd.M m => m Id.RulerId Source #

Ruler of the track under the selection.

upgrade to Meter.Meter

replace_meters :: Ui.M m => Bool -> Upgrade -> m String Source #

LRuler.replace_meters LRuler.upgrade_gong
LRuler.replace_meters (LRuler.upgrade_infer Meters.m44)

replace_meter :: Ui.M m => Bool -> Upgrade -> Id.RulerId -> m String Source #

Add a Meter for the ruler if not already present.


append :: Cmd.M m => m Modify Source #

Copy the meter under the selection and append it to the end of the ruler.

append_ruler_id :: Cmd.M m => Id.RulerId -> m Modify Source #

Append another ruler to this one.

delete :: Cmd.M m => m Modify Source #

Remove the selected range of the ruler and shift the rest up.

insert :: Cmd.M m => TrackTime -> m Modify Source #

Insert the selected meter range at the given time.

measures :: Cmd.M m => Meter.AbstractMeter -> Sections -> Measures -> m Modify Source #

Set the ruler to a number of measures of the given meter, where each measure gets 1t:

LRuler.local $ LRuler.measures Meters.m44 4 4
LRuler.modify $ LRuler.measures Meters.m34 4 8

gongs :: Cmd.M m => Gong.Gongs -> Gong.Jegogans -> m Modify Source #

Create gongs with gongs.

concat :: Cmd.M m => [Id.BlockId] -> m Modify Source #

Replace the meter with the concatenation of the rulers of the given blocks. This is like extract except it doesn't infer the blocks from the calls and doesn't scale the extracted rulers.

pull_up, push_down

pull_up :: Cmd.M m => m Modify Source #

Extract the meter marklists from the sub-blocks called on the given track, concatenate them, and replace the current meter with it.

push_down :: Cmd.M m => Bool -> m () Source #


tracks :: Cmd.M m => m Modify -> m Modify Source #

Change a Modify so it modifies only the selected tracks.

block :: Cmd.M m => m Modify -> m Modify Source #

Change a Modify so it modifies all rulers on the block.

data Modify Source #

Enough information to modify a ruler.

TODO I could also include entire block, and then add_cue etc. could use it, in addition to being able to clip the entire block.

local :: Cmd.M m => m Modify -> m [Id.RulerId] Source #

modify :: Cmd.M m => m Modify -> m () Source #

local_m :: Cmd.M m => Modify -> m [Id.RulerId] Source #

Modify a ruler or rulers, making a copy if they're shared with another block.

modify_m :: Cmd.M m => Modify -> m () Source #

Modify the ruler on the focused block. Other blocks with the same ruler will also be modified.

local_ruler :: Ui.M m => Id.BlockId -> (Ruler.Ruler -> Ruler.Ruler) -> m Id.RulerId Source #

Modify a local copy of the main block ruler.


set_start :: Cmd.M m => m Id.RulerId Source #

Set the block's logical start time to the selection. Notes before this will play before the start of the calling event.

set_end :: Cmd.M m => m Id.RulerId Source #

Set the block's logical end time to the selection. Notes after this will play after the end of the calling event.


add_cue :: Text -> Cmd.CmdL Id.RulerId Source #

Drop a mark at the selected point in the "cue" ruler.


selection_range :: Cmd.M m => m (TrackTime, TrackTime) Source #

Ruler operations don't care about selection orientation.