Module:MOS in EDO: Difference between revisions
Added comments; corrected code regarding degenerate mosses (mosses that become edos) |
m rename |
||
| (58 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local mos = require("Module:MOS") | |||
local step_vis = require("Module:Step vis") | |||
local tamnams = require("Module:TAMNAMS") | |||
local utils = require("Module:Utils") | |||
local yesno = require("Module:Yesno") | |||
-- Global variables for cell colors | |||
-- Dark blue for large steps, light blue for small steps | |||
-- For mosses that are reversed (starts with s and ends with L), use orange instead | |||
p.cell_color_none = "" -- For cells that don't have a color (default cell color applies) | |||
p.cell_color_perfect_size = "" -- Only applies for steps of an edo | |||
p.cell_color_large = "#BDD7EE" | |||
p.cell_color_small = "#DDEBF7" | |||
p.cell_color_lg_rev = "#F8CBAD" | |||
p.cell_color_sm_rev = "#FCE4D6" | |||
-- Helper function | -- Helper function | ||
| Line 51: | Line 64: | ||
end | end | ||
return string.format("%iL %is", large_step_count, small_step_count) | return string.format("%iL %is", large_step_count, small_step_count) | ||
end | end | ||
| Line 145: | Line 158: | ||
-- Primary function | -- Primary function | ||
-- Create a rectangular horogram depicting a mos for a given pair of generators | -- Create a rectangular horogram depicting a mos for a given pair of generators | ||
function p. | function p.mos_in_edo(edo, gen_in_edosteps, number_of_periods, temperament) | ||
local edo = edo or 24 | local edo = edo or 24 | ||
local gen_in_edosteps = gen_in_edosteps or 14 | local gen_in_edosteps = gen_in_edosteps or 14 | ||
local number_of_periods = number_of_periods or 1 | local number_of_periods = number_of_periods or 1 | ||
local temperament = temperament or "meantone" | local temperament = temperament --or "meantone" | ||
-- Check whether the number of periods divides the edo | -- Check whether the number of periods divides the edo | ||
| Line 161: | Line 174: | ||
-- Calculate whether to include temperament names | -- Calculate whether to include temperament names | ||
local show_temperament = temperament ~= "" | local show_temperament = temperament ~= "" and temperament ~= nil | ||
-- Calculate the generator complement | -- Calculate the generator complement | ||
| Line 178: | Line 191: | ||
-- Create table, starting with headers | -- Create table, starting with headers | ||
local result = | local result = "{| class=\"wikitable center-all\"\n" | ||
.. "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. string.format("Generators %i\\%i and %i\\%i\n", gen_in_edosteps, edo, comp_in_edosteps, edo) | |||
.. "|-\n" | |||
.. string.format("! colspan=\"%i\" | Steps\n", edo) | |||
.. "! MOS (name)\n" | |||
.. "! Step ratio\n" | |||
if show_temperament then | if show_temperament then | ||
result = result .. string.format( | result = result .. string.format("! Temperament\n") | ||
end | end | ||
-- Add the step pattern for successive mosses until the pattern becomes that for an edo | -- Add the step pattern for successive mosses until the pattern becomes that for an edo | ||
while current_scale ~= nil and starting_mos_valid do | while current_scale ~= nil and starting_mos_valid do | ||
-- Calculate current step ratio | |||
-- Use this to determine which cell colors to use | |||
local current_step_sizes = p.calculate_step_sizes(current_scale) | |||
local step_ratio_gcd = utils._gcd(current_step_sizes["L"], current_step_sizes["s"]) | |||
local large_step_size = current_step_sizes["L"] | |||
local small_step_size = current_step_sizes["s"] | |||
-- Is the first step a large step? | |||
local first_step_is_large_step = current_scale[1] == large_step_size | |||
-- Add the step sizes | -- Add the step sizes | ||
result = result .. | result = result .. "|-\n" | ||
for i = 1, #current_scale do | for i = 1, #current_scale do | ||
local current_step = current_scale[i] | local current_step = current_scale[i] | ||
-- Calculate cell color | |||
local cell_color = "NONE" | |||
if large_step_size == small_step_size then | |||
cell_color = p.cell_color_none | |||
elseif first_step_is_large_step then | |||
if current_step == large_step_size then | |||
cell_color = p.cell_color_large | |||
elseif current_step == small_step_size then | |||
cell_color = p.cell_color_small | |||
end | |||
elseif not first_step_is_large_step then | |||
if current_step == large_step_size then | |||
cell_color = p.cell_color_lg_rev | |||
elseif current_step == small_step_size then | |||
cell_color = p.cell_color_sm_rev | |||
end | |||
end | |||
if current_step == 1 then | if current_step == 1 then | ||
result = result .. string.format( | if large_step_size == small_step_size then | ||
result = result .. "| 1\n" | |||
else | |||
result = result .. string.format("| style=\"background-color: %s;\" | 1\n", cell_color) | |||
end | |||
else | else | ||
result = result .. string.format( | if cell_color == p.cell_color_none then | ||
result = result .. string.format("| colspan=\"%i\" | %i\n", current_step, current_step) | |||
else | |||
result = result .. string.format("| style=\"background-color: %s\" colspan=\"%i\" | %i\n", cell_color, current_step, current_step) | |||
end | |||
end | end | ||
end | end | ||
-- Add the scale sig | -- Add the scale sig | ||
local scale_sig = p.mos_step_pattern_to_scale_sig(current_scale) | local scale_sig = p.mos_step_pattern_to_scale_sig(current_scale) | ||
local | |||
local | -- Get the tamnams name, if there is one | ||
-- Don't show tamnams names for mosses with 5 notes or fewer (to keep the table from being cluttered) | |||
local tamnams_name = tamnams.lookup_name(scale_sig) | |||
local current_step_count = #current_scale | |||
-- Use step sizes to determine whether the mos is an edo | |||
local reduced_large_step_size = current_step_sizes["L"] / step_ratio_gcd | local reduced_large_step_size = current_step_sizes["L"] / step_ratio_gcd | ||
local reduced_small_step_size = current_step_sizes["s"] / step_ratio_gcd | local reduced_small_step_size = current_step_sizes["s"] / step_ratio_gcd | ||
if reduced_large_step_size == reduced_small_step_size then | if reduced_large_step_size == reduced_small_step_size then | ||
result = result .. string.format("| %iedo\n", edo / step_ratio_gcd) | result = result .. string.format("| [[%iedo]]\n", edo / step_ratio_gcd) | ||
elseif tamnams_name ~= nil and current_step_count > 5 then | |||
result = result .. string.format("| [[%s]] (%s)\n", scale_sig, tamnams_name) | |||
else | else | ||
result = result .. string.format("| [[%s]]\n", scale_sig) | result = result .. string.format("| [[%s]]\n", scale_sig) | ||
| Line 217: | Line 274: | ||
result = result .. string.format("| %s:%s\n", current_step_sizes["L"] / step_ratio_gcd, current_step_sizes["s"] / step_ratio_gcd) | result = result .. string.format("| %s:%s\n", current_step_sizes["L"] / step_ratio_gcd, current_step_sizes["s"] / step_ratio_gcd) | ||
-- Add the tamnams name | -- Add the temperament name, if there is one | ||
local tamnams_name = | if show_temperament then | ||
local current_step_count = #current_scale | |||
result = result .. string.format("| %s\n", tamnams_name) | result = result .. string.format("| %s[%i]\n", temperament, current_step_count) | ||
end | |||
-- Produce the next scale in the sequence | |||
current_scale = p.calculate_next_mos_step_pattern(current_scale) | |||
end | |||
result = result .. "|}" | |||
return result | |||
end | |||
-- Alternate primary function | |||
-- Instead of a "rectangular horogram", use the same type of visualization shown | |||
-- on the diasem page | |||
function p.mos_in_edo_simplified(edo, gen_in_edosteps, number_of_periods, generation_limit, temperament) | |||
local edo = edo or 24 | |||
local gen_in_edosteps = gen_in_edosteps or 14 | |||
local number_of_periods = number_of_periods or 1 | |||
local generation_limit = generation_limit or edo - 1 | |||
local temperament = temperament --or "meantone" | |||
-- Check whether the number of periods divides the edo | |||
-- If so, the starting scale will be a multiperiod mos | |||
local period_in_edosteps = edo | |||
local verified_number_of_periods = 1 | |||
if edo % number_of_periods == 0 then | |||
period_in_edosteps = edo / number_of_periods | |||
verified_number_of_periods = number_of_periods | |||
end | |||
-- Check whether the generation limit is valid | |||
-- If it's -1, then show all generations (period_in_edosteps-1) | |||
if generation_limit == -1 then | |||
generation_limit = period_in_edosteps - 1 | |||
end | |||
-- Calculate whether to include temperament names | |||
local show_temperament = temperament ~= "" and temperament ~= nil | |||
-- Calculate the generator complement | |||
local comp_in_edosteps = period_in_edosteps - gen_in_edosteps | |||
-- Are the args for the starting mos valid? | |||
-- The number of steps in the generator must be between 1 (inclusive) and the number of steps in the period (exclusive) | |||
local starting_mos_valid = gen_in_edosteps >= 1 and gen_in_edosteps <= period_in_edosteps | |||
-- Calculate the starting mos | |||
local current_scale = {} | |||
for i = 1, number_of_periods do | |||
table.insert(current_scale, gen_in_edosteps) | |||
table.insert(current_scale, comp_in_edosteps) | |||
end | |||
-- Create table, starting with headers | |||
local result = "{| class=\"wikitable center-all\"\n" | |||
.. "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. string.format("Generators %i\\%i and %i\\%i\n", gen_in_edosteps, edo, comp_in_edosteps, edo) | |||
.. "|-\n" | |||
.. "! Step visualization\n" | |||
.. "! MOS (name)\n" -- Scale sig (and name) | |||
.. "! Step sizes\n" -- Step sizes | |||
.. "! Step ratio\n" -- Step ratio | |||
if show_temperament then | |||
result = result .. "! Temperament\n" -- Temperament, if given | |||
end | |||
-- Add the step pattern for successive mosses until the pattern becomes that for an edo | |||
local generation_count = 1 | |||
while current_scale ~= nil and starting_mos_valid and generation_count <= generation_limit do | |||
-- Calculate current step ratio | |||
-- Use this to determine which cell colors to use | |||
local current_step_sizes = p.calculate_step_sizes(current_scale) | |||
local step_ratio_gcd = utils._gcd(current_step_sizes["L"], current_step_sizes["s"]) | |||
local large_step_size = current_step_sizes["L"] | |||
local small_step_size = current_step_sizes["s"] | |||
-- New row | |||
result = result .. "|-\n" | |||
-- Add the step visualization | |||
local sv = step_vis._step_vis(current_scale) | |||
result = result .. string.format("| %s\n", sv) | |||
-- Add the scale sig | |||
-- Also add tamnams name if there is one | |||
local scale_sig = p.mos_step_pattern_to_scale_sig(current_scale) | |||
local tamnams_name = tamnams.lookup_name(scale_sig) | |||
local current_step_count = #current_scale | |||
if large_step_size == small_step_size then | |||
result = result .. string.format("| [[%iedo]]\n", edo / step_ratio_gcd) | |||
elseif tamnams_name ~= nil and current_step_count > 5 then | |||
result = result .. string.format("| [[%s]] (%s)\n", scale_sig, tamnams_name) | |||
else | else | ||
result = result .. string.format("|\n") | result = result .. string.format("| [[%s]]\n", scale_sig) | ||
end | end | ||
-- Add the step sizes | |||
result = result .. string.format("| %i, %i\n", current_step_sizes["L"], current_step_sizes["s"]) | |||
-- Add step ratio | |||
local reduced_large_step_size = large_step_size / step_ratio_gcd | |||
local reduced_small_step_size = small_step_size / step_ratio_gcd | |||
result = result .. string.format("| %s:%s\n", reduced_large_step_size, reduced_small_step_size) | |||
-- Add the temperament name, if there is one | -- Add the temperament name, if there is one | ||
| Line 233: | Line 389: | ||
-- Produce the next scale in the sequence | -- Produce the next scale in the sequence | ||
current_scale = p.calculate_next_mos_step_pattern(current_scale) | current_scale = p.calculate_next_mos_step_pattern(current_scale) | ||
-- Increment the generation (row) count | |||
generation_count = generation_count + 1 | |||
end | end | ||
result = result .. | result = result .. "|}" | ||
return result | return result | ||
| Line 241: | Line 400: | ||
-- Function to be called by a template | -- Function to be called by a template | ||
function p. | function p.mos_in_edo_frame(frame) | ||
local edo = tonumber(frame.args["EDO"]) | local edo = tonumber(frame.args["EDO"]) | ||
local gen_in_edosteps = tonumber(frame.args["Generator"]) | local gen_in_edosteps = tonumber(frame.args["Generator"]) | ||
local temperament = frame.args["Temperament"] | local temperament = frame.args["Temperament"] | ||
local number_of_periods = tonumber(frame.args[" | local number_of_periods = tonumber(frame.args["Periods"]) | ||
local generation_limit = tonumber(frame.args["Generation Limit"]) | |||
local debugg = yesno(frame.args["debug"]) | |||
local result = p.mos_in_edo_simplified(edo, gen_in_edosteps, number_of_periods, generation_limit, temperament) | |||
-- Debugger option | |||
if debugg == true then | |||
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>" | |||
end | |||
return frame:preprocess(result) | |||
end | end | ||
return p | return p | ||