Module:MOS degrees: Difference between revisions
Added support for notation; notation is optional now |
ArrowHead294 (talk | contribs) mNo edit summary |
||
| (21 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") | ||
-- | 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 30: | 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 66: | 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 106: | 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 115: | 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 | ||
-- Helper function | -- Helper function | ||
-- | -- For producing row highlighting for the table | ||
-- | -- Alterations are highlighted, except for singy augmented/diminished intervals for generators | ||
function p. | function p.calculate_row_colors(input_mos, number_of_alterations) | ||
local | -- Default parameters for input mos and step ratio (5L 2s and 2:1 step ratio) | ||
local input_mos = input_mos or mos.new(4, 4, 2) | |||
local number_of_alterations = number_of_alterations or 1 | |||
local | -- Get the number of mossteps per period and equave | ||
local mossteps_per_equave = input_mos.nL + input_mos.ns | |||
local periods_per_equave = utils._gcd(input_mos.nL, input_mos.ns) | |||
local mossteps_per_period = mossteps_per_equave / periods_per_equave | |||
local row_colors = {} | |||
for i = 1, mossteps_per_equave + 1 do | |||
local mosstep = i - 1 | |||
for | local is_period = mosstep % mossteps_per_period == 0 | ||
local is_root = mosstep == 0 | |||
table.insert( | local is_equave = mosstep == mossteps_per_equave | ||
-- Row colors for pre-alterations | |||
-- If this is the root, don't add rows before it | |||
if not is_root then | |||
for i = 1, number_of_alterations do | |||
table.insert(row_colors, "#eaeaff") | |||
end | |||
end | |||
-- Row colors for main mossetps (default row color) | |||
if is_period then | |||
table.insert(row_colors, "none") | |||
else | |||
table.insert(row_colors, "none") | |||
table.insert(row_colors, "none") | |||
end | |||
-- Row colors for post-alterations | |||
-- If this is the equave, don't add rows after it | |||
if not is_equave then | |||
for i = 1, number_of_alterations do | |||
table.insert(row_colors, "#eaeaff") | |||
end | |||
end | end | ||
end | end | ||
return row_colors | |||
end | end | ||
| Line 140: | Line 173: | ||
-- Calculates note names and stores it in an associative array | -- Calculates note names and stores it in an associative array | ||
-- Default notation is diamond-mos, unless it's 5L 2s, then it's standard notation | -- Default notation is diamond-mos, unless it's 5L 2s, then it's standard notation | ||
function p. | function p.calculate_note_names(input_mos, udp, note_symbols, chroma_plus_symbol, chroma_minus_symbol, number_of_alterations) | ||
-- Default parameters for input mos and step ratio (5L 2s and 2:1 step ratio) | -- Default parameters for input mos and step ratio (5L 2s and 2:1 step ratio) | ||
local input_mos = input_mos or mos.new(5 | local input_mos = input_mos or mos.new(5, 2) | ||
local udp = {5, | local udp = udp or {5,2} | ||
local note_symbols = note_symbols or "CDEFGAB" | local note_symbols = note_symbols or "CDEFGAB" | ||
local chroma_plus_symbol = chroma_plus_symbol or "#" | local chroma_plus_symbol = chroma_plus_symbol or "#" | ||
local chroma_minus_symbol = chroma_minus_symbol or "b" | local chroma_minus_symbol = chroma_minus_symbol or "b" | ||
local number_of_alterations = number_of_alterations or | local number_of_alterations = number_of_alterations or 0 | ||
-- Get the number of mossteps per period and equave | -- Get the number of mossteps per period and equave | ||
| Line 186: | 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) | ||
-- Convert the encoded degree into text | -- Convert the encoded degree into text | ||
local degree_encoded = ascending_degchain[j][i] | local degree_encoded = ascending_degchain[j][i] | ||
local degree_decoded = mosnot. | local degree_decoded = mosnot.decode_mosstep_quality(degree_encoded, "m", "mosdegree", "abbreviated") | ||
-- Add to note names | -- Add to note names | ||
| Line 201: | 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 210: | Line 243: | ||
-- For the descending chain, any mossteps that correspond to the root of | -- For the descending chain, any mossteps that correspond to the root of | ||
-- a period should correspond instead to the root one period up (EG, if | -- a period should correspond instead to the root one period up (EG, if | ||
-- the root refers to the unison, it should be the degree one octave up) | -- the root refers to the unison for a single-period mos, it should be | ||
-- the degree one octave up) | |||
if | if degree_encoded["Mossteps"] % mossteps_per_period == 0 then | ||
-- Transpose the mosstep by one period | |||
degree_encoded["Mossteps"] = degree_encoded["Mossteps"] + mossteps_per_period | |||
end | |||
-- 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. | |||
if degree_encoded["Mossteps"] % mossteps_per_period == 0 and degree_encoded["Mossteps"] == 0 then | |||
-- Correct the note name | |||
note_symbol = string.sub(note_symbols, 1, 1) | |||
note_name = note_symbol .. string.rep(chroma_minus_symbol, chroma_count) | |||
elseif degree_encoded["Mossteps"] % mossteps_per_period == 0 and degree_encoded["Mossteps"] == 0 then | |||
-- Correct the note name | |||
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) | |||
end | end | ||
local degree_decoded = mosnot. | -- Pass the encoded degree, along with the other args | ||
local degree_decoded = mosnot.decode_mosstep_quality(degree_encoded, "m", "mosdegree", "abbreviated") | |||
-- Add to note names | -- Add to note names | ||
| Line 222: | Line 269: | ||
end | end | ||
end | end | ||
return note_names | return note_names | ||
| Line 232: | Line 274: | ||
-- Helper function; generate the step vectors for every interval required for the table | -- Helper function; generate the step vectors for every interval required for the table | ||
function p. | function p.calculate_mosstep_vectors(input_mos, number_of_alterations) | ||
-- Default params | -- Default params | ||
local input_mos = input_mos or mos.new(5, 2) | local input_mos = input_mos or mos.new(5, 2) | ||
| Line 280: | 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 292: | Line 334: | ||
-- Helper function; generate the mosdegree names and their abbreviations for the mos | -- Helper function; generate the mosdegree names and their abbreviations for the mos | ||
function p. | function p.calculate_mosdegree_names_and_abbrevs(input_mos, mos_prefix, number_of_alterations) | ||
-- Default params | -- Default params | ||
local input_mos = input_mos or mos.new(5, 2) | local input_mos = input_mos or mos.new(5, 2) | ||
| Line 304: | 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 335: | Line 377: | ||
-- Diminished degree is formatted as "Diminished degree"; more than 1 augmentation is "2× Diminished", "3× Diminished", and so on | -- Diminished degree is formatted as "Diminished degree"; more than 1 augmentation is "2× Diminished", "3× Diminished", and so on | ||
local dim_degree = "" | local dim_degree = "" | ||
if j == 1 then dim_degree = string.format("Diminished %d-% | if j == 1 then dim_degree = string.format("Diminished %d-%sdegree", mossteps, mos_prefix) | ||
else dim_degree = string.format("%d× Diminished %d-% | else dim_degree = string.format("%d× Diminished %d-%sdegree", j, mossteps, mos_prefix) | ||
end | end | ||
| Line 349: | Line 391: | ||
-- Calculate the main degree name and abbreviation | -- Calculate the main degree name and abbreviation | ||
local degree_name = string.format("Perfect %d-% | local degree_name = string.format("Perfect %d-%sdegree", mossteps, mos_prefix) | ||
local abbrev_name = string.format("P%dmd", mossteps) | local abbrev_name = string.format("P%dmd", mossteps) | ||
| Line 361: | Line 403: | ||
-- Augmented degree is formatted as "Augmented degree"; more than 1 augmentation is "2× Augmented", "3× Augmented", and so on | -- Augmented degree is formatted as "Augmented degree"; more than 1 augmentation is "2× Augmented", "3× Augmented", and so on | ||
local aug_degree = "" | local aug_degree = "" | ||
if j == 1 then aug_degree = string.format("Augmented %d-% | if j == 1 then aug_degree = string.format("Augmented %d-%sdegree", mossteps, mos_prefix) | ||
else aug_degree = string.format("%d× Augmented %d-% | else aug_degree = string.format("%d× Augmented %d-%sdegree", j, mossteps, mos_prefix) | ||
end | end | ||
| Line 387: | Line 429: | ||
-- Diminished degree is formatted as "Diminished degree"; more than 1 augmentation is "2× Diminished", "3× Diminished", and so on | -- Diminished degree is formatted as "Diminished degree"; more than 1 augmentation is "2× Diminished", "3× Diminished", and so on | ||
local dim_degree = "" | local dim_degree = "" | ||
if dim_amount == 1 then dim_degree = string.format("Diminished %d-% | if dim_amount == 1 then dim_degree = string.format("Diminished %d-%sdegree", mossteps, mos_prefix) | ||
else dim_degree = string.format("%d× Diminished %d-% | else dim_degree = string.format("%d× Diminished %d-%sdegree", dim_amount, mossteps, mos_prefix) | ||
end | end | ||
| Line 401: | Line 443: | ||
-- Calculate the small and large names and abbreviations | -- Calculate the small and large names and abbreviations | ||
-- Non-generator intervals for non-nL-ns mosses are minor (small) and major (large) | |||
local small_degree_label = "Minor" | local small_degree_label = "Minor" | ||
local large_degree_label = "Major" | local large_degree_label = "Major" | ||
| Line 420: | Line 463: | ||
-- Main operation | -- Main operation | ||
local small_degree_name = string.format("%s %d-% | local small_degree_name = string.format("%s %d-%sdegree", small_degree_label, mossteps, mos_prefix) | ||
local large_degree_name = string.format("%s %d-% | local large_degree_name = string.format("%s %d-%sdegree", large_degree_label, mossteps, mos_prefix) | ||
local small_abbrev_name = string.format("%s%dmd", small_degree_abbrev, mossteps) | local small_abbrev_name = string.format("%s%dmd", small_degree_abbrev, mossteps) | ||
local large_abbrev_name = string.format("%s%dmd", large_degree_abbrev, mossteps) | local large_abbrev_name = string.format("%s%dmd", large_degree_abbrev, mossteps) | ||
| Line 441: | Line 484: | ||
-- Augmented degree is formatted as "Augmented degree"; more than 1 augmentation is "2× Augmented", "3× Augmented", and so on | -- Augmented degree is formatted as "Augmented degree"; more than 1 augmentation is "2× Augmented", "3× Augmented", and so on | ||
local aug_degree = "" | local aug_degree = "" | ||
if aug_amount == 1 then aug_degree = string.format("Augmented %d-% | if aug_amount == 1 then aug_degree = string.format("Augmented %d-%sdegree", mossteps, mos_prefix) | ||
else aug_degree = string.format("%d× Augmented %d-% | else aug_degree = string.format("%d× Augmented %d-%sdegree", aug_amount, mossteps, mos_prefix) | ||
end | end | ||
| Line 460: | Line 503: | ||
-- Separate function for testing; the main "frame" function will call this | -- Separate function for testing; the main "frame" function will call this | ||
function p.mos_degrees(input_mos, step_ratios, mos_prefix, show_abbreviations, number_of_alterations, ji_ratios, udp, notation) | function p.mos_degrees(input_mos, step_ratios, mos_prefix, show_abbreviations, number_of_alterations, ji_ratios, udp, notation, show_notation) | ||
-- Default params | -- Default params; all parameters are already parsed | ||
local input_mos = input_mos or mos.new(5, 2) | local input_mos = input_mos or mos.new(5, 2) | ||
local step_ratios = step_ratios or {{2,1}, {3,1}, {3,2}} | local step_ratios = step_ratios or {{2,1}, {3,1}, {3,2}} | ||
| Line 468: | Line 511: | ||
local number_of_alterations = number_of_alterations or 1 | local number_of_alterations = number_of_alterations or 1 | ||
local ji_ratios = ji_ratios or {["P0md"]="1/1"} | local ji_ratios = ji_ratios or {["P0md"]="1/1"} | ||
local udp = udp or {5,1} | |||
local notation = " | local notation = notation or mosnot.parse_notation("CDEFGAB; #; b") | ||
local show_notation = show_notation == 1 | |||
-- Get the scale sig | -- Get the scale sig | ||
| Line 485: | 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 496: | Line 540: | ||
-- How many decimal places to round to? (hardcoded) | -- How many decimal places to round to? (hardcoded) | ||
local round = 1 | local round = 1 | ||
-- Precalculate row colors | |||
local row_colors = p.calculate_row_colors(input_mos, number_of_alterations) | |||
-- Precalculate the ets for each step ratio | -- Precalculate the ets for each step ratio | ||
| Line 507: | Line 554: | ||
-- Precalculate degree names, degree abbreviations, and mosstep vectors | -- Precalculate degree names, degree abbreviations, and mosstep vectors | ||
local degree_names, degree_abbrevs = p. | local degree_names, degree_abbrevs = p.calculate_mosdegree_names_and_abbrevs(input_mos, mos_prefix, number_of_alterations) | ||
local mosstep_vectors = p. | local mosstep_vectors = p.calculate_mosstep_vectors(input_mos, number_of_alterations) | ||
-- Precalculate default comments for JI ratios; there's only two entries here | -- Precalculate default comments for JI ratios; there's only two entries here | ||
| Line 514: | Line 561: | ||
default_ji_comments["P0md"] = "1/1 (exact)" | default_ji_comments["P0md"] = "1/1 (exact)" | ||
default_ji_comments[string.format("P%dmd", mossteps_per_equave)] = string.format("%s (exact)", rat.as_ratio(input_mos.equave)) | default_ji_comments[string.format("P%dmd", mossteps_per_equave)] = string.format("%s (exact)", rat.as_ratio(input_mos.equave)) | ||
-- Then, using the UDP, get the notation | -- Then, using the UDP, get the notation | ||
| Line 531: | Line 567: | ||
-- If no notation is passed in, notation will not be displayed | -- If no notation is passed in, notation will not be displayed | ||
local note_names = {} | local note_names = {} | ||
local root_note = "" | local root_note = "" | ||
if | if show_notation then | ||
note_names = p.calculate_note_names(input_mos, udp, notation["Naturals"], notation["Sharp"], notation["Flat"], number_of_alterations) | |||
root_note = string.sub(notation["Naturals"], 1, 1) | |||
root_note = string.sub( | |||
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 | if show_notation then | ||
result = result .. string.format( | result = result .. string.format("! rowspan=\"2\" class=\"unsortable\" | On %s\n", root_note) | ||
end | end | ||
| Line 573: | 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 596: | 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 609: | 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 617: | Line 641: | ||
for i = 1, #degree_names do | for i = 1, #degree_names do | ||
-- Start new row | -- Start new row | ||
result = result .. "|-\n" | -- Add row highlighting if provided | ||
local row_color = row_colors[i] | |||
if row_color == "" then | |||
result = result .. "|-\n" | |||
else | |||
result = result .. string.format("|- style=\"background: %s\"\n", row_color) | |||
end | |||
-- Add degree name | -- Add degree name | ||
| Line 623: | Line 653: | ||
local degree_name = degree_names[i] | local degree_name = degree_names[i] | ||
if string.find(degree_name, "Perfect") then | if string.find(degree_name, "Perfect") then | ||
result = result .. string.format("| '''%s'''\n", degree_names[i]) | if i == 1 then | ||
result = result .. string.format("| '''%s (unison)'''\n", degree_names[i]) | |||
elseif i == #degree_names and equave_in_cents == 1200 then | |||
result = result .. string.format("| '''%s (octave)'''\n", degree_names[i]) | |||
elseif i == #degree_names and equave_in_cents ~= 1200 then | |||
result = result .. string.format("| '''%s (equave)'''\n", degree_names[i]) | |||
else | |||
result = result .. string.format("| '''%s'''\n", degree_names[i]) | |||
end | |||
else | else | ||
result = result .. string.format("| %s\n", degree_names[i]) | result = result .. string.format("| %s\n", degree_names[i]) | ||
| Line 636: | Line 674: | ||
-- Add note names if allowed | -- Add note names if allowed | ||
-- Use the degree_abbrev as the key when accessing key-value pairs | -- Use the degree_abbrev as the key when accessing key-value pairs | ||
if | if show_notation then | ||
result = result .. string.format("| %s\n", note_names[degree_abbrev]) | result = result .. string.format("| %s\n", note_names[degree_abbrev]) | ||
end | end | ||
| Line 642: | Line 680: | ||
-- Add mossteps and cent values | -- Add mossteps and cent values | ||
-- Rounding is hardcoded to one decimal place | -- Rounding is hardcoded to one decimal place | ||
-- Also record the cent value for JI ratio search | |||
local round = 1 | local round = 1 | ||
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) | ||
result = result .. string.format("| %s\n", etsteps) | result = result .. string.format("| %s\n", etsteps) | ||
result = result .. string.format("| %s\n", cents) | result = result .. string.format("| %s\n", cents) | ||
average_cents = average_cents + cents / #ets_for_mos | |||
end | end | ||
-- Calculate JI ratio approximations using jiraf module | |||
-- For now: | |||
-- - Cent value is the average of the sizes given the step ratios | |||
-- - Tolerance is hardcoded to +/-15 cents | |||
-- - Prime limit is hardocoded to 19 | |||
-- - Odd limit hardcoded to 49 | |||
--local approx_ratios = jiraf.find_ratios_for_cents(average_cents, 15, 19, 39) | |||
--local ratios_as_text = jiraf.ratios_to_text(approx_ratios); | |||
-- Add JI ratios if any | -- Add JI ratios if any | ||
local ji_comment_entry = "" | local ji_comment_entry = "" | ||
local default_ji_comment = default_ji_comments[degree_abbrev] | local default_ji_comment = default_ji_comments[degree_abbrev] | ||
-- Add ratios found using jiraf | |||
local entered_ji_comment = ji_ratios[degree_abbrev] | local entered_ji_comment = ji_ratios[degree_abbrev] | ||
--local default_ji_comment = nil | |||
--local entered_ji_comment = ratios_as_text | |||
if default_ji_comment == nil and entered_ji_comment == nil then | if default_ji_comment == nil and entered_ji_comment == nil then | ||
-- No comments | -- No comments | ||
| Line 679: | 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 685: | 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 692: | 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 711: | 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 | ||
result = p.mos_degrees(input_mos, step_ratios, mos_prefix, show_abbreviations, number_of_alterations, ji_ratios_parsed) | -- Get the number of mossteps per period and equave, and periods per equave | ||
-- Needed for calculating default UDP and notation | |||
return result | local mossteps_per_equave = (input_mos.nL + input_mos.ns) | ||
local periods_per_equave = utils._gcd(input_mos.nL, input_mos.ns) | |||
local mossteps_per_period = mossteps_per_equave / periods_per_equave | |||
-- Get UDP | |||
-- If no UDP is found, a default will be calculated as the middle mode, or the | |||
-- brighter of two middle modes (as with an even number of modes in a mos) | |||
local udp_parsed = { periods_per_equave * math.ceil((mossteps_per_period - 1)/ 2), periods_per_equave * math.floor((mossteps_per_period - 1) / 2) } | |||
if scale_sig == "5L 2s" then | |||
udp_parsed = { 5, 1 } | |||
end | |||
if #frame.args["UDP"] > 0 then | |||
udp_parsed = mosnot.parse_udp(frame.args["UDP"]) | |||
end | |||
-- Get notation | |||
-- This also determines whether to show notation | |||
-- Typing in "Default" is a shortcut to default notation, wherein standard notation (for 5L 2s) or diamond-mos (for other mosses) is used | |||
local notation_parsed = {} | |||
local show_notation = 0 | |||
if #frame.args["Notation"] > 0 then | |||
if frame.args["Notation"] == "Default" and scale_sig == "5L 2s" then | |||
notation_parsed = { ["Naturals"] = "CDEFGAB", ["Sharp"] = "#", ["Flat"] = "b" } | |||
show_notation = 1 | |||
elseif frame.args["Notation"] == "Default" and scale_sig ~= "5L 2s" then | |||
local default_nominals = "JKLMNOPQRSTUVWXYZ" | |||
notation_parsed = { ["Naturals"] = string.sub(default_nominals, 1, mossteps_per_equave), ["Sharp"] = "&", ["Flat"] = "@" } | |||
show_notation = 1 | |||
else | |||
notation_parsed = mosnot.parse_notation(frame.args["Notation"]) | |||
if notation_parsed ~= nil then | |||
show_notation = 1 | |||
end | |||
end | |||
end | |||
result = p.mos_degrees(input_mos, step_ratios, mos_prefix, show_abbreviations, number_of_alterations, ji_ratios_parsed, udp_parsed, notation_parsed, show_notation) | |||
-- 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 | ||