Module:MOS modes

From Xenharmonic Wiki
Jump to navigation Jump to search

Documentation transcluded from /doc
Note: Do not invoke this module directly; use the corresponding template instead: Template:MOS modes.
Icon-Todo.png Todo: Documentation

local mos = require("Module:MOS")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local tip = require("Module:Template input parse")
local tamnams = require("Module:TAMNAMS")
local yesno = require("Module:Yesno")
local p = {}

-- 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 UDPs and CPOs
	local udps = tamnams.mos_mode_udps(input_mos)
	local cpos = tamnams.mos_mode_cpos(input_mos)
	
	-- Get the mos's modes
	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
	
	-- Table caption
	local scale_sig = mos.as_string(input_mos)
	
	-- Start of table
	local result = "{| class=\"wikitable sortable center-2 center-3 mw-collapsible" .. (is_collapsed and " mw-collapsed\"\n" or "\"\n")
		.. "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. string.format("Modes of %s\n", scale_sig)
		.. "|-\n"
		
	-- Table headers
	result = result
		.. "! [[UDP]]"
		.. " !! Cyclic<br />order"
		.. " !! Step<br />pattern"
	
	-- Add header for mode names, if provided.
	if add_mode_names then
		result = result .. " !! class=\"unsortable\" | Mode names"
	end
	
	-- Add column headers for supplementary info, if provided.
	if add_columns then
		for i = 1, #headers do
			result = result .. " !! class=\"unsortable\" | " .. headers[i]
		end
	end
	
	result = result .. "\n"
	
	-- Enter each row
	for i = 1, #mos_modes do
		result = result .. "|-\n"
		
		-- Add the UDP, brightness order, and the mode's step pattern
		result = result .. "| " .. udps[i] .. " || " .. cpos[i] .. " || " .. mos_modes[i]
		
		-- Add the mode's name, if given
		if add_mode_names  then
			result = result .. " || " .. 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 .. " || " .. entries[index]
			end
		end
		
		result = result .. "\n"
	end
	
	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
	
	-- 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)

	return p._mos_modes(input_mos, mode_names, headers, entries, is_collapsed)
end

return p