Module:MOS degrees: Difference between revisions
ArrowHead294 (talk | contribs) Move Module:MOS degrees v2 back over here |
ArrowHead294 (talk | contribs) mNo edit summary |
||
| (15 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
-- | local et = require("Module:ET") | ||
-- | --local jiraf = require("Module:JI ratio finder") | ||
-- and | local mos = require("Module:MOS") | ||
-- | local mosnot = require("Module:MOS notation") | ||
local rat = require("Module:Rational") | |||
local tamnams = require("Module:TAMNAMS") | |||
local utils = require("Module:Utils") | |||
local yesno = require("Module:Yesno") | |||
-- TODO: | |||
-- Rewrite "main function" into a underscore-prefixed function to be called by Lua code and a wrapper to be called by templates. (HIGH PRIORITY!!!) | |||
-- Adopt MOS arithmetic function (MEDIUM-PRIORITY!!!) | |||
-- Add support for double accidentals (low-priority) | |||
-- Move certain helper functions to helper modules (low-priority) | |||
-- Helper function | -- Helper function | ||
-- Parses entries from a semicolon-delimited string and returns them in an array | -- 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 | -- 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, | -- in various modules at this point, such as: scale tree, MOS modes | ||
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 32: | Line 34: | ||
function p.parse_pair(unparsed) | function p.parse_pair(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 68: | Line 70: | ||
function p.parse_step_ratio(unparsed) | function p.parse_step_ratio(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 108: | Line 110: | ||
end | end | ||
local mosstep_vector = { [ | local mosstep_vector = { ["L"] = large_step_count, ["s"] = small_step_count } | ||
return mosstep_vector | return mosstep_vector | ||
end | end | ||
| Line 117: | Line 119: | ||
-- calculates number of et-steps. | -- calculates number of et-steps. | ||
function p.interval_to_etsteps(mosstep_vector, step_ratios) | function p.interval_to_etsteps(mosstep_vector, step_ratios) | ||
return mosstep_vector[ | return mosstep_vector["L"] * step_ratios[1] + mosstep_vector["s"] * step_ratios[2] | ||
end | end | ||
| Line 154: | Line 137: | ||
local row_colors = {} | local row_colors = {} | ||
for i = 1, mossteps_per_equave + 1 do | for i = 1, mossteps_per_equave + 1 do | ||
local mosstep = i - 1 | local mosstep = i - 1 | ||
local is_period = mosstep % mossteps_per_period == 0 | local is_period = mosstep % mossteps_per_period == 0 | ||
| Line 164: | Line 146: | ||
if not is_root then | if not is_root then | ||
for i = 1, number_of_alterations do | for i = 1, number_of_alterations do | ||
table.insert(row_colors, "eaeaff") | table.insert(row_colors, "#eaeaff") | ||
end | end | ||
end | end | ||
| Line 170: | Line 152: | ||
-- Row colors for main mossetps (default row color) | -- Row colors for main mossetps (default row color) | ||
if is_period then | if is_period then | ||
table.insert(row_colors, "") | table.insert(row_colors, "none") | ||
else | else | ||
table.insert(row_colors, "") | table.insert(row_colors, "none") | ||
table.insert(row_colors, "") | table.insert(row_colors, "none") | ||
end | end | ||
| Line 180: | Line 162: | ||
if not is_equave then | if not is_equave then | ||
for i = 1, number_of_alterations do | for i = 1, number_of_alterations do | ||
table.insert(row_colors, "eaeaff") | table.insert(row_colors, "#eaeaff") | ||
end | end | ||
end | end | ||
| Line 237: | Line 219: | ||
-- Convert the notationally agnostic form into a form that uses given notation | -- Convert the notationally agnostic form into a form that uses given notation | ||
local note = ascending_genchain[j][i] | local note = ascending_genchain[j][i] | ||
local note_symbol = string.sub(note_symbols, note[ | local note_symbol = string.sub(note_symbols, note["Mossteps"] + 1, note["Mossteps"] + 1) | ||
local chroma_count = note[ | local chroma_count = note["Chromas"] | ||
local note_name = note_symbol .. string.rep(chroma_plus_symbol, chroma_count) | local note_name = note_symbol .. string.rep(chroma_plus_symbol, chroma_count) | ||
| Line 252: | Line 234: | ||
-- Convert the notationally agnostic form into a form that uses given notation | -- Convert the notationally agnostic form into a form that uses given notation | ||
local note = descending_genchain[j][i] | local note = descending_genchain[j][i] | ||
local note_symbol = string.sub(note_symbols, note[ | local note_symbol = string.sub(note_symbols, note["Mossteps"] + 1, note["Mossteps"] + 1) | ||
local chroma_count = note[ | local chroma_count = note["Chromas"] * -1 | ||
local note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | local note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | ||
| Line 263: | Line 245: | ||
-- the root refers to the unison for a single-period mos, it should be | -- the root refers to the unison for a single-period mos, it should be | ||
-- the degree one octave up) | -- the degree one octave up) | ||
if degree_encoded[ | if degree_encoded["Mossteps"] % mossteps_per_period == 0 then | ||
-- Transpose the mosstep by one period | -- Transpose the mosstep by one period | ||
degree_encoded[ | degree_encoded["Mossteps"] = degree_encoded["Mossteps"] + mossteps_per_period | ||
end | end | ||
-- Correct the note name based on whether it should be a note that is | -- Correct the note name based on whether it should be a note that is | ||
-- one period up. If the mos is single-period, then do not transpose. | -- one period up. If the mos is single-period, then do not transpose. | ||
if degree_encoded[ | if degree_encoded["Mossteps"] % mossteps_per_period == 0 and degree_encoded["Mossteps"] == 0 then | ||
-- Correct the note name | -- Correct the note name | ||
note_symbol = string.sub(note_symbols, 1, 1) | note_symbol = string.sub(note_symbols, 1, 1) | ||
note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | ||
elseif degree_encoded[ | elseif degree_encoded["Mossteps"] % mossteps_per_period == 0 and degree_encoded["Mossteps"] == 0 then | ||
-- Correct the note name | -- Correct the note name | ||
note_symbol = string.sub(note_symbols, degree_encoded[ | note_symbol = string.sub(note_symbols, degree_encoded["Mossteps"] + 1, degree_encoded["Mossteps"] + 1) | ||
note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | ||
end | end | ||
| Line 340: | Line 322: | ||
-- j is the number of chromas to add or subtract from the base vector | -- j is the number of chromas to add or subtract from the base vector | ||
-- Since a chroma is defined as (L-s), add j large steps and subtract j small steps from the current mosstep vector | -- Since a chroma is defined as (L-s), add j large steps and subtract j small steps from the current mosstep vector | ||
local L_count = current_mosstep_vector[ | local L_count = current_mosstep_vector["L"] + j | ||
local s_count = current_mosstep_vector[ | local s_count = current_mosstep_vector["s"] - j | ||
local current_mosstep_vector = { [ | local current_mosstep_vector = { ["L"] = L_count, ["s"] = s_count } | ||
table.insert(mosstep_vectors, current_mosstep_vector) | table.insert(mosstep_vectors, current_mosstep_vector) | ||
end | end | ||
| Line 364: | Line 346: | ||
-- Get the step counts for the bright and dark generators | -- Get the step counts for the bright and dark generators | ||
local bright_gen = mos.bright_gen(input_mos) | local bright_gen = mos.bright_gen(input_mos) | ||
local mossteps_per_bright_gen = bright_gen[ | local mossteps_per_bright_gen = bright_gen["L"] + bright_gen["s"] | ||
local mossteps_per_dark_gen = mossteps_per_period - mossteps_per_bright_gen | local mossteps_per_dark_gen = mossteps_per_period - mossteps_per_bright_gen | ||
| Line 547: | Line 529: | ||
-- Get the step counts for the bright and dark generators | -- Get the step counts for the bright and dark generators | ||
local bright_gen = mos.bright_gen(input_mos) | local bright_gen = mos.bright_gen(input_mos) | ||
local steps_per_bright_gen = bright_gen[ | local steps_per_bright_gen = bright_gen["L"] + bright_gen["s"] | ||
local steps_per_dark_gen = mossteps_per_period - steps_per_bright_gen | local steps_per_dark_gen = mossteps_per_period - steps_per_bright_gen | ||
-- Get the step counts as a vector (or associative array, rather) | -- Get the step counts as a vector (or associative array, rather) | ||
local input_mos_step_vector = {[ | local input_mos_step_vector = {["L"] = input_mos.nL, ["s"] = input_mos.ns} | ||
-- What's the equave in cents? | -- What's the equave in cents? | ||
| Line 587: | Line 569: | ||
local root_note = "" | local root_note = "" | ||
if show_notation then | if show_notation then | ||
note_names = p.calculate_note_names(input_mos, udp, notation[ | note_names = p.calculate_note_names(input_mos, udp, notation["Naturals"], notation["Sharp"], notation["Flat"], number_of_alterations) | ||
root_note = string.sub(notation[ | root_note = string.sub(notation["Naturals"], 1, 1) | ||
end | end | ||
-- Create the table, starting with the headers | -- Create the table, starting with the headers | ||
local result = | local result = "{| class=\"wikitable sortable mw-collapsible mw-collapsed\"\n" | ||
-- First row | -- First row | ||
result = result .. string.format(" | result = result | ||
.. "|+ style=\"font-size: 105%%; white-space: nowrap;\" | " .. string.format("Scale degree of %s\n", scale_sig) | |||
.. "|-\n" | |||
.. "! rowspan=\"2\" class=\"unsortable\" | Scale degree\n" | |||
-- Add column for abbreviations | -- Add column for abbreviations | ||
-- Abbreviations do not use a mos-prefix or mos-name | -- Abbreviations do not use a mos-prefix or mos-name | ||
if show_abbrevs then | if show_abbrevs then | ||
result = result .. | result = result .. "! rowspan=\"2\" class=\"unsortable\" | Abbrev.\n" | ||
end | end | ||
-- Add column for note names | -- Add column for note names | ||
if show_notation then | if show_notation then | ||
result = result .. string.format( | result = result .. string.format("! rowspan=\"2\" class=\"unsortable\" | On %s\n", root_note) | ||
end | end | ||
| Line 613: | Line 597: | ||
-- Step ratio names, for reference | -- Step ratio names, for reference | ||
local tamnams_step_ratios = { | local tamnams_step_ratios = { | ||
[ | ["1:1"] = "Equalized", | ||
[ | ["4:3"] = "Supersoft", | ||
[ | ["3:2"] = "Soft", | ||
[ | ["5:3"] = "Semisoft", | ||
[ | ["2:1"] = "Basic", | ||
[ | ["5:2"] = "Semihard", | ||
[ | ["3:1"] = "Hard", | ||
[ | ["4:1"] = "Superhard", | ||
[ | ["1:0"] = "Collapsed", | ||
} | } | ||
| Line 636: | Line 620: | ||
-- Add the step ratio name if there is one | -- Add the step ratio name if there is one | ||
if step_ratio_name == nil then | if step_ratio_name == nil then | ||
result = result .. | result = result .. "! colspan=\"2\" | " .. et_as_string .. " (L:s = " .. step_ratio_key .. ")\n" | ||
else | else | ||
result = result .. | result = result .. "! colspan=\"2\" | " .. et_as_string .. " (" .. step_ratio_name .. ", L:s = " .. step_ratio_key .. ")\n" | ||
end | end | ||
end | end | ||
-- Add JI ratio column header | -- Add JI ratio column header | ||
result = result .. | result = result .. "! rowspan=\"2\" class=\"unsortable\" | Approx. JI Ratios\n" | ||
-- Second row | -- Second row | ||
| Line 649: | Line 633: | ||
-- Add headers for the steps and cents up to 5 times | -- Add headers for the steps and cents up to 5 times | ||
for i = 1, #step_ratios do | for i = 1, #step_ratios do | ||
result = result .. | result = result .. "! Steps\n" | ||
result = result .. | result = result .. "! Cents\n" | ||
end | end | ||
| Line 662: | Line 646: | ||
result = result .. "|-\n" | result = result .. "|-\n" | ||
else | else | ||
result = result .. string.format( | result = result .. string.format("|- style=\"background: %s\"\n", row_color) | ||
end | end | ||
| Line 700: | Line 684: | ||
local average_cents = 0 | local average_cents = 0 | ||
for j = 1, #ets_for_mos do | for j = 1, #ets_for_mos do | ||
local etsteps = mosstep_vectors[i][ | local etsteps = mosstep_vectors[i]["L"] * step_ratios[j][1] + mosstep_vectors[i]["s"] * step_ratios[j][2] | ||
local cents = utils._round_dec(et.cents(ets_for_mos[j], etsteps), round) | local cents = utils._round_dec(et.cents(ets_for_mos[j], etsteps), round) | ||
| Line 751: | Line 735: | ||
function p.mos_degrees_frame(frame) | function p.mos_degrees_frame(frame) | ||
-- Default param for input mos is 5L 2s | -- Default param for input mos is 5L 2s | ||
local input_mos = mos.parse(frame.args[ | local input_mos = mos.parse(frame.args["Scale Signature"]) or mos.new(2, 5, 2) | ||
-- Get the scale sig; for calculating the mos prefix | -- Get the scale sig; for calculating the mos prefix | ||
| Line 757: | Line 741: | ||
-- Get the step ratio | -- Get the step ratio | ||
local step_ratios = p.parse_step_ratio(frame.args[ | local step_ratios = p.parse_step_ratio(frame.args["Step Ratio"]) or p.parse_step_ratio("2/1") | ||
-- Default param for mos prefix | -- Default param for mos prefix | ||
| Line 764: | Line 748: | ||
-- If not left blank, use the prefix passed in instead | -- If not left blank, use the prefix passed in instead | ||
local mos_prefix = "mos" | local mos_prefix = "mos" | ||
if frame.args[ | if frame.args["MOS Prefix"] == "NONE" then | ||
mos_prefix = "" | mos_prefix = "" | ||
elseif string.len(frame.args[ | elseif string.len(frame.args["MOS Prefix"]) == 0 then | ||
mos_prefix_lookup = | mos_prefix_lookup = tamnams.lookup_prefix(input_mos) or "" | ||
if string.len(mos_prefix_lookup) ~= 0 then | if string.len(mos_prefix_lookup) ~= 0 then | ||
mos_prefix = mos_prefix_lookup | mos_prefix = mos_prefix_lookup | ||
end | end | ||
else | else | ||
mos_prefix = frame.args[ | mos_prefix = frame.args["MOS Prefix"] | ||
end | end | ||
-- Get whether to display abbreviations | -- Get whether to display abbreviations | ||
local show_abbreviations = 0 | local show_abbreviations = 0 | ||
if frame.args[ | if frame.args["Show Abbreviations"] == "1" or frame.args["Show Abbreviations"] == 1 then | ||
show_abbreviations = 1 | show_abbreviations = 1 | ||
end | end | ||
| Line 783: | Line 767: | ||
-- Get the number of alterations | -- Get the number of alterations | ||
local number_of_alterations = 0 | local number_of_alterations = 0 | ||
if string.len(frame.args[ | if string.len(frame.args["Number of Alterations"]) ~= 0 then | ||
number_of_alterations = tonumber(frame.args[ | number_of_alterations = tonumber(frame.args["Number of Alterations"]) | ||
end | end | ||
-- Get JI ratios | -- Get JI ratios | ||
local ji_ratios_parsed = {} | local ji_ratios_parsed = {} | ||
if #frame.args[ | if #frame.args["JI Ratios"] > 0 then | ||
-- If the comments can't be parsed, default to an empty table | -- If the comments can't be parsed, default to an empty table | ||
ji_ratios_parsed = p.parse_kv_pairs(frame.args[ | ji_ratios_parsed = p.parse_kv_pairs(frame.args["JI Ratios"]) or {} | ||
end | end | ||
| Line 818: | Line 802: | ||
if #frame.args["Notation"] > 0 then | if #frame.args["Notation"] > 0 then | ||
if frame.args["Notation"] == "Default" and scale_sig == "5L 2s" then | if frame.args["Notation"] == "Default" and scale_sig == "5L 2s" then | ||
notation_parsed = { [ | notation_parsed = { ["Naturals"] = "CDEFGAB", ["Sharp"] = "#", ["Flat"] = "b" } | ||
show_notation = 1 | show_notation = 1 | ||
elseif frame.args["Notation"] == "Default" and scale_sig ~= "5L 2s" then | elseif frame.args["Notation"] == "Default" and scale_sig ~= "5L 2s" then | ||
local default_nominals = "JKLMNOPQRSTUVWXYZ" | local default_nominals = "JKLMNOPQRSTUVWXYZ" | ||
notation_parsed = { [ | notation_parsed = { ["Naturals"] = string.sub(default_nominals, 1, mossteps_per_equave), ["Sharp"] = "&", ["Flat"] = "@" } | ||
show_notation = 1 | show_notation = 1 | ||
else | else | ||
| Line 833: | Line 817: | ||
result = p.mos_degrees(input_mos, step_ratios, mos_prefix, show_abbreviations, number_of_alterations, ji_ratios_parsed, udp_parsed, notation_parsed, show_notation) | result = p.mos_degrees(input_mos, step_ratios, mos_prefix, show_abbreviations, number_of_alterations, ji_ratios_parsed, udp_parsed, notation_parsed, show_notation) | ||
return result | -- Debugger | ||
local debugg = yesno(frame.args["debug"]) | |||
if debugg == true then | |||
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>" | |||
end | |||
return frame:preprocess(result) | |||
end | end | ||
return p | return p | ||