Module:MOS: Difference between revisions
a bugfix; reduce functions now accept negative intervals |
Bugfixes; complement code handles negative intervals; code simplifications |
||
| Line 93: | Line 93: | ||
if interval['L'] == 1 then | if interval['L'] == 1 then | ||
L_string = "L" | L_string = "L" | ||
elseif interval['L'] ~= 0 | elseif interval['L'] ~= 0 or interval['L'] ~= 1 then | ||
L_string = string.format("%dL", interval['L']) | L_string = string.format("%dL", interval['L']) | ||
end | end | ||
if interval['s'] == 1 then | if interval['s'] == 1 then | ||
s_string = "s" | s_string = "s" | ||
elseif interval['s'] ~= 0 | elseif interval['s'] ~= 0 or interval['s'] ~= 1 then | ||
s_string = string.format("%ds", interval['s']) | s_string = string.format("%ds", interval['s']) | ||
end | end | ||
| Line 216: | Line 216: | ||
function p.period(mos) | function p.period(mos) | ||
local gcd = utils._gcd(mos.nL, mos.ns) | local gcd = utils._gcd(mos.nL, mos.ns) | ||
return { | |||
['L'] = mos.nL / gcd, | ['L'] = mos.nL / gcd, | ||
['s'] = mos.ns / gcd | ['s'] = mos.ns / gcd | ||
} | } | ||
end | end | ||
| Line 227: | Line 226: | ||
-- the same for single-period mosses. | -- the same for single-period mosses. | ||
function p.equave(mos) | function p.equave(mos) | ||
return { | |||
['L'] = mos.nL, | ['L'] = mos.nL, | ||
['s'] = mos.ns | ['s'] = mos.ns | ||
} | } | ||
end | end | ||
| Line 243: | Line 241: | ||
-- The unison only has one size: perfect. | -- The unison only has one size: perfect. | ||
function p.unison() | function p.unison() | ||
return { ['L'] = 0, ['s'] = 0 } | |||
end | end | ||
| Line 253: | Line 247: | ||
-- Adding or subtracting any interval by this interval changes its "size". | -- Adding or subtracting any interval by this interval changes its "size". | ||
function p.chroma() | function p.chroma() | ||
return { ['L'] = 1, ['s'] = -1 } | |||
end | |||
-- Compute the vector for an augmented step. It's a large step plus a chroma. | |||
return | function p.augmented_step() | ||
return { ['L'] = 2, ['s'] = -1 } | |||
end | end | ||
-- Compute the vector for a single large step. | -- Compute the vector for a single large step. | ||
function p.large_step() | function p.large_step() | ||
return { ['L'] = 1, ['s'] = 0 } | |||
end | end | ||
-- Compute the vector for a single small step. | -- Compute the vector for a single small step. | ||
function p.small_step() | function p.small_step() | ||
return { ['L'] = 0, ['s'] = 1 } | |||
end | end | ||
-- Compute the vector for a diminished step. It's a small step minus a chroma. | -- Compute the vector for a diminished step. It's a small step minus a chroma. | ||
function p.diminished_step() | function p.diminished_step() | ||
return | return { ['L'] = -1, ['s'] = 2 } | ||
end | end | ||
| Line 311: | Line 293: | ||
local interval_vector = p.interval_from_step_sequence(step_sequence) | local interval_vector = p.interval_from_step_sequence(step_sequence) | ||
local chromas = p.interval_mul(p.chroma(), size_offset) | |||
interval_vector | interval_vector = p.interval_add(interval_vector, chromas) | ||
return interval_vector | return interval_vector | ||
end | end | ||
| Line 326: | Line 309: | ||
function p.interval_from_step_sequence(step_sequence) | function p.interval_from_step_sequence(step_sequence) | ||
local mossteps = #step_sequence | local mossteps = #step_sequence | ||
local interval_vector = | local interval_vector = p.unison() | ||
for i = 1, mossteps do | for i = 1, mossteps do | ||
local step = string.sub(step_sequence, i, i) | local step = string.sub(step_sequence, i, i) | ||
if step == "L" then | if step == "L" then | ||
interval_vector | interval_vector = p.interval_add(interval_vector, p.large_step()) | ||
elseif step == "s" or step == "S" then | elseif step == "s" or step == "S" then | ||
interval_vector | interval_vector = p.interval_add(interval_vector, p.small_step()) | ||
elseif step == "c" then | elseif step == "c" then | ||
interval_vector | interval_vector = p.interval_add(interval_vector, p.chroma()) | ||
elseif step == "A" then | elseif step == "A" then | ||
interval_vector | interval_vector = p.interval_add(interval_vector, p.augmented_step()) | ||
elseif step == "d" then | elseif step == "d" then | ||
interval_vector | interval_vector = p.interval_add(interval_vector, p.diminished_step()) | ||
end | end | ||
end | end | ||
| Line 419: | Line 396: | ||
-- Add two intervals together by adding their respective vectors. | -- Add two intervals together by adding their respective vectors. | ||
function p.interval_add(interval_1, interval_2) | function p.interval_add(interval_1, interval_2) | ||
return { | |||
['L'] = interval_1['L'] + interval_2['L'], | ['L'] = interval_1['L'] + interval_2['L'], | ||
['s'] = interval_1['s'] + interval_2['s'] | ['s'] = interval_1['s'] + interval_2['s'] | ||
} | } | ||
end | end | ||
-- Subtract two intervals by subtracting their respective vectors. | -- Subtract two intervals by subtracting their respective vectors. | ||
function p.interval_sub(interval_1, interval_2) | function p.interval_sub(interval_1, interval_2) | ||
return { | |||
['L'] = interval_1['L'] - interval_2['L'], | ['L'] = interval_1['L'] - interval_2['L'], | ||
['s'] = interval_1['s'] - interval_2['s'] | ['s'] = interval_1['s'] - interval_2['s'] | ||
} | } | ||
end | end | ||
-- Repeatedly add the same interval to itself. | -- Repeatedly add the same interval to itself. | ||
function p.interval_mul(interval, amt) | function p.interval_mul(interval, amt) | ||
return { | |||
['L'] = interval['L'] * amt, | ['L'] = interval['L'] * amt, | ||
['s'] = interval['s'] * amt | ['s'] = interval['s'] * amt | ||
} | } | ||
end | end | ||
| Line 448: | Line 422: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- Given an interval vector and a mos, find its period complement. | -- 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) | function p.period_complement(interval, mos) | ||
local sign = p.interval_step_count(interval) < 0 and -1 or 1 | |||
local period_vector = p.period(mos) | local period_vector = p.period(mos) | ||
return p.interval_sub(period_vector, interval) | return p.interval_sub(p.interval_mul(period_vector, sign), interval) | ||
end | end | ||
-- Given an interval vector and a mos, find its equave complement. | -- 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) | 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) | local equave_vector = p.equave(mos, interval) | ||
return p.interval_sub(equave_vector, interval) | return p.interval_sub(p.interval_mul(equave_vector, sign), interval) | ||
end | end | ||
| Line 463: | Line 441: | ||
-- modular arithmetic, so passing a negative interval returns a positive one. | -- modular arithmetic, so passing a negative interval returns a positive one. | ||
function p.period_reduce(interval, mos) | function p.period_reduce(interval, mos) | ||
local step_count = p.interval_step_count(interval) | local step_count = p.interval_step_count(interval) | ||
local reduce_amt = math.floor(step_count / p.period_step_count(mos)) | local reduce_amt = math.floor(step_count / p.period_step_count(mos)) | ||
| Line 473: | Line 450: | ||
-- Given an interval vector and a mos, equave-reduce it. This works like | -- Given an interval vector and a mos, equave-reduce it. This works like | ||
-- modular arithmetic, so passing a negative interval returns a positive one. | -- modular arithmetic, so passing a negative interval returns a positive one. | ||
function p.equave_reduce(interval | function p.equave_reduce(interval, mos) | ||
local step_count = p.interval_step_count(interval) | local step_count = p.interval_step_count(interval) | ||
local reduce_amt = math.floor(step_count / p.equave_step_count(mos)) | local reduce_amt = math.floor(step_count / p.equave_step_count(mos)) | ||
| Line 602: | Line 578: | ||
--local interval = p.dark_gen(p.new(5,2)) | --local interval = p.dark_gen(p.new(5,2)) | ||
--return p.interval_chroma_count(interval, p.new(5,2), -1) | --return p.interval_chroma_count(interval, p.new(5,2), -1) | ||
return p. | --return p.equave_reduce({['L']=-3,['s']=-1},p.new(5,2)) | ||
--return p.interval(p.new(5,2), 4, 1) | |||
return p.interval_from_step_sequence("LLLdLLc") | |||
end | end | ||
return p | return p | ||