「モジュール:TAMNAMS」の版間の差分

編集の要約なし
Furcht968 (トーク | 投稿記録)
編集の要約なし
1行目: 1行目:
-- Module for TAMNAMS-related things as it pertains to mosses
-- This module is meant to be used with other modules, not as part of a template
-- Work in progress
local mos = require('Module:MOS')
local rat = require('Module:Rational')
local utils = require('Module:Utils')
local p = {}
local p = {}
local mos = require("Module:MOS")
local rat = require("Module:Rational")
-- TODO
--Function to parse a UDP and (possibly) scale degrees.
--Separate interval/degree lookup into separate functions for for abbrevs and non-abbrev formats.
--Added arbitrary hardness lookup for a single ratio (e.g., passing in 13:8 would return "quasisoft".


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
------------------------------- LOOKUP TABLES ----------------------------------
--------------------------- NAME LOOKUP TABLES ---------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Lookup table for tamnams step ratios
-- Lookup table for tamnams step ratios
p.tamnams_ratios = {
p.step_ratios = {
['1:1'] = '均一',
['1:1'] = '均一',
['4:3'] = '緩慢',
['4:3'] = '緩慢',
25行目: 28行目:


-- And step ratio ranges
-- And step ratio ranges
p.tamnams_ranges = {
p.step_ratio_ranges = {
['1:1 to 2:1'] = 'soft-of-basic',
["1:1 to 2:1"] = "soft-of-basic",
['1:1 to 4:3'] = 'ultrasoft',
["1:1 to 3:2"] = "soft",
['4:3 to 3:2'] = 'parasoft',
["1:1 to 4:3"] = "ultrasoft",
['3:2 to 2:1'] = 'hyposoft',
["4:3 to 3:2"] = "parasoft",
['3:2 to 5:3'] = 'quasisoft',
["3:2 to 2:1"] = "hyposoft",
['5:3 to 2:1'] = 'minisoft',
["3:2 to 5:3"] = "quasisoft",
['2:1 to 5:2'] = 'minihard',
["5:3 to 2:1"] = "minisoft",
['5:2 to 3:1'] = 'quasihard',
["2:1 to 5:2"] = "minihard",
['2:1 to 3:1'] = 'hypohard',
["5:2 to 3:1"] = "quasihard",
['3:1 to 4:1'] = 'parahard',
["2:1 to 3:1"] = "hypohard",
['4:1 to 1:0'] = 'ultrahard',
["3:1 to 4:1"] = "parahard",
['2:1 to 1:0'] = 'hard-of-basic'
["4:1 to 1:0"] = "ultrahard",
["3:1 to 1:0"] = "hard",
["2:1 to 1:0"] = "hard-of-basic"
}
}


-- Lookup table for tamnams extended step ratios
-- Lookup table for tamnams extended step ratios
p.tamnams_ratios_ext = {
p.step_ratios_ext = {
['1:1'] = 'equalized',
["1:1"] = "equalized",
['6:5'] = 'semiequalized',
["6:5"] = "semiequalized",
['4:3'] = 'supersoft',
["4:3"] = "supersoft",
['3:2'] = 'soft',
["3:2"] = "soft",
['5:3'] = 'semisoft',
["5:3"] = "semisoft",
['2:1'] = 'basic',
["2:1"] = "basic",
['5:2'] = 'semihard',
["5:2"] = "semihard",
['3:1'] = 'hard',
["3:1"] = "hard",
['4:1'] = 'superhard',
["4:1"] = "superhard",
['6:1'] = 'extrahard',
["6:1"] = "extrahard",
['10:1'] = 'semicollapsed',
["10:1"] = "semicollapsed",
['1:0'] = 'collapsed'
["1:0"] = "collapsed"
}
}


-- And extended step ratio ranges
-- And extended step ratio ranges
p.tamnams_ranges_ext = {
p.step_ratio_ranges_ext = {
['1:1 to 2:1'] = 'soft-of-basic',
["1:1 to 2:1"] = "soft-of-basic",
['1:1 to 6:5'] = 'pseudoequalized',
["1:1 to 3:2"] = "soft",
['6:5 to 4:3'] = 'ultrasoft',
["1:1 to 6:5"] = "pseudoequalized",
['4:3 to 3:2'] = 'parasoft',
["6:5 to 4:3"] = "ultrasoft",
['3:2 to 2:1'] = 'hyposoft',
["4:3 to 3:2"] = "parasoft",
['3:2 to 5:3'] = 'quasisoft',
["3:2 to 2:1"] = "hyposoft",
['5:3 to 2:1'] = 'minisoft',
["3:2 to 5:3"] = "quasisoft",
['2:1 to 5:2'] = 'minihard',
["5:3 to 2:1"] = "minisoft",
['5:2 to 3:1'] = 'quasihard',
["2:1 to 5:2"] = "minihard",
['2:1 to 3:1'] = 'hypohard',
["5:2 to 3:1"] = "quasihard",
['3:1 to 4:1'] = 'parahard',
["2:1 to 3:1"] = "hypohard",
['4:1 to 6:1'] = 'hyperhard',
["3:1 to 4:1"] = "parahard",
['6:1 to 10:1'] = 'clustered',
["4:1 to 6:1"] = "hyperhard",
['4:1 to 10:1'] = 'ultrahard',
["6:1 to 10:1"] = "clustered",
['10:1 to 1:0'] = 'pseudocollapsed',
["4:1 to 10:1"] = "ultrahard",
['2:1 to 1:0'] = 'hard-of-basic'
["10:1 to 1:0"] = "pseudocollapsed",
["3:1 to 1:0"] = "hard",
["2:1 to 1:0"] = "hard-of-basic"
}
}


-- Lookup table for tamnams names within the range of 6-10 steps
-- Lookup table for tamnams names within the range of 6-10 steps
p.tamnams_name = {
p.mos_names = {
['1L 1s'] = 'monowood',
["1L 1s"] = "monowood",
['2L 2s'] = 'biwood',
["2L 2s"] = "biwood",
['1L 5s'] = 'antimachinoid',
["1L 5s"] = "antimachinoid",
['2L 4s'] = 'malic',
["2L 4s"] = "malic",
['3L 3s'] = 'triwood',
["3L 3s"] = "triwood",
['4L 2s'] = 'citric',
["4L 2s"] = "citric",
['5L 1s'] = 'machinoid',
["5L 1s"] = "machinoid",
['1L 6s'] = 'onyx',
["1L 6s"] = "onyx",
['2L 5s'] = 'antidiatonic',
["2L 5s"] = "antidiatonic",
['3L 4s'] = 'mosh',
["3L 4s"] = "mosh",
['4L 3s'] = 'smitonic',
["4L 3s"] = "smitonic",
['5L 2s'] = 'diatonic',
["5L 2s"] = "diatonic",
['6L 1s'] = 'archaeotonic',
["6L 1s"] = "archaeotonic",
['1L 7s'] = 'antipine',
["1L 7s"] = "antipine",
['2L 6s'] = 'subaric',
["2L 6s"] = "subaric",
['3L 5s'] = 'checkertonic',
["3L 5s"] = "checkertonic",
['4L 4s'] = 'tetrawood',
["4L 4s"] = "tetrawood",
['5L 3s'] = 'oneirotonic',
["5L 3s"] = "oneirotonic",
['6L 2s'] = 'ekic',
["6L 2s"] = "ekic",
['7L 1s'] = 'pine',
["7L 1s"] = "pine",
['1L 8s'] = 'antisubneutralic',
["1L 8s"] = "antisubneutralic",
['2L 7s'] = 'balzano',
["2L 7s"] = "balzano",
['3L 6s'] = 'tcherepnin',
["3L 6s"] = "tcherepnin",
['4L 5s'] = 'gramitonic',
["4L 5s"] = "gramitonic",
['5L 4s'] = 'semiquartal',
["5L 4s"] = "semiquartal",
['6L 3s'] = 'hyrulic',
["6L 3s"] = "hyrulic",
['7L 2s'] = 'armotonic',
["7L 2s"] = "armotonic",
['8L 1s'] = 'subneutralic',
["8L 1s"] = "subneutralic",
['1L 9s'] = 'antisinatonic',
["1L 9s"] = "antisinatonic",
['2L 8s'] = 'jaric',
["2L 8s"] = "jaric",
['3L 7s'] = 'sephiroid',
["3L 7s"] = "sephiroid",
['4L 6s'] = 'lime',
["4L 6s"] = "lime",
['5L 5s'] = 'pentawood',
["5L 5s"] = "pentawood",
['6L 4s'] = 'lemon',
["6L 4s"] = "lemon",
['7L 3s'] = 'dicoid',
["7L 3s"] = "dicoid",
['8L 2s'] = 'taric',
["8L 2s"] = "taric",
['9L 1s'] = 'sinatonic'
["9L 1s"] = "sinatonic"
}
}


-- And prefixes
-- And prefixes
p.tamnams_prefix = {
p.mos_prefixes = {
['1L 1s'] = 'monwd',
["1L 1s"] = "monwd",
['2L 2s'] = 'biwd',
["2L 2s"] = "biwd",
['1L 5s'] = 'amech',
["2L 3s"] = "pent",
['2L 4s'] = 'mal',
["1L 5s"] = "amech",
['3L 3s'] = 'triwd',
["2L 4s"] = "mal",
['4L 2s'] = 'citro',
["3L 3s"] = "triwd",
['5L 1s'] = 'mech',
["4L 2s"] = "citro",
['1L 6s'] = 'on',
["5L 1s"] = "mech",
['2L 5s'] = 'pel',
["1L 6s"] = "on",
['3L 4s'] = 'mosh',
["2L 5s"] = "pel",
['4L 3s'] = 'smi',
["3L 4s"] = "mosh",
['5L 2s'] = 'dia',
["4L 3s"] = "smi",
['6L 1s'] = 'arch',
["5L 2s"] = "dia",
['1L 7s'] = 'apine',
["6L 1s"] = "arch",
['2L 6s'] = 'subar',
["1L 7s"] = "apine",
['3L 5s'] = 'check',
["2L 6s"] = "subar",
['4L 4s'] = 'tetrawd',
["3L 5s"] = "check",
['5L 3s'] = 'oneiro',
["4L 4s"] = "tetrawd",
['6L 2s'] = 'ek',
["5L 3s"] = "oneiro",
['7L 1s'] = 'pine',
["6L 2s"] = "ek",
['1L 8s'] = 'ablu',
["7L 1s"] = "pine",
['2L 7s'] = 'bal',
["1L 8s"] = "ablu",
['3L 6s'] = 'cher',
["2L 7s"] = "bal",
['4L 5s'] = 'gram',
["3L 6s"] = "cher",
['5L 4s'] = 'cthon',
["4L 5s"] = "gram",
['6L 3s'] = 'hyru',
["5L 4s"] = "cthon",
['7L 2s'] = 'arm',
["6L 3s"] = "hyru",
['8L 1s'] = 'blu',
["7L 2s"] = "arm",
['1L 9s'] = 'asina',
["8L 1s"] = "blu",
['2L 8s'] = 'jara',
["1L 9s"] = "asina",
['3L 7s'] = 'seph',
["2L 8s"] = "jara",
['4L 6s'] = 'lime',
["3L 7s"] = "seph",
['5L 5s'] = 'pentawd',
["4L 6s"] = "lime",
['6L 4s'] = 'lem',
["5L 5s"] = "pentawd",
['7L 3s'] = 'dico',
["6L 4s"] = "lem",
['8L 2s'] = 'tara',
["7L 3s"] = "dico",
['9L 1s'] = 'sina'
["8L 2s"] = "tara",
["9L 1s"] = "sina"
}
}


-- And abbrevs
-- And abbrevs
p.tamnams_abbrev = {
p.mos_abbrevs = {
['1L 1s'] = 'wood',
["1L 1s"] = "w",
['2L 2s'] = 'bw',
["2L 2s"] = "bw",
['1L 5s'] = 'amech',
["1L 5s"] = "amk",
['2L 4s'] = 'mal',
["2L 4s"] = "mal",
['3L 3s'] = 'trw',
["3L 3s"] = "tw",
['4L 2s'] = 'cit',
["4L 2s"] = "cit",
['5L 1s'] = 'mech',
["5L 1s"] = "mk",
['1L 6s'] = 'on',
["1L 6s"] = "on",
['2L 5s'] = 'pel',
["2L 5s"] = "pel",
['3L 4s'] = 'mosh',
["3L 4s"] = "mosh",
['4L 3s'] = 'smi',
["4L 3s"] = "smi",
['5L 2s'] = 'dia',
["5L 2s"] = "dia",
['6L 1s'] = 'arch',
["6L 1s"] = "arc",
['1L 7s'] = 'apine',
["1L 7s"] = "ap",
['2L 6s'] = 'subar',
["2L 6s"] = "sb",
['3L 5s'] = 'chk',
["3L 5s"] = "chk",
['4L 4s'] = 'ttw',
["4L 4s"] = "ttw",
['5L 3s'] = 'onei',
["5L 3s"] = "onei",
['6L 2s'] = 'ek',
["6L 2s"] = "ek",
['7L 1s'] = 'pine',
["7L 1s"] = "p",
['1L 8s'] = 'ablu',
["1L 8s"] = "ablu",
['2L 7s'] = 'bal',
["2L 7s"] = "bz",
['3L 6s'] = 'ch',
["3L 6s"] = "ch",
['4L 5s'] = 'gram',
["4L 5s"] = "gm",
['5L 4s'] = 'cth',
["5L 4s"] = "ct",
['6L 3s'] = 'hyru',
["6L 3s"] = "hy",
['7L 2s'] = 'arm',
["7L 2s"] = "arm",
['8L 1s'] = 'blu',
["8L 1s"] = "blu",
['1L 9s'] = 'asi',
["1L 9s"] = "asi",
['2L 8s'] = 'jar',
["2L 8s"] = "ja",
['3L 7s'] = 'seph',
["3L 7s"] = "sp",
['4L 6s'] = 'lime',
["4L 6s"] = "lm",
['5L 5s'] = 'pw',
["5L 5s"] = "pw",
['6L 4s'] = 'lem',
["6L 4s"] = "le",
['7L 3s'] = 'dico',
["7L 3s"] = "di",
['8L 2s'] = 'tar',
["8L 2s"] = "ta",
['9L 1s'] = 'si'
["9L 1s"] = "si"
}
 
-- TAMNAMS equave-agnostic names
p.equave_agnostic_names = {
["1L 1s"] = "trivial",
["1L 2s"] = "antrial",
["2L 1s"] = "trial",
["1L 3s"] = "antetric",
["3L 1s"] = "tetric",
["1L 4s"] = "pedal",
["2L 3s"] = "pentic",
["3L 2s"] = "anpentic",
["4L 1s"] = "manual"
}
 
-- And prefixes
p.equave_agnostic_prefixes = {
["1L 1s"] = "trv",
["1L 2s"] = "at",
["2L 1s"] = "t",
["1L 3s"] = "att",
["3L 1s"] = "tt",
["1L 4s"] = "pd",
["2L 3s"] = "pt",
["3L 2s"] = "apt",
["4L 1s"] = "mnu"
}
 
-- And abbrevs
p.equave_agnostic_abbrevs = {
["1L 1s"] = "trv",
["1L 2s"] = "at",
["2L 1s"] = "t",
["1L 3s"] = "att",
["3L 1s"] = "tt",
["1L 4s"] = "ped",
["2L 3s"] = "pt",
["3L 2s"] = "apt",
["4L 1s"] = "mnu"
}
}


210行目: 257行目:
if type(step_ratio) == "string" then
if type(step_ratio) == "string" then
return step_ratio
return step_ratio
elseif (type(step_ratio) == "table" and type(step_ratio[1]) == 'number' and type(step_ratio[2]) == 'number') then
elseif (type(step_ratio) == "table" and type(step_ratio[1]) == "number" and type(step_ratio[2]) == "number") then
return rat.new(step_ratio[1], step_ratio[2])
return rat.new(step_ratio[1], step_ratio[2])
else
else
219行目: 266行目:
-- Mosses for name lookup are entered either as a scalesig or as a mos as
-- Mosses for name lookup are entered either as a scalesig or as a mos as
-- defined in the mos module. If of the latter, it's converted into a textual
-- defined in the mos module. If of the latter, it's converted into a textual
-- scalesig.
-- scalesig. Scalesigs should have a normal space, not a nonbreaking space, as
-- the lookup tables use a normal space.
function p.preprocess_scalesig(input_mos)
function p.preprocess_scalesig(input_mos)
if type(input_mos) == "string" then
if type(input_mos) == "string" then
return input_mos
local parsed_mos = mos.parse(input_mos)
return mos.as_string(parsed_mos, false)
elseif type(input_mos) == "table" then
elseif type(input_mos) == "table" then
return mos.as_string(input_mos)
return mos.as_string(input_mos, false)
else
else
return nil
return nil
231行目: 280行目:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------------------- LOOKUP FUNCTIONS ---------------------------------
------------------------ TEMPLATE HELPER FUNCTIONS -----------------------------
--------------------------------------------------------------------------------
 
-- Verifier function that checks for a prefix already provided by TAMNAMS.
-- If there is one provided, use that. If there is none, use the one passed in.
-- If no prefix is provided, defualt to "mos". If "NONE" is entered, return an
-- empty string.
function p.verify_prefix(input_mos, mos_prefix)
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos"
if mos_prefix == "NONE" or mos_prefix == "none" then
mos_prefix = ""
elseif mos_prefix == "" then
mos_prefix = "mos"
end
return mos_prefix
end
 
-- Verifier function that checks for an abbrev already provided by TAMNAMS.
-- If there is one provided, use that. If there is none, use the one passed in.
-- If no abbrev is provided, defualt to "m". If "NONE" is entered, return an
-- empty string.
function p.verify_abbrev(input_mos, mos_abbrev)
local mos_abbrev = p.lookup_abbrev(input_mos) or mos_abbrev or "m"
if mos_abbrev == "NONE" or mos_abbrev == "none" then
mos_abbrev = ""
elseif mos_abbrev == "" then
mos_abbrev = "m"
end
return mos_abbrev
end
 
--------------------------------------------------------------------------------
------------------------- NAME LOOKUP FUNCTIONS --------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


238行目: 319行目:
function p.lookup_name(input_mos)  
function p.lookup_name(input_mos)  
local scalesig = p.preprocess_scalesig(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
return p.tamnams_name[scalesig]
return p.mos_names[scalesig]
end
end


245行目: 326行目:
function p.lookup_prefix(input_mos)
function p.lookup_prefix(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
return p.tamnams_prefix[scalesig]
return p.mos_prefixes[scalesig]
end
end


252行目: 333行目:
function p.lookup_abbrev(input_mos)  
function p.lookup_abbrev(input_mos)  
local scalesig = p.preprocess_scalesig(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
return p.tamnams_abbrev[scalesig]
return p.mos_abbrevs[scalesig]
end
end


263行目: 344行目:
-- Produce the key needed to lookup the step ratio name
-- Produce the key needed to lookup the step ratio name
-- use_extended is used to toggle between central range and extended range
-- use_extended is used to toggle between central range and extended range
local key = rat.as_ratio(step_ratio, ':')
local key = rat.as_ratio(step_ratio, ":")
local named_ratio = use_extended and p.tamnams_ratios_ext[key] or p.tamnams_ratios[key]
local named_ratio = use_extended and p.step_ratios_ext[key] or p.step_ratios[key]
return named_ratio ~= nil and named_ratio or key
return named_ratio
end
end


282行目: 363行目:
local float_2 = rat.as_float(step_ratio_2)
local float_2 = rat.as_float(step_ratio_2)
if (float_1 > float_2) then
if (float_1 > float_2) then
key = string.format('%s to %s', rat.as_ratio(step_ratio_2, ':'), rat.as_ratio(step_ratio_1, ':'))
key = string.format("%s to %s", rat.as_ratio(step_ratio_2, ":"), rat.as_ratio(step_ratio_1, ":"))
else
else
key = string.format('%s to %s', rat.as_ratio(step_ratio_1, ':'), rat.as_ratio(step_ratio_2, ':'))
key = string.format("%s to %s", rat.as_ratio(step_ratio_1, ":"), rat.as_ratio(step_ratio_2, ":"))
end
end
-- use_extended is used to toggle between central range and extended range
-- use_extended is used to toggle between central range and extended range
local named_ratio_range = use_extended and p.tamnams_ranges_ext[key] or p.tamnams_ranges[key]
local named_ratio_range = use_extended and p.step_ratio_ranges_ext[key] or p.step_ratio_ranges[key]
return named_ratio_range
end
 
--------------------------------------------------------------------------------
------------------------- NAME FINDER FUNCTIONS --------------------------------
--------------------------------------------------------------------------------
 
-- Helper function
-- "Rounds" step ratios up to the nearest named ratio
function p.step_ratio_ceil(step_ratio)
local hardness = step_ratio[1] / step_ratio[2]
return named_ratio_range ~= nil and named_ratio_range or key
local rounded_step_ratio = nil
if hardness > 1/1 and hardness <= 4/3 then
rounded_step_ratio = {4,3}
elseif hardness > 4/3 and hardness <= 3/2 then
rounded_step_ratio = {3,2}
elseif hardness > 3/2 and hardness <= 5/3 then
rounded_step_ratio = {5,3}
elseif hardness > 5/3 and hardness <= 2/1 then
rounded_step_ratio = {2,1}
elseif hardness > 2/1 and hardness <= 5/2 then
rounded_step_ratio = {5,2}
elseif hardness > 5/2 and hardness <= 3/1 then
rounded_step_ratio = {3,1}
elseif hardness > 3/1 and hardness <= 4/1 then
rounded_step_ratio = {4,1}
elseif hardness > 4/1 and hardness <= 1/0 then
rounded_step_ratio = {1,0}
end
return rounded_step_ratio
end
 
-- Helper function
-- "Rounds" step ratios down to the nearest named ratio
function p.step_ratio_floor(step_ratio)
local hardness = step_ratio[1] / step_ratio[2]
local rounded_step_ratio = nil
if hardness >= 1/1 and hardness < 4/3 then
rounded_step_ratio = {1,1}
elseif hardness >= 4/3 and hardness < 3/2 then
rounded_step_ratio = {4,3}
elseif hardness >= 3/2 and hardness < 5/3 then
rounded_step_ratio = {3,2}
elseif hardness >= 5/3 and hardness < 2/1 then
rounded_step_ratio = {5,3}
elseif hardness >= 2/1 and hardness < 5/2 then
rounded_step_ratio = {2,1}
elseif hardness >= 5/2 and hardness < 3/1 then
rounded_step_ratio = {5,2}
elseif hardness >= 3/1 and hardness < 4/1 then
rounded_step_ratio = {3,1}
elseif hardness >= 4/1 and hardness < 1/0 then
rounded_step_ratio = {4,1}
end
return rounded_step_ratio
end
 
-- Function for finding the smallest step ratio range that encompasses the two
-- ratios passed in.
function p.find_step_ratio_range_for_ratio_pair(step_ratio_1, step_ratio_2, use_extended)
local use_extended = use_extended == true -- Does nothing for now
-- Swap ratios so they're in the right order
local hardness_1 = step_ratio_1[1] / step_ratio_1[2]
local hardness_2 = step_ratio_2[1] / step_ratio_2[2]
local lower_ratio = nil
local upper_ratio = nil
local named_ratio_range = ""
if hardness_1 <= hardness_2 then
lower_ratio = p.step_ratio_floor(step_ratio_1)
upper_ratio = p.step_ratio_ceil (step_ratio_2)
else
lower_ratio = p.step_ratio_floor(step_ratio_2)
upper_ratio = p.step_ratio_ceil (step_ratio_1)
end
-- If one ratio corresponds to the endpoint of a named hardness range
-- but the other ratio exceeds that of a smaller range, default to the
-- largest range that would accommodate it.
-- 2:1 to (L:s > 3:1) = hard-of-basic
-- 4:1 and up = ultrahard
-- (L:s < 3:2) to 2:1 = soft-of-basic
-- 4:3 and lower = ultrasoft
if (lower_ratio[1]/lower_ratio[2] == 2/1 and upper_ratio[1]/upper_ratio[2] > 3/1) or lower_ratio[1]/lower_ratio[2] == 4/1 then
upper_ratio = {1,0}
elseif (upper_ratio[1]/upper_ratio[2] == 2/1 and lower_ratio[1]/lower_ratio[2] < 3/2) or upper_ratio[1]/upper_ratio[2] == 4/3 then
lower_ratio = {1,1}
end
 
local named_ratio_range = p.lookup_step_ratio_range(lower_ratio, upper_ratio, use_extended)
return named_ratio_range
end
end


312行目: 485行目:
end
end
return p.new(z, w, mos.equave)
return mos.new(z, w, input_mos.equave)
end
end


432行目: 605行目:
if abbrev_format == "abbrev" or abbrev_format == "ABBREV" then
if abbrev_format == "abbrev" or abbrev_format == "ABBREV" then
return string.format("%s%d%ss", quality, step_count, mos_prefix)
return string.format("%s%d%sd", quality, step_count, mos_prefix)
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then
return string.format("%s %d-%sd.", quality, step_count, mos_prefix)
return string.format("%s %d-%sd.", quality, step_count, mos_prefix)
627行目: 800行目:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------------------- TESTER FUNCTION ----------------------------------
-------------------- MODE NOTATION/COMPARISON FUNCTIONS ------------------------
-------------------------- BASED ON UDP NOTATION -------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


function p.tester()
-- Given the number of gens up and down per period and a period count (u, d, and
local input_mos = mos.new(4,3)
-- p respectively), construct the UDP as a string, as up|dp(p) or u|d, for
local brightest_mode = mos.brightest_mode(input_mos)
-- multi-period and single-period respectively.
local interval_qualities = {}
-- If only u is known, then d = p - u - 1.
-- If only d is known, then u = p - d - 1. (Basically, u + d + 1 = steps/p.)
-- A table of alterations can also be passed in, assuming they are already
-- written out (EG, d3md or, if notation is established, b4).
function p.udp_as_string(gens_up_per_period, gens_down_per_period, periods, alterations)
local periods = periods or 1
local alterations_as_string = ""
if alterations ~= nil then
for i = 1, #alterations do
alterations_as_string = alterations_as_string .. "&nbsp;" .. alterations[i]
end
end
 
return (periods == 1
and string.format("%s{{pipe}}%s", gens_up_per_period, gens_down_per_period)
or string.format("%s{{pipe}}%s(%s)", gens_up_per_period * periods, gens_down_per_period * periods, periods))
.. alterations_as_string
end
 
-- Given an input mos, list the udps for each of its modes, listed in order of
-- decreasing brightness.
function p.mos_mode_udps(input_mos)
local steps_per_period = mos.period_step_count(input_mos)
local period_count = mos.period_count(input_mos)
local udps = {}
for i = 1, steps_per_period do
local gens_up = steps_per_period - i
local gens_down = steps_per_period - gens_up - 1
local udp = p.udp_as_string(gens_up, gens_down, period_count)
table.insert(udps, udp)
end
return udps
end
 
-- Given an input mos, list the cpos for each of its modes. The circular
-- permutation orderings are listed starting from the brightest mode.
-- Example with 5L 2s modes
--  MODE NAME  | UDP | CPO
-- ------------+-----+-----
--  Lydian    | 6|0 | 1
--  Ionian    | 5|1 | 5
--  Mixolydian | 4|2 | 2
--  Dorian    | 3|3 | 6
--  Aeolian    | 2|4 | 3
--  Phrygian  | 1|5 | 7
--  Lociran    | 0|6 | 4
function p.mos_mode_cpos(input_mos)
local steps_per_period = mos.period_step_count(input_mos)
local period_count = mos.period_count(input_mos)
local steps_per_bright_gen = mos.bright_gen_step_count(input_mos)
local cpos = {}
for i = 1, steps_per_period do
local cpo = ((i - 1) * steps_per_bright_gen) % steps_per_period + 1
table.insert(cpos, cpo)
end
return cpos
end
 
-- Given a string that represents a mode, return the udps for each of its
-- rotations. If the mode is a modmos, the closest mode and its alterations
-- are returned as a string.
-- NOTES:
-- - A period of repetition will always have as many modes as there are steps
--  in that period. If it were any less, then the true period of repetition
--  is a substring of that.
function p.mode_rotation_udps(input_mode, input_mos, mos_abbrev, use_brightest_mode_search)
local use_brightest_mode_search = use_brightest_mode_search == nil or use_brightest_mode_search
local modes = mos.mode_rotations(input_mode)
local udps = {}
for i = 1, #modes do
table.insert(udps, p.mode_udp(modes[i], input_mos, mos_abbrev, use_brightest_mode_search))
end
return udps
end
 
-- Given a string that represents a mode, return its udp.
-- Helper function for mode_rotation_udps().
-- If a mode is for a modmos, it will return the closest brightest mode followed
-- by its altered scale degrees. Alterations require a mos abbrev, which is
-- automatically looked up, defaulting to "m" if no abbrev can be found.
-- NOTES:
-- - This is inefficient when used on true-mos modes since it's a brute-force
--  search for what mode it's closest to. It is, however, effective on
--  modmosses, which is the primary use for this function.
function p.mode_udp(input_mode, input_mos, mos_abbrev, use_brightest_mode_search)
local use_brightest_mode_search = use_brightest_mode_search == nil or use_brightest_mode_search
local mos_abbrev = mos_abbrev or p.lookup_abbrev(input_mos) or "m"
local true_modes = mos.modes_to_step_matrices(input_mos)
local input_mode_as_step_matrix = mos.mode_to_step_matrix(input_mode)
-- For each mode, count the number of differences between each true mode
-- and the entered mode and keep track of which mode has the fewest diffs.
-- That mode is considered the closest mode, whose UDP will be used for the
-- mode name, followed by which scale degrees are changed.
-- If the number of diffs is ever zero, then the entered mode was a true-mos
-- mode and has zero alterations.
local lowest_differences = #input_mode_as_step_matrix
local bright_gens_down_per_period = 0
local differences = {}
for i = 1, #true_modes do
local current_true_mode = true_modes[i]
local current_differences = p.differences_between_modes(current_true_mode, input_mode_as_step_matrix)
-- It's possible for more than one mode to be closest. The tiebreaker is
-- whichever mode is brightest (or darkest, which can be toggled).
if use_brightest_mode_search then
if #current_differences < lowest_differences then
-- Brightest-closest match
bright_gens_down_per_period = i - 1
lowest_differences = #current_differences
differences = current_differences
end
else
if #current_differences <= lowest_differences then
-- Darkest-closest match
bright_gens_down_per_period = i - 1
lowest_differences = #current_differences
differences = current_differences
end
end
end
-- Parse the differences as scale degrees.
-- The differences between the true mode and the input mode are denoted as
-- interval vectors. These should be parsed into a list of altered scale
-- degrees before being passed into udp_as_string. Coding it this way allows
-- for the possibility of adding custom mos notation (EG, diamond-mos).
local alterations = {}
for i = 1, #differences do
table.insert(alterations, p.degree_quality(differences[i], input_mos, "ABBREV", mos_abbrev))
end
-- Produce the UDP (as text) for the mode, formatted as up|dp(p) for multi-
-- period mosses, or u|d for single-period mosses.
local period_count = mos.period_count(input_mos)
local bright_gens_up_per_period = mos.period_step_count(input_mos) - 1 - bright_gens_down_per_period
udp = p.udp_as_string(bright_gens_up_per_period, bright_gens_down_per_period, period_count, alterations)
return udp
end


local step_matrices = mos.modes_to_step_matrices(input_mos)
-- Helper function for mode_udp, but can be used standalone.
for i = 1, mos.equave_step_count(input_mos) do
-- Given two modes as step matrices, produce a list of differences between the
local qualities = ""
-- base mode and the altered mode. Diffs are listed as an array of mosstep
for j = 1, #step_matrices[i] do
-- vectors (a table containing the number of L's and s's for that interval).
qualities = qualities .. p.decode_quality(step_matrices[i][j], input_mos, "shortened") .. " "
function p.differences_between_modes(base_step_matrix, altered_step_matrix)
--qualities = qualities .. (step_matrices[i][j] ~= nil and "Y" or "N") .. " "
local differences = {}
for i = 1, #altered_step_matrix do
local altered_interval = altered_step_matrix[i]
-- If i is greater than the number of intervals in base_step_matrix,
-- then the interval being accessed is an extra-equave interval. Instead
-- of accessing the ith interval (which would lead to a nil error),
-- access the corresponding equave-reduced interval, then raise it by
-- the necessary number of equaves.
local base_interval = {}
if i > #base_step_matrix then
local current_mossteps = i - 1
local equave_step_count = #base_step_matrix - 1
local equave_interval = base_step_matrix[#base_step_matrix]
local equave_reduced_interval = base_step_matrix[current_mossteps % equave_step_count + 1]
local equave_count = math.floor(current_mossteps / equave_step_count)
local equaves = mos.interval_mul(equave_interval, equave_count)
base_interval = mos.interval_add(equave_reduced_interval, equaves)
else
base_interval = base_step_matrix[i]
end
if not mos.interval_eq(base_interval, altered_interval) then
table.insert(differences, altered_interval)
end
end
table.insert(interval_qualities, qualities)
end
end
return interval_qualities
return differences
end
 
--------------------------------------------------------------------------------
----------------------------- TESTER FUNCTION ----------------------------------
--------------------------------------------------------------------------------
 
function p.tester()
local input_mos = mos.new(5, 2)
return p.preprocess_scalesig(input_mos)
end
end


return p
return p