Module:MOS: Difference between revisions
Added (the skeletons for) two more functions: interval() and interval_from_mossteps(); these serve the same role as bright_gen(), dark_gen(), and period(), but apply to all other mos intervals |
Fleshed out module; basically redefining module:mos as a module for doing mos arithmetic, with tamnams-related things being moved to module:tamnams |
||
| Line 1: | Line 1: | ||
-- Module for working with mosses in code, plus some basic arithmetic functions | |||
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 p = {} | local p = {} | ||
-- | -------------------------------------------------------------------------------- | ||
------------------------------- HELPER FUNCTIONS ------------------------------- | |||
-------------------------------------------------------------------------------- | |||
function round(num, numDecimalPlaces) | |||
local mult = 10^(numDecimalPlaces or 0) | |||
return math.floor(num * mult + 0.5) / mult | |||
end | end | ||
-- | -------------------------------------------------------------------------------- | ||
-------------------------------- BASE FUNCTIONS -------------------------------- | |||
-------------------------------------------------------------------------------- | |||
-- create a MOS structure (nL)L (ns)s <equave> | -- create a MOS structure (nL)L (ns)s <equave> | ||
| Line 148: | Line 24: | ||
local equave = equave or 2 | local equave = equave or 2 | ||
return { nL = nL, ns = ns, equave = equave } | return { nL = nL, ns = ns, equave = equave } | ||
end | end | ||
| Line 167: | Line 38: | ||
return p.new(nL, ns, equave) | return p.new(nL, ns, equave) | ||
end | end | ||
-------------------------------------------------------------------------------- | |||
------------------------------ SCALESIG FUNCTIONS ------------------------------ | |||
-------------------------------------------------------------------------------- | |||
-- Construct a string representation (scalesig) for a MOS structure | -- Construct a string representation (scalesig) for a MOS structure | ||
| Line 187: | Line 62: | ||
return '' .. mos.nL .. 'L ' .. mos.ns .. 's' .. suffix | return '' .. mos.nL .. 'L ' .. mos.ns .. 's' .. suffix | ||
end | end | ||
-------------------------------------------------------------------------------- | |||
--------------- INTERVAL FUNCTIONS FOR PERFECTABLE INTERVALS ------------------- | |||
------------------ (IE, GENERATORS AND PERIOD INTERVALS) ----------------------- | |||
-------------------------------------------------------------------------------- | |||
-- Find the brightest mode of a mos (the Christoffel word) | -- Find the brightest mode of a mos (the Christoffel word) | ||
| Line 242: | Line 122: | ||
['L'] = mos.nL / gcd, | ['L'] = mos.nL / gcd, | ||
['s'] = mos.ns / 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 | return result | ||
| Line 286: | Line 175: | ||
return dark_gen | return dark_gen | ||
end | end | ||
-------------------------------------------------------------------------------- | |||
---------------- INTERVAL FUNCTIONS FOR ARBITRARY INTERVALS -------------------- | |||
-------------------------------------------------------------------------------- | |||
-- 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, | -- The mossteps 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. | ||
-- Mossteps larger than the equave (analogous to the minor 9th in standard | |||
-- notation) are allowed. | |||
-- The size param is a value that denotes whether the interval is the large size | -- The size param is a value that denotes whether the interval is the large size | ||
-- (0) or the small size (-1). This can exceed the range of [-1, 0] to represent | -- (0) or the small size (-1). This can exceed the range of [-1, 0] to represent | ||
| Line 296: | Line 191: | ||
-- 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, mossteps, size) | ||
local step_sequence = p.brightest_mode(mos) | |||
step_sequence = string.rep(step_sequence, math.ceil(mossteps/(mos.nL + mos.ns))) | |||
step_sequence = string.sub(step_sequence, 1, mossteps) | |||
local interval_vector = p.interval_from_step_sequence(mos, step_sequence) | |||
interval_vector['L'] = interval_vector['L'] + size | |||
interval_vector['s'] = interval_vector['s'] - size | |||
return interval_vector | |||
end | end | ||
-- 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. | -- and s's. This also serves as a helper function for p.interval(). | ||
-- This has the same output as the | -- This has the same output as the above function, except arbitrary strings can | ||
-- | -- be entered, such as with step sequences for certain modmosses. The step types | ||
-- | -- are as follows: | ||
-- - L: large step. | -- - L: large step. | ||
-- - s: small step. | -- - s: small step. | ||
| Line 308: | Line 211: | ||
-- - A: an augmented step; a large step plus a chroma. | -- - A: an augmented step; a large step plus a chroma. | ||
-- - d: a diminished step, or diesis; a small step minus a chroma. | -- - d: a diminished step, or diesis; a small step minus a chroma. | ||
function p. | function p.interval_from_step_sequence(mos, step_sequence) | ||
local mossteps = #step_sequence | |||
local interval_vector = { | |||
['L'] = 0, | |||
['s'] = 0 | |||
} | |||
for i = 1, mossteps do | |||
local step = string.sub(step_sequence, i, i) | |||
if step == "L" then | |||
interval_vector['L'] = interval_vector['L'] + 1 | |||
elseif step == "s" or step == "S" then | |||
interval_vector['s'] = interval_vector['s'] + 1 | |||
elseif step == "c" then | |||
interval_vector['L'] = interval_vector['L'] + 1 | |||
interval_vector['s'] = interval_vector['s'] - 1 | |||
elseif step == "A" then | |||
interval_vector['L'] = interval_vector['L'] + 2 | |||
interval_vector['s'] = interval_vector['s'] - 1 | |||
elseif step == "d" then | |||
interval_vector['L'] = interval_vector['L'] - 1 | |||
interval_vector['s'] = interval_vector['s'] + 2 | |||
end | |||
end | |||
return interval_vector | |||
end | |||
-------------------------------------------------------------------------------- | |||
---------------------- INTERVAL ARITHMETIC FUNCTIONS --------------------------- | |||
-------------------------------------------------------------------------------- | |||
-- Add two intervals together by adding their respective vectors | |||
function p.add_intervals(v1, v2) | |||
local interval_vector = { | |||
['L'] = v1['L'] + v2['L'], | |||
['s'] = v1['s'] + v2['s'] | |||
} | |||
return interval_vector | |||
end | |||
-- Subtract two intervals together by subtracting their respective vectors | |||
function p.subtract_intervals(v1, v2) | |||
local interval_vector = { | |||
['L'] = v1['L'] - v2['L'], | |||
['s'] = v1['s'] - v2['s'] | |||
} | |||
return interval_vector | |||
end | |||
-- Repeatedly add the same interval to itself | |||
function p.multiply_interval(v1, amt) | |||
local interval_vector = { | |||
['L'] = v1['L'] * amt, | |||
['s'] = v1['s'] * amt | |||
} | |||
return interval_vector | |||
end | end | ||
-------------------------------------------------------------------------------- | |||
--------- INTERVAL STEP COUNT FUNCTIONS FOR PERFECTABLE INTERVALS -------------- | |||
-------------------------------------------------------------------------------- | |||
-- Compute the size of the period in mossteps (L's plus s's) | -- 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 period = p. | local interval = p.period(mos) | ||
return | return interval['L'] + interval['s'] | ||
end | |||
-- Compute the size of the equave in mossteps (L's plus s's) | |||
function p.equave_step_count(mos) | |||
local interval = p.equave(mos) | |||
return interval['L'] + interval['s'] | |||
end | end | ||
-- Compute the size of the bright gen in mossteps (L's plus s's) | -- Compute the size of the bright gen in mossteps (L's plus s's) | ||
function p.bright_gen_step_count(mos) | function p.bright_gen_step_count(mos) | ||
local | local interval = p.bright_gen(mos) | ||
return | return interval['L'] + interval['s'] | ||
end | end | ||
-- Compute the size of the dark gen in mossteps (L's plus s's) | -- Compute the size of the dark gen in mossteps (L's plus s's) | ||
function p.dark_gen_step_count(mos) | function p.dark_gen_step_count(mos) | ||
local | local interval = p.dark_gen(mos) | ||
return | return interval['L'] + interval['s'] | ||
end | end | ||
-------------------------------------------------------------------------------- | |||
------------ UNUSED FUNCTIONS OR FUNCTIONS TO MOVE TO OTHER MODULES ------------ | |||
-------------------------------------------------------------------------------- | |||
-- Given mos a MOS structure, hardness = L/s a rational number, | -- Given mos a MOS structure, hardness = L/s a rational number, | ||
-- return the et and the bright MOS generator corresponding to the hardness. | -- return the et and the bright MOS generator corresponding to the hardness. | ||
-- | -- Currently unused | ||
function p.et_tuning_by_hardness(mos, hardness) | function p.et_tuning_by_hardness(mos, hardness) | ||
local nL, ns, equave = mos.nL, mos.ns, mos.equave | local nL, ns, equave = mos.nL, mos.ns, mos.equave | ||
| Line 368: | Line 341: | ||
return p.new(z, w, mos.equave) | return p.new(z, w, mos.equave) | ||
end | end | ||
-- Table of official tamnams names (2/1-equave only) | |||
p.tamnams_name = { -- Only mosses with 2/1-equave names in TAMNAMS | |||
['1L 1s'] = 'monowood', | |||
['2L 2s'] = 'biwood', | |||
['1L 5s'] = 'antimachinoid', | |||
['2L 4s'] = 'malic', | |||
['3L 3s'] = 'triwood', | |||
['4L 2s'] = 'citric', | |||
['5L 1s'] = 'machinoid', | |||
['1L 6s'] = 'onyx', | |||
['2L 5s'] = 'antidiatonic', | |||
['3L 4s'] = 'mosh', | |||
['4L 3s'] = 'smitonic', | |||
['5L 2s'] = 'diatonic', | |||
['6L 1s'] = 'archaeotonic', | |||
['1L 7s'] = 'antipine', | |||
['2L 6s'] = 'subaric', | |||
['3L 5s'] = 'checkertonic', | |||
['4L 4s'] = 'tetrawood', | |||
['5L 3s'] = 'oneirotonic', | |||
['6L 2s'] = 'ekic', | |||
['7L 1s'] = 'pine', | |||
['1L 8s'] = 'antisubneutralic', | |||
['2L 7s'] = 'balzano', | |||
['3L 6s'] = 'tcherepnin', | |||
['4L 5s'] = 'gramitonic', | |||
['5L 4s'] = 'semiquartal', | |||
['6L 3s'] = 'hyrulic', | |||
['7L 2s'] = 'armotonic', | |||
['8L 1s'] = 'subneutralic', | |||
['1L 9s'] = 'antisinatonic', | |||
['2L 8s'] = 'jaric', | |||
['3L 7s'] = 'sephiroid', | |||
['4L 6s'] = 'lime', | |||
['5L 5s'] = 'pentawood', | |||
['6L 4s'] = 'lemon', | |||
['7L 3s'] = 'dicoid', | |||
['8L 2s'] = 'taric', | |||
['9L 1s'] = 'sinatonic' | |||
} | |||
-- Prefixes | |||
p.tamnams_prefix = { -- Only mosses with 2/1-equave names in TAMNAMS | |||
['1L 1s'] = 'monwd-', | |||
['2L 2s'] = 'biwd-', | |||
['1L 5s'] = 'amech-', | |||
['2L 4s'] = 'mal-', | |||
['3L 3s'] = 'triwd-', | |||
['4L 2s'] = 'citro-', | |||
['5L 1s'] = 'mech-', | |||
['1L 6s'] = 'on-', | |||
['2L 5s'] = 'pel-', | |||
['3L 4s'] = 'mosh-', | |||
['4L 3s'] = 'smi-', | |||
['5L 2s'] = 'dia-', | |||
['6L 1s'] = 'arch-', | |||
['1L 7s'] = 'apine-', | |||
['2L 6s'] = 'subar-', | |||
['3L 5s'] = 'check-', | |||
['4L 4s'] = 'tetrawd-', | |||
['5L 3s'] = 'oneiro-', | |||
['6L 2s'] = 'ek-', | |||
['7L 1s'] = 'pine-', | |||
['1L 8s'] = 'ablu-', | |||
['2L 7s'] = 'bal-', | |||
['3L 6s'] = 'cher-', | |||
['4L 5s'] = 'gram-', | |||
['5L 4s'] = 'cthon-', | |||
['6L 3s'] = 'hyru-', | |||
['7L 2s'] = 'arm-', | |||
['8L 1s'] = 'blu-', | |||
['1L 9s'] = 'asina-', | |||
['2L 8s'] = 'jara-', | |||
['3L 7s'] = 'seph-', | |||
['4L 6s'] = 'lime-', | |||
['5L 5s'] = 'pentawd-', | |||
['6L 4s'] = 'lem-', | |||
['7L 3s'] = 'dico-', | |||
['8L 2s'] = 'tara-', | |||
['9L 1s'] = 'sina-' | |||
} | |||
-- Abbreviations (most abbrevs are the same as the prefixes but there are exceptions) | |||
p.tamnams_abbrev = { -- Only mosses with 2/1-equave names in TAMNAMS | |||
['1L 1s'] = 'wood', | |||
['2L 2s'] = 'bw', | |||
['1L 5s'] = 'amech', | |||
['2L 4s'] = 'mal', | |||
['3L 3s'] = 'trw', | |||
['4L 2s'] = 'cit', | |||
['5L 1s'] = 'mech', | |||
['1L 6s'] = 'on', | |||
['2L 5s'] = 'pel', | |||
['3L 4s'] = 'mosh', | |||
['4L 3s'] = 'smi', | |||
['5L 2s'] = 'dia', | |||
['6L 1s'] = 'arch', | |||
['1L 7s'] = 'apine', | |||
['2L 6s'] = 'subar', | |||
['3L 5s'] = 'chk', | |||
['4L 4s'] = 'ttw', | |||
['5L 3s'] = 'onei', | |||
['6L 2s'] = 'ek', | |||
['7L 1s'] = 'pine', | |||
['1L 8s'] = 'ablu', | |||
['2L 7s'] = 'bal', | |||
['3L 6s'] = 'ch', | |||
['4L 5s'] = 'gram', | |||
['5L 4s'] = 'cth', | |||
['6L 3s'] = 'hyru', | |||
['7L 2s'] = 'arm', | |||
['8L 1s'] = 'blu', | |||
['1L 9s'] = 'asi', | |||
['2L 8s'] = 'jar', | |||
['3L 7s'] = 'seph', | |||
['4L 6s'] = 'lime', | |||
['5L 5s'] = 'pw', | |||
['6L 4s'] = 'lem', | |||
['7L 3s'] = 'dico', | |||
['8L 2s'] = 'tar', | |||
['9L 1s'] = 'si' | |||
} | |||
function table_invert(t) | |||
local s={} | |||
for k,v in pairs(t) do | |||
s[v]=k | |||
end | |||
return s | |||
end | |||
-- Create a table that parses a mos string from the TAMNAMS name. | |||
p.parse_name = table_invert(p.tamnams_name) | |||
-------------------------------------------------------------------------------- | |||
----------------------------------- TESTER ------------------------------------- | |||
-------------------------------------------------------------------------------- | |||
-- Tester function | -- Tester function | ||
function p.tester() | function p.tester() | ||
return p. | return p.add_intervals({ ['L'] = 3, ['s'] = 1}, { ['L'] = 3, ['s'] = 1}) | ||
end | end | ||
return p | return p | ||