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



Work with rulers and meters. A meter is a marklist on a ruler named Ruler.meter, and is used by Cmd.TimeStep to align things. By convention the meter has regular subdivisions, with Ruler.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 Meter.LabeledMeter, but Ruler.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.local $ LRuler.renumber 7
  • 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.local $ 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.local $ LRuler.measures Meters.m44 6 4
  • Or if you want each quarter note to get 1t, and 8 sections with 4 measures per section:

    LRuler.local $ LRuler.ruler $
          Meter.make_measures Meter.default_config 4 Meters.m44 8 4
  • Or put the selection at the where the 4 meters should end, then:

    LRuler.local $ LRuler.ruler $
          LRuler.fit_to_selection LRuler.config Meter.m44
  • Make the last measure 5/4 by selecting a quarter note and running LRuler.append.
  • 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 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 => Ruler.Ruler -> 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 => Ruler.Rank -> m [Ruler.PosMark] 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.


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

Double the meter of the current block. You can then trim it down to size.

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

Clip the meter to end at the selection.

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.

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

Replace the selected region with another marklist.

replace_range :: TrackTime -> TrackTime -> Meter.LabeledMeter -> Meter.LabeledMeter -> Meter.LabeledMeter Source #

Replace the selected region with another marklist.

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

Strip out ranks below a certain value, for the whole block. Larger scale blocks don't need the fine resolution and can wind up with huge rulers.

measures Source #


:: Cmd.M m 
=> Meter.AbstractMeter 
-> Int


-> Int

measures per section

-> m Modify 

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 Source #


:: Cmd.M m 
=> Int

number of gongs

-> Int

number of jegogans in one gong

-> m Modify 

Create gongs with Gong.gongs.

fit_to_end :: Ui.M m => Meter.Config -> [Meter.AbstractMeter] -> Id.BlockId -> m Ruler.Ruler Source #

Create a meter ruler fitted to the end of the last event on the block.

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.

renumber :: Cmd.M m => Int -> m Modify Source #

Renumber the ruler to start at the given number.

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.


reset_colors :: Cmd.CmdL () Source #

Used to adjust mark colors interactively.


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

Ruler operations don't care about selection orientation.