Module:MOS modes: Difference between revisions

Ganaram inukshuk (talk | contribs)
No edit summary
ArrowHead294 (talk | contribs)
mNo edit summary
 
(92 intermediate revisions by 4 users not shown)
Line 1: Line 1:
local mos = require('Module:MOS')
local rat = require('Module:Rational')
local p = {}
local p = {}


-- Function that takes a mos and produces all of the modes by brightness
local mos = require("Module:MOS")
-- The mos is entered as a data structure provided by Module:MOS
local rat = require("Module:Rational")
function p.modes_by_brightness(input_mos)
local tamnams = require("Module:TAMNAMS")
-- Default parameter, which corresponds to 5L 2s <2/1>
local tip = require("Module:Template input parse")
local input_mos = input_mos or mos.new(5, 2, 2)
local utils = require("Module:Utils")
local yesno = require("Module:Yesno")
 
-- TODO:
-- - Add ability to autocollapse on large mos pages (say, more than 12 modes)
 
-- "Main" function
-- To be called by wrapper
function p._mos_modes(input_mos, mode_names, headers, entries, is_collapsed)
local is_collapsed = is_collapsed == true
local input_mos = input_mos or mos.new(5,2)
local mode_names = mode_names or {}
local headers = headers or {}
local entries = entries or {}
-- Get the number of L's, s's, and periods
-- Get UDPs and CPOs
local nL = input_mos.nL
local udps = tamnams.mos_mode_udps(input_mos)
local ns = input_mos.ns
local cpos = tamnams.mos_mode_cpos(input_mos)
local periods = rat.gcd(nL, ns)
-- Find its brightest mode as a string of L's and s's
-- Get the mos's modes
local brightest_mode = mos.brightest_mode(input_mos)
local mos_modes = mos.modes_by_brightness(input_mos)
 
-- Check whether to add mode names
local add_mode_names = #mode_names == #mos_modes
 
-- Check whether the number of headers times the number of modes equals the
-- number of entries. Supplementary info can only be added if this condition
-- is met. Limited to 3 columns of supplementary info.
local add_columns = #headers > 0 and #entries > 0
if add_columns then
add_columns = add_columns and #mos_modes * #headers == #entries and #headers <= 3
end
-- Find the size of the generator aned period in mossteps
-- Table caption
local gen = mos.bright_gen(input_mos)
local scale_sig = mos.as_string(input_mos)
local gen_in_mossteps = gen['L'] + gen['s']
local period_size  = round((nL + ns) / periods)
-- For a mos xL ys, there are x+y unique modes that can be obtained by the following process:
-- Start of table
-- For a generator g in mossteps (g < x+y) and starting with the brightest mode (as a string
local result = "{| class=\"wikitable sortable center-2 center-3 mw-collapsible" .. (is_collapsed and " mw-collapsed\"\n" or "\"\n")
-- of L's and s's), move the first g steps to the end to get the next-brightest mode.
.. "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. string.format("Modes of %s\n", scale_sig)
-- Repeat this process with the rotated string to get all modes. The x+y-1th time this is done
.. "|-\n"
-- will be the darkest mode.
-- In the case of a multiperiod mos nxL nys, consider it as the mos for xL ys and duplicate
-- Table headers
-- each result n times. This way, the number of rotations needed to be performed is still x+y-1.
result = result
local brightest_mode_substr = string.sub(brightest_mode, 1, period_size)
.. "! [[UDP]]"
local modes = { brightest_mode }
.. " !! Cyclic<br />order"
local current_mode = brightest_mode_substr
.. " !! Step<br />pattern"
for i = 1, period_size - 1 do
-- Add header for mode names, if provided.
-- Move the first g strings from the beginning to the end
if add_mode_names then
local first_substr = string.sub(current_mode, 1, gen_in_mossteps)
result = result .. " !! class=\"unsortable\" | Mode names"
local second_substr = string.sub(current_mode, gen_in_mossteps + 1, period_size)
current_mode = second_substr .. first_substr
-- Duplicate the string (just in case) then add it to the array of modes
local current_mode_duplicated = string.rep(current_mode, periods)
table.insert(modes, current_mode_duplicated)
end
end
return modes
-- Add column headers for supplementary info, if provided.
end
if add_columns then
 
for i = 1, #headers do
-- Test function that produces the modes of a mos as a table
result = result .. string.format(" !! class=\"unsortable\" | %s", headers[i])
-- TODO:
end
-- - Allow for mos to be extracted from the page's title for use as a future template
end
-- - Allow for input of mode names
-- - Expand this (possibly as a separate template) for mos intervals
function p.modes_table(frame)
-- Mos is entered as "xL ys" since the mos module can parse that format
local mosstring = "3L 4s"
local input_mos = mos.parse(mosstring)
local mos_modes = p.modes_by_brightness(input_mos)
result = result .. "\n"
local periods = rat.gcd(input_mos.nL, input_mos.ns) -- Needed for UDP
-- Make a table with a column for the mode (as a string of L's and s's) and UDP
local result = '{| class="wikitable"\n'
result = result .. "|+ " .. "Modes of " .. mosstring .. "\n"
result = result .. "|-\n"
result = result .. "! Mode\n"
result = result .. "! [[UDP]]\n"
-- Enter each row
-- Enter each row
Line 71: Line 70:
result = result .. "|-\n"
result = result .. "|-\n"
-- Add the mode's string
-- Add the UDP, brightness order, and the mode's step pattern
result = result .. "|" .. mos_modes[i] .. "\n"
result = result .. string.format("| %s || %s || %s",
udps[i], cpos[i], mos_modes[i])
-- Add the mode's name, if given
if add_mode_names  then
result = result .. string.format(" || %s", mode_names[i])
end
-- Add columns if given
if add_columns then
for j = 1, #headers do
local index = (i - 1) * #headers + j
result = result .. string.format(" || %s", entries[index])
end
end
-- Add the UDP, formatted as up|dp, where u is the number of bright generators going up,
result = result .. "\n"
-- d is the number of bright generators going down, and p is the number of periods
-- (slightly different from standard UDP notation of u|d(p))
local gens_down = (i - 1) * periods
local gens_up = (#mos_modes - i) * periods
result = result .. "| " .. "<nowiki>" .. gens_up .. "|" .. gens_down .. "</nowiki>\n"
end
end
result = result .. "|}"
result = result .. "|}"
return result
end
-- Wrapper function; to be called by template
function p.modes_table(frame)
local scale_sig = frame.args["Scale Signature"] or "5L 2s"
local input_mos = mos.parse(scale_sig)
-- Get the mos's mode names, if given
-- Mode names are entered as a semicolon-delimited list
-- 5L 2s gets default names
local mode_names = nil
if scale_sig == "5L 2s" then
mode_names = {
"Lydian",
"Ionian (major)",
"Mixolydian",
"Dorian",
"Aeolian (minor)",
"Phrygian",
"Locrian"
}
end
return result
-- Get mode names entered
if #frame.args["Mode Names"] ~= 0 then
mode_names = tip.parse_entries(frame.args["Mode Names"], "$")
end
 
-- Get supplementary info
local headers_unparsed = frame.args["Table Headers"]
local headers = tip.parse_entries(headers_unparsed, "$")
local entries_unparsed = frame.args["Table Entries"]
local entries = tip.parse_entries(entries_unparsed, "$")
local is_collapsed = yesno(frame.args["Collapsed"], false)
local debugg = yesno(frame.args["debug"])
local result = p._mos_modes(input_mos, mode_names, headers, entries, is_collapsed)
-- Current means of adding entries is unmaintainable; to be deprecated.
if headers_unparsed ~= "" and entries_unparsed ~= "" then
result = result .. "[[Category:Pages with deprecated template parameters]]"
end
-- Debugger option
if debugg == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
return frame:preprocess(result)
end
end


return p
return p