Module:MOS: Difference between revisions

Ganaram inukshuk (talk | contribs)
Fleshed out module; basically redefining module:mos as a module for doing mos arithmetic, with tamnams-related things being moved to module:tamnams
Ganaram inukshuk (talk | contribs)
Comments; organization
Line 1: Line 1:
-- Module for working with mosses in code, plus some basic arithmetic functions
-- 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.
-- Functionality includes:
-- - Creating/parsing mosses
-- - Creating scalesigs (string representations) of mosses
-- - Finding certain modes of a mos
-- - Finding generators for a mos
-- - Interval arithmetic, in the form of adding vectors of L's and s's
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') -- Used for unused function
local p = {}
local p = {}


Line 18: Line 25:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- create a MOS structure (nL)L (ns)s <equave>
-- Create a new mos.
function p.new(nL, ns, equave)
function p.new(nL, ns, equave)
local nL = nL or 5
local nL = nL or 5
Line 26: Line 33:
end
end


-- parse a MOS structure from its scalesig
-- Pasre 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 43: Line 50:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Construct a string representation (scalesig) for a MOS structure
-- Construct a string representation (scalesig) for a MOS structure.
-- Scalesig is "xL ys", or "xL ys<p/q>" for nonoctave scales
-- Scalesig is "xL ys", or "xL ys<p/q>" for nonoctave scales.
function p.as_string(mos)
function p.as_string(mos)
local suffix = ''
local suffix = ''
Line 53: Line 60:
end
end


-- Construct a longer string representation for a MOS structure
-- Construct a longer string representation for a MOS structure.
-- Scalesig is "xL ys", or "xL ys (p/q-equivalent)" for nonoctave scales
-- Scalesig is "xL ys", or "xL ys (p/q-equivalent)" for nonoctave scales.
function p.as_long_string(mos)
function p.as_long_string(mos)
local suffix = ''
local suffix = ''
Line 64: Line 71:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------- INTERVAL FUNCTIONS FOR PERFECTABLE INTERVALS -------------------
------------------------------- MODE FUNCTIONS ---------------------------------
------------------ (IE, GENERATORS AND PERIOD INTERVALS) -----------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Find the brightest mode of a mos (the Christoffel word)
-- Find the brightest true-mos mode of a mos.
-- using its definition as a 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 92: Line 99:
end
end


-- Find the darkest mode of a mos
-- Find the darkest true-mos mode of a mos.
-- It's the reverse of the brightest mode
-- 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 116: Line 123:
end
end


-- Compute the period as a vector of L's and s's.
--------------------------------------------------------------------------------
function p.period(mos)
--------------- INTERVAL FUNCTIONS FOR PERFECTABLE INTERVALS -------------------
local gcd = utils._gcd(mos.nL, mos.ns)
------------------ (IE, GENERATORS AND PERIOD INTERVALS) -----------------------
local result = {
--------------------------------------------------------------------------------
['L'] = mos.nL / gcd,
['s'] = mos.ns / gcd
}
return result
end
 
-- Compute the equave as a vector of L's and s's.
function p.period(mos)
local result = {
['L'] = mos.nL,
['s'] = mos.ns
}
return result
end


-- 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.
Line 174: Line 167:
}
}
return dark_gen
return dark_gen
end
-- Compute the period as a vector of L's and s's.
function p.period(mos)
local gcd = utils._gcd(mos.nL, mos.ns)
local result = {
['L'] = mos.nL / gcd,
['s'] = mos.ns / gcd
}
return result
end
-- Compute the equave as a vector of L's and s's.
function p.equave(mos)
local result = {
['L'] = mos.nL,
['s'] = mos.ns
}
return result
end
end


Line 181: Line 193:


-- Compute an arbitrary mos interval as a vector of L's and s's.
-- Compute an arbitrary mos interval as a vector of L's and s's.
-- The mossteps param is the number of mossteps in the interval. EG, in 5L 2s,
-- The step_count param is the number of mossteps in the interval. EG, in 5L 2s,
-- the large 2-mosstep is "LL", so the corresponding vector has L=2, s=0.
-- the large 2-mosstep is "LL", so the corresponding vector has L=2, s=0.
-- Mossteps larger than the equave (analogous to the minor 9th in standard
-- Mossteps larger than the equave (analogous to the minor 9th in standard
Line 190: Line 202:
-- Note that for period intervals (eg, the root and equave), there is only one
-- 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.
-- size (0 = perfect), so -1 is diminished and 1 is augmented.
function p.interval(mos, mossteps, size)
function p.interval(mos, step_count, size)
local size = size or 0 -- Optional param; defaults to large size, or perfect size
local step_sequence = p.brightest_mode(mos)
local step_sequence = p.brightest_mode(mos)
step_sequence = string.rep(step_sequence, math.ceil(mossteps/(mos.nL + mos.ns)))
step_sequence = string.rep(step_sequence, math.ceil(step_count/(mos.nL + mos.ns)))
step_sequence = string.sub(step_sequence, 1, mossteps)
step_sequence = string.sub(step_sequence, 1, step_count)
local interval_vector = p.interval_from_step_sequence(mos, step_sequence)
local interval_vector = p.interval_from_step_sequence(mos, step_sequence)
Line 203: Line 216:
-- Compute an arbitrary mos interval (as a string of steps) as a vector of L's
-- 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().
-- and s's. This also serves as a helper function for p.interval().
-- This has the same output as the above function, except arbitrary strings can
-- This operates similarly to the above function, except arbitrary strings can
-- be entered, such as with step sequences for certain modmosses. The step types
-- be entered, such as with step sequences for certain modmosses. The step types
-- are as follows:
-- are as follows:
Line 268: Line 281:
}
}
return interval_vector
return interval_vector
end
function p.period_complement(mos, v1)
end
function p.equave_complement(mos, v1)
end
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------- INTERVAL STEP COUNT FUNCTIONS FOR PERFECTABLE INTERVALS --------------
----------------------- INTERVAL STEP COUNT FUNCTIONS --------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Compute the size of the period in mossteps (L's plus s's)
-- Given a mos, compute the size of the bright gen in mossteps (L's plus s's).
function p.bright_gen_step_count(mos)
local interval = p.bright_gen(mos)
return interval['L'] + interval['s']
end
 
-- Given a mos, compute the size of the dark gen in mossteps (L's plus s's).
function p.dark_gen_step_count(mos)
local interval = p.dark_gen(mos)
return interval['L'] + interval['s']
end
 
-- Given a mos, compute the size of the period in mossteps (L's plus s's).
function p.period_step_count(mos)
function p.period_step_count(mos)
local interval = p.period(mos)
local interval = p.period(mos)
Line 280: Line 311:
end
end


-- Compute the size of the equave in mossteps (L's plus s's)
-- Given a mos, compute the size of the equave in mossteps (L's plus s's).
function p.equave_step_count(mos)
function p.equave_step_count(mos)
local interval = p.equave(mos)
local interval = p.equave(mos)
Line 286: Line 317:
end
end


-- Compute the size of the bright gen in mossteps (L's plus s's)
-- Compute the k-mosstep corresponding to a vector of L's and s's.
function p.bright_gen_step_count(mos)
-- This does not require the mos it corresponds to.
local interval = p.bright_gen(mos)
function p.interval_step_count(interval)
return interval['L'] + interval['s']
end
 
-- Compute the size of the dark gen in mossteps (L's plus s's)
function p.dark_gen_step_count(mos)
local interval = p.dark_gen(mos)
return interval['L'] + interval['s']
return interval['L'] + interval['s']
end
end