|
|
| Line 5: |
Line 5: |
| local tip = require('Module:Template input parse') | | local tip = require('Module:Template input parse') |
| local p = {} | | local p = {} |
|
| |
| -- Helper function that parses entries from a semicolon-delimited string and returns them in an array
| |
| function p.parse_entries(unparsed)
| |
| local parsed = {}
| |
| for entry in string.gmatch(unparsed, '([^;]+)') do
| |
| table.insert(parsed, entry) -- Add to array
| |
| end
| |
| return parsed
| |
| end
| |
|
| |
|
| -- Helper function | | -- Helper function |
| Line 71: |
Line 62: |
| | | |
| return sentence | | return sentence |
| end
| |
|
| |
| -- Helper function
| |
| -- Introduces the mos by its step counts and number of periods
| |
| -- This is meant to immediately follow the sentence provided by:
| |
| -- - mos_intro_tamnams_names()
| |
| function p.mos_intro_steps_and_periods(input_mos)
| |
| local input_mos = input_mos or mos.new(3, 6, 3)
| |
|
| |
| -- Get the equave and the equave in cents
| |
| local equave = input_mos.equave
| |
| local equave_in_cents = rat.cents(equave)
| |
| local equave_as_ratio = rat.as_ratio(equave)
| |
|
| |
| -- Get the step counts and number of periods
| |
| local nL = input_mos.nL -- Number of large steps per equave
| |
| local ns = input_mos.ns -- Number of small steps per equave
| |
| local n = utils._gcd(nL, ns) -- Number of periods
| |
| local x = round(nL / n) -- Number of large steps per period
| |
| local y = round(ns / n) -- Number of small steps per period
| |
|
| |
| -- Construct the sentence
| |
| sentence = " is "
| |
|
| |
| -- Is the scale nonoctave?
| |
| if equave_in_cents == 1200 then
| |
| sentence = sentence .. string.format("an [[octave equivalence|octave-equivalent]] [[moment of symmetry]] scale")
| |
| else
| |
| sentence = sentence .. string.format("a [[non-octave]] [[moment of symmetry]] scale", equave_as_ratio)
| |
| end
| |
|
| |
| -- What are the step counts? Should the word "step" contain an s?
| |
| local s_nl = ""
| |
| local s_ns = ""
| |
| if nL ~= 1 then
| |
| s_nl = "s"
| |
| end
| |
| if ns ~= 1 then
| |
| s_ns = "s"
| |
| end
| |
| sentence = sentence .. string.format(" containing %d large step%s and %d small step%s", nL, s_nl, ns, s_ns)
| |
|
| |
| -- How large is the period in cents? Round to 3 decimal places
| |
| local round = 3
| |
| local equave_rounded = tostring(utils._round_dec(equave_in_cents, round))
| |
| local period_rounded = tostring(utils._round_dec(equave_in_cents / n, round))
| |
| -- Should step be singular or plural?
| |
| local s_x = ""
| |
| local s_y = ""
| |
| local repetition = ""
| |
| if x ~= 1 then
| |
| s_x = "s"
| |
| end
| |
| if y ~= 1 then
| |
| s_y = "s"
| |
| end
| |
| if n == 2 then
| |
| repetition = "twice"
| |
| elseif n > 2 then
| |
| repetition = string.format("%d times", n)
| |
| end
| |
| if n == 1 and equave_in_cents == 1200 then
| |
| sentence = sentence .. string.format(", repeating every [[octave]].")
| |
| elseif n == 1 and equave_in_cents ~= 1200 then
| |
| sentence = sentence .. string.format(", repeating every interval of [[%s]] (%s¢).", equave_as_ratio, equave_rounded)
| |
| elseif n ~= 1 and equave_in_cents == 1200 then
| |
| sentence = sentence .. string.format(", with a [[period]] of %d large step%s and %d small step%s", x, s_x, y, s_y)
| |
| sentence = sentence .. string.format(" that repeats every %s¢, or %s every [[octave]].", period_rounded, repetition)
| |
| elseif n ~= 1 and equave_in_cents ~= 1200 then
| |
| sentence = sentence .. string.format(", with a [[period]] of %d large step%s and %d small step%s", x, s_x, y, s_y)
| |
| sentence = sentence .. string.format(" that repeats every %s¢, or %s every interval of %s (%s¢).", period_rounded, repetition, equave_as_ratio, equave_rounded)
| |
| end
| |
|
| |
| return sentence
| |
| end
| |
|
| |
| -- Helper function
| |
| -- Calculates the brightest mode of the true mos
| |
| function p.mos_intro_step_pattern(input_mos)
| |
| local input_mos = input_mos or mos.new(5, 2)
| |
|
| |
| local brightest_mode = mos.brightest_mode(input_mos)
| |
|
| |
| local sentence = string.format("[[mode|Modes]] of this scale are rotations of the step pattern '''%s'''.", brightest_mode)
| |
|
| |
| return sentence
| |
| end
| |
|
| |
| -- Helper function
| |
| -- Calculates the generator ranges of the mos
| |
| function p.mos_intro_generator_ranges(input_mos)
| |
| local input_mos = input_mos or mos.new(5, 2)
| |
|
| |
| -- Get the step counts and number of periods
| |
| local nL = input_mos.nL -- Number of large steps per equave
| |
| local ns = input_mos.ns -- Number of small steps per equave
| |
| local n = utils._gcd(nL, ns) -- Number of periods
| |
|
| |
| -- Get the equave as a ratio and in cents
| |
| local equave = input_mos.equave
| |
| local equave_in_cents = rat.cents(equave)
| |
|
| |
| -- Get the eds (ets) corresponding to the collapsed and equalized mosses
| |
| local collapsed_et = et.new(nL, input_mos.equave)
| |
| local equalized_et = et.new(nL + ns, input_mos.equave)
| |
|
| |
| -- Get the sizes of the bright generator for the collapsed and equalized et in steps
| |
| -- These are used to calculate cent values for the generators
| |
| -- The values for the dark generator are the period complements
| |
| local generator = mos.bright_gen(input_mos)
| |
| local gen_collapsed_in_steps = generator["L"]
| |
| local gen_equalized_in_steps = generator["L"] + generator["s"]
| |
| local bright_gen_max = et.cents(collapsed_et, gen_collapsed_in_steps)
| |
| local bright_gen_min = et.cents(equalized_et, gen_equalized_in_steps)
| |
|
| |
| local dark_gen_min = equave_in_cents / n - bright_gen_max
| |
| local dark_gen_max = equave_in_cents / n - bright_gen_min
| |
|
| |
| -- Round values
| |
| local round = 3
| |
| local bright_gen_min_r = tostring(utils._round_dec(bright_gen_min, round))
| |
| local bright_gen_max_r = tostring(utils._round_dec(bright_gen_max, round))
| |
| local dark_gen_min_r = tostring(utils._round_dec(dark_gen_min, round))
| |
| local dark_gen_max_r = tostring(utils._round_dec(dark_gen_max, round))
| |
|
| |
| local sentence = string.format("[[generator|Generators]] that produce this scale range from %s¢ to %s¢, or from %s¢ to %s¢.", bright_gen_min_r, bright_gen_max_r, dark_gen_min_r, dark_gen_max_r)
| |
|
| |
| return sentence
| |
| end
| |
|
| |
| -- Function that creates a mos intro, given a mos and any other names
| |
| -- Intro (or lead section) consists of multiple sentences, and each is called individually
| |
| function p.mos_intro(input_mos, other_names)
| |
| local input_mos = input_mos or mos.new(5, 2)
| |
| local other_names = other_names or "name1; name2; name3"
| |
|
| |
| -- Get the scale sig
| |
| local scale_sig = mos.as_string(input_mos)
| |
|
| |
| -- Get tamnams names
| |
| local tamnams_name = mos.tamnams_name[scale_sig] or ""
| |
|
| |
| -- Parse names
| |
| local tamnams_parsed = p.parse_entries(tamnams_name)
| |
| local other_parsed = p.parse_entries(other_names)
| |
|
| |
| -- Construct the sentence
| |
| local scalesig_and_names = p.mos_intro_names(scale_sig, tamnams_parsed, other_parsed)
| |
| local steps_and_periods = p.mos_intro_steps_and_periods(input_mos)
| |
| local step_pattern = p.mos_intro_step_pattern(input_mos)
| |
| local gens = p.mos_intro_generator_ranges(input_mos)
| |
|
| |
| return string.format("%s %s %s %s", scalesig_and_names, steps_and_periods, step_pattern, gens)
| |
| end | | end |
|
| |
|
| Line 258: |
Line 96: |
| | | |
| -- Add equave equivalence | | -- Add equave equivalence |
| intro = intro .. (equave_in_cents == 1200 and " is an [[octave equivalence|octave-equivalent]] [[moment of symmetry]] scale" or "is a [[nonoctave|non-octave]] [[moment of symmetry scale]]") | | intro = intro .. (equave_in_cents == 1200 and " is an [[octave equivalence|octave-equivalent]] [[moment of symmetry]] scale" or "is a [[nonoctave|non-octave]] [[moment of symmetry]] scale") |
| | | |
| -- Add step counts | | -- Add step counts |