Module:TAMNAMS: Difference between revisions

Ganaram inukshuk (talk | contribs)
Added code skeleton for function to decode an interval to MmAPd
Ganaram inukshuk (talk | contribs)
Added base functionality for quality-decode function (large/small -> MmAPd)
Line 6: Line 6:
local utils = require('Module:Utils')
local utils = require('Module:Utils')
local p = {}
local p = {}
-- TODO
-- - Adjust formatting of abbreviations for decode function


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 208: Line 211:
function p.preprocess_step_ratio(step_ratio)
function p.preprocess_step_ratio(step_ratio)
return (#step_ratio == 2 and type(step_ratio[1]) == 'number' and type(step_ratio[2]) == 'number') and rat.new(step_ratio[1], step_ratio[2]) or step_ratio
return (#step_ratio == 2 and type(step_ratio[1]) == 'number' and type(step_ratio[2]) == 'number') and rat.new(step_ratio[1], step_ratio[2]) or step_ratio
end
function p.preprocess_scalesig(input_mos)
end
end


Line 217: Line 223:
-- Can accept either a mos (defined by mos module) or its scalesig.
-- Can accept either a mos (defined by mos module) or its scalesig.
function p.lookup_name(input_mos)  
function p.lookup_name(input_mos)  
local scalesig = type(input_mos) == "string" and input_mos or mos.as_string(input_mos)
local scalesig
if type(input_mos) == "string" then
scalesig = input_mos
elseif type(input_mos) == "table" then
scalesig = mos.as_string(input_mos)
end
return p.tamnams_name[scalesig]
return p.tamnams_name[scalesig]
end
end
Line 224: Line 235:
-- Can accept either a mos (defined by mos module) or its scalesig.
-- Can accept either a mos (defined by mos module) or its scalesig.
function p.lookup_prefix(input_mos)  
function p.lookup_prefix(input_mos)  
local scalesig = type(input_mos) == "string" and input_mos or mos.as_string(input_mos)
local scalesig
if type(input_mos) == "string" then
scalesig = input_mos
elseif type(input_mos) == "table" then
scalesig = mos.as_string(input_mos)
end
return p.tamnams_prefix[scalesig]
return p.tamnams_prefix[scalesig]
end
end
Line 231: Line 247:
-- Can accept either a mos (defined by mos module) or its scalesig.
-- Can accept either a mos (defined by mos module) or its scalesig.
function p.lookup_abbrev(input_mos)  
function p.lookup_abbrev(input_mos)  
local scalesig = type(input_mos) == "string" and input_mos or mos.as_string(input_mos)
local scalesig
if type(input_mos) == "string" then
scalesig = input_mos
elseif type(input_mos) == "table" then
scalesig = mos.as_string(input_mos)
end
return p.tamnams_abbrev[scalesig]
return p.tamnams_abbrev[scalesig]
end
end
Line 280: Line 301:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


function p.decode_interval_quality(interval, inupt_mos, is_abbrev, mos_prefix)
function p.decode_interval_quality(interval, input_mos, abbrev_format, mos_prefix)
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix
local abbrev_format = abbrev_format or none
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos"
local interval = mos.period_reduce(interval, input_mos)
-- Normalize the interval so negative values aren't being used.
local interval = mos.normalize_interval(interval)
-- Get the step count of the interval. The sum of L's and s's will always
-- determine what k-mosstep the interval is.
local step_count = mos.interval_step_count(interval)
local step_count = mos.interval_step_count(interval)
local base_interval = mos.interval_from_mos(input_mos, step_count)
local is_period_interval = interval == mos.period_step_count(input_mos)
-- Determine what "special" type the interval is so that the designations
local is_bright_gen = interval == mos.bright_gen_step_count(input_mos)
-- of augmented/perfect/diminished (APd) apply, skipping major/minor (Mm).
local is_dark_gen = interval == mos.dark_gen_step_count(input_mos)
-- If it's the period or equave, then it's a multiple of the period.
-- If it's any one of the gens, then reducing it should produce that gen.
local is_period    = step_count % mos.period_step_count(input_mos) == 0
local is_bright_gen = step_count % mos.period_step_count(input_mos) == mos.bright_gen_step_count(input_mos)
local is_dark_gen   = step_count % mos.period_step_count(input_mos) == mos.dark_gen_step_count(input_mos)
-- If the interval is a period or generator of a non-root mos, then it's
-- perfectable.
local is_perfectable = (is_period or is_bright_gen or is_dark_gen) and not is_root_mos
-- Special case: APd does not apply to a root mos's (nL ns) generators;
-- instead, it's Mm.
local is_root_mos = input_mos.nL == input_mos.ns
local is_root_mos = input_mos.nL == input_mos.ns
-- Get chroma count and adjust as needed
local chroma_count = 0
local quality = ""
if is_perfectable then
if is_equave or is_period then
-- Chroma count 0 is the perfect size. This interval does not appear
-- as any other size across all mos modes.
chroma_count = mos.interval_chroma_count(interval, input_mos)
elseif is_bright_gen and not is_root_mos then
-- Chroma count 0 is the large size, and -1 the small size; these
-- are perfect and diminished respectively.
chroma_count = mos.interval_chroma_count(interval, input_mos)
elseif is_dark_gen and not is_root_mos then
-- Chroma count 0 is the large size, and -1 the small size; these
-- are augmented and perfect respectively. Since the perfect size
-- corresponds to a chroma count of -1, pass in -1 as the 3rd arg.
chroma_count = mos.interval_chroma_count(interval, input_mos, -1)
end
quality = p.chroma_count_to_perfectable_interval_quality(chroma_count, abbrev_format)
else
-- Chroma count 0 is the large size, and -1 the small size; these are
-- major and minor respectively.
chroma_count = mos.interval_chroma_count(interval, input_mos)
quality = p.chroma_count_to_nonperfectable_interval_quality(chroma_count, abbrev_format)
end
return string.format("%s %d-%s%s", quality, step_count, mos_prefix, abbrev_format == "none" and "step" or "s")
end
end


-- Given the chroma count for a perfectable interval, return the quality it
-- corresponds to:
--  4 = 4x augmented
--  3 = 3x augmented
--  2 = 2x augmented
--  1 = augmented
--  0 = perfect
-- -1 = diminished
-- -2 = 2x diminished
-- -3 = 3x diminished
-- -4 = 4x diminished
function p.chroma_count_to_perfectable_interval_quality(chromas, abbrev_format)
local abbrev_format = abbrev_format or "none"
-- Get absolute value of chroma count
local chroma_abs = math.abs(chromas)
-- Get quality
local quality = ""
if abbrev_format == "none" or abbrev_format == "NONE" then
if chromas < 0 then
quality = "diminished"
elseif chromas > 0 then
quality = "augmented"
else
quality = "perfect"
end
if chroma_abs > 1 then
quality = string.format("%d× %s", chroma_abs, quality)
end
elseif abbrev_format == "short" or abbrev_format == "SHORT" then
if chromas < 0 then
quality = "Dim."
elseif chromas > 0 then
quality = "Aug."
else
quality = "Perf."
end
if chroma_abs > 1 then
quality = string.format("%d× %s", chroma_abs, quality)
end
elseif abbrev_format == "abbrev" or abbrev_format == "ABBREV" then
if chromas < 0 then
quality = "d"
elseif chromas > 0 then
quality = "A"
else
quality = "p"
end
if chroma_abs > 3 then
quality = string.format("%s<sup>%d</sup>", quality, chroma_abs)
elseif chroma_abs > 1 and chroma_abs <= 3 then
quality = string.rep(quality, chroma_abs)
end
end
return quality
end
-- Given the chroma count for a nonperfectable interval, return the quality it
-- corresponds to:
--  4 = 4x augmented
--  3 = 3x augmented
--  2 = 2x augmented
--  1 = augmented
--  0 = major
-- -1 = minor
-- -2 = diminished
-- -3 = 2x diminished
-- -4 = 3x diminished
-- -5 = 4x diminished
function p.chroma_count_to_nonperfectable_interval_quality(chromas, abbrev_format)
local abbrev_format = abbrev_format or "none"
-- Is the interval major
local is_positive = chromas >= 0
-- Get absolute value of chroma count
local chroma_abs = math.abs(chromas)
if not is_positive then
chroma_abs = chroma_abs - 1
end
-- Get quality
local quality = ""
if abbrev_format == "none" or abbrev_format == "NONE" then
if chroma_abs > 0 and is_positive then
quality = "augmented"
elseif chroma_abs > 0 and not is_positive then
quality = "diminished"
else
quality = is_positive and "major" or "minor"
end
if chroma_abs > 1 then
quality = string.format("%d× %s", chroma_abs, quality)
end
elseif abbrev_format == "short" or abbrev_format == "SHORT" then
if chroma_abs > 0 and is_positive then
quality = "Aug."
elseif chroma_abs > 0 and not is_positive then
quality = "Dim."
else
quality = is_positive and "Maj." or "Min."
end
if chroma_abs > 1 then
quality = string.format("%d× %s", chroma_abs, quality)
end
elseif abbrev_format == "abbrev" or abbrev_format == "ABBREV" then
if chroma_abs > 0 and is_positive then
quality = "A"
elseif chroma_abs > 0 and not is_positive then
quality = "d"
else
quality = is_positive and "M" or "m"
end
if chroma_abs > 3 then
quality = string.format("%s<sup>%d</sup>", quality, chroma_abs)
elseif chroma_abs > 1 and chroma_abs <= 3 then
quality = string.rep(quality, chroma_abs)
end
end
return quality
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 301: Line 494:
function p.tester()
function p.tester()
--return p.lookup_step_ratio_range(rat.new(10, 1), rat.new(1, 0), true)
--return p.lookup_step_ratio_range(rat.new(10, 1), rat.new(1, 0), true)
return p.lookup_step_ratio_range(rat.new(6,5), rat.new(1,1), true)
--return p.lookup_step_ratio_range(rat.new(6,5), rat.new(1,1), true)
local abbrev_code = "short"
local input_mos = mos.new(5,2)
--[[
return
p.chroma_count_to_nonperfectable_interval_quality( 4, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality( 3, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality( 2, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality( 1, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality( 0, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality(-1, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality(-2, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality(-3, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality(-4, abbrev_code) .. "\n" ..
p.chroma_count_to_nonperfectable_interval_quality(-5, abbrev_code)
]]--
local output_string = 
p.decode_interval_quality({['L']= 6,['s']=-4}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']= 5,['s']=-3}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']= 4,['s']=-2}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']= 3,['s']=-1}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']= 2,['s']= 0}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']= 1,['s']= 1}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']= 0,['s']= 2}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']=-1,['s']= 3}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']=-2,['s']= 4}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']=-3,['s']= 5}, input_mos, abbrev_code)
return output_string
end
end


return p
return p