Module:TAMNAMS: Difference between revisions
Jump to navigation
Jump to search
Added base functionality for quality-decode function (large/small -> MmAPd) |
Consolidated helper functions; rewrote preprocess functions; interval_quality() and degree_quality() added |
||
| Line 208: | Line 208: | ||
-- Step ratios are entered as an array of two numeric values, or alternatively, | -- Step ratios are entered as an array of two numeric values, or alternatively, | ||
-- as a ratio as defined by the rational module. If of the former, this helper | -- as a ratio as defined by the rational module. If of the former, this helper | ||
-- function converts it to the latter. | -- function converts it to the latter. This preprocess step is for simplifying | ||
-- ratios. | |||
function p.preprocess_step_ratio(step_ratio) | function p.preprocess_step_ratio(step_ratio) | ||
return ( | if type(step_ratio) == "string" then | ||
return step_ratio | |||
elseif (type(step_ratio) == "table" and type(step_ratio[1]) == 'number' and type(step_ratio[2]) == 'number') then | |||
return rat.new(step_ratio[1], step_ratio[2]) | |||
else | |||
return nil | |||
end | |||
end | end | ||
-- Mosses for name lookup are entered either as a scalesig or as a mos as | |||
-- defined in the mos module. If of the latter, it's converted into a textual | |||
-- scalesig. | |||
function p.preprocess_scalesig(input_mos) | function p.preprocess_scalesig(input_mos) | ||
if type(input_mos) == "string" then | |||
return input_mos | |||
elseif type(input_mos) == "table" then | |||
return mos.as_string(input_mos) | |||
else | |||
return nil | |||
end | |||
end | end | ||
| Line 223: | Line 240: | ||
-- 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 | local scalesig = p.preprocess_scalesig(input_mos) | ||
return p.tamnams_name[scalesig] | return p.tamnams_name[scalesig] | ||
end | end | ||
| Line 234: | Line 246: | ||
-- Function for looking up a mos's prefix (octave-equivalent mosses only). | -- Function for looking up a mos's prefix (octave-equivalent mosses only). | ||
-- 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 | local scalesig = p.preprocess_scalesig(input_mos) | ||
return p.tamnams_prefix[scalesig] | return p.tamnams_prefix[scalesig] | ||
end | end | ||
| Line 247: | Line 254: | ||
-- 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 | local scalesig = p.preprocess_scalesig(input_mos) | ||
return p.tamnams_abbrev[scalesig] | return p.tamnams_abbrev[scalesig] | ||
end | end | ||
| Line 298: | Line 300: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
--------------------- | --------------------- MOSSTEP/MOSDEGREE QUALITY FUNCTIONS ---------------------- | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
function p. | function p.interval_quality(interval, input_mos, abbrev_format, mos_prefix) | ||
local abbrev_format = abbrev_format or none | local abbrev_format = abbrev_format or "none" | ||
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos" | local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos" | ||
-- 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) | |||
-- Decode the quality | |||
local quality = p.decode_quality(interval, input_mos, abbrev_format) | |||
if abbrev_format == "abbrev" or abbrev_format == "ABBREV" then | |||
return string.format("%s%d%ss.", quality, step_count, mos_prefix) | |||
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then | |||
return string.format("%s %d-%ss.", quality, step_count, mos_prefix) | |||
else | |||
return string.format("%s %d-%sstep", quality, step_count, mos_prefix) | |||
end | |||
end | |||
function p.degree_quality(interval, input_mos, abbrev_format, mos_prefix) | |||
local abbrev_format = abbrev_format or "none" | |||
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos" | |||
-- 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) | |||
-- Decode the quality | |||
local quality = p.decode_quality(interval, input_mos, abbrev_format) | |||
if abbrev_format == "abbrev" or abbrev_format == "ABBREV" then | |||
return string.format("%s%d%ss.", quality, step_count, mos_prefix) | |||
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then | |||
return string.format("%s %d-%sd.", quality, step_count, mos_prefix) | |||
else | |||
return string.format("%s %d-%sdegree", quality, step_count, mos_prefix) | |||
end | |||
end | |||
-- Decodes the quality of a mosstep. Helper function to interval_quality() and | |||
-- degree_quality(), but can be used standalone if only the keyword (maj, min, | |||
-- aug, perf, dim) is needed. The chroma amounts are as follows: | |||
-- AMT| PERFECTABLE | NONPERFECTABLE | DARK GEN ONLY | |||
-- ---+-----------------+-------------------+------------------ | |||
-- ...| . . . | . . . | . . . | |||
-- 4 | 4x augmented | 4x augmented | 5x augmented | |||
-- 3 | 3x augmented | 3x augmented | 4x augmented | |||
-- 2 | 2x augmented | 2x augmented | 3x augmented | |||
-- 1 | augmented | augmented | 4x augmented | |||
-- 0 | perfect | major | augmented | |||
-- -1 | diminished | minor | perfect | |||
-- -2 | 2x diminished | diminished | diminished | |||
-- -3 | 3x diminished | 2x diminished | 2x diminished | |||
-- -4 | 4x diminished | 3x diminished | 3x diminished | |||
-- -5 | 5x diminished | 4x diminished | 4x diminished | |||
-- ...| . . . | . . . | . . . | |||
function p.decode_quality(interval, input_mos, abbrev_format) | |||
-- Normalize the interval so negative values aren't being used. | -- Normalize the interval so negative values aren't being used. | ||
local interval = mos.normalize_interval(interval) | local interval = mos.normalize_interval(interval) | ||
| Line 330: | Line 387: | ||
-- Get chroma count and adjust as needed | -- Get chroma count and adjust as needed | ||
local chroma_count = 0 | local chroma_count = 0 | ||
if is_perfectable then | if is_perfectable then | ||
if is_equave or is_period then | if is_equave or is_period then | ||
| Line 346: | Line 402: | ||
chroma_count = mos.interval_chroma_count(interval, input_mos, -1) | chroma_count = mos.interval_chroma_count(interval, input_mos, -1) | ||
end | end | ||
else | else | ||
-- Chroma count 0 is the large size, and -1 the small size; these are | -- Chroma count 0 is the large size, and -1 the small size; these are | ||
-- major and minor respectively. | -- major and minor respectively. | ||
chroma_count = mos.interval_chroma_count(interval, input_mos) | chroma_count = mos.interval_chroma_count(interval, input_mos) | ||
end | end | ||
-- Get absolute value of chroma count | -- Get absolute value of chroma count | ||
local chroma_abs = math.abs( | local chroma_abs = math.abs(chroma_count) | ||
local quality = "" | local quality = "" | ||
if | if is_perfectable then | ||
-- Get the quality for perfectable intervals | |||
if chroma_abs > 1 then | if abbrev_format == "none" or abbrev_format == "NONE" then | ||
if chroma_count < 0 then | |||
quality = "diminished" | |||
elseif chroma_count > 0 then | |||
quality = "augmented" | |||
else | |||
quality = "perfect" | |||
quality = " | end | ||
else | |||
quality = " | if chroma_abs > 1 then | ||
quality = string.format("%d× %s", chroma_abs, quality) | |||
end | |||
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then | |||
if chroma_count < 0 then | |||
quality = "Dim." | |||
elseif chroma_count > 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 chroma_count < 0 then | |||
quality = "d" | |||
elseif chroma_count > 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 | end | ||
else | |||
-- Get the quality for nonperfectable intervals | |||
-- Is the interval major? If not, decrement chroma_abs by 1 | |||
local is_positive = chroma_count >= 0 | |||
chroma_abs = is_positive and chroma_abs or chroma_abs - 1 | |||
if chroma_abs > 3 then | 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 == "shortened" or abbrev_format == "SHORTENED" 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 | end | ||
end | end | ||
| Line 495: | Line 512: | ||
--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 = " | local abbrev_code = "abbrev" | ||
local input_mos = mos.new(5,2) | local input_mos = mos.new(5,2) | ||
--[[ | --[[ | ||
| Line 511: | Line 528: | ||
]]-- | ]]-- | ||
local output_string = | local output_string = | ||
p. | p.interval_quality({['L']= 6,['s']=-4}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']= 5,['s']=-3}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']= 4,['s']=-2}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']= 3,['s']=-1}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']= 2,['s']= 0}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']= 1,['s']= 1}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']= 0,['s']= 2}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']=-1,['s']= 3}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']=-2,['s']= 4}, input_mos, abbrev_code) .. "\n" .. | ||
p. | p.interval_quality({['L']=-3,['s']= 5}, input_mos, abbrev_code) | ||
return | return p.decode_quality({['L']=2,['s']=1}, input_mos, abbrev_code) | ||
end | end | ||
return p | return p | ||
Revision as of 08:43, 4 June 2024
- This module primarily serves as a library for other modules and has no corresponding template.
This module is designed to handle TAMNAMS as it pertains to MOS scales. It is meant to be used with other modules, rather than something invoked directly or as part of a template.
| Introspection summary for Module:TAMNAMS | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||
No function descriptions were provided. The Lua code may have further information.
-- Module for TAMNAMS-related things as it pertains to mosses
-- This module is meant to be used with other modules, not as part of a template
-- Work in progress
local mos = require('Module:MOS')
local rat = require('Module:Rational')
local utils = require('Module:Utils')
local p = {}
-- TODO
-- - Adjust formatting of abbreviations for decode function
--------------------------------------------------------------------------------
------------------------------- LOOKUP TABLES ----------------------------------
--------------------------------------------------------------------------------
-- Lookup table for tamnams step ratios
p.tamnams_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'
}
-- And step ratio ranges
p.tamnams_ranges = {
['1:1 to 2:1'] = 'soft-of-basic',
['1:1 to 4:3'] = 'ultrasoft',
['4:3 to 3:2'] = 'parasoft',
['3:2 to 2:1'] = 'hyposoft',
['3:2 to 5:3'] = 'quasisoft',
['5:3 to 2:1'] = 'minisoft',
['2:1 to 5:2'] = 'minihard',
['5:2 to 3:1'] = 'quasihard',
['2:1 to 3:1'] = 'hypohard',
['3:1 to 4:1'] = 'parahard',
['4:1 to 1:0'] = 'ultrahard',
['2:1 to 1:0'] = 'hard-of-basic'
}
-- Lookup table for tamnams extended step ratios
p.tamnams_ratios_ext = {
['1:1'] = 'equalized',
['6:5'] = 'semiequalized',
['4:3'] = 'supersoft',
['3:2'] = 'soft',
['5:3'] = 'semisoft',
['2:1'] = 'basic',
['5:2'] = 'semihard',
['3:1'] = 'hard',
['4:1'] = 'superhard',
['6:1'] = 'extrahard',
['10:1'] = 'semicollapsed',
['1:0'] = 'collapsed'
}
-- And extended step ratio ranges
p.tamnams_ranges_ext = {
['1:1 to 2:1'] = 'soft-of-basic',
['1:1 to 6:5'] = 'pseudoequalized',
['6:5 to 4:3'] = 'ultrasoft',
['4:3 to 3:2'] = 'parasoft',
['3:2 to 2:1'] = 'hyposoft',
['3:2 to 5:3'] = 'quasisoft',
['5:3 to 2:1'] = 'minisoft',
['2:1 to 5:2'] = 'minihard',
['5:2 to 3:1'] = 'quasihard',
['2:1 to 3:1'] = 'hypohard',
['3:1 to 4:1'] = 'parahard',
['4:1 to 6:1'] = 'hyperhard',
['6:1 to 10:1'] = 'clustered',
['4:1 to 10:1'] = 'ultrahard',
['10:1 to 1:0'] = 'pseudocollapsed',
['2:1 to 1:0'] = 'hard-of-basic'
}
-- Lookup table for official tamnams names
p.tamnams_name = {
['1L 1s'] = 'monowood',
['2L 2s'] = 'biwood',
['1L 5s'] = 'antimachinoid',
['2L 4s'] = 'malic',
['3L 3s'] = 'triwood',
['4L 2s'] = 'citric',
['5L 1s'] = 'machinoid',
['1L 6s'] = 'onyx',
['2L 5s'] = 'antidiatonic',
['3L 4s'] = 'mosh',
['4L 3s'] = 'smitonic',
['5L 2s'] = 'diatonic',
['6L 1s'] = 'archaeotonic',
['1L 7s'] = 'antipine',
['2L 6s'] = 'subaric',
['3L 5s'] = 'checkertonic',
['4L 4s'] = 'tetrawood',
['5L 3s'] = 'oneirotonic',
['6L 2s'] = 'ekic',
['7L 1s'] = 'pine',
['1L 8s'] = 'antisubneutralic',
['2L 7s'] = 'balzano',
['3L 6s'] = 'tcherepnin',
['4L 5s'] = 'gramitonic',
['5L 4s'] = 'semiquartal',
['6L 3s'] = 'hyrulic',
['7L 2s'] = 'armotonic',
['8L 1s'] = 'subneutralic',
['1L 9s'] = 'antisinatonic',
['2L 8s'] = 'jaric',
['3L 7s'] = 'sephiroid',
['4L 6s'] = 'lime',
['5L 5s'] = 'pentawood',
['6L 4s'] = 'lemon',
['7L 3s'] = 'dicoid',
['8L 2s'] = 'taric',
['9L 1s'] = 'sinatonic'
}
-- And prefixes
p.tamnams_prefix = {
['1L 1s'] = 'monwd',
['2L 2s'] = 'biwd',
['1L 5s'] = 'amech',
['2L 4s'] = 'mal',
['3L 3s'] = 'triwd',
['4L 2s'] = 'citro',
['5L 1s'] = 'mech',
['1L 6s'] = 'on',
['2L 5s'] = 'pel',
['3L 4s'] = 'mosh',
['4L 3s'] = 'smi',
['5L 2s'] = 'dia',
['6L 1s'] = 'arch',
['1L 7s'] = 'apine',
['2L 6s'] = 'subar',
['3L 5s'] = 'check',
['4L 4s'] = 'tetrawd',
['5L 3s'] = 'oneiro',
['6L 2s'] = 'ek',
['7L 1s'] = 'pine',
['1L 8s'] = 'ablu',
['2L 7s'] = 'bal',
['3L 6s'] = 'cher',
['4L 5s'] = 'gram',
['5L 4s'] = 'cthon',
['6L 3s'] = 'hyru',
['7L 2s'] = 'arm',
['8L 1s'] = 'blu',
['1L 9s'] = 'asina',
['2L 8s'] = 'jara',
['3L 7s'] = 'seph',
['4L 6s'] = 'lime',
['5L 5s'] = 'pentawd',
['6L 4s'] = 'lem',
['7L 3s'] = 'dico',
['8L 2s'] = 'tara',
['9L 1s'] = 'sina'
}
-- And abbrevs
p.tamnams_abbrev = {
['1L 1s'] = 'wood',
['2L 2s'] = 'bw',
['1L 5s'] = 'amech',
['2L 4s'] = 'mal',
['3L 3s'] = 'trw',
['4L 2s'] = 'cit',
['5L 1s'] = 'mech',
['1L 6s'] = 'on',
['2L 5s'] = 'pel',
['3L 4s'] = 'mosh',
['4L 3s'] = 'smi',
['5L 2s'] = 'dia',
['6L 1s'] = 'arch',
['1L 7s'] = 'apine',
['2L 6s'] = 'subar',
['3L 5s'] = 'chk',
['4L 4s'] = 'ttw',
['5L 3s'] = 'onei',
['6L 2s'] = 'ek',
['7L 1s'] = 'pine',
['1L 8s'] = 'ablu',
['2L 7s'] = 'bal',
['3L 6s'] = 'ch',
['4L 5s'] = 'gram',
['5L 4s'] = 'cth',
['6L 3s'] = 'hyru',
['7L 2s'] = 'arm',
['8L 1s'] = 'blu',
['1L 9s'] = 'asi',
['2L 8s'] = 'jar',
['3L 7s'] = 'seph',
['4L 6s'] = 'lime',
['5L 5s'] = 'pw',
['6L 4s'] = 'lem',
['7L 3s'] = 'dico',
['8L 2s'] = 'tar',
['9L 1s'] = 'si'
}
--------------------------------------------------------------------------------
------------------------------ HELPER FUNCTIONS --------------------------------
--------------------------------------------------------------------------------
-- Step ratios are entered as an array of two numeric values, or alternatively,
-- as a ratio as defined by the rational module. If of the former, this helper
-- function converts it to the latter. This preprocess step is for simplifying
-- ratios.
function p.preprocess_step_ratio(step_ratio)
if type(step_ratio) == "string" then
return step_ratio
elseif (type(step_ratio) == "table" and type(step_ratio[1]) == 'number' and type(step_ratio[2]) == 'number') then
return rat.new(step_ratio[1], step_ratio[2])
else
return nil
end
end
-- Mosses for name lookup are entered either as a scalesig or as a mos as
-- defined in the mos module. If of the latter, it's converted into a textual
-- scalesig.
function p.preprocess_scalesig(input_mos)
if type(input_mos) == "string" then
return input_mos
elseif type(input_mos) == "table" then
return mos.as_string(input_mos)
else
return nil
end
end
--------------------------------------------------------------------------------
----------------------------- LOOKUP FUNCTIONS ---------------------------------
--------------------------------------------------------------------------------
-- Function for looking up a mos's name (octave-equivalent mosses only).
-- Can accept either a mos (defined by mos module) or its scalesig.
function p.lookup_name(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
return p.tamnams_name[scalesig]
end
-- Function for looking up a mos's prefix (octave-equivalent mosses only).
-- Can accept either a mos (defined by mos module) or its scalesig.
function p.lookup_prefix(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
return p.tamnams_prefix[scalesig]
end
-- Function for looking up a mos's abbrev (octave-equivalent mosses only).
-- Can accept either a mos (defined by mos module) or its scalesig.
function p.lookup_abbrev(input_mos)
local scalesig = p.preprocess_scalesig(input_mos)
return p.tamnams_abbrev[scalesig]
end
-- Function for looking up a step ratio range
-- Module:Rational is used to help simplify ratios
function p.lookup_step_ratio(step_ratio, use_extended)
local step_ratio = p.preprocess_step_ratio(step_ratio)
local use_extended = use_extended == true
-- Produce the key needed to lookup the step ratio name
-- use_extended is used to toggle between central range and extended range
local key = rat.as_ratio(step_ratio, ':')
local named_ratio = use_extended and p.tamnams_ratios_ext[key] or p.tamnams_ratios[key]
return named_ratio ~= nil and named_ratio or key
end
-- Function for looking up a step ratio range
-- Module:Rational is used to help simplify ratios
function p.lookup_step_ratio_range(step_ratio_1, step_ratio_2, use_extended)
local step_ratio_1 = p.preprocess_step_ratio(step_ratio_1)
local step_ratio_2 = p.preprocess_step_ratio(step_ratio_2)
local use_extended = use_extended == true
-- Produce the key needed for the lookup table as a/b to c/d
-- Swap ratios if ratio 1 has a higher hardness than ratio 2
local key = ""
local float_1 = rat.as_float(step_ratio_1)
local float_2 = rat.as_float(step_ratio_2)
if (float_1 > float_2) then
key = string.format('%s to %s', rat.as_ratio(step_ratio_2, ':'), rat.as_ratio(step_ratio_1, ':'))
else
key = string.format('%s to %s', rat.as_ratio(step_ratio_1, ':'), rat.as_ratio(step_ratio_2, ':'))
end
-- use_extended is used to toggle between central range and extended range
local named_ratio_range = use_extended and p.tamnams_ranges_ext[key] or p.tamnams_ranges[key]
return named_ratio_range ~= nil and named_ratio_range or key
end
function p.lookup_named_ancestor(input_mos)
end
--------------------------------------------------------------------------------
--------------------- MOSSTEP/MOSDEGREE QUALITY FUNCTIONS ----------------------
--------------------------------------------------------------------------------
function p.interval_quality(interval, input_mos, abbrev_format, mos_prefix)
local abbrev_format = abbrev_format or "none"
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos"
-- 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)
-- Decode the quality
local quality = p.decode_quality(interval, input_mos, abbrev_format)
if abbrev_format == "abbrev" or abbrev_format == "ABBREV" then
return string.format("%s%d%ss.", quality, step_count, mos_prefix)
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then
return string.format("%s %d-%ss.", quality, step_count, mos_prefix)
else
return string.format("%s %d-%sstep", quality, step_count, mos_prefix)
end
end
function p.degree_quality(interval, input_mos, abbrev_format, mos_prefix)
local abbrev_format = abbrev_format or "none"
local mos_prefix = p.lookup_prefix(input_mos) or mos_prefix or "mos"
-- 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)
-- Decode the quality
local quality = p.decode_quality(interval, input_mos, abbrev_format)
if abbrev_format == "abbrev" or abbrev_format == "ABBREV" then
return string.format("%s%d%ss.", quality, step_count, mos_prefix)
elseif abbrev_format == "shortened" or abbrev_format == "SHORTENED" then
return string.format("%s %d-%sd.", quality, step_count, mos_prefix)
else
return string.format("%s %d-%sdegree", quality, step_count, mos_prefix)
end
end
-- Decodes the quality of a mosstep. Helper function to interval_quality() and
-- degree_quality(), but can be used standalone if only the keyword (maj, min,
-- aug, perf, dim) is needed. The chroma amounts are as follows:
-- AMT| PERFECTABLE | NONPERFECTABLE | DARK GEN ONLY
-- ---+-----------------+-------------------+------------------
-- ...| . . . | . . . | . . .
-- 4 | 4x augmented | 4x augmented | 5x augmented
-- 3 | 3x augmented | 3x augmented | 4x augmented
-- 2 | 2x augmented | 2x augmented | 3x augmented
-- 1 | augmented | augmented | 4x augmented
-- 0 | perfect | major | augmented
-- -1 | diminished | minor | perfect
-- -2 | 2x diminished | diminished | diminished
-- -3 | 3x diminished | 2x diminished | 2x diminished
-- -4 | 4x diminished | 3x diminished | 3x diminished
-- -5 | 5x diminished | 4x diminished | 4x diminished
-- ...| . . . | . . . | . . .
function p.decode_quality(interval, input_mos, abbrev_format)
-- 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)
-- Determine what "special" type the interval is so that the designations
-- of augmented/perfect/diminished (APd) apply, skipping major/minor (Mm).
-- 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
-- Get chroma count and adjust as needed
local chroma_count = 0
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
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)
end
-- Get absolute value of chroma count
local chroma_abs = math.abs(chroma_count)
local quality = ""
if is_perfectable then
-- Get the quality for perfectable intervals
if abbrev_format == "none" or abbrev_format == "NONE" then
if chroma_count < 0 then
quality = "diminished"
elseif chroma_count > 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 == "shortened" or abbrev_format == "SHORTENED" then
if chroma_count < 0 then
quality = "Dim."
elseif chroma_count > 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 chroma_count < 0 then
quality = "d"
elseif chroma_count > 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
else
-- Get the quality for nonperfectable intervals
-- Is the interval major? If not, decrement chroma_abs by 1
local is_positive = chroma_count >= 0
chroma_abs = is_positive and chroma_abs or chroma_abs - 1
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 == "shortened" or abbrev_format == "SHORTENED" 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
end
return quality
end
--------------------------------------------------------------------------------
----------------------------- TESTER FUNCTION ----------------------------------
--------------------------------------------------------------------------------
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(6,5), rat.new(1,1), true)
local abbrev_code = "abbrev"
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.interval_quality({['L']= 6,['s']=-4}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']= 5,['s']=-3}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']= 4,['s']=-2}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']= 3,['s']=-1}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']= 2,['s']= 0}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']= 1,['s']= 1}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']= 0,['s']= 2}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']=-1,['s']= 3}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']=-2,['s']= 4}, input_mos, abbrev_code) .. "\n" ..
p.interval_quality({['L']=-3,['s']= 5}, input_mos, abbrev_code)
return p.decode_quality({['L']=2,['s']=1}, input_mos, abbrev_code)
end
return p