Module:MOS in EDO allperiods: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
ArrowHead294 (talk | contribs) mNo edit summary |
||
(48 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
local mos = require( | local mos = require("Module:MOS") | ||
local rat = require( | local rat = require("Module:Rational") | ||
local utils = require( | local utils = require("Module:Utils") | ||
local mosinedo = require( | local mosinedo = require("Module:MOS in EDO") | ||
local yesno = require("Module:Yesno") | |||
local p = {} | local p = {} | ||
Line 11: | Line 12: | ||
function p.parse_entries(unparsed) | function p.parse_entries(unparsed) | ||
local parsed = {} | local parsed = {} | ||
for entry in string.gmatch(unparsed, | for entry in string.gmatch(unparsed, "([^;]+)") do | ||
local trimmed = entry:gsub("^%s*(.-)%s*$", "%1") | local trimmed = entry:gsub("^%s*(.-)%s*$", "%1") | ||
table.insert(parsed, trimmed) -- Add to array | table.insert(parsed, trimmed) -- Add to array | ||
Line 19: | Line 20: | ||
-- Main function | -- Main function | ||
-- Creates | -- Creates tables for every mos in an edo, for every possible period count | ||
function p.mos_in_edo_allperiods(edo, max_number_of_periods, show_subsets, generation_limit, temperaments) | |||
function p. | |||
local edo = edo or 12 | local edo = edo or 12 | ||
local | local max_number_of_periods = max_number_of_periods or -1 | ||
local show_subsets = show_subsets == 1 | local show_subsets = show_subsets == 1 | ||
local generation_limit = generation_limit or edo - 1 | |||
local temperaments = temperaments | local temperaments = temperaments | ||
is_debug = (is_debug or false) | |||
-- Include temperament names? | -- Include temperament names? | ||
local show_temperament = temperaments ~= nil and #temperaments == math.floor(period_in_edosteps / verified_number_of_periods / 2) | local show_temperament = temperaments ~= nil --and #temperaments == math.floor(period_in_edosteps / verified_number_of_periods / 2) | ||
-- Temporarily disable entry of temperament names | -- Temporarily disable entry of temperament names | ||
Line 56: | Line 37: | ||
show_temperament = false | show_temperament = false | ||
-- | -- Keep track of how many section headers have been written thus far | ||
-- If there are multiperiod mosses, then create an L2 header for multi- | |||
for | -- period mosses, then for each successive period count, create an L3 | ||
-- header. | |||
local multi_period_header_written = false | |||
-- Process max number of periods | |||
-- If -1 was entered, then the maximum is math.floor(edo / 2) - 1, the default max | |||
-- Otherwise, make sure that value doesn't exceed the default max | |||
local default_max = math.floor(edo / 2) - 1 | |||
if max_number_of_periods == -1 then | |||
max_number_of_periods = default_max | |||
else | |||
max_number_of_periods = math.min(default_max, max_number_of_periods) | |||
end | end | ||
-- Check whether the generation limit is valid | |||
-- Technically, any number above the edo works with showing all generations (rows) | |||
-- If it's -1, then show all generations (period_in_edosteps-1) | |||
if generation_limit == -1 then | |||
generation_limit = edo - 1 | |||
end | |||
-- Lead section | |||
-- TODO: Show period/note/subset limits if applicable | |||
-- | local result = "" | ||
-- | result = result .. string.format("This page lists all [[moment of symmetry]] scales in [[%iedo]].\n__TOC__\n", edo) | ||
local | |||
-- Call a for loop that produces a set of tables for each period count | -- Call a for loop that produces a set of tables for each period count | ||
-- Loop from 1 to half the edo minus 1 | |||
for j = 1, | -- Skip mosses with period count of edo/2, since that would immediately be | ||
-- a degenerate mos, hence the minus 1. | |||
for j = 1, max_number_of_periods do | |||
local number_of_periods = j | local number_of_periods = j | ||
if edo % number_of_periods == 0 then | if edo % number_of_periods == 0 then | ||
Line 108: | Line 75: | ||
-- If the generator and its complement are the same, skip that genpair by | -- If the generator and its complement are the same, skip that genpair by | ||
-- incrementing the starting generator by 1 | -- incrementing the starting generator by 1 | ||
local period_in_edosteps = edo | local period_in_edosteps = edo / number_of_periods | ||
local starting_generator = math.ceil(period_in_edosteps / 2) | local starting_generator = math.ceil(period_in_edosteps / 2) | ||
local complement = period_in_edosteps - starting_generator | local complement = period_in_edosteps - starting_generator | ||
Line 117: | Line 84: | ||
-- Add a section header | -- Add a section header | ||
if number_of_periods == 1 then | if number_of_periods == 1 then | ||
result = result .. | result = result .. "<h2>Single-period MOS scales</h2>\n" | ||
else | else | ||
result = result .. string.format(" | -- If the L2 header wasn't written yet, write that, followed by | ||
-- the corresponding L3 header. Otherwise, write only the L3 | |||
-- header. | |||
if not multi_period_header_written then | |||
result = result .. string.format("<h2>Multi-period MOS scales</h2>\n") | |||
multi_period_header_written = true | |||
end | |||
result = result .. string.format("<h3>%i periods</h3>\n", number_of_periods) | |||
end | end | ||
Line 140: | Line 114: | ||
local temperament_index = 1 + i - starting_generator | local temperament_index = 1 + i - starting_generator | ||
if show_temperament then | if show_temperament then | ||
result = result .. mosinedo. | result = result .. mosinedo.mos_in_edo_simplified(edo, i, number_of_periods, generation_limit, temperaments[temperament_index]) | ||
else | else | ||
result = result .. mosinedo. | result = result .. mosinedo.mos_in_edo_simplified(edo, i, number_of_periods, generation_limit) | ||
end | end | ||
result = result .. "\n\n" | |||
end | end | ||
end | end | ||
Line 149: | Line 124: | ||
end | end | ||
-- Add categories | |||
result = result .. string.format("[[Category:%iedo]]\n", edo) | |||
.. "[[Category:Lists of scales]]\n" | |||
.. "[[Category:MOS scales]]" | |||
return result | return result | ||
end | end | ||
function p. | function p.test() | ||
return tonumber("") | |||
end | |||
-- Wrapper function to be called by a template | |||
-- Args (TODO: implement): | |||
-- - EDO: the number of divisions; this should be later set up to extract it from the page's title. | |||
-- - Temperaments: the temperament names entered as key-value pairs, where the key is the genpair separated with a dash. | |||
-- - Show Subsets: set to 1 to show mosses of subset edos, such as 12edo mosses for 24edo. | |||
-- - Period Limit: the Period Limit for mosses to display; default is "15" | |||
-- - Number of Periods: if ever set, then the template will show mosses for a specific period count. | |||
-- - Maximum Number of Steps: if set, mosses with more than this value will not be shown; default is 60. | |||
-- - Hide Step Pattern: if ever set to 1, this disables the step pattern visualization; will automatically set to 1 for mosses over 60edo, unless overridden. | |||
-- Maximum values can be overridden to have no max if set to "-1" | |||
function p.mos_in_edo_allperiods_frame(frame) | |||
local edo = tonumber(frame.args["EDO"]) | local edo = tonumber(frame.args["EDO"]) | ||
local temperaments = p.parse_entries(frame.args["Temperaments"]) | local temperaments = p.parse_entries(frame.args["Temperaments"]) | ||
local show_subsets = tonumber(frame.args["Show Subsets"]) | local show_subsets = tonumber(frame.args["Show Subsets"]) | ||
local max_periods = tonumber(frame.args["Period Limit"]) or -1 | |||
local generation_limit = tonumber(frame.args["Generation Limit"]) or -1 | |||
local debugg = yesno(frame.args["debug"]) | |||
local result = p.mos_in_edo_allperiods(edo, max_periods, show_subsets, generation_limit, temperaments) | |||
-- Debugger option | |||
if | if debugg == true then | ||
result = | result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>" | ||
end | end | ||
return result | return frame:preprocess(result) | ||
end | end | ||
return p | return p |
Latest revision as of 12:31, 1 June 2025
Note: Do not invoke this module directly; use the corresponding template instead: Template:MOS in EDO allperiods.
This module calls Template:MOS in EDO allgens repeatedly to list every MOS scale in a particular equal temperament tuning over all possible periods.
local mos = require("Module:MOS")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local mosinedo = require("Module:MOS in EDO")
local yesno = require("Module:Yesno")
local p = {}
-- Helper function
-- Parses entries from a semicolon-delimited string and returns them in an array
-- TODO: Separate this and related functions (parse_pair and parse_kv_pairs) into its own module, as they're included
-- in various modules at this point, such as: scale tree, mos mdoes
function p.parse_entries(unparsed)
local parsed = {}
for entry in string.gmatch(unparsed, "([^;]+)") do
local trimmed = entry:gsub("^%s*(.-)%s*$", "%1")
table.insert(parsed, trimmed) -- Add to array
end
return parsed
end
-- Main function
-- Creates tables for every mos in an edo, for every possible period count
function p.mos_in_edo_allperiods(edo, max_number_of_periods, show_subsets, generation_limit, temperaments)
local edo = edo or 12
local max_number_of_periods = max_number_of_periods or -1
local show_subsets = show_subsets == 1
local generation_limit = generation_limit or edo - 1
local temperaments = temperaments
is_debug = (is_debug or false)
-- Include temperament names?
local show_temperament = temperaments ~= nil --and #temperaments == math.floor(period_in_edosteps / verified_number_of_periods / 2)
-- Temporarily disable entry of temperament names
-- Temperament names will be entered as a set of key-value pairs instead of an array
show_temperament = false
-- Keep track of how many section headers have been written thus far
-- If there are multiperiod mosses, then create an L2 header for multi-
-- period mosses, then for each successive period count, create an L3
-- header.
local multi_period_header_written = false
-- Process max number of periods
-- If -1 was entered, then the maximum is math.floor(edo / 2) - 1, the default max
-- Otherwise, make sure that value doesn't exceed the default max
local default_max = math.floor(edo / 2) - 1
if max_number_of_periods == -1 then
max_number_of_periods = default_max
else
max_number_of_periods = math.min(default_max, max_number_of_periods)
end
-- Check whether the generation limit is valid
-- Technically, any number above the edo works with showing all generations (rows)
-- If it's -1, then show all generations (period_in_edosteps-1)
if generation_limit == -1 then
generation_limit = edo - 1
end
-- Lead section
-- TODO: Show period/note/subset limits if applicable
local result = ""
result = result .. string.format("This page lists all [[moment of symmetry]] scales in [[%iedo]].\n__TOC__\n", edo)
-- Call a for loop that produces a set of tables for each period count
-- Loop from 1 to half the edo minus 1
-- Skip mosses with period count of edo/2, since that would immediately be
-- a degenerate mos, hence the minus 1.
for j = 1, max_number_of_periods do
local number_of_periods = j
if edo % number_of_periods == 0 then
-- Calculate the starting genpair
-- If the generator and its complement are the same, skip that genpair by
-- incrementing the starting generator by 1
local period_in_edosteps = edo / number_of_periods
local starting_generator = math.ceil(period_in_edosteps / 2)
local complement = period_in_edosteps - starting_generator
if starting_generator == complement then
starting_generator = starting_generator + 1
end
-- Add a section header
if number_of_periods == 1 then
result = result .. "<h2>Single-period MOS scales</h2>\n"
else
-- If the L2 header wasn't written yet, write that, followed by
-- the corresponding L3 header. Otherwise, write only the L3
-- header.
if not multi_period_header_written then
result = result .. string.format("<h2>Multi-period MOS scales</h2>\n")
multi_period_header_written = true
end
result = result .. string.format("<h3>%i periods</h3>\n", number_of_periods)
end
-- Add a table for each genpair
for i = starting_generator, period_in_edosteps - 1 do
-- Calculate current generators
local gen = i
local comp = period_in_edosteps - gen
-- Skip mosses that are supported by subset edos; this happens if the
-- gen and comp have a gcd > 1; if show_subsets is set to true, then
-- show them anyway.
local gcd = utils._gcd(gen, comp)
local add_table = gcd == 1 or show_subsets
-- Add table
if add_table then
-- TODO: Rewrite code here for entry of temperaments as a set of
-- key-value pairs
local temperament_index = 1 + i - starting_generator
if show_temperament then
result = result .. mosinedo.mos_in_edo_simplified(edo, i, number_of_periods, generation_limit, temperaments[temperament_index])
else
result = result .. mosinedo.mos_in_edo_simplified(edo, i, number_of_periods, generation_limit)
end
result = result .. "\n\n"
end
end
end
end
-- Add categories
result = result .. string.format("[[Category:%iedo]]\n", edo)
.. "[[Category:Lists of scales]]\n"
.. "[[Category:MOS scales]]"
return result
end
function p.test()
return tonumber("")
end
-- Wrapper function to be called by a template
-- Args (TODO: implement):
-- - EDO: the number of divisions; this should be later set up to extract it from the page's title.
-- - Temperaments: the temperament names entered as key-value pairs, where the key is the genpair separated with a dash.
-- - Show Subsets: set to 1 to show mosses of subset edos, such as 12edo mosses for 24edo.
-- - Period Limit: the Period Limit for mosses to display; default is "15"
-- - Number of Periods: if ever set, then the template will show mosses for a specific period count.
-- - Maximum Number of Steps: if set, mosses with more than this value will not be shown; default is 60.
-- - Hide Step Pattern: if ever set to 1, this disables the step pattern visualization; will automatically set to 1 for mosses over 60edo, unless overridden.
-- Maximum values can be overridden to have no max if set to "-1"
function p.mos_in_edo_allperiods_frame(frame)
local edo = tonumber(frame.args["EDO"])
local temperaments = p.parse_entries(frame.args["Temperaments"])
local show_subsets = tonumber(frame.args["Show Subsets"])
local max_periods = tonumber(frame.args["Period Limit"]) or -1
local generation_limit = tonumber(frame.args["Generation Limit"]) or -1
local debugg = yesno(frame.args["debug"])
local result = p.mos_in_edo_allperiods(edo, max_periods, show_subsets, generation_limit, temperaments)
-- Debugger option
if debugg == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
return frame:preprocess(result)
end
return p