モジュール:Chord consistency
ナビゲーションに移動
検索に移動
このモジュールについての説明文ページを モジュール:Chord consistency/doc に作成できます
local limits = require('Module:Limits')
local ET = require('Module:ET')
local rat = require('Module:Rational')
local utils = require("Module:Utils")
local p = {}
-- determine maximum error
function p.max_error(et, ratios)
local maxe = 0.0
for a_key, a in pairs(ratios) do
local a_approx = ET.approximate(et, rat.as_float(a))
local e = math.abs((ET.cents(et, a_approx) - rat.cents(a)) / ET.cents(et, 1))
if (e > maxe) then
maxe = e
end
end
return maxe
end
function p.consistent_edos(harmonics, distance, ed, maxlen)
distance = distance or 1.0
ed = ed or 'edo' or '平均律'
local max_n = 72
maxlen = maxlen or max_n
if max_n < maxlen then max_n = maxlen end
local all_interval = {}
for i, h in ipairs(harmonics) do
-- compute all ratio
for j, g in ipairs(harmonics) do
if j > i then
local a = rat.new(g, h)
all_interval[rat.as_ratio(a)] = a
end
end
end
local vals = {}
for i = 1, max_n do
local et = ET.parse('' .. i .. ed)
local consistent = limits.additively_consistent(et, all_interval, false, false, nil)
if consistent then
local maxe = p.max_error(et, all_interval)
if maxe <= 5.0e-11 then
table.insert(vals, "[[" .. i .. ed .. "]]" .. "(just)")
break
end
local dist = 0.5/maxe
local up = (dist >= distance)
local llevel = 0
while (dist >= 2) do
llevel = llevel + 1
dist = dist / 2
end
if up then
if #vals >= maxlen then
table.insert(vals, "…")
break
end
table.insert(vals, "[[" .. i .. ed .. "]]" .. string.rep("*", llevel))
end
end
end
return table.concat(vals, ", ")
end
function p.noinfobox_chord(frame)
local distance = tonumber(frame.args["Distance"])
local debug_data = ""
local infobox_data = {}
local cats = ""
--if utils.value_provided(frame.args["Harmonics"]) then
local harmonics = {}
for hs in string.gmatch(frame.args["Harmonics"], "[^:]+") do
h = tonumber(hs) -- TODO: support rational entries?
assert(h > 0, "invalid harmonic")
table.insert(harmonics, h)
end
if distance == nil then
if #harmonics >= 5 then
distance = 1.5
elseif #harmonics >= 3 then
distance = 2.0
else
distance = 3.0
end
end
-- reduce harmonics to simplest terms, in case the user accidentally failed to reduce them
local gcd = harmonics[1]
for i, h in ipairs(harmonics) do
gcd = utils._gcd(gcd, h)
if gcd == 1 then break end
end
if gcd > 1 then
for i, h in ipairs(harmonics) do
harmonics[i] = harmonics[i] / gcd
end
end
local root = harmonics[1]
local root_interval_links = {}
local step_interval_links = {}
for i, h in ipairs(harmonics) do
-- compute ratio of this harmonic relative to the root
local gcd = utils._gcd(h, root)
local numer = h / gcd
local denom = root / gcd
table.insert(root_interval_links, "[[" .. numer .. "/" .. denom .. "]]")
-- compute ratio of this harmonic relative to the previous
if i > 1 then
local prev = harmonics[i-1]
local step_gcd = utils._gcd(h, prev)
local step_numer = h / step_gcd
local step_denom = prev / step_gcd
table.insert(step_interval_links, "[[" .. step_numer .. "/" .. step_denom .. "]]")
end
end
cat = "(d >= " .. distance .. ") " .. p.consistent_edos(harmonics, distance, 'edo', 4)
--end
return cat
end
return p