|
|
| Line 6: |
Line 6: |
| local tamnams = require('Module:TAMNAMS') | | local tamnams = require('Module:TAMNAMS') |
| local p = {} | | local p = {} |
|
| |
| -- TODO:
| |
| -- - Adopt mos arithmetic functions provided by mos module
| |
|
| |
| -- Helper function that turns a mosstep into a step count as a string
| |
| -- EG, the 3-mosstep of "LLsLsLs" becomes "2L + s"
| |
| function p.mos_interval_to_step_count_string(step_pattern, mossteps)
| |
| local L_count = 0
| |
| local s_count = 0
| |
| for i = 1, mossteps do
| |
| local step = string.sub(step_pattern, i, i)
| |
| if step == "L" then
| |
| L_count = L_count + 1
| |
| elseif step == "s" then
| |
| s_count = s_count + 1
| |
| end
| |
| end
| |
|
| |
| -- There are 9 combinations to write xL + ys, based on whether x and y are
| |
| -- 0, 1, or greater than 1
| |
| local return_string = ""
| |
| if L_count == 0 and s_count == 0 then
| |
| return_string = "0"
| |
| elseif L_count == 0 and s_count == 1 then
| |
| return_string = "s"
| |
| elseif L_count == 0 and s_count > 1 then
| |
| return_string = s_count .. "s"
| |
| elseif L_count == 1 and s_count == 0 then
| |
| return_string = "L"
| |
| elseif L_count == 1 and s_count == 1 then
| |
| return_string = "L + s"
| |
| elseif L_count == 1 and s_count > 1 then
| |
| return_string = "L + " .. s_count .. "s"
| |
| elseif L_count > 1 and s_count == 0 then
| |
| return_string = L_count .. "L"
| |
| elseif L_count > 1 and s_count == 1 then
| |
| return_string = L_count .. "L + s"
| |
| else
| |
| return_string = L_count .. "L + " .. s_count .. "s"
| |
| end
| |
| return return_string
| |
| end
| |
|
| |
| -- Helper function
| |
| -- Produces the cent range of a mosstep
| |
| function p.mos_interval_to_cent_range(step_pattern, mossteps, input_mos)
| |
| local step_pattern = step_pattern or "LLsLLLs"
| |
| local mossteps = mossteps or 1
| |
| local input_mos = input_mos or mos.new(5, 5, 2)
| |
|
| |
| local L_count = 0
| |
| local s_count = 0
| |
| for i = 1, mossteps do
| |
| local step = string.sub(step_pattern, i, i)
| |
| if step == "L" then
| |
| L_count = L_count + 1
| |
| elseif step == "s" then
| |
| s_count = s_count + 1
| |
| end
| |
| end
| |
|
| |
| -- The range of a small step is from 0 to 1 step of the equalized mos
| |
| -- The range of a large step is from 1 step of equalized to 1 step of collapsed
| |
| -- These ranges do not apply if the mosstep interval is for a period; instead
| |
| -- it's a fixed value.
| |
| local equave_in_cents = rat.cents(input_mos.equave)
| |
| local s_size_min = 0
| |
| local s_size_max = equave_in_cents / (input_mos.nL + input_mos.ns)
| |
| local L_size_min = s_size_max
| |
| local L_size_max = equave_in_cents / input_mos.nL
| |
| local mossteps_per_period = (input_mos.nL + input_mos.ns) / utils._gcd(input_mos.nL, input_mos.ns)
| |
| local is_period = mossteps % mossteps_per_period == 0
| |
|
| |
| local result = ""
| |
| if not is_period then
| |
| local min_cents = L_count * L_size_min + s_count * s_size_max
| |
| local max_cents = L_count * L_size_max + s_count * s_size_min
| |
| result = string.format("%.1f¢ to %.1f¢", math.min(min_cents, max_cents), math.max(min_cents, max_cents))
| |
| else
| |
| local period_in_cents = equave_in_cents / utils._gcd(input_mos.nL, input_mos.ns)
| |
| local number_of_periods = mossteps / mossteps_per_period
| |
| result = string.format("%.1f¢", period_in_cents * number_of_periods)
| |
| end
| |
| return result
| |
| end
| |
|
| |
|
| -- Main function; to be called by wrapper | | -- Main function; to be called by wrapper |
| Line 101: |
Line 16: |
| local scale_sig = mos.as_string(input_mos) | | local scale_sig = mos.as_string(input_mos) |
| | | |
| -- Get the brightest and darkest modes for the mos | | -- Get the brightest and darkest modes as step matrices |
| local brightest_mode = mos.brightest_mode(input_mos) | | local bright_step_matrix = mos.mode_to_step_matrix(mos.brightest_mode(input_mos)) |
| local darkest_mode = string.reverse(brightest_mode) | | local dark_step_matrix = mos.mode_to_step_matrix(mos.darkest_mode(input_mos)) |
| | | |
| -- Get the number of steps per period and equave | | -- Get the number of steps per period and equave |
| local steps_per_equave = (input_mos.nL + input_mos.ns) | | local equave_step_count = mos.equave_step_count(input_mos) |
| local steps_per_period = steps_per_equave / utils._gcd(input_mos.nL, input_mos.ns) | | local period_step_count = mos.period_step_count(input_mos) |
| | | |
| -- Get the step counts for the bright and dark generators | | -- Get the step counts for the bright and dark generators |
| local bright_gen = mos.bright_gen(input_mos) | | local bright_gen_step_count = mos.bright_gen_step_count(input_mos) |
| local steps_per_bright_gen = bright_gen['L'] + bright_gen['s'] | | local dark_gen_step_count = mos.dark_gen_step_count(input_mos) |
| local steps_per_dark_gen = steps_per_period - steps_per_bright_gen
| |
| | | |
| -- Create the table, starting with the headers | | -- Create the table, starting with the headers |
| Line 126: |
Line 40: |
| result = result .. '! Range in cents\n' | | result = result .. '! Range in cents\n' |
| | | |
| -- First row is the unison | | -- Write each row |
| result = result .. "|-\n" | | for i = 1, #bright_step_matrix do |
| result = result .. "| '''0-" .. mos_prefix .. "step (root)'''\n"
| | |
| result = result .. "| Perfect 0-" .. mos_prefix .. "step\n"
| | -- Compare the bright and dark intervals. If they're the same, then the |
| result = result .. "| 0\n"
| | -- current interval class is a period interval. |
| result = result .. string.format("| %.1f¢\n", 0)
| | local current_bright_interval = bright_step_matrix[i] |
| result = result .. string.format("| P0ms\n")
| | local current_dark_interval = dark_step_matrix[i] |
|
| | local is_period = mos.interval_eq(current_bright_interval, current_dark_interval) |
| -- Successive rows are the mossteps, starting at the 1-mosstep
| | |
| -- Name the interval according to whether it's major/minor or
| | -- If it's a period interval, then there is only one row to write. |
| -- perf/aug/dim; for nL ns mosses, it's only major/minor for any
| | -- Otherwise, there are two rows to write. |
| -- non-period intervals.
| | if is_period then |
| local is_nL_ns = input_mos.nL == input_mos.ns
| |
| for i = 1, steps_per_equave - 1 do
| |
| if i % steps_per_period == steps_per_bright_gen and not is_nL_ns then | |
| -- If i corresponds to the bright generator, then the large size is
| |
| -- perfect and the small size is diminished. Add two rows.
| |
| result = result .. "|-\n" | | result = result .. "|-\n" |
| result = result .. '| rowspan="2" ' .. "| '''" .. i .. "-" .. mos_prefix .. "step'''\n" | | result = result .. string.format("| '''%s-%sstep'''\n", i-1, mos_prefix) |
| result = result .. "| Diminished " .. i .. "-" .. mos_prefix .. "step\n"
| | result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos)) |
| result = result .. "| " .. p.mos_interval_to_step_count_string(darkest_mode, i) .. "\n"
| | result = result .. string.format("| %s\n" , mos.interval_as_string(current_bright_interval)) |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(darkest_mode, i, input_mos)) | | result = result .. string.format("| %d¢\n", mos.interval_to_cents(current_bright_interval, input_mos, {1,1})) |
| result = result .. string.format("| d%ims\n", i) | | result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos, "abbrev", "m")) |
| result = result .. "|-\n"
| | else |
| result = result .. "| Perfect " .. i .. "-" .. mos_prefix .. "step\n"
| |
| result = result .. "| " .. p.mos_interval_to_step_count_string(brightest_mode, i) .. "\n"
| |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(brightest_mode, i, input_mos)) | |
| result = result .. string.format("| P%ims\n", i) | |
|
| |
| elseif i % steps_per_period == steps_per_dark_gen and not is_nL_ns then
| |
| -- If i corresponds to the dark generator, then the large size is
| |
| -- augmented and the small size is perfect. Add two rows.
| |
| result = result .. "|-\n"
| |
| result = result .. '| rowspan="2" ' .. "|'''" .. i .. "-" .. mos_prefix .. "step'''\n"
| |
| result = result .. "| Perfect " .. i .. "-" .. mos_prefix .. "step\n"
| |
| result = result .. "| " .. p.mos_interval_to_step_count_string(darkest_mode, i) .. "\n"
| |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(darkest_mode, i, input_mos))
| |
| result = result .. string.format("| P%ims\n", i)
| |
| result = result .. "|-\n" | | result = result .. "|-\n" |
| result = result .. "| Augmented " .. i .. "-" .. mos_prefix .. "step\n" | | result = result .. string.format("| rowspan=\"2\" | '''%s-%sstep'''\n", i-1, mos_prefix) |
| result = result .. "| " .. p.mos_interval_to_step_count_string(brightest_mode, i) .. "\n" | | result = result .. string.format("| %s\n" , tamnams.interval_quality(current_dark_interval, input_mos)) |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(brightest_mode, i, input_mos)) | | result = result .. string.format("| %s\n" , mos.interval_as_string(current_dark_interval)) |
| result = result .. string.format("| A%ims\n", i) | | result = result .. string.format("| %.3f¢ to %.3f¢\n", mos.interval_to_cents(current_dark_interval, input_mos, {1,1}), mos.interval_to_cents(current_dark_interval, input_mos, {1,0})) |
| | result = result .. string.format("| %s\n" , tamnams.interval_quality(current_dark_interval, input_mos, "abbrev", "m")) |
| | | |
| elseif i % steps_per_period == 0 and i ~= mossteps_per_equave then
| |
| -- If i corresponds to the period, then the large and small sizes are
| |
| -- the same and they're perfect. This also applies to the equave. Add one row.
| |
| result = result .. "|-\n" | | result = result .. "|-\n" |
| result = result .. "| '''" .. i .. "-" .. mos_prefix .. "step (period)'''\n"
| | result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos)) |
| result = result .. "| Perfect " .. i .. "-" .. mos_prefix .. "step\n"
| | result = result .. string.format("| %s\n" , mos.interval_as_string(current_bright_interval)) |
| result = result .. "| " .. p.mos_interval_to_step_count_string(darkest_mode, i) .. "\n"
| | result = result .. string.format("| %.3f¢ to %.3f¢\n", mos.interval_to_cents(current_bright_interval, input_mos, {1,1}), mos.interval_to_cents(current_dark_interval, input_mos, {1,0})) |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(darkest_mode, i, input_mos)) | | result = result .. string.format("| %s\n" , tamnams.interval_quality(current_bright_interval, input_mos, "abbrev", "m")) |
| result = result .. string.format("| P%ims\n", i) | |
|
| |
| else
| |
| -- For any other interval, and for generators for nL ns mosses, the
| |
| -- large size is major and the small size is minor. Add two rows.
| |
| result = result .. "|-\n"
| |
| result = result .. '| rowspan="2" ' .. "|" .. i .. "-" .. mos_prefix .. "step\n"
| |
| result = result .. "| Minor " .. i .. "-" .. mos_prefix .. "step\n"
| |
| result = result .. "|" .. p.mos_interval_to_step_count_string(darkest_mode, i) .. "\n"
| |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(darkest_mode, i, input_mos)) | |
| result = result .. string.format("| m%ims\n", i)
| |
| result = result .. "|-\n"
| |
| result = result .. "| Major " .. i .. "-" .. mos_prefix .. "step\n"
| |
| result = result .. "| " .. p.mos_interval_to_step_count_string(brightest_mode, i) .. "\n"
| |
| result = result .. string.format("| %s\n", p.mos_interval_to_cent_range(brightest_mode, i, input_mos)) | |
| result = result .. string.format("| M%ims\n", i)
| |
|
| |
| end | | end |
| end
| | |
|
| |
| -- Add the last row of the table, which is either the equave or octave
| |
| local equave_name = ""
| |
| if rat.eq(input_mos.equave, 2) then
| |
| result = result .. "|-\n"
| |
| result = result .. "| '''" .. steps_per_equave .. "-" .. mos_prefix .. "step (octave)'''\n"
| |
| result = result .. "| Perfect " .. steps_per_equave .. "-" .. mos_prefix .. "step'''\n"
| |
| result = result .. "| " .. p.mos_interval_to_step_count_string(darkest_mode, steps_per_equave) .. "\n"
| |
| result = result .. string.format("| %.1f¢\n", 1200)
| |
| result = result .. string.format("| P%ims\n", steps_per_equave)
| |
| else
| |
| result = result .. "|-\n"
| |
| result = result .. "| '''" .. steps_per_equave .. "-" .. mos_prefix .. "step (equave)'''\n"
| |
| result = result .. "| Perfect " .. steps_per_equave .. "-" .. mos_prefix .. "step'''\n"
| |
| result = result .. "| " .. p.mos_interval_to_step_count_string(darkest_mode, steps_per_equave) .. "\n"
| |
| result = result .. string.format("| %.1f¢\n", rat.cents(input_mos.equave))
| |
| result = result .. string.format("| P%ims\n", steps_per_equave)
| |
| end | | end |
| | | |