Module:TAMNAMS: Difference between revisions

Ganaram inukshuk (talk | contribs)
m Code readability
Ganaram inukshuk (talk | contribs)
Separated some functions, rewrote udp function to accept alterations and made periods an optional arg
Line 680: Line 680:
-- If only u is known, then d = p - u - 1.
-- If only u is known, then d = p - u - 1.
-- If only d is known, then u = p - d - 1. (Basically, u + d + 1 = steps/p.)
-- If only d is known, then u = p - d - 1. (Basically, u + d + 1 = steps/p.)
function p.udp(gens_up_per_period, gens_down_per_period, periods)
-- A table of alterations can also be passed in, assuming they are already
-- written out (EG, d3md or, if notation is established, b4).
function p.udp_as_string(gens_up_per_period, gens_down_per_period, periods, alterations)
local periods = periods or 1
local alterations_as_string = ""
if alterations ~= nil then
for i = 1, #alterations do
alterations_as_string = alterations_as_string .. " " .. alterations[i]
end
end
if periods == 1 then
if periods == 1 then
return string.format("%s|%s", gens_up_per_period, gens_down_per_period)
return string.format("%s|%s", gens_up_per_period, gens_down_per_period) .. alterations_as_string
else
else
return string.format("%s|%s(%s)", gens_up_per_period * periods, gens_down_per_period * periods, periods)
return string.format("%s|%s(%s)", gens_up_per_period * periods, gens_down_per_period * periods, periods) .. alterations_as_string
end
end
end
end
Line 699: Line 708:
local gens_down = steps_per_period - gens_up - 1
local gens_down = steps_per_period - gens_up - 1
local udp = p.udp(gens_up, gens_down, period_count)
local udp = p.udp_as_string(gens_up, gens_down, period_count)
table.insert(udps, udp)
table.insert(udps, udp)
end
end
Line 734: Line 743:
-- are returned as a string.
-- are returned as a string.
-- NOTES:
-- NOTES:
-- - It's advised to use this for modmosses as this is less efficient if
-- - A period of repetition will always have as many modes as there are steps
--  used on true-mos modes. Conversely, since modal brightness doesn't make
--  in that period. If it were any less, then the true period of repetition
--  much sense for modmosses, it's advised to use this for modmosses.
--  is a substring of that.
-- - There will always be as many modes as there are steps in a period of
--  repetition, even if a modmos's period of repetition spans more than one
--  period of the original mos. EG, LLsLsLss and LLssLLss are modmosses of
--  4L 4s (LsLsLsLs), and their periods are 8, 4, and 2 steps respectively,
--  meaning they have 8, 4, and 2 unique modes respectively. Also, only the 1st
--  period of repetition is needed, as other modes reached by rotation after
--  that are literally redendant.
-- - If the step pattern is for a modmos, then the closest brightest mode will
--  be returned by default. The darkest can be returned instead.
function p.mode_rotation_udps(input_mode, input_mos, mos_abbrev, use_brightest_mode_search)
function p.mode_rotation_udps(input_mode, input_mos, mos_abbrev, use_brightest_mode_search)
local use_brightest_mode_search = use_brightest_mode_search == nil or use_brightest_mode_search
local use_brightest_mode_search = use_brightest_mode_search == nil or use_brightest_mode_search
Line 762: Line 762:
-- by its altered scale degrees. Alterations require a mos abbrev, which is
-- by its altered scale degrees. Alterations require a mos abbrev, which is
-- automatically looked up, defaulting to "m" if no abbrev can be found.
-- automatically looked up, defaulting to "m" if no abbrev can be found.
-- NOTES:
-- - This is inefficient when used on true-mos modes since it's a brute-force
--  search for what mode it's closest to. It is, however, effective on
--  modmosses, which is the primary use for this function.
function p.mode_udp(input_mode, input_mos, mos_abbrev, use_brightest_mode_search)
function p.mode_udp(input_mode, input_mos, mos_abbrev, use_brightest_mode_search)
local use_brightest_mode_search = use_brightest_mode_search == nil or use_brightest_mode_search
local use_brightest_mode_search = use_brightest_mode_search == nil or use_brightest_mode_search
Line 770: Line 774:
-- For each mode, count the number of differences between each true mode
-- For each mode, count the number of differences between each true mode
-- and the entered mode and keep track of which mode has the fewest diffs.
-- and the entered mode and keep track of which mode has the fewest diffs.
-- That mode is considered the closest mode, whose UDP will be used for the
-- mode name, followed by which scale degrees are changed.
-- If the number of diffs is ever zero, then the entered mode was a true-mos
-- If the number of diffs is ever zero, then the entered mode was a true-mos
-- mode and has zero alterations.
-- mode and has zero alterations.
local lowest_differences = #input_mode_as_step_matrix
local lowest_differences = #input_mode_as_step_matrix
local bright_gens_down_per_period = 0
local bright_gens_down_per_period = 0
local closest_mode_as_step_matrix = true_modes[1]
local differences = {}
for i = 1, #true_modes do
for i = 1, #true_modes do
local differences = 0
local current_true_mode = true_modes[i]
local current_true_mode = true_modes[i]
local current_differences = p.differences_between_modes(current_true_mode, input_mode_as_step_matrix)
for j = 1, #input_mode_as_step_matrix do
-- It's possible for more than one mode to be closest. The tiebreaker is
local mode_interval = input_mode_as_step_matrix[j]
-- whichever mode is brightest (or darkest, which can be toggled).
-- If j is greater than the number of intervals in the current true
-- mode, then the interval being accessed is an extra-equave
-- interval. Instead of accessing the jth interval (which would lead
-- to a nil error), instead access the corresponding equave-reduced
-- interval, then raise it by the necessary number of equaves.
local true_interval = {}
if j > #current_true_mode then
local current_mossteps = j - 1
local equave_step_count = mos.equave_step_count(input_mos)
local equave_reduced_interval = current_true_mode[current_mossteps % equave_step_count + 1]
local equave_count = math.floor(current_mossteps / equave_step_count)
local equaves = mos.interval_mul(mos.equave(input_mos), equave_count)
true_interval = mos.interval_add(equave_reduced_interval, equaves)
else
true_interval = current_true_mode[j]
end
if not mos.interval_eq(mode_interval, true_interval) then
differences = differences + 1
end
end
if use_brightest_mode_search then
if use_brightest_mode_search then
if differences < lowest_differences then
if #current_differences < lowest_differences then
-- Brightest-closest match
bright_gens_down_per_period = i - 1
bright_gens_down_per_period = i - 1
lowest_differences = differences
lowest_differences = #current_differences
closest_mode_as_step_matrix = current_true_mode
differences = current_differences
end
end
else
else
if differences <= lowest_differences then
if #current_differences <= lowest_differences then
-- Darkest-closest match
bright_gens_down_per_period = i - 1
bright_gens_down_per_period = i - 1
lowest_differences = differences
lowest_differences = #current_differences
closest_mode_as_step_matrix = current_true_mode
differences = current_differences
end
end
end
end
end
-- Parse the differences as scale degrees.
-- The differences between the true mode and the input mode are denoted as
-- interval vectors. These should be parsed into a list of altered scale
-- degrees before being passed into udp_as_string. Coding it this way allows
-- for the possibility of adding custom mos notation (EG, diamond-mos).
local alterations = {}
for i = 1, #differences do
table.insert(alterations, p.degree_quality(differences[i], input_mos, "ABBREV", mos_abbrev))
end
end
Line 823: Line 818:
local period_count = mos.period_count(input_mos)
local period_count = mos.period_count(input_mos)
local bright_gens_up_per_period = mos.period_step_count(input_mos) - 1 - bright_gens_down_per_period
local bright_gens_up_per_period = mos.period_step_count(input_mos) - 1 - bright_gens_down_per_period
udp = p.udp(bright_gens_up_per_period, bright_gens_down_per_period, period_count)
udp = p.udp_as_string(bright_gens_up_per_period, bright_gens_down_per_period, period_count, alterations)
-- Produce the list of alterations, if the mode is for a modmos.
return udp
local alterations = ""
end
local closest_true_mode = true_modes[bright_gens_down_per_period + 1]
 
if lowest_differences > 0 then
--------------------------------------------------------------------------------
for i = 1, #input_mode_as_step_matrix do
------------------------- MODE COMPARING FUNCTIONS -----------------------------
mode_interval = input_mode_as_step_matrix[i]
--------------------------------------------------------------------------------
 
-- Helper function for mode_udp, but can be used standalone.
-- Given two modes as step matrices, produce a list of differences between the
-- base mode and the altered mode. Diffs are listed as an array of mosstep
-- vectors (a table containing the number of L's and s's for that interval).
function p.differences_between_modes(base_step_matrix, altered_step_matrix)
local differences = {}
for i = 1, #altered_step_matrix do
local altered_interval = altered_step_matrix[i]
-- If i is greater than the number of intervals in base_step_matrix,
-- then the interval being accessed is an extra-equave interval. Instead
-- of accessing the ith interval (which would lead to a nil error),
-- access the corresponding equave-reduced interval, then raise it by
-- the necessary number of equaves.
local base_interval = {}
if i > #base_step_matrix then
local current_mossteps = i - 1
local equave_step_count = #base_step_matrix - 1
local equave_interval = base_step_matrix[#base_step_matrix]
-- If i is greater than the number of intervals in the current true
local equave_reduced_interval = base_step_matrix[current_mossteps % equave_step_count + 1]
-- mode, then the interval being accessed is an extra-equave
local equave_count = math.floor(current_mossteps / equave_step_count)
-- interval. Instead of accessing the ith interval (which would lead
-- to a nil error), instead access the corresponding equave-reduced
-- interval, then raise it by the necessary number of equaves.
local true_interval = {}
if i > #closest_true_mode then
local current_mossteps = i - 1
local equave_step_count = mos.equave_step_count(input_mos)
local equave_reduced_interval = closest_true_mode[current_mossteps % equave_step_count + 1]
local equave_count = math.floor(current_mossteps / equave_step_count)
local equaves = mos.interval_mul(mos.equave(input_mos), equave_count)
true_interval = mos.interval_add(equave_reduced_interval, equaves)
else
true_interval = closest_true_mode[i]
end
if not mos.interval_eq(mode_interval, true_interval) then
local equaves = mos.interval_mul(equave_interval, equave_count)
altered_degree = p.degree_quality(mode_interval, input_mos, "ABBREV", mos_abbrev)
base_interval = mos.interval_add(equave_reduced_interval, equaves)
alterations = alterations .. " " .. altered_degree
else
end
base_interval = base_step_matrix[i]
end
if not mos.interval_eq(base_interval, altered_interval) then
table.insert(differences, altered_interval)
end
end
end
end
return udp .. alterations
return differences
end
end


Line 872: Line 878:
output_ = output_ .. "LLsLsAs" .. " " .. p.mode_udp("LLsLsAs", mos.new(5,2))
output_ = output_ .. "LLsLsAs" .. " " .. p.mode_udp("LLsLsAs", mos.new(5,2))
return p.mode_rotation_udps("sAsLsAs", mos.new(5, 2), "m", false)
return p.mode_rotation_udps("LsLLsAs", mos.new(5, 2), "m", true)
--return p.degree_quality({4, -1}, mos.new(5,2), "ABBREV", 'm')
--return p.degree_quality({4, -1}, mos.new(5,2), "ABBREV", 'm')