Module:MOS: Difference between revisions

Ganaram inukshuk (talk | contribs)
No edit summary
ArrowHead294 (talk | contribs)
m Comment formatting
Line 1: Line 1:
-- Module for working with mosses in lua code; this serves as a "library" for
--[[
-- mos-related modules and thus does not have a corresponding template.
  Module for working with mosses in lua code; this serves as a "library" for
-- Functionality includes:
  mos-related modules and thus does not have a corresponding template.
-- - Creating/parsing mosses
 
-- - Creating scalesigs (string representations) of mosses
  Functionality includes:
-- - Finding certain modes of a mos
  - Creating/parsing mosses
-- - Finding generators for a mos
  - Creating scalesigs (string representations) of mosses
-- - Producing vectors for simple mos intervals
  - Finding certain modes of a mos
-- - Interval arithmetic, in the form of adding vectors of L's and s's, and
  - Finding generators for a mos
--  period/equave-reducing intervals
  - Producing vectors for simple mos intervals
-- - Finding equal tunings for mosses
  - Interval arithmetic, in the form of adding vectors of L's and s's, and
    period/equave-reducing intervals
  - Finding equal tunings for mosses
]]--
 
local rat = require("Module:Rational")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local utils = require("Module:Utils")
local et = require("Module:ET")
local et = require("Module:ET")
local tip = require("Module:Template input parse")
local p = {}
local p = {}


-- Naming scheme for function names:
--[[
-- - Functions related to mosses don't have any special names.
  Naming scheme for function names:
-- - Functions related to a mos's modes generally end with "mode".
  - Functions related to mosses don't have any special names.
-- - Functions related to a mos's generators, equave, or period contain the
  - Functions related to a mos's modes generally end with "mode".
--  corresponding interval as part of its name.
  - Functions related to a mos's generators, equave, or period contain the
-- - Functions related to intervals generally begin with "interval".
    corresponding interval as part of its name.
-- - Interval complement/reduce functions end with "complement" and "reduce".
  - Functions related to intervals generally begin with "interval".
-- - Functions that produce strings generally have the phrase "as string".
  - Interval complement/reduce functions end with "complement" and "reduce".
-- - Functions that "count" something generally end with "count".
  - Functions that produce strings generally have the phrase "as string".
-- - If a function requires an interval and mos as input, the interval(s) come
  - Functions that "count" something generally end with "count".
--  after the mos.
  - If a function requires an interval and mos as input, the interval(s) come
-- - Functions that have to do with equal tunings will have "et" in its name.
    after the mos.
  - Functions that have to do with equal tunings will have "et" in its name.
]]--


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 57: Line 64:
end
end


-- Pasre a mos from its scalesig.
-- Parse a mos from its scalesig.
function p.parse(unparsed)
function p.parse(unparsed)
local nL, ns, equave = unparsed:match("^(%d+)[Ll]%s*(%d+)[Ss]%s*(.*)$")
local nL, ns, equave = unparsed:match("^(%d+)[Ll]%s*(%d+)[Ss]%s*(.*)$")
Line 75: Line 82:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Construct a string representation (scalesig) for a MOS structure.
--[[
-- Scalesig is "xL ys", or "xL ys<p/q>" for nonoctave scales.
  Construct a string representation (scalesig) for a MOS structure.
-- Option to use nbsp is provided using the second param; default is no nbsp
  Scalesig is "xL ys", or "xL ys<p/q>" for nonoctave scales.
  Option to use nbsp is provided using the second param; default is no nbsp
]]--
function p.as_string(mos, use_nbsp)
function p.as_string(mos, use_nbsp)
local use_nbsp = use_nbsp or true
local use_nbsp = use_nbsp or true
Line 87: Line 96:
end
end


-- Construct a longer string representation for a MOS structure.
--[[
-- Scalesig is "xL ys", or "xL ys (p/q-equivalent)" for nonoctave scales.
  Construct a longer string representation for a MOS structure.
-- Option to use nbsp is provided using the second param; default is no nbsp
 
  Scalesig is "xL ys", or "xL ys (p/q-equivalent)" for nonoctave scales.
 
  Option to use nbsp is provided using the second param; default is no nbsp
]]--
function p.as_long_string(mos, use_nbsp)
function p.as_long_string(mos, use_nbsp)
local use_nbsp = use_nbsp or true
local use_nbsp = use_nbsp or true
Line 100: Line 113:
end
end


-- Given an interval as a vector of L's and s's, produce a string "iL + js",
--[[
-- where i and j are the quantities for L and s.
  Given an interval as a vector of L's and s's, produce a string "iL + js",
  where i and j are the quantities for L and s.
]]--
function p.interval_as_string(interval)
function p.interval_as_string(interval)
Line 162: Line 177:
------------------------------- MODE FUNCTIONS ---------------------------------
------------------------------- MODE FUNCTIONS ---------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 
--[[
-- Find the brightest (true-mos) mode of a mos, as a string of L's and s's.
  Find the brightest (true-mos) mode of a mos, as a string of L's and s's.
-- Calculation is based on the definition of a Christoffel word, as the closest
 
-- integer approximation to line y = #s/#L*x.
  Calculation is based on the definition of a Christoffel word, as the closest
  integer approximation to line y = #s/#L*x.
]]--
function p.brightest_mode(mos)
function p.brightest_mode(mos)
local nL = mos.nL
local nL = mos.nL
Line 188: Line 205:
end
end


-- Find the darkest true-mos mode of a mos.
 
-- It's the reverse of the brightest mode.
-- Find the darkest true-mos mode of a mos. It's the reverse of the brightest mode.
function p.darkest_mode(mos)
function p.darkest_mode(mos)
local nL = mos.nL
local nL = mos.nL
Line 213: Line 230:
end
end


-- Given a mos, return a mode based on how it's ranked by modal brightness.
--[[
-- Ordering here is based on the number of bright gens going DOWN PER PERIOD:
  Given a mos, return a mode based on how it's ranked by modal brightness.
-- 0 is the brightest mode, 1 is 2nd brightest, etc...
 
  Ordering here is based on the number of bright gens going DOWN PER PERIOD:
  0 is the brightest mode, 1 is 2nd brightest, etc...
]]--
function p.mode_from_mos(mos, bright_gens_down)
function p.mode_from_mos(mos, bright_gens_down)
return p.rotate_mode(p.brightest_mode(mos), bright_gens_down * p.bright_gen_step_count(mos))
return p.rotate_mode(p.brightest_mode(mos), bright_gens_down * p.bright_gen_step_count(mos))
Line 239: Line 259:
end
end


-- List all unique rotations for a mode. Order of modes is by rotation.
--[[
-- Note: there will always be s/p modes, where s is the number of steps in the
  List all unique rotations for a mode. Order of modes is by rotation.
-- entered mode, and p is the period of repetition. At most, there will be s
 
-- modes, but if there is a substring of length p that repeats within the mode
  Note: there will always be s/p modes, where s is the number of steps in the
-- (where p divides s with remainder = 0), then there will be p modes. It's also
  entered mode, and p is the period of repetition. At most, there will be s
-- possible to have only one mode, but this can only happen if there is only one
  modes, but if there is a substring of length p that repeats within the mode
-- step size, meaning it's a unary scale (only one step size).
  (where p divides s with remainder = 0), then there will be p modes. It's also
  possible to have only one mode, but this can only happen if there is only one
  step size, meaning it's a unary scale (only one step size).
]]--
function p.mode_rotations(mode_string)
function p.mode_rotations(mode_string)
local rotations = {}
local rotations = {}
Line 258: Line 281:
end
end


-- Rotate a mode by shifting the step sequence to the left. Negative values
--[[
-- shift it to the right. Helper function for mode_from_mos().
  Rotate a mode by shifting the step sequence to the left. Negative values
  shift it to the right. Helper function for mode_from_mos().
]]--
function p.rotate_mode(mode_string, shift_amt)
function p.rotate_mode(mode_string, shift_amt)
local shift_amt = shift_amt == nil and 1 or shift_amt % #mode_string -- Default is 1
local shift_amt = shift_amt == nil and 1 or shift_amt % #mode_string -- Default is 1
Line 270: Line 295:
---------------------------- STEP MATRIX FUNCTIONS -----------------------------
---------------------------- STEP MATRIX FUNCTIONS -----------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 
--[[
-- Convert a single mode (as a string) into a step matrix. This is a listing of
  Convert a single mode (as a string) into a step matrix. This is a listing of
-- every interval's step vector in the mode.
  every interval's step vector in the mode.
]]--
function p.mode_to_step_matrix(mode_string)
function p.mode_to_step_matrix(mode_string)
local matrix = {}
local matrix = {}
Line 282: Line 308:
end
end


-- Given a mos, produce every step matrix for every mode. Modes are listed in
--[[
-- order of brightness.
  Given a mos, produce every step matrix for every mode. Modes are listed in
  order of brightness.
]]--
function p.modes_to_step_matrices(mos)
function p.modes_to_step_matrices(mos)
local modes = p.modes_by_brightness(mos)
local modes = p.modes_by_brightness(mos)
Line 294: Line 322:
end
end


-- Given a single mode (as a string), produce the step matrices for each  
--[[
-- rotation of that mode. Modes are listed in order of rotation.
  Given a single mode (as a string), produce the step matrices for each  
  rotation of that mode. Modes are listed in order of rotation.
]]--
function p.mode_rotations_to_step_matrices(mode_string)
function p.mode_rotations_to_step_matrices(mode_string)
local modes = p.mode_rotations(mode_string)
local modes = p.mode_rotations(mode_string)
Line 306: Line 336:
end
end


-- Given an input mos, produce its modal union.
--[[
-- This is a listing of every interval's large and small sizes.
  Given an input mos, produce its modal union.
 
  This is a listing of every interval's large and small sizes.
]]--
function p.modal_union(input_mos)
function p.modal_union(input_mos)
local brightest_mode = p.brightest_mode(input_mos)
local brightest_mode = p.brightest_mode(input_mos)
Line 336: Line 369:
------------------ (IE, GENERATORS AND PERIOD INTERVALS) -----------------------
------------------ (IE, GENERATORS AND PERIOD INTERVALS) -----------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 
--[[
-- Compute the bright gen as a vector of L's and s's.
  Compute the bright gen as a vector of L's and s's.
-- Bright gen has two sizes: perfect (large) and diminished (small). The size
 
-- given by this function is the large size.
  Bright gen has two sizes: perfect (large) and diminished (small). The size
  given by this function is the large size.
]]--
function p.bright_gen(mos)
function p.bright_gen(mos)
local nL = mos.nL
local nL = mos.nL
Line 370: Line 405:
end
end


-- Compute the dark gen as a vector of L's and s's.
--[[
-- Dark gen has two sizes: augmented (large) and perfect (small). The size given
  Compute the dark gen as a vector of L's and s's.
-- by this function is the small size. It's the period complement of the bright
 
-- gen.
  Dark gen has two sizes: augmented (large) and perfect (small). The size given
  by this function is the small size and is equal to the period complement of the
  bright gen.
]]--
function p.dark_gen(mos)
function p.dark_gen(mos)
local bright_gen = p.bright_gen(mos)
local bright_gen = p.bright_gen(mos)
Line 379: Line 417:
end
end


-- Compute the period as a vector of L's and s's.
-- Compute the period as a vector of L's and s's. Period intervals only have one size: perfect.
-- Period intervals only have one size: perfect.
function p.period(mos)  
function p.period(mos)  
local gcd = utils._gcd(mos.nL, mos.ns)
local gcd = utils._gcd(mos.nL, mos.ns)
Line 389: Line 426:
end
end


-- Compute the equave as a vector of L's and s's.
--[[
-- Equave intervals only have one size: perfect. Equave and period intervals are
  Compute the equave as a vector of L's and s's.
-- the same for single-period mosses.
 
  Equave intervals only have one size: perfect. Equave and period intervals are
  the same for single-period mosses.
]]--
function p.equave(mos)  
function p.equave(mos)  
return {
return {
Line 402: Line 442:
------------------ INTERVAL FUNCTIONS FOR SIMPLE INTERVALS ---------------------
------------------ INTERVAL FUNCTIONS FOR SIMPLE INTERVALS ---------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 
--[[
-- Compute the unison as a vector of L's and s's.
  Compute the unison as a vector of L's and s's.
-- The unison is denoted by moving up from the root by zero steps, and thus does
 
-- not need a mos as input. It's basically a zero vector.
  The unison is denoted by moving up from the root by zero steps, and thus does
-- The unison only has one size: perfect.
  not need a mos as input. It's basically a zero vector.
 
  The unison only has one size: perfect.
]]--
function p.unison()
function p.unison()
return { ["L"] = 0, ["s"] = 0 }
return { ["L"] = 0, ["s"] = 0 }
end
end


-- Compute the vector for a single chroma. It's a large step minus a small step.
--[[
-- Adding or subtracting any interval by this interval changes its "size".
  Compute the vector for a single chroma. It's a large step minus a small step.
  Adding or subtracting any interval by this interval changes its "size".
]]--
function p.chroma()
function p.chroma()
return { ["L"] = 1, ["s"] = -1 }
return { ["L"] = 1, ["s"] = -1 }
Line 446: Line 491:
end
end


-- Compute an arbitrary mos interval as a vector of L's and s's.
--[[
-- The step_count param is the number of mossteps in the interval. EG, in 5L 2s,
  Compute an arbitrary mos interval as a vector of L's and s's.
-- the large 2-mosstep is "LL", so the corresponding vector has L=2, s=0.
 
-- Mossteps larger than the equave (eg, the minor 9th in non-xen music theory)
  The step_count param is the number of mossteps in the interval. EG, in 5L 2s,
-- are allowed.
  the large 2-mosstep is "LL", so the corresponding vector has L=2, s=0.
-- The size_offset denotes whether the interval is the large size (0) or the
 
-- small size (-1). This can exceed the range of [-1, 0] to represent intervals
  Mossteps larger than the equave (eg, the minor 9th in non-xen music theory)
-- raised/lowered by multiple chromas (augmented, diminished, etc).
  are allowed.
-- Note that for period intervals (eg, the root and equave), there is only one
 
-- size (0 = perfect), so -1 is diminished and 1 is augmented.
  The size_offset denotes whether the interval is the large size (0) or the
-- EG, a perfect 4-diastep (perf. 5th) is 4 steps. Since it's the large size,
  small size (-1). This can exceed the range of [-1, 0] to represent intervals
-- the offset is 0, but to get the diminished 5th, the offset should be -1.
  raised/lowered by multiple chromas (augmented, diminished, etc).
 
  Note that for period intervals (eg, the root and equave), there is only one
  size (0 = perfect), so -1 is diminished and 1 is augmented.
 
  E.G., a perfect 4-diastep (perf. 5th) is 4 steps. Since it's the large size,
  the offset is 0, but to get the diminished 5th, the offset should be -1.
]]--
function p.interval_from_mos(mos, step_count, size_offset)
function p.interval_from_mos(mos, step_count, size_offset)
local size_offset = size_offset or 0 -- Optional param; defaults to large size
local size_offset = size_offset or 0 -- Optional param; defaults to large size
Line 471: Line 523:
end
end


-- Compute an arbitrary mos interval (as a string of steps) as a vector of L's
--[[
-- and s's. This also serves as a helper function for p.interval_from_mos().
  Compute an arbitrary mos interval (as a string of steps) as a vector of L's
-- Sequences of steps can be entered, where each step is one of five sizes:
  and s's. This also serves as a helper function for p.interval_from_mos().
-- - L: large step.
 
-- - s: small step.
  Sequences of steps can be entered, where each step is one of five sizes:
-- - c: a chroma; the difference between a large and small step.
  - L: large step.
-- - A: an augmented step; a large step plus a chroma.
  - s: small step.
-- - d: a diminished step, or diesis; a small step minus a chroma.
  - c: a chroma; the difference between a large and small step.
  - A: an augmented step; a large step plus a chroma.
  - d: a diminished step, or diesis; a small step minus a chroma.
]]--
function p.interval_from_step_sequence(step_sequence)
function p.interval_from_step_sequence(step_sequence)
local mossteps = #step_sequence
local mossteps = #step_sequence
Line 531: Line 586:
end
end


-- Given a vector representing an interval, compute the number of mossteps it
--[[
-- corresponds to. Knowledge of the corresponding mos is not needed. Intervals
  Given a vector representing an interval, compute the number of mossteps it
-- can be negative, resulting in a negative output.
  corresponds to. Knowledge of the corresponding mos is not needed. Intervals
  can be negative, resulting in a negative output.
]]--
function p.interval_step_count(interval)
function p.interval_step_count(interval)
return interval["L"] + interval["s"]
return interval["L"] + interval["s"]
end
end


-- Given a vector representing an interval, compute the number of chromas it was
--[[
-- raised or lowered by from its large size (for non-period intervals) or its
  Given a vector representing an interval, compute the number of chromas it was
-- perfect size (for period/root/equave intervals). This requires the mos as
  raised or lowered by from its large size (for non-period intervals) or its
-- input.
  perfect size (for period/root/equave intervals). This requires the mos as
-- If the number of chromas from a small (EG minor) interval is desired, then
  input.
-- using the param size_offset can be used: 0 for chromas from large size, -1
 
-- for chromas from small size. This can exceed the range [-1, 0] if needed.
  If the number of chromas from a small (EG minor) interval is desired, then
-- EG, a diminished 2-diastep (dim. 3rd) has the vector {0,2}. It's reached by
  using the param size_offset can be used: 0 for chromas from large size, -1
-- either lowering the major 2-step by 2 chromas, or lowering the minor 2-step
  for chromas from small size. This can exceed the range [-1, 0] if needed.
-- by 1 chroma.
 
  E.G., a diminished 2-diastep (dim. 3rd) has the vector {0,2}. It's reached by
  either lowering the major 2-step by 2 chromas, or lowering the minor 2-step
  by 1 chroma.
]]--
function p.interval_chroma_count(interval, mos, size_offset)
function p.interval_chroma_count(interval, mos, size_offset)
local size_offset = size_offset or 0 -- Default of 0.
local size_offset = size_offset or 0 -- Default of 0.
Line 593: Line 654:
---------------------- INTERVAL MANIPULATION FUNCTIONS -------------------------
---------------------- INTERVAL MANIPULATION FUNCTIONS -------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 
--[[
-- Given an interval vector and a mos, find its period complement. This is the
  Given an interval vector and a mos, find its period complement. This is the
-- interval to add to produce the period.
  interval to add to produce the period.
]]--
function p.period_complement(interval, mos)
function p.period_complement(interval, mos)
local sign = p.interval_step_count(interval) < 0 and -1 or 1
local sign = p.interval_step_count(interval) < 0 and -1 or 1
Line 602: Line 664:
end
end


-- Given an interval vector and a mos, find its equave complement. This is the
--[[
-- interval to add to produce the equave.
  Given an interval vector and a mos, find its equave complement. This is the
  interval to add to produce the equave.
]]--
function p.equave_complement(interval, mos)
function p.equave_complement(interval, mos)
local sign = p.interval_step_count(interval) < 0 and -1 or 1
local sign = p.interval_step_count(interval) < 0 and -1 or 1
Line 610: Line 674:
end
end


-- Given an interval vector and a mos, period-reduce it. This works like
--[[
-- modular arithmetic, so passing a negative interval returns a positive one.
  Given an interval vector and a mos, period-reduce it. This works like
  modular arithmetic, so passing a negative interval returns a positive one.
]]--
function p.period_reduce(interval, mos)
function p.period_reduce(interval, mos)
local step_count = p.interval_step_count(interval)
local step_count = p.interval_step_count(interval)
Line 620: Line 686:
end
end


-- Given an interval vector and a mos, equave-reduce it. This works like
--[[
-- modular arithmetic, so passing a negative interval returns a positive one.
  Given an interval vector and a mos, equave-reduce it. This works like
  modular arithmetic, so passing a negative interval returns a positive one.
]]--
function p.equave_reduce(interval, mos)
function p.equave_reduce(interval, mos)
local step_count = p.interval_step_count(interval)
local step_count = p.interval_step_count(interval)
Line 635: Line 703:
end
end


-- Intervals usually denote distances between two scale degrees and should be
--[[
-- positive values. Normalizing makes a negative interval positive again.
  Intervals usually denote distances between two scale degrees and should be
  positive values. Normalizing makes a negative interval positive again.
]]--
function p.normalize_interval(interval)
function p.normalize_interval(interval)
return p.interval_step_count(interval) < 0 and p.interval_mul(interval, -1) or interval
return p.interval_step_count(interval) < 0 and p.interval_mul(interval, -1) or interval
Line 644: Line 714:
---------------------------- EQUAL-TUNING FUNCTIONS ----------------------------
---------------------------- EQUAL-TUNING FUNCTIONS ----------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 
--[[
-- Given a mos and a step ratio, return an equal tuning (or equal division).
  Given a mos and a step ratio, return an equal tuning (or equal division).
-- The step ratio is entered as a 2-element array to allow non-simplified
  The step ratio is entered as a 2-element array to allow non-simplified
-- ratios to be entered. (The rational module isn't suitable since it simplifies
  ratios to be entered. (The rational module isn't suitable since it simplifies
-- ratios.)
  ratios.)
]]--
function p.mos_to_et(mos, step_ratio, suffix)
function p.mos_to_et(mos, step_ratio, suffix)
local suffix = suffix or nil
local suffix = suffix or nil
Line 655: Line 726:
end
end


-- Given a mos and a step ratio, return the number of et-steps for its bright
--[[
-- generator.
  Given a mos and a step ratio, return the number of et-steps for its bright
  generator.
]]--
function p.bright_gen_to_et_steps(mos, step_ratio)
function p.bright_gen_to_et_steps(mos, step_ratio)
return p.interval_to_et_steps(p.bright_gen(mos), step_ratio)
return p.interval_to_et_steps(p.bright_gen(mos), step_ratio)
end
end


-- Given a mos and a step ratio, return the number of et-steps for its dark
-- Given a mos and a step ratio, return the number of et-steps for its dark generator.
-- generator.
function p.dark_gen_to_et_steps(mos, step_ratio)
function p.dark_gen_to_et_steps(mos, step_ratio)
return p.interval_to_et_steps(p.dark_gen(mos), step_ratio)
return p.interval_to_et_steps(p.dark_gen(mos), step_ratio)
Line 677: Line 749:
end
end


-- Given an interval vector and step ratio, compute the number of et-steps it
-- Given an interval vector and step ratio, compute the number of et-steps it corresponds to.
-- corresponds to.
function p.interval_to_et_steps(interval, step_ratio)
function p.interval_to_et_steps(interval, step_ratio)
return interval["L"] * step_ratio[1] + interval["s"] * step_ratio[2]
return interval["L"] * step_ratio[1] + interval["s"] * step_ratio[2]
Line 687: Line 758:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Given a mos, return its equal temperament suffix as a string (edo, edt, edf,
-- Given a mos, return its equal temperament suffix as a string (edo, edt, edf, or ed-p/q).
-- or ed-p/q).
function p.mos_to_et_suffix(mos)
function p.mos_to_et_suffix(mos)
if rat.eq(mos.equave, rat.new(2)) then
if rat.eq(mos.equave, rat.new(2)) then
Line 701: Line 771:
end
end


-- Given a mos and step ratio, return its equal temperament as a string
-- Given a mos and step ratio, return its equal temperament as a string "{steps}\{division}{suffix}".
-- "{steps}\{division}{suffix}".
function p.mos_to_et_as_string(mos, step_ratio, suffix)
function p.mos_to_et_as_string(mos, step_ratio, suffix)
local suffix = suffix or nil
local suffix = suffix or nil
Line 760: Line 829:
end
end


-- Given a mos and a step ratio, return the number of cents for its period.
--[[
-- The period is the interval at which the step pattern repeats, so no step
  Given a mos and a step ratio, return the number of cents for its period.
-- ratio is needed.
 
  The period is the interval at which the step pattern repeats, so no step
  ratio is needed.
]]--
function p.period_to_cents(mos)
function p.period_to_cents(mos)
return rat.cents(mos.equave) / p.period_count(mos)
return rat.cents(mos.equave) / p.period_count(mos)
end
end


-- Given a mos and a step ratio, return the number of cents for its equave.
--[[
-- The period is the interval at which the step pattern repeats, and the equave
  Given a mos and a step ratio, return the number of cents for its equave.
-- is a multiple of that (at least for multi-period mosses), so no step ratio is
  The period is the interval at which the step pattern repeats, and the equave
-- needed.
  is a multiple of that (at least for multi-period mosses), so no step ratio is
  needed.
]]--
function p.equave_to_cents(mos)
function p.equave_to_cents(mos)
return rat.cents(mos.equave)
return rat.cents(mos.equave)
end
end


-- Given an interval vector and step ratio, convert it to cents. This requires
-- Given an interval vector and step ratio, convert it to cents. This requires info about the mos itself.
-- info about the mos itself.
function p.interval_to_cents(interval, mos, step_ratio)
function p.interval_to_cents(interval, mos, step_ratio)
local interval_steps = p.interval_to_et_steps(interval, step_ratio)
local interval_steps = p.interval_to_et_steps(interval, step_ratio)
Line 800: Line 873:


--return p.mos_to_et(p.new(5,2), {2,1})
--return p.mos_to_et(p.new(5,2), {2,1})
end
end


return p
return p