Module:TAMNAMS: Difference between revisions
Added code skeleton for function to decode an interval to MmAPd |
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 | 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 | 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 | 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, | 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. | -- 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 | -- Determine what "special" type the interval is so that the designations | ||
local is_bright_gen = | -- of augmented/perfect/diminished (APd) apply, skipping major/minor (Mm). | ||
local is_dark_gen = | -- 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 | ||