Module:MOS notation: Difference between revisions
Separated functions from mos degrees module into a helper module |
No edit summary |
||
| Line 53: | Line 53: | ||
local note_name = note_symbol .. string.rep(chroma_symbol, math.abs(chromas)) | local note_name = note_symbol .. string.rep(chroma_symbol, math.abs(chromas)) | ||
return note_name | return note_name | ||
end | |||
-- Helper function for creating a genchain, or specifically, a nominal-accidental chain. | |||
-- This can only work in one direction at a time, so it's necessary to call this twice, | |||
-- once for each direction (going up by the bright generator, or down). One genchain | |||
-- is generated for each period, so this returns an array of arrays. | |||
-- This genchain is agnostic of notation, and only denotes the mossteps needed to reach | |||
-- a note, followed by the number of chromas. For example, F# is reached going up 3 | |||
-- mossteps and adding one chroma; Fb is the same except subtracting one chroma. | |||
-- Specific notation is needed to interpret this into note names. | |||
-- Parameters: | |||
-- - input_mos - the mos itself represented as a data structure from Module:MOS | |||
-- - genchain_init_per_period - how many named pitches per period are there without accidentals added? | |||
-- This is either the value u or d for the UDP of up|dp. | |||
-- - genchain_length_per_period - how many generators should the genchain extend after the root? | |||
-- - going_up - bool; whether the genchain is going up or down; true for up, false for down | |||
function p.mos_nomacc_chain(input_mos, genchain_init_per_period, genchain_length_per_period, going_up) | |||
-- Default parameters for testing | |||
--[[ | |||
local input_mos = input_mos or mos.new(5, 2, 2) | |||
local genchain_init_per_period = genchain_init_per_period or 5 | |||
local genchain_length_per_period = genchain_length_per_period or 10 | |||
local note_symbols = note_symbols or "CDEFGAB" | |||
local chroma_symbol = chroma_symbol or "#" | |||
local going_up = going_up or true | |||
]]-- | |||
-- Get the number of mossteps per period and equave | |||
local mossteps_per_equave = input_mos.nL + input_mos.ns | |||
local periods_per_equave = rat.gcd(input_mos.nL, input_mos.ns) | |||
local mossteps_per_period = mossteps_per_equave / periods_per_equave | |||
--[[ | |||
-- Split the note symbols string into subsets | |||
-- This is only necessary if the mos is multi-period | |||
local note_subsets = {} | |||
for i = 1, periods_per_equave do | |||
local start_index = (i - 1) * mossteps_per_period + 1 | |||
local stop_index = i * mossteps_per_period | |||
local substr = string.sub(note_symbols, start_index, stop_index) | |||
table.insert(note_subsets, substr) | |||
end | |||
]]-- | |||
-- Create the genchain for each period | |||
local genchains = {} | |||
for i = 1, periods_per_equave do | |||
--local note_names = note_subsets[i] | |||
-- Get the size of the generator in mossteps | |||
local gen = mos.bright_gen(input_mos) | |||
local gen_in_mossteps = gen['L'] + gen['s'] | |||
-- If the genchain is descending (ie, going_up is false), switch to | |||
-- using the dark gen in mossteps, which is the period complement | |||
-- of the bright gen; going up by the dark gen is the same as going | |||
-- down by the bright gen | |||
if not going_up then | |||
gen_in_mossteps = mossteps_per_period - gen_in_mossteps | |||
end | |||
-- Use this value, with modular arithmteic, as an index to get the note name | |||
local accumulator = 0 | |||
-- Create a genchain that initially starts at the root | |||
--local root = string.sub(note_names, 1, 1) | |||
--local genchain = { root } | |||
local root_offest = (i - 1) * mossteps_per_period -- To make sure that, across all periods, every note has a unique index | |||
local root = { ['mossteps'] = root_offest, ['chromas'] = 0 } | |||
local genchain = { root } | |||
-- Create the rest of the genchain | |||
for j = 1, genchain_length_per_period do | |||
-- Increment the index by the generator | |||
accumulator = accumulator + gen_in_mossteps | |||
-- Convert the accumulator into an index | |||
local index = accumulator % mossteps_per_period | |||
-- Add accidentals | |||
-- This is negative if the genchain is descending | |||
local accidentals_to_add = 0 | |||
if j > genchain_init_per_period then | |||
accidentals_to_add = math.ceil((j - genchain_init_per_period) / mossteps_per_period) | |||
end | |||
if not going_up then | |||
accidentals_to_add = accidentals_to_add * -1 | |||
end | |||
-- Get the final note name | |||
local note_name = {} | |||
note_name['mossteps'] = index + root_offest -- Mossteps needed to reach a note | |||
note_name['chromas'] = accidentals_to_add -- How many chromas | |||
-- Add the note name | |||
table.insert(genchain, note_name) | |||
end | |||
-- Add the genchain | |||
table.insert(genchains, genchain) | |||
end | |||
return genchains | |||
end | end | ||
| Line 98: | Line 201: | ||
-- - -2 = 1x diminished | -- - -2 = 1x diminished | ||
-- - -3 = 2x diminished | -- - -3 = 2x diminished | ||
function p. | function p.mos_degree_chain(input_mos, genchain_length_per_period, going_up) | ||
-- Default parameters for testing | -- Default parameters for testing | ||
--[[ | --[[ | ||