ホーム
おまかせ表示
ログイン
設定
Xenharmonic Wikiについて
免責事項
Xenharmonic Wiki
検索
モジュール:MOSのソースを表示
←
モジュール:MOS
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループに属する利用者のみが実行できます:
登録利用者
。
このページのソースの閲覧やコピーができます。
-- Module for working with mosses in lua code; this serves as a "library" for -- mos-related modules and thus does not have a corresponding template. -- Functionality includes: -- - Creating/parsing mosses -- - Creating scalesigs (string representations) of mosses -- - Finding certain modes of a mos -- - Finding generators for a mos -- - Producing vectors for simple mos intervals -- - Interval arithmetic, in the form of adding vectors of L's and s's, and -- period/equave-reducing intervals -- - Finding equal tunings for mosses local rat = require('Module:Rational') local utils = require('Module:Utils') local et = require('Module:ET') local p = {} -- Naming scheme for function names: -- - Functions related to mosses don't have any special names. -- - Functions related to a mos's modes generally end with "mode". -- - Functions related to a mos's generators, equave, or period contain the -- corresponding interval as part of its name. -- - Functions related to intervals generally begin with "interval". -- - Interval complement/reduce functions end with "complement" and "reduce". -- - Functions that produce strings generally have the phrase "as string". -- - Functions that "count" something generally end with "count". -- - If a function requires an interval and mos as input, the interval(s) come -- after the mos. -- - Functions that have to do with equal tunings will have "et" in its name. -------------------------------------------------------------------------------- ------------------------------- HELPER FUNCTIONS ------------------------------- -------------------------------------------------------------------------------- function p.find_item_in_table(table, item) local item_found = false for i = 1, #table do if table[i] == item then item_found = true break end end return item_found end -------------------------------------------------------------------------------- -------------------------------- BASE FUNCTIONS -------------------------------- -------------------------------------------------------------------------------- -- Create a new mos. (Contains the number of large and small steps, and equave.) function p.new(nL, ns, equave) local nL = nL or 5 local ns = ns or 2 local equave = equave or 2 return { nL = nL, ns = ns, equave = equave } end -- Pasre a mos from its scalesig. function p.parse(unparsed) local nL, ns, equave = unparsed:match('^(%d+)[Ll]%s*(%d+)[Ss]%s*(.*)$') nL = tonumber(nL) ns = tonumber(ns) equave = equave:match('^%((.*)-equivalent%)$') or equave:match('^⟨(.*)⟩$') or equave:match('^<(.*)>$') or '2/1' -- Assumes this is a rational ratio written a/b equave = rat.parse(equave) if nL == nil or ns == nil or equave == nil then return nil end return p.new(nL, ns, equave) end -------------------------------------------------------------------------------- ------------------------------- STRING FUNCTIONS ------------------------------- -------------------------------------------------------------------------------- -- Construct a string representation (scalesig) for a MOS structure. -- Scalesig is "xL ys", or "xL ys<p/q>" for nonoctave scales. function p.as_string(mos) local suffix = '' if not rat.eq(mos.equave, 2) then suffix = '⟨' .. rat.as_ratio(mos.equave):lower() .. '⟩' end return '' .. mos.nL .. 'L ' .. mos.ns .. 's' .. suffix end -- Construct a longer string representation for a MOS structure. -- Scalesig is "xL ys", or "xL ys (p/q-equivalent)" for nonoctave scales. function p.as_long_string(mos) local suffix = '' if not rat.eq(mos.equave, 2) then suffix = string.format(" (%s-equivalent)", rat.as_ratio(mos.equave):lower()) end return '' .. mos.nL .. 'L ' .. mos.ns .. 's' .. suffix end -- Given an interval as a vector of L's and s's, produce a string "iL + js", -- where i and j are the quantities for L and s. function p.interval_as_string(interval) -- Quantity of L's as a string local L_string = "" if interval['L'] == 0 then L_string = "" elseif interval['L'] == 1 then L_string = "L" else L_string = string.format("%dL", interval['L']) end -- Quantity of s's as a string local s_string = "" if math.abs(interval['s']) == 0 then s_string = "" elseif math.abs(interval['s']) == 1 then s_string = "s" else s_string = string.format("%ds", math.abs(interval['s'])) end if interval['L'] == 0 and interval['s'] == 0 then return "0" elseif interval['L'] == 0 and interval['s'] ~= 0 then return s_string elseif interval['L'] ~= 0 and interval['s'] == 0 then return L_string else return L_string .. (interval['s'] > 0 and " + " or " - ") .. s_string end end -------------------------------------------------------------------------------- ------------------------------- MODE FUNCTIONS --------------------------------- -------------------------------------------------------------------------------- -- Find the brightest (true-mos) mode of a mos, as a string of L's and s's. -- Calculation is based on the definition of a Christoffel word, as the closest -- integer approximation to line y = #s/#L*x. function p.brightest_mode(mos) local nL = mos.nL local ns = mos.ns local d = utils._gcd(nL, ns) if d > 1 then -- use single period mos, with period as new equave nL = utils._round_dec(nL/d) ns = utils._round_dec(ns/d) end local current_L, current_s = 0, 0 local result = '' while current_L < nL or current_s < ns do if (current_s + 1) * nL <= ns * (current_L) then current_s = current_s + 1 result = result .. 's' else current_L = current_L + 1 result = result .. 'L' end end return string.rep(result, d) end -- Find the darkest true-mos mode of a mos. -- It's the reverse of the brightest mode. function p.darkest_mode(mos) local nL = mos.nL local ns = mos.ns local d = utils._gcd(nL, ns) if d > 1 then -- use single period mos, with period as new equave nL = utils._round_dec(nL/d) ns = utils._round_dec(ns/d) end local current_L, current_s = 0, 0 local result = '' while current_L < nL or current_s < ns do if (current_s + 1) * nL <= ns * (current_L) then current_s = current_s + 1 result = 's' .. result -- !esreveR else current_L = current_L + 1 result = 'L' .. result -- !esreveR end end return string.rep(result, d) end -- Given a mos, return a mode based on how it's ranked by modal brightness. -- Ordering here is based on the number of bright gens going DOWN: 0 is the -- brightest mode, 1 is 2nd brightest, etc... function p.mode_from_mos(mos, bright_gens_going_down) return p.rotate_mode(p.brightest_mode(mos), bright_gens_going_down * p.bright_gen_step_count(mos)) end -------------------------------------------------------------------------------- --------------------------- MODE ROTATION FUNCTIONS ---------------------------- -------------------------------------------------------------------------------- -- Given a mos, list all modes in descending order of brightness. function p.modes_by_brightness(mos) local bright_gen_step_count = p.bright_gen_step_count(mos) local period_step_count = p.period_step_count(mos) local modes = {} local current_mode = p.brightest_mode(mos) for i = 1, period_step_count do table.insert(modes, current_mode) current_mode = p.rotate_mode(current_mode, bright_gen_step_count) end return modes end -- List all unique rotations for a mode. Order of modes is by rotation. -- Note: there will always be s/p modes, where s is the number of steps in the -- entered mode, and p is the period of repetition. At most, there will be s -- modes, but if there is a substring of length p that repeats within the mode -- (where p divides s with remainder = 0), then there will be p modes. It's also -- possible to have only one mode, but this can only happen if there is only one -- step size, meaning it's a unary scale (only one step size). function p.mode_rotations(mode_string) local rotations = {} local current_mode = mode_string for i = 1, #mode_string do if not p.find_item_in_table(rotations, current_mode) then table.insert(rotations, current_mode) end current_mode = p.rotate_mode(current_mode) end return rotations end -- Rotate a mode by shifting the step sequence to the left. Negative values -- shift it to the right. Helper function for mode_from_mos(). function p.rotate_mode(mode_string, shift_amt) local shift_amt = shift_amt == nil and 1 or shift_amt % #mode_string -- Defualt is 1 local first = string.sub(mode_string, 1, shift_amt) local second = string.sub(mode_string, shift_amt + 1, #mode_string) return second .. first end -------------------------------------------------------------------------------- ---------------------------- STEP MATRIX FUNCTIONS ----------------------------- -------------------------------------------------------------------------------- -- Convert a single mode (as a string) into a step matrix. This is a listing of -- every interval's step vector in the mode. function p.mode_to_step_matrix(mode_string) local matrix = {} for i = 1, #mode_string + 1 do local steps = i - 1 local interval = p.interval_from_step_sequence(string.sub(mode_string, 0, steps)) table.insert(matrix, interval) end return matrix end -- Given a mos, produce every step matrix for every mode. Modes are listed in -- order of brightness. function p.modes_to_step_matrices(mos) local modes = p.modes_by_brightness(mos) local matrices = {} for i = 1, #modes do table.insert(matrices, p.mode_to_step_matrix(modes[i])) end return matrices end -- Given a single mode (as a string), produce the step matrices for each -- rotation of that mode. Modes are listed in order of rotation. function p.mode_rotations_to_step_matrices(mode_string) local modes = p.mode_rotations(mode_string) local matrices = {} for i = 1, #modes do table.insert(matrices, p.mode_to_step_matrix(modes[i])) end return matrices end -------------------------------------------------------------------------------- --------------- INTERVAL FUNCTIONS FOR PERFECTABLE INTERVALS ------------------- ------------------ (IE, GENERATORS AND PERIOD INTERVALS) ----------------------- -------------------------------------------------------------------------------- -- Compute the bright gen as a vector of L's and s's. -- Bright gen has two sizes: perfect (large) and diminished (small). The size -- given by this function is the large size. function p.bright_gen(mos) local nL = mos.nL local ns = mos.ns local d = utils._gcd(nL, ns) if d > 1 then -- use single period mos, with period as new equave nL = utils._round_dec(nL/d) ns = utils._round_dec(ns/d) end local min_dist = 2; -- the distance we get will always be <= sqrt(2) local current_L, current_s = 0, 0 local result = {['L'] = 0, ['s'] = 0} while current_L < nL or current_s < ns do if (current_s + 1) * nL <= ns * (current_L) then current_s = current_s + 1 else current_L = current_L + 1 end if current_L < nL or current_s < ns then -- check to exclude (current_L, current_s) = (nL, ns) local distance_here = math.abs(nL*current_s - ns*current_L)/math.sqrt(nL^2 + ns^2) if distance_here < min_dist then min_dist = distance_here result['L'] = current_L result['s'] = current_s end end end return result end -- Compute the dark gen as a vector of L's and s's. -- Dark gen has two sizes: augmented (large) and perfect (small). The size given -- by this function is the small size. It's the period complement of the bright -- gen. function p.dark_gen(mos) local bright_gen = p.bright_gen(mos) return p.period_complement(bright_gen, mos) end -- Compute the period as a vector of L's and s's. -- Period intervals only have one size: perfect. function p.period(mos) local gcd = utils._gcd(mos.nL, mos.ns) return { ['L'] = mos.nL / gcd, ['s'] = mos.ns / gcd } end -- Compute the equave as a vector of L's and s's. -- Equave intervals only have one size: perfect. Equave and period intervals are -- the same for single-period mosses. function p.equave(mos) return { ['L'] = mos.nL, ['s'] = mos.ns } end -------------------------------------------------------------------------------- ------------------ INTERVAL FUNCTIONS FOR SIMPLE INTERVALS --------------------- -------------------------------------------------------------------------------- -- Compute the unison as a vector of L's and s's. -- The unison is denoted by moving up from the root by zero steps, and thus does -- not need a mos as input. It's basically a zero vector. -- The unison only has one size: perfect. function p.unison() return { ['L'] = 0, ['s'] = 0 } end -- Compute the vector for a single chroma. It's a large step minus a small step. -- Adding or subtracting any interval by this interval changes its "size". function p.chroma() return { ['L'] = 1, ['s'] = -1 } end -- Compute the vector for an augmented step. It's a large step plus a chroma. function p.augmented_step() return { ['L'] = 2, ['s'] = -1 } end -- Compute the vector for a single large step. function p.large_step() return { ['L'] = 1, ['s'] = 0 } end -- Compute the vector for a single small step. function p.small_step() return { ['L'] = 0, ['s'] = 1 } end -- Compute the vector for a diminished step. It's a small step minus a chroma. function p.diminished_step() return { ['L'] = -1, ['s'] = 2 } end -------------------------------------------------------------------------------- ---------------- INTERVAL FUNCTIONS FOR ARBITRARY INTERVALS -------------------- -------------------------------------------------------------------------------- -- Create a new interval using step counts (the quantities of L's and s's). function p.interval_from_step_counts(i, j) return { ['L'] = i, ['s'] = j } end -- Compute an arbitrary mos interval as a vector of L's and s's. -- The step_count param is the number of mossteps in the interval. EG, in 5L 2s, -- the large 2-mosstep is "LL", so the corresponding vector has L=2, s=0. -- Mossteps larger than the equave (eg, the minor 9th in non-xen music theory) -- are allowed. -- The size_offset denotes whether the interval is the large size (0) or the -- small size (-1). This can exceed the range of [-1, 0] to represent intervals -- raised/lowered by multiple chromas (augmented, diminished, etc). -- Note that for period intervals (eg, the root and equave), there is only one -- size (0 = perfect), so -1 is diminished and 1 is augmented. -- EG, a perfect 4-diastep (perf. 5th) is 4 steps. Since it's the large size, -- the offset is 0, but to get the diminished 5th, the offset should be -1. function p.interval_from_mos(mos, step_count, size_offset) local size_offset = size_offset or 0 -- Optional param; defaults to large size local step_sequence = p.brightest_mode(mos) step_sequence = string.rep(step_sequence, math.ceil(step_count/(mos.nL + mos.ns))) step_sequence = string.sub(step_sequence, 1, step_count) local interval_vector = p.interval_from_step_sequence(step_sequence) local chromas = p.interval_mul(p.chroma(), size_offset) interval_vector = p.interval_add(interval_vector, chromas) return interval_vector end -- Compute an arbitrary mos interval (as a string of steps) as a vector of L's -- and s's. This also serves as a helper function for p.interval_from_mos(). -- Sequences of steps can be entered, where each step is one of five sizes: -- - L: large step. -- - s: small step. -- - c: a chroma; the difference between a large and small step. -- - A: an augmented step; a large step plus a chroma. -- - d: a diminished step, or diesis; a small step minus a chroma. function p.interval_from_step_sequence(step_sequence) local mossteps = #step_sequence local interval_vector = p.unison() for i = 1, mossteps do local step = string.sub(step_sequence, i, i) if step == "L" then interval_vector = p.interval_add(interval_vector, p.large_step()) elseif step == "s" or step == "S" then interval_vector = p.interval_add(interval_vector, p.small_step()) elseif step == "c" then interval_vector = p.interval_add(interval_vector, p.chroma()) elseif step == "A" then interval_vector = p.interval_add(interval_vector, p.augmented_step()) elseif step == "d" then interval_vector = p.interval_add(interval_vector, p.diminished_step()) end end return interval_vector end -------------------------------------------------------------------------------- ------------------------------- COUNT FUNCTIONS -------------------------------- -------------------------------------------------------------------------------- -- Given a mos, compute the number of steps in its bright gen (L's plus s's). function p.bright_gen_step_count(mos) local interval = p.bright_gen(mos) return interval['L'] + interval['s'] end -- Given a mos, compute the number of steps in its dark gen (L's plus s's). function p.dark_gen_step_count(mos) return p.period_step_count(mos) - p.bright_gen_step_count(mos) end -- Given a mos, compute the number of steps in its period (L's plus s's). function p.period_step_count(mos) return (mos.nL + mos.ns) / utils._gcd(mos.nL, mos.ns) end -- Given a mos, compute the number of steps in its equave (L's plus s's). function p.equave_step_count(mos) return mos.nL + mos.ns end -- Given a mos, compute the number of periods it has. function p.period_count(mos) return utils._gcd(mos.nL, mos.ns) end -- Given a vector representing an interval, compute the number of mossteps it -- corresponds to. Knowledge of the corresponding mos is not needed. Intervals -- can be negative, resulting in a negative output. function p.interval_step_count(interval) return interval['L'] + interval['s'] end -- Given a vector representing an interval, compute the number of chromas it was -- raised or lowered by from its large size (for non-period intervals) or its -- perfect size (for period/root/equave intervals). This requires the mos as -- input. -- If the number of chromas from a small (EG minor) interval is desired, then -- using the param size_offset can be used: 0 for chromas from large size, -1 -- for chromas from small size. This can exceed the range [-1, 0] if needed. -- EG, a diminished 2-diastep (dim. 3rd) has the vector {0,2}. It's reached by -- either lowering the major 2-step by 2 chromas, or lowering the minor 2-step -- by 1 chroma. function p.interval_chroma_count(interval, mos, size_offset) local size_offset = size_offset or 0 -- Default of 0. local step_count = p.interval_step_count(interval) local base_interval = p.interval_from_mos(mos, step_count, 0) return interval['L'] - base_interval['L'] - size_offset end -------------------------------------------------------------------------------- ----------------------- INTERVAL ARITHMETIC FUNCTIONS -------------------------- -------------------------------------------------------------------------------- -- Add two intervals together by adding their respective vectors. function p.interval_add(interval_1, interval_2) return { ['L'] = interval_1['L'] + interval_2['L'], ['s'] = interval_1['s'] + interval_2['s'] } end -- Subtract two intervals by subtracting their respective vectors. function p.interval_sub(interval_1, interval_2) return { ['L'] = interval_1['L'] - interval_2['L'], ['s'] = interval_1['s'] - interval_2['s'] } end -- Repeatedly add the same interval to itself. function p.interval_mul(interval, amt) return { ['L'] = interval['L'] * amt, ['s'] = interval['s'] * amt } end -- Check whether two intervals are equal to one another. function p.interval_eq(interval_1, interval_2) return interval_1['L'] == interval_2['L'] and interval_1['s'] == interval_2['s'] end -------------------------------------------------------------------------------- ---------------------- INTERVAL MANIPULATION FUNCTIONS ------------------------- -------------------------------------------------------------------------------- -- Given an interval vector and a mos, find its period complement. This is the -- interval to add to produce the period. function p.period_complement(interval, mos) local sign = p.interval_step_count(interval) < 0 and -1 or 1 local period_vector = p.period(mos) return p.interval_sub(p.interval_mul(period_vector, sign), interval) end -- Given an interval vector and a mos, find its equave complement. This is the -- interval to add to produce the equave. function p.equave_complement(interval, mos) local sign = p.interval_step_count(interval) < 0 and -1 or 1 local equave_vector = p.equave(mos, interval) return p.interval_sub(p.interval_mul(equave_vector, sign), interval) end -- Given an interval vector and a mos, period-reduce it. This works like -- modular arithmetic, so passing a negative interval returns a positive one. function p.period_reduce(interval, mos) local step_count = p.interval_step_count(interval) local reduce_amt = math.floor(step_count / p.period_step_count(mos)) local periods = p.interval_mul(p.period(mos), reduce_amt) return p.interval_sub(interval, periods) end -- Given an interval vector and a mos, equave-reduce it. This works like -- modular arithmetic, so passing a negative interval returns a positive one. function p.equave_reduce(interval, mos) local step_count = p.interval_step_count(interval) local reduce_amt = math.floor(step_count / p.equave_step_count(mos)) local equaves = p.interval_mul(p.equave(mos), reduce_amt) return p.interval_sub(interval, equaves) end -- Invert an interval. This makes an interval negative. function p.invert_interval(interval) return p.interval_mul(interval, -1) end -- Intervals usually denote distances between two scale degrees and should be -- positive values. Normalizing makes a negative interval positive again. function p.normalize_interval(interval) return p.interval_step_count(interval) < 0 and p.interval_mul(interval, -1) or interval end -------------------------------------------------------------------------------- ---------------------------- EQUAL-TUNING FUNCTIONS ---------------------------- -------------------------------------------------------------------------------- -- Given a mos and a step ratio, return an equal tuning (or equal division). -- The step ratio is entered as a 2-element array to allow non-simplified -- ratios to be entered. (The rational module isn't suitable since it simplifies -- ratios.) function p.mos_to_et(mos, step_ratio) local et_size = mos.nL * step_ratio[1] + mos.ns * step_ratio[2] return et.new(et_size, mos.equave, rat.as_ratio(mos.equave)) end -- Given a mos and a step ratio, return the number of et-steps for its bright -- generator. function p.bright_gen_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.bright_gen(mos), step_ratio) end -- Given a mos and a step ratio, return the number of et-steps for its dark -- generator. function p.dark_gen_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.dark_gen(mos), step_ratio) end -- Given a mos and a step ratio, return the number of et-steps for its period. function p.period_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.period(mos), step_ratio) end -- Given a mos and a step ratio, return the number of et-steps for its equave. function p.equave_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.equave(mos), step_ratio) end -- Given an interval vector and step ratio, compute the number of et-steps it -- corresponds to. function p.interval_to_et_steps(interval, step_ratio) return interval['L'] * step_ratio[1] + interval['s'] * step_ratio[2] end -------------------------------------------------------------------------------- ------------------------------- CENT FUNCTIONS --------------------------------- -------------------------------------------------------------------------------- -- Given a mos and a step ratio, return the number of cents for its bright gen. function p.bright_gen_to_cents(mos, step_ratio) local interval_steps = p.interval_to_et_steps(p.bright_gen(mos), step_ratio) local equave_steps = p.equave_to_et_steps(mos, step_ratio) return interval_steps * rat.cents(mos.equave) / equave_steps end -- Given a mos and a step ratio, return the number of cents for its dark gen. function p.dark_gen_to_cents(mos, step_ratio) local interval_steps = p.interval_to_et_steps(p.dark_gen(mos), step_ratio) local equave_steps = p.equave_to_et_steps(mos, step_ratio) return interval_steps * rat.cents(mos.equave) / equave_steps end -- Given a mos and a step ratio, return the number of cents for its period. -- The period is the interval at which the step pattern repeats, so no step -- ratio is needed. function p.period_to_cents(mos) return rat.cents(mos.equave) / p.period_count(mos) end -- Given a mos and a step ratio, return the number of cents for its equave. -- The period is the interval at which the step pattern repeats, and the equave -- is a multiple of that (at least for multi-period mosses), so no step ratio is -- needed. function p.equave_to_cents(mos) return rat.cents(mos.equave) end -- Given an interval vector and step ratio, convert it to cents. This requires -- info about the mos itself. function p.interval_to_cents(interval, mos, step_ratio) local interval_steps = p.interval_to_et_steps(interval, step_ratio) local equave_steps = p.equave_to_et_steps(mos, step_ratio) return interval_steps * rat.cents(mos.equave) / equave_steps end -------------------------------------------------------------------------------- ------------ UNUSED FUNCTIONS OR FUNCTIONS TO MOVE TO OTHER MODULES ------------ -------------------------------------------------------------------------------- -- Given a mos, find the ancestor mos with a target note count (default 10) -- or less; to be moved to tamnams module function p.find_ancestor(mos, target_note_count) local mos = mos or p.new(5, 2) local target_note_count = target_note_count or 10 local z = mos.nL local w = mos.ns while (z ~= w) and (z + w > target_note_count) do local m1 = math.max(z, w) local m2 = math.min(z, w) -- For use with updating ancestor mos chunks local z_prev = z -- Update step ratios z = m2 w = m1 - m2 end return p.new(z, w, mos.equave) end -------------------------------------------------------------------------------- ---------------------------- EQUAL-TUNING FUNCTIONS ---------------------------- -------------------------------------------------------------------------------- -- Given a mos and a step ratio, return an equal tuning (or equal division). -- The step ratio is entered as a 2-element array to allow non-simplified -- ratios to be entered. (The rational module isn't suitable since it simplifies -- ratios.) function p.as_et(mos, step_ratio, suffix) local suffix = suffix or nil local et_size = mos.nL * step_ratio[1] + mos.ns * step_ratio[2] return et.new(et_size, mos.equave, suffix) end -- Given an interval vector and step ratio, compute the number of et-steps it corresponds to. function p.interval_to_et_steps(interval, step_ratio) return interval["L"] * step_ratio[1] + interval["s"] * step_ratio[2] end -------------------------------------------------------------------------------- ------------------------ EQUAL-TUNING STRING FUNCTIONS ------------------------- -------------------------------------------------------------------------------- -- Given a mos and step ratio, return its equal temperament as a string "{steps}\{division}{suffix}". function p.et_string(mos, step_ratio, suffix) local suffix = suffix or nil local et_mos = p.as_et(mos, step_ratio, suffix) return et.as_string(et_mos) end -- Given a mos, return its equal temperament suffix as a string (edo, edt, edf, or ed-p/q). function p.et_suffix(mos) if rat.eq(mos.equave, rat.new(2)) then return "平均律" elseif rat.eq(mos.equave, rat.new(3)) then return "edt" elseif rat.eq(mos.equave, rat.new(3, 2)) then return "edf" else return "ed" .. rat.as_ratio(mos.equave) end end -- Given a mos and a step ratio, return the number of et-steps for its bright -- generator. function p.bright_gen_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.bright_gen(mos), step_ratio) end -- Given a mos and a step ratio, return the number of et-steps for its dark generator. function p.dark_gen_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.dark_gen(mos), step_ratio) end -- Given a mos and a step ratio, return the number of et-steps for its period. function p.period_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.period(mos), step_ratio) end -- Given a mos and a step ratio, return the number of et-steps for its equave. function p.equave_to_et_steps(mos, step_ratio) return p.interval_to_et_steps(p.equave(mos), step_ratio) end -- Given an interval vector and step ratio, compute the number of et-steps it corresponds to. function p.interval_to_et_steps(interval, step_ratio) return interval["L"] * step_ratio[1] + interval["s"] * step_ratio[2] end -------------------------------------------------------------------------------- ----------------------------------- TESTER ------------------------------------- -------------------------------------------------------------------------------- -- Tester function function p.tester() --local interval = p.dark_gen(p.new(5,2)) --return p.interval_chroma_count(interval, p.new(5,2), -1) --return p.equave_reduce({['L']=-3,['s']=-1},p.new(5,2)) --return p.interval_from_mos(p.new(5,2), 4, 1) --return p.interval_from_step_sequence("LLLdLLc") --return p.mode_from_mos(p.new(5,2), -90673) --return p.mode_to_step_matrix(p.brightest_mode(p.new(5,4))) --return p.mode_rotations("LssLLssL") --return p.mode_rotations_to_step_matrices("LLsLsAs") --return p.mode_from_mos(p.new(5,2),1) local string_return = "" for i = 1, 7 do string_return = string_return .. p.mode_from_mos(p.new(5,2), i-1) .. "\n" end return string_return end return p
このページで使用されているテンプレート:
モジュール:MOS/doc
(
ソースを閲覧
)
モジュール:MOS
に戻る。