Module:MOS: Difference between revisions

Ganaram inukshuk (talk | contribs)
Bugfixes, added size-offset param to chroma-count function; added normalize function that turns negative intervals back into positive intervals (since intervals here are meant to be interpreted as distances between two scale degrees)
Ganaram inukshuk (talk | contribs)
Better comments; rewrote et_tuning_by_hardness() function as mos_to_et() and several interval_to_et_step functions
Line 6: Line 6:
-- - Finding certain modes of a mos
-- - Finding certain modes of a mos
-- - Finding generators for a mos
-- - Finding generators for a mos
-- - Producing vectors for simple mos intervals
-- - Interval arithmetic, in the form of adding vectors of L's and s's, and
-- - Interval arithmetic, in the form of adding vectors of L's and s's, and
--  period/equave-reducing intervals
--  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') -- Used for unused function
local et = require('Module:ET')
local p = {}
local p = {}


Line 24: Line 26:
-- - If a function requires an interval and mos as input, the interval(s) come
-- - If a function requires an interval and mos as input, the interval(s) come
--  after the mos.
--  after the mos.
-- - Functions that have to do with equal tunings will have "et" in its name.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 243: Line 246:
['L'] = 0,
['L'] = 0,
['s'] = 0
['s'] = 0
}
return result
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".
function p.chroma()
local result = {
['L'] = 1,
['s'] = -1
}
}
return result
return result
Line 261: Line 274:
['L'] = 0,
['L'] = 0,
['s'] = 1
['s'] = 1
}
return result
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".
function p.chroma()
local result = {
['L'] = 1,
['s'] = -1
}
}
return result
return result
Line 299: Line 302:
-- 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.
-- EG, 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(mos, step_count, size_offset)
function p.interval(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 347: Line 352:
end
end


-- Intervals always denote positive values as they are distances between two
-- Intervals usually denote distances between two scale degrees and should be
-- scale degrees, even if in the interval vector, one value is negative.
-- positive values. Normalizing makes a negative interval positive again.
-- In cases where a negative interval is encountered or was previously needed,
-- such as if negative intervals denote direction (downwards stacking instead of
-- upwards stacking), normalize_interavl() makes those intervals positive again.
-- EG, a perfect 4-diastep (perfect 5th) is the vector { 3, 1 }, but so is
-- { -3, -1 }.
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 398: Line 398:
-- perfect size (for period/root/equave intervals). This requires the mos as
-- perfect size (for period/root/equave intervals). This requires the mos as
-- input.
-- input.
-- The offset param is used to denote whether the interval is the large size (0)
-- If the number of chromas from a small (EG minor) interval is desired, then
-- or the small size (-1). This way, the small size of an interval is shown as
-- using the param size_offset can be used: 0 for chromas from large size, -1
-- having zero chromas IF the interval is to be viewed as its small size rather
-- for chromas from small size. This can exceed the range [-1, 0] if needed.
-- than the large size. This can exceed the range [-1, 0] if needed.
-- EG, 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
local size_offset = size_offset or 0 -- Default of 0.
local step_count = p.interval_step_count(interval)
local step_count = p.interval_step_count(interval)
local base_interval = p.interval(mos, step_count, 0)
local base_interval = p.interval(mos, step_count, 0)
Line 476: Line 478:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
------------ UNUSED FUNCTIONS OR FUNCTIONS TO MOVE TO OTHER MODULES ------------
---------------------------- EQUAL-TUNING FUNCTIONS ----------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Given mos a MOS structure, hardness = L/s a rational number,
-- Given a mos and a step ratio, return an equal tuning (or equal division).
-- return the et and the bright MOS generator corresponding to the hardness.
-- The step ratio is entered as a 2-element array to allow non-simplified
-- Currently unused
-- ratios to be entered. (The rational module isn't suitable since it simplifies
--[[
-- ratios.)
function p.et_tuning_by_hardness(mos, hardness)
function p.mos_to_et(mos, step_ratio)
local nL, ns, equave = mos.nL, mos.ns, mos.equave
local et_size = mos.nL * step_ratio[1] + mos.ns * step_ratio[2]
hardness = rat.parse(hardness) or rat.new(hardness) or hardness
return et.new(et_size, mos.equave, rat.as_ratio(mos.equave))
if nL == nil or ns == nil or equave == nil or hardness == nil then
end
return nil
 
end
-- Given a mos and a step ratio, return the number of et-steps for its bright
L_in_et_steps, s_in_et_steps = rat.as_pair(hardness)
-- generator.
local et = et.new(nL*L_in_et_steps + ns*s_in_et_steps, equave)
function p.bright_gen_to_et_steps(mos, step_ratio)
local gen = p.bright_gen(mos)
return interval_to_et_steps(p.bright_gen(mos), step_ratio)
local gen_steps = gen['L']*L_in_et_steps + gen['s']*s_in_et_steps
end
return et, gen_steps
 
-- Given a mos and a step ratio, return the number of et-steps for its dark
-- generator.
function p.dark_gen_to_et_steps(mos, step_ratio)
return interval_to_et_steps(p.dark_gen(mos), step_ratio)
end
 
-- Given a mos and a step ratio, return the number of et-steps for its period.
function p.period_to_et_steps(mos, step_ratio)
return interval_to_et_steps(p.period(mos), step_ratio)
end
 
-- Given a mos and a step ratio, return the number of et-steps for its equave.
function p.equave_to_et_steps(mos, step_ratio)
return interval_to_et_steps(p.equave(mos), step_ratio)
end
 
-- Given an interval vector and step ratio, compute the number of et-steps it
-- corresponds to. (To find an et's cent value, use this as input for the et
-- module's cents() function.)
function p.interval_to_et_steps(interval, step_ratio)
local et_size = interval['L'] * step_ratio[1] + interval['s'] * step_ratio[2]
end
end
]]--
 
--------------------------------------------------------------------------------
------------ UNUSED FUNCTIONS OR FUNCTIONS TO MOVE TO OTHER MODULES ------------
--------------------------------------------------------------------------------


-- Given a mos, find the ancestor mos with a target note count (default 10)
-- Given a mos, find the ancestor mos with a target note count (default 10)
Line 528: Line 554:
function p.tester()
function p.tester()


local interval = p.dark_gen(p.new(5,2))
--local interval = p.dark_gen(p.new(5,2))
return p.interval_chroma_count(interval, p.new(5,2), -1)
--return p.interval_chroma_count(interval, p.new(5,2), -1)
return p.mos_to_et(p.new(5,2), {5,4})
end
end


return p
return p