Module:MOS intervals: Difference between revisions

Ganaram inukshuk (talk | contribs)
mNo edit summary
Ganaram inukshuk (talk | contribs)
todo
 
(88 intermediate revisions by 3 users not shown)
Line 1: Line 1:
local mos = require('Module:MOS')
local rat = require('Module:Rational')
local ord = require('Module:Ordinal')
local utils = require('Module:Utils')
local et = require('Module:ET')
local tamnams = require('Module:TAMNAMS')
local p = {}
local p = {}


-- TODO:
local getArgs = require("Module:Arguments").getArgs
-- - Convert tooltips to footnotes... somehow
local mos = require("Module:MOS")
local rat = require("Module:Rational")
local tamnams = require("Module:TAMNAMS")
local yesno = require("Module:Yesno")
 
-- -- TODO:
-- - (High priority): Refactor code so instead of string concatenation, lines
--  are appended to a table, where table.concat() is called at the end.
 
-- EXPERIMENTAL FEATURE: lookup table for intervals
-- Mostly based off Margo Schulter's categories (without large/medium/small),
-- but other interpretations are possible. Plus, this only goes up to 1200c.
p.interval_ranges = {
    { name = "Pure unison (1:1)"        , range = {  0,    0} },
    { name = "Comma/diesis"            , range = {  0,  60} },
    { name = "Minor second"            , range = {  60,  125} },
    { name = "Neutral second"          , range = { 125,  170} },
    { name = "Major second"            , range = { 180,  240} },
    { name = "Interseptimal (Maj2-min3)", range = { 240,  260} },
    { name = "Minor third"              , range = { 260,  330} },
    { name = "Neutral third"            , range = { 330,  372} },
    { name = "Major third"              , range = { 372,  440} },
    { name = "Interseptimal (Maj3-4)"  , range = { 440,  468} },
    { name = "Perfect fourth"          , range = { 468,  528} },
    { name = "Superfourth"              , range = { 528,  560} },
    { name = "Tritonic region"          , range = { 560,  640} },
    { name = "Subfifth"                , range = { 640,  672} },
    { name = "Perfect fifth"            , range = { 672,  732} },
    { name = "Interseptimal (5-min6)"  , range = { 732,  760} },
    { name = "Minor sixth"              , range = { 760,  828} },
    { name = "Neutral sixth"            , range = { 828,  870} },
    { name = "Major sixth"              , range = { 870,  940} },
    { name = "Interseptimal (Maj6-min7)", range = { 940,  960} },
    { name = "Minor seventh"            , range = { 960, 1020} },
    { name = "Neutral seventh"          , range = {1030, 1075} },
    { name = "Major seventh"            , range = {1075, 1140} },
    { name = "Octave less comma/diesis" , range = {1140, 1200} },
    { name = "Pure octave (2:1)"        , range = {1200, 1200} }
}
 
-- EXPERIMENTAL FEATURE: interval lookup function
function p.lookup_interval_range(cents)
    for _, interval in ipairs(p.interval_ranges) do
        if cents >= interval.range[1] and cents <= interval.range[2] then
            return interval.name
        end
    end
    return "Out of range"
end


-- Main function; to be called by wrapper
-- Main function; to be called by wrapper
function p._mos_intervals(input_mos, mos_prefix, mos_abbrev)
function p._mos_intervals(args)
-- Default param for input mos is 5L 2s
-- Default param for input mos is 5L 2s
local input_mos = input_mos or mos.new(5, 2, 2)
local input_mos   = args["Input MOS"  ] or mos.new(5, 2, 2)
local mos_prefix = mos_prefix or "mos"
local mos_prefix   = args["MOS Prefix"  ] or "mos"
local mos_abbrev = mos_abbrev or "m"
local mos_abbrev   = args["MOS Abbrev"  ] or "m"
local is_collapsed = args["Is Collapsed"] == true
local show_inregs  = false
-- Get the scale sig
-- Get the scale sig
Line 32: Line 76:
local dark_gen_step_count = mos.dark_gen_step_count(input_mos)
local dark_gen_step_count = mos.dark_gen_step_count(input_mos)
-- Create the table, starting with the headers
-- Create the table
local result = '{| class="wikitable"\n'
local result = '{| class="wikitable mw-collapsible' .. (is_collapsed and ' mw-collapsed"\n' or '"\n')
result = result .. '|+ Intervals of ' .. scale_sig .. '\n'
result = result .. '! colspan="3" | Intervals\n'
result = result .. '! rowspan="2" | <abbr title="The number of large and small steps the interval spans.">Steps subtended</abbr>\n'
result = result .. '! rowspan="2" | Range in cents\n'
result = result .. '|-\n'
result = result .. '! Generic<sup>[[#mosstep-1|[1]]]</sup>\n'
result = result .. '! Specific<sup>[[#mosstep-2|[2]]]</sup>\n'
result = result .. '! Abbrev.<sup>[[#mosstep-3|[3]]]</sup>\n'
-- Create table title
result = result
.. '|+ style="font-size: 105%; white-space: nowrap;" | ' .. string.format('Intervals of %s', scale_sig) .. '\n'
.. '|-\n'
-- Create table headers
result = result
.. '! colspan="3" | Intervals\n'
.. '! rowspan="2" | Steps<br />subtended\n'
.. '! rowspan="2" | Range in cents\n'
.. '|-\n' -- Start of second row of header cells
.. '! Generic\n'
.. '! Specific\n'
.. '! Abbrev.\n'
.. (show_inregs and '! Interval Regions\n' or '')
-- Write each row
-- Write each row
for i = 1, #bright_step_matrix do
for i = 1, #bright_step_matrix do
-- Compare the bright and dark intervals. If they're the same, then the
-- Compare the bright and dark intervals. If they're the same, then the
-- current interval class is a period interval.
-- current interval class is a period interval.
Line 55: Line 106:
-- Otherwise, there are two rows to write, one for each size.
-- Otherwise, there are two rows to write, one for each size.
if is_period then
if is_period then
local cents = mos.interval_to_cents(current_bright_interval, input_mos, {1,1})
local cents = mos.interval_to_cents(current_bright_interval, input_mos, {1, 1})
local cents_formatted = string.format("%.1f{{c}}", cents)
result = result .. "|-\n"
result = result
result = result .. string.format("| '''%s-%sstep'''\n", i-1, mos_prefix)
.. "|-\n"
result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos, "sentence-case"))
.. "| '''" .. i-1 .. "-" .. mos_prefix .. "step'''\n"
result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos, "abbrev", "m"))
.. "| " .. tamnams.interval_quality(current_bright_interval, input_mos, "sentence-case", mos_prefix) .. "\n"
result = result .. string.format("| %s\n" , mos.interval_as_string(current_bright_interval))
.. "| " .. tamnams.interval_quality(current_bright_interval, input_mos, "abbrev"       , mos_abbrev) .. "\n"
result = result .. string.format("| %.1f¢\n", cents)
.. "| <span style=\"white-space: nowrap;\">" .. mos.interval_as_string(current_bright_interval) .. "</span>\n"
.. "| " .. cents_formatted .. "\n"
.. (show_inregs and string.format("| %s\n", p.lookup_interval_range(cents)) or "")
else
else
-- Calculate the cent values min and max for the current intervals
-- Calculate the cent values min and max for the current intervals
Line 72: Line 126:
-- Then sort, as the min and max may be swapped  
-- Then sort, as the min and max may be swapped  
-- This happens if the dark interval has more small steps than large steps
-- This happens if the dark interval has more small steps than large steps
local dark_interval_range  = string.format("%.1f¢ to %.1f¢", math.min(sm_min_cents, sm_max_cents), math.max(sm_min_cents, sm_max_cents))
local sm_min_sorted = math.min(sm_min_cents, sm_max_cents)
local bright_interval_range = string.format("%.1f¢ to %.1f¢", math.min(lg_min_cents, lg_max_cents), math.max(lg_min_cents, lg_max_cents))
local sm_max_sorted = math.max(sm_min_cents, sm_max_cents)
local lg_min_sorted = math.min(lg_min_cents, lg_max_cents)
local lg_max_sorted = math.max(lg_min_cents, lg_max_cents)
result = result .. "|-\n"
-- Produce text ranges for intervals
result = result .. string.format("| rowspan=\"2\" | %s-%sstep\n", i-1, mos_prefix)
local dark_interval_range  = string.format("%.1f{{c}} to %.1f{{c}}", sm_min_sorted, sm_max_sorted)
result = result .. string.format("| %s\n" , tamnams.interval_quality(current_dark_interval, input_mos, "sentence-case"))
local bright_interval_range = string.format("%.1f{{c}} to %.1f{{c}}", lg_min_sorted, lg_max_sorted)
result = result .. string.format("| %s\n" , tamnams.interval_quality(current_dark_interval, input_mos, "abbrev", "m"))
result = result .. string.format("| %s\n" , mos.interval_as_string(current_dark_interval))
result = result
result = result .. string.format("| %s\n" , dark_interval_range)
.. "|-\n"
.. '| rowspan="2" | ' .. i-1 .. '-' .. mos_prefix .. 'step\n'
result = result .. "|-\n"
.. "| " .. tamnams.interval_quality(current_dark_interval, input_mos, "sentence-case", mos_prefix) .. "\n"
result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos, "sentence-case"))
.. "| " .. tamnams.interval_quality(current_dark_interval, input_mos, "abbrev"       , mos_abbrev) .. "\n"
result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos, "abbrev", "m"))
.. "| <span style=\"white-space: nowrap;\">" .. mos.interval_as_string(current_dark_interval) .. "</span>\n"
result = result .. string.format("| %s\n" , mos.interval_as_string(current_bright_interval))
.. "| " .. dark_interval_range .. "\n"
result = result .. string.format("| %s\n" , bright_interval_range)
.. (show_inregs and string.format("| %s to %s\n", p.lookup_interval_range(sm_min_sorted), p.lookup_interval_range(sm_max_sorted)) or "")
.. "|-\n"
.. "| " .. tamnams.interval_quality(current_bright_interval, input_mos, "sentence-case", mos_prefix) .. "\n"
.. "| " .. tamnams.interval_quality(current_bright_interval, input_mos, "abbrev"       , mos_abbrev) .. "\n"
.. "| <span style=\"white-space: nowrap;\">" .. mos.interval_as_string(current_bright_interval) .. "</span>\n"
.. "| " .. bright_interval_range .. "\n"
.. (show_inregs and string.format("| %s to %s\n", p.lookup_interval_range(lg_min_sorted), p.lookup_interval_range(lg_max_sorted)) or "")
end
end
end
result = result .. "|}"


end
result = result .. "|}\n"
result = result .. "<small>\n"
result = result .. '# <span id="mosstep-1">A mos interval denoted solely by the number of steps it subtends.</span>\n'
result = result .. '# <span id="mosstep-2">A mos interval denoted by the large and small steps it subtends. More large steps makes it major or augmented; more small steps makes it minor or diminished.</span>\n'
result = result .. '# <span id="mosstep-3">The abbreviated form of the interval. The abbreviation can be further shortened to &#39;ms&#39; if context allows.</span>\n'
result = result .. "</small>\n"
return result
return result
end
end


-- Wrapper function; to be called by template
-- Wrapper function; to be called by template
function p.mos_intervals(frame)
function p.mos_intervals(frame)
-- Get input mos
local args = getArgs(frame)
local input_mos = mos.parse(frame.args['Scale Signature'])
-- Preprocess scalesig into input mos
local input_mos = mos.parse(args["Scale Signature"])
args["Input MOS"] = input_mos
args["Scale Signature"] = nil
 
-- Preprocess collapse option
args["Collapsed"] = yesno(args["Collapsed"], false)
-- EXPERIMENTAL: option to show interval regions
args["Show Interval Regions"] = yesno(args["Show Interval Regions"], false)
-- Default param for mos prefix
-- Preprocess (verify) prefix/abbrev
-- If "NONE" is given, no prefix will be used
args["MOS Prefix"] = tamnams.verify_prefix(input_mos, args["MOS Prefix"])
-- If left blank, try to find the appropriate mos prefix, or else defualt to "mos"
args["MOS Abbrev"] = tamnams.verify_abbrev(input_mos, args["MOS Abbrev"])
-- If not left blank, use the prefix passed in instead
 
local scale_sig = mos.as_string(input_mos)
local result = p._mos_intervals(args)
local mos_prefix = tamnams.lookup_prefix(input_mos)
local debugg = yesno(args["debug"])
local mos_abbrev = tamnams.lookup_abbrev(input_mos)
if frame.args['MOS Prefix'] == "NONE" then
-- Debugger option
mos_prefix = ""
if debugg == true then
mos_abbrev = ""
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
elseif string.len(frame.args['MOS Prefix']) > 0 then
mos_prefix = frame.args['MOS Prefix']
mos_abbrev = frame.args['MOS Prefix']
end
end
if frame.args['MOS Abbrev'] == "NONE" then
return frame:preprocess(result)
mos_abbrev = ""
elseif string.len(frame.args['MOS Abbrev']) > 0 then
mos_abbrev = frame.args['MOS Abbrev']
end
 
local result = p._mos_intervals(input_mos, mos_prefix, mos_abbrev)
 
return result
end
end


return p
return p