Module:TAMNAMS: Difference between revisions
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 | ||