Module:MOS mode degrees: Difference between revisions

Ganaram inukshuk (talk | contribs)
m TODO added
ArrowHead294 (talk | contribs)
mNo edit summary
 
(45 intermediate revisions by 3 users not shown)
Line 1: Line 1:
local p = {}
local mos = require("Module:MOS")
local mos = require("Module:MOS")
local tamnams = require("Module:TAMNAMS")
local tip = require("Module:Template input parse")
local tip = require("Module:Template input parse")
local tamnams = require("Module:TAMNAMS")
local yesno = require("Module:Yesno")
local p = {}


-- TODO
-- TODO
-- Add an option to collapse the table, and have the table collapsed by default
-- - Split off modmos mode degrees as a separate template


-- Global variables for cell colors
-- Global variables for cell colors
-- Colors are as follows:
-- Colors are as follows:
-- Large intervals are yellow, small intervals are blue, augmented intervals are dark yellow, and diminished intervals are dark blue
-- - Orange and blue for small and large sizes, respectively
-- - Darker colors for altered scale degrees
-- - No color for period intervals
p.cell_color_none = "NONE" -- For cells that don't have a color (default cell color applies)
p.cell_color_none = "NONE" -- For cells that don't have a color (default cell color applies)
p.cell_color_perfect_size = "NONE" -- Only applies for periods, including the root and equave
p.cell_color_perfect_size = "NONE" -- Only applies for periods, including the root and equave
Line 53: Line 57:
-- Create a table of a mos's degrees
-- Create a table of a mos's degrees
-- If a step pattern is provided, it's assumed to be that of a modmos
-- If a step pattern is provided, it's assumed to be that of a modmos
function p._mos_mode_degrees(input_mos, mos_prefix, mode_names, use_default_mode_names, step_pattern)
function p._mos_mode_degrees(input_mos, mos_prefix, is_collapsed, step_pattern)
local is_true_mos = step_pattern == nil
local is_true_mos = step_pattern == nil
local input_mos = input_mos or mos.new(5, 2)
local input_mos = input_mos or mos.new(5, 2)
local mos_prefix = mos_prefix or "mos"
local mos_prefix = mos_prefix or "mos"
local is_collapsed = is_collapsed == true
-- If default mode names are to be used, they'll overwrite whatever mode names are passed in, even if there aren't any
local mode_names = mode_names or nil
local use_default_mode_names = use_default_mode_names == true
-- Get the modes as strings and step vectors
-- Get the modes as strings and step vectors
Line 88: Line 88:
udps = tamnams.mos_mode_udps(input_mos)
udps = tamnams.mos_mode_udps(input_mos)
cpos = tamnams.mos_mode_cpos(input_mos)
cpos = tamnams.mos_mode_cpos(input_mos)
-- Produce default mode names if needed
if use_default_mode_names then
local default_mode_names = {}
for i = 1, #udps do
table.insert(default_mode_names, string.format("%s %s", scale_sig, udps[i]))
end
mode_names = default_mode_names
end
else
else
-- Modmos udps require a mosabbrev; this is forced to be "m" since some
-- Modmos udps require a mosabbrev; this is forced to be "m" since some
Line 109: Line 100:
table.insert(udps, udps_closest_bright[i])
table.insert(udps, udps_closest_bright[i])
else
else
table.insert(udps, string.format("%s<br>%s", udps_closest_bright[i], udps_closest_dark[i]))
table.insert(udps, string.format("%s<br />%s", udps_closest_bright[i], udps_closest_dark[i]))
end
end
table.insert(cpos, i)
table.insert(cpos, i)
end
-- Produce default mode names if needed
if use_default_mode_names then
local default_mode_names = {}
for i = 1, #udps_closest_bright do
if udps_closest_bright[i] == udps_closest_dark[i] then
table.insert(default_mode_names, string.format("%s %s", scale_sig, udps_closest_bright[i]))
else
table.insert(default_mode_names, string.format("%s %s<br>%s %s", scale_sig, udps_closest_bright[i], scale_sig, udps_closest_dark[i]))
end
end
mode_names = default_mode_names
end
end
end
end
-- Create table
-- Create table
local result = "{| class=\"wikitable sortable\"\n"
local result = "{| class=\"wikitable sortable mw-collapsible center-2 center-3"
.. (is_collapsed and " mw-collapsed\"" or "\"") .. "\n"
-- Table header
-- Table's title
-- If it's for a modmos, add the step pattern
-- If it's for a modmos, add the step pattern
result = result .. string.format("|+ style=\"font-size: 105%%;\" | Scale degree qualities of %s modes", scale_sig) .. (is_true_mos and "\n" or string.format(" (%s)\n", step_pattern))
result = result .. "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. string.format("Scale degrees of the modes of %s", scale_sig)
.. (is_true_mos and "\n" or string.format(" (%s)\n", step_pattern))
.. "|-\n"
-- Add table headers for first row
-- Add table headers for first row
result = result
result = result
.. "! rowspan=\"2\" | UDP " .. (is_true_mos and "" or " and alterations ") -- If modmos, add "and alterations" string
.. "! rowspan=\"2\" | UDP" .. (is_true_mos and "\n" or " and<br />alterations\n") -- If modmos, add "and alterations" string
.. "!! rowspan=\"2\" | Rotational Order "
.. "! rowspan=\"2\" | Cyclic<br />order\n"
.. "!! rowspan=\"2\" | Step pattern"
.. "! rowspan=\"2\" | Step<br />pattern\n"
-- Add mode names if present
local mode_names_given = mode_names ~= nil and #mode_names == #step_patterns
if mode_names_given then
result = result .. " !! rowspan=\"2\" class=\"unsortable\" | Mode names"
end
-- Add header for scale degrees
-- Add header for scale degrees
result = result .. string.format(" !! colspan=\"%d\" class=\"unsortable\" | Scale degree (%sdegree)\n", #step_matrices[1], mos_prefix)
result = result .. string.format("! colspan=\"%d\" class=\"unsortable\" | Scale degree (%sdegree)\n", #step_matrices[1], mos_prefix)
-- Add second row of headers
-- Add second row of headers
Line 154: Line 129:
.. "! 0"
.. "! 0"
for i = 1, #step_patterns[1] do
for i = 1, #step_patterns[1] do
result = result .. string.format(" !! %d", i)
result = result .. string.format("\n! %d", i)
end
end
Line 164: Line 139:
-- Add brightness order (as UDP), rotational order, and step pattern
-- Add brightness order (as UDP), rotational order, and step pattern
.. string.format("| %s || %s || %s", udps[i], cpos[i], step_patterns[i])
.. string.format("| %s\n| %s\n| %s\n", udps[i], cpos[i], step_patterns[i])
 
-- Add mode name if given
if mode_names_given then
result = result .. string.format(" || %s", mode_names[i])
end
-- Add scale degrees with cell coloring
-- Add scale degrees with cell coloring
for j = 1, #step_matrices[i] do
for j = 1, #step_matrices[i] do
Line 177: Line 147:
local cell_color = p.cell_color(current_interval, input_mos)
local cell_color = p.cell_color(current_interval, input_mos)
local style_code = cell_color == p.cell_color_none and "" or string.format("style=\"background: %s;\" | ", cell_color)
local style_code = (cell_color == p.cell_color_none and "" or string.format("style=\"background: %s;\" | ", cell_color))
result = result .. string.format(" || %s%s", style_code, degree_quality)
result = result .. string.format("| %s%s\n", style_code, degree_quality)
end
end
result = result .. "\n"
end
end
Line 192: Line 161:
-- Function to be called as part of a template
-- Function to be called as part of a template
function p.mos_mode_degrees(frame)
function p.mos_mode_degrees(frame)
-- Default param for input mos is 5L 2s
-- Get args
local input_mos = mos.parse(frame.args["Scale Signature"]) or mos.new(2, 5, 2)
local input_mos   = mos.parse(frame.args["Scale Signature"])
local mos_prefix  = frame.args["MOS Prefix"]
local step_pattern = frame.args["MODMOS Step Pattern"]
local mode_names_unparsed = frame.args["Mode Names"]
-- Parse debugging option
local debugg = yesno(frame.args["debug"])
-- Get the scale sig; for calculating the mos prefix
-- Get the scale sig; for calculating the mos prefix
local scale_sig = mos.as_string(input_mos)
local scale_sig = mos.as_string(input_mos)
-- Default param for mos prefix
-- Verify mosprefix
-- If "NONE" is given, no prefix will be used
mos_prefix = tamnams.verify_prefix(input_mos, mos_prefix)
-- If left blank, try to find the appropriate mos prefix, or else defualt to "mos"
-- If not left blank, use the prefix passed in instead
local mos_prefix = "mos"
if frame.args["MOS Prefix"] == "NONE" then
mos_prefix = ""
elseif string.len(frame.args["MOS Prefix"]) == 0 then
mos_prefix_lookup = tamnams.lookup_prefix(input_mos) or ""
if string.len(mos_prefix_lookup) ~= 0 then
mos_prefix = mos_prefix_lookup
end
else
mos_prefix = frame.args["MOS Prefix"]
end
-- Get the step pattern
local step_pattern = frame.args["MODMOS Step Pattern"]
-- Get the mode names
-- Get the mode names
Line 230: Line 189:
-- Closest-mode search always returns one name
-- Closest-mode search always returns one name
mode_names = {
mode_names = {
"Harmonic minor<br>(Aeolian ♮7)",
"Harmonic minor<br />(Aeolian ♮7)",
"Locrian ♮6",
"Locrian ♮6",
"Ionian augmented<br>(Ionian #5)",
"Ionian augmented<br />(Ionian ♯5)",
"Dorian #4",
"Dorian ♯4",
"Phrygian dominant<br>(Phrygian ♮3)",
"Phrygian dominant<br />(Phrygian ♮3)",
"Lydian #2",
"Lydian ♯2",
"Altered diminished<br>(Locrian b4 bb7)",
"Altered diminished<br />(Locrian ♭4 𝄫7)",
}
}
elseif step_pattern == "LLsLsAs" then
elseif step_pattern == "LLsLsAs" then
Line 242: Line 201:
-- Closest-mode search always returns one name
-- Closest-mode search always returns one name
mode_names = {
mode_names = {
"Harmonic major<br>(Ionian b6)",
"Harmonic major<br />(Ionian ♭6)",
"Dorian b5",
"Dorian ♭5",
"Phrygian b4",
"Phrygian ♭4",
"Lydian b3",
"Lydian ♭3",
"Mixolydian b2",
"Mixolydian ♭2",
"Lydian augmented #2<br>(Lydian #2 #5)",
"Lydian augmented ♯2<br />(Lydian ♯2 ♯5)",
"Locrian bb7",
"Locrian 𝄫7",
}
}
elseif step_pattern == "LsLLLLs" then
elseif step_pattern == "LsLLLLs" then
Line 254: Line 213:
-- Closest-mode search sometimes returns two names
-- Closest-mode search sometimes returns two names
mode_names = {
mode_names = {
"Melodic minor<br>(Ionian b3, Dorian ♮7)",
"Melodic minor<br />(Ionian ♭3, Dorian ♮7)",
"Dorian b2, Phrygian ♮6",
"Dorian ♭2, Phrygian ♮6",
"Lydian augmented<br>(Lydian #5)",
"Lydian augmented<br />(Lydian ♯5)",
"Lydian dominant<br>(Lydian b7, Mixolydian #4)",
"Lydian dominant<br />(Lydian ♭7, Mixolydian ♯4)",
"Mixolydian b6, Aeolian ♮3",
"Mixolydian ♭6, Aeolian ♮3",
"Half-diminished<br>(Aeolian b5, Locrian ♮2)",
"Half-diminished<br />(Aeolian ♭5, Locrian ♮2)",
"Altered, Altered dominant<br>(Locrian b4)",
"Altered, Altered dominant<br />(Locrian ♭4)",
}
}
elseif step_pattern == "sLLLLLs" then
elseif step_pattern == "sLLLLLs" then
Line 266: Line 225:
-- Closest-mode search sometimes returns two names
-- Closest-mode search sometimes returns two names
mode_names = {
mode_names = {
"Neapolitan major<br>(Ionian b2 b3, Phrigian ♮6 ♮7)",
"Neapolitan major<br />(Ionian ♭2 ♭3, Phrigian ♮6 ♮7)",
"Lydian augmented #6<br>(Lydian #5 #6)",
"Lydian augmented ♯6<br />(Lydian ♯5 ♯6)",
"Lydian augmented dominant<br>(Lydian #5 b7, Mixolydian #4 #5)",
"Lydian augmented dominant<br />(Lydian ♯5 ♭7, Mixolydian ♯4 ♯5)",
"Lydian minor<br>(Lydian b6 b7, Aeolian ♮3 #4)",
"Lydian minor<br />(Lydian ♭6 ♭7, Aeolian ♮3 ♯4)",
"Major locrian<br>(Mixolydian b5 b6, Locrian ♮2 ♮3)",
"Major locrian<br />(Mixolydian ♭5 ♭6, Locrian ♮2 ♮3)",
"Altered dominant ♮2<br>(Aeolian b4 b5, Locrian ♮2, b4)",
"Altered dominant ♮2<br />(Aeolian ♭4 ♭5, Locrian ♮2, ♭4)",
"Altered dominant bb3<br>(Locrian bb3 b4)",
"Altered dominant 𝄫3<br />(Locrian 𝄫3 ♭4)",
}
}
elseif step_pattern == "sLLLsAs" then
elseif step_pattern == "sLLLsAs" then
Line 278: Line 237:
-- Closest-mode search always returns one name
-- Closest-mode search always returns one name
mode_names = {
mode_names = {
"Neapolitan minor<br>(Phrygian ♮7)",
"Neapolitan minor<br />(Phrygian ♮7)",
"Lydian #6",
"Lydian ♯6",
"Mixolydian augmented<br>(Mixolydian #5)",
"Mixolydian augmented<br />(Mixolydian ♯5)",
"Aeolian #4",
"Aeolian ♯4",
"Locrian dominant<br>(Locrian ♮3)",
"Locrian dominant<br />(Locrian ♮3)",
"Ionian #2",
"Ionian ♯2",
"Altered diminished bb3<br>(Locrian bb3 b4 bb7)",
"Altered diminished 𝄫3<br />(Locrian 𝄫3 ♭4 𝄫7)",
}
}
elseif step_pattern == "sAsLsAs" then
elseif step_pattern == "sAsLsAs" then
Line 290: Line 249:
-- Closest-mode search sometimes returns two names
-- Closest-mode search sometimes returns two names
mode_names = {
mode_names = {
"Double harmonic<br>(Ionian b2 b6, Phrygian ♮3 ♮7)",
"Double harmonic<br />(Ionian ♭2 ♭6, Phrygian ♮3 ♮7)",
"Lydian #2 #6",
"Lydian ♯2 ♯6",
"Altered ♮5 bb6<br>(Phrygian b4 bb7)",
"Altered ♮5 𝄫6<br />(Phrygian ♭4 𝄫7)",
"Double harmonic minor<br>(Lydian b3 b6, Aeolian #4 ♮7)",
"Double harmonic minor<br />(Lydian ♭3 ♭6, Aeolian ♯4 ♮7)",
"Mixolydian b2 b5, Locrian ♮3 ♮6",
"Mixolydian ♭2 ♭5, Locrian ♮3 ♮6",
"Ionian augmented #2<br>(Ionian #2 #5)",
"Ionian augmented ♯2<br />(Ionian ♯2 ♯5)",
"Locrian bb3 bb7",
"Locrian 𝄫3 𝄫7",
}
}
elseif #step_pattern == 0 then
elseif #step_pattern == 0 then
Line 315: Line 274:
-- If using default mode names (scalesig+udp), those names are auto-added by the relevant function
-- If using default mode names (scalesig+udp), those names are auto-added by the relevant function
local use_default_names = false
local use_default_names = false
if #frame.args["Mode Names"] ~= 0 then
if #mode_names_unparsed ~= 0 then
if frame.args["Mode Names"] == "Default" then
if mode_names_unparsed == "Default" then
use_default_names = true
use_default_names = true
else
else
mode_names = tip.parse_entries(frame.args["Mode Names"])
mode_names = tip.parse_entries(mode_names_unparsed)
end
end
end
end
-- Check if the table should start collapsed
local is_collapsed = yesno(frame.args["Collapsed"], false)
-- If a modmos step pattern was never provided, call the function mos_mode_degrees
-- If a modmos step pattern was never provided, call the function mos_mode_degrees
Line 327: Line 289:
local result = ""
local result = ""
if step_pattern == "" then
if step_pattern == "" then
result = p._mos_mode_degrees(input_mos, mos_prefix, mode_names, use_default_names)
result = p._mos_mode_degrees(input_mos, mos_prefix, is_collapsed)
--elseif #step_pattern == input_mos.nL + input_mos.ns then
--elseif #step_pattern == input_mos.nL + input_mos.ns then
else
else
result = p._mos_mode_degrees(input_mos, mos_prefix, mode_names, use_default_names, step_pattern)
result = p._mos_mode_degrees(input_mos, mos_prefix, is_collapsed, step_pattern)
end
end
return result
-- Debugger option
if debugg == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
return frame:preprocess(result)
end
end


return p
return p