Module:TAMNAMS: Difference between revisions

Ganaram inukshuk (talk | contribs)
Added base functionality for quality-decode function (large/small -> MmAPd)
Ganaram inukshuk (talk | contribs)
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 (#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
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 scalesig
local scalesig = p.preprocess_scalesig(input_mos)
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 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 scalesig
local scalesig = p.preprocess_scalesig(input_mos)
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 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 scalesig
local scalesig = p.preprocess_scalesig(input_mos)
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 298: Line 300:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-------------------------- ENCODE/DECODE FUNCTIONS -----------------------------
--------------------- MOSSTEP/MOSDEGREE QUALITY FUNCTIONS ----------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


function p.decode_interval_quality(interval, input_mos, abbrev_format, mos_prefix)
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
local quality = ""
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
quality = p.chroma_count_to_perfectable_interval_quality(chroma_count, abbrev_format)
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)
quality = p.chroma_count_to_nonperfectable_interval_quality(chroma_count, abbrev_format)
end
end
return string.format("%s %d-%s%s", quality, step_count, mos_prefix, abbrev_format == "none" and "step" or "s")
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
-- Get absolute value of chroma count
local chroma_abs = math.abs(chromas)
local chroma_abs = math.abs(chroma_count)
-- Get quality
local quality = ""
local quality = ""
if abbrev_format == "none" or abbrev_format == "NONE" then
if is_perfectable then
if chromas < 0 then
-- Get the quality for perfectable intervals
quality = "diminished"
elseif chromas > 0 then
quality = "augmented"
else
quality = "perfect"
end
if chroma_abs > 1 then
if abbrev_format == "none" or abbrev_format == "NONE" then
quality = string.format("%d× %s", chroma_abs, quality)
if chroma_count < 0 then
end
quality = "diminished"
elseif abbrev_format == "short" or abbrev_format == "SHORT" then
elseif chroma_count > 0 then
if chromas < 0 then
quality = "augmented"
quality = "Dim."
else
elseif chromas > 0 then
quality = "perfect"
quality = "Aug."
end
else
quality = "Perf."
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
if chroma_abs > 1 then
-- Is the interval major? If not, decrement chroma_abs by 1
quality = string.format("%d× %s", chroma_abs, quality)
local is_positive = chroma_count >= 0
end
chroma_abs = is_positive and chroma_abs or chroma_abs - 1
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
if abbrev_format == "none" or abbrev_format == "NONE" then
quality = string.format("%s<sup>%d</sup>", quality, chroma_abs)
if chroma_abs > 0 and is_positive then
elseif chroma_abs > 1 and chroma_abs <= 3 then
quality = "augmented"
quality = string.rep(quality, chroma_abs)
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 = "short"
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.decode_interval_quality({['L']= 6,['s']=-4}, input_mos, abbrev_code) .. "\n" ..
p.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.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.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.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.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.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.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.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.interval_quality({['L']=-2,['s']= 4}, input_mos, abbrev_code) .. "\n" ..
p.decode_interval_quality({['L']=-3,['s']= 5}, input_mos, abbrev_code)
p.interval_quality({['L']=-3,['s']= 5}, input_mos, abbrev_code)
return output_string
return p.decode_quality({['L']=2,['s']=1}, input_mos, abbrev_code)
end
end


return p
return p