|
|
| (17 intermediate revisions by 4 users not shown) |
| Line 1: |
Line 1: |
| local getArgs = require('Module:Arguments').getArgs | | local limits = require("Module:Limits") |
| local u = require('Module:Utils')
| | local rat = require("Module:Rational") |
| local rat = require('Module:Rational') | |
| local p = {} | | local p = {} |
|
| |
|
| -- return measure in cents of an interval ratio, rounded to prec decimal places | | -- Compute Harmonic Shannon entropy for an interval of `c` cents |
| function p.to_cents(frame) | | -- `c`, `deviation`: in cents |
| local args = getArgs(frame) | | -- `ratios`: an array of rational numbers |
| return p._to_cents(args[1], args[2]) | | -- `norm`: a function of rational numbers |
| end | | function p.harmonic_entropy(c, ratios, deviation, norm) |
| | norm = norm or function(ratio) |
| | return math.sqrt(rat.benedetti_height(ratio)) |
| | end |
| | deviation = deviation or 1200 * math.log(1.01, 2) |
| | ratios = ratios |
| | or limits.integer_limit(200, function(ratio) |
| | if math.abs(rat.cents(ratio) - c) > 3 * deviation then |
| | return 1 / 0 |
| | end |
| | return norm(ratio) |
| | end, 100) |
|
| |
|
| function p._to_cents(ratio, prec) | | local function gaussian(x) |
| -- ratio defaults to 1
| | return math.exp(-x * x / (2 * deviation * deviation)) / (deviation * math.sqrt(2 * math.pi)) |
| ratio = u.eval_num_arg(ratio, 1)
| |
| -- prec defaults to nil
| |
| prec = u.eval_num_arg(prec)
| |
| local result = 1200*u._log(ratio), prec
| |
| if prec == nil then
| |
| return result
| |
| else
| |
| return u._round(result, prec)
| |
| end | | end |
| end
| |
|
| |
|
| -- edf = ed3/2, edo = ed2, edt = ed3
| | local function weighted_gaussian(ratio) |
| local equaves = | | return gaussian(rat.cents(ratio) - c) / norm(ratio) |
| {
| | end |
| ['f'] = rat.new(3, 2),
| |
| ['o'] = 2,
| |
| ['t'] = 3
| |
| }
| |
|
| |
|
| -- returns size of an ET given its name
| | local q_norm = 0 |
| function p.parse_ET_size(frame)
| | for _, ratio in pairs(ratios) do |
| local args = getArgs(frame) | | q_norm = q_norm + weighted_gaussian(ratio) |
| local size, equave = p.parse_ET(args[1]) | | end |
| return size
| |
| end
| |
| | |
| -- returns equave of an ET given its name
| |
| function p.parse_ET_equave(frame)
| |
| local args = getArgs(frame)
| |
| local size, equave = p.parse_ET(args[1])
| |
| return rat.as_float(equave) | |
| end | |
|
| |
|
| -- returns size and equave of an ET given its name; cannot be used with {{#invoke:}}
| | local function probability(ratio) |
| function p.parse_ET(input)
| | return weighted_gaussian(ratio) / q_norm |
| input = string.lower(input)
| |
| local size, equave | |
| -- size defaults to 12
| |
| size = u.eval_num_arg(input:match("^([0-9]+)"), 12)
| |
| if input:match("^[0-9]*[%-]?ed[fot]$") then
| |
| equave = equaves[tostring(input:match("[fot]"))]
| |
| else
| |
| -- equave defaults to 2 | |
| equave = rat.parse(input:match("^.-ed(.+)%s*$")) or 2
| |
| end | | end |
| return size, equave
| |
| end
| |
|
| |
| -- return ratio corresponding to an interval written in backslash notation
| |
| -- ("steps" of "size" equal divisions of the "equave")
| |
|
| |
| function p.backslash_ratio(frame)
| |
| local args = getArgs(frame)
| |
| return p._backslash_ratio(args[1])
| |
| end
| |
|
| |
|
| function p._backslash_ratio(input)
| | local entropy = 0 |
| -- result defaults to 0
| | for _, ratio in pairs(ratios) do |
| local result = 0 | | local p_i = probability(ratio) |
| -- steps defaults to 1 | | if p_i > 1e-5 then |
| local steps = input:match("%s*(%-?[0-9]+)\\.-") or 1
| | entropy = entropy - p_i * math.log(p_i) |
| local size, equave = p.parse_ET(input:match("\\(.*)"))
| | end |
| if tonumber(size) == 0 then
| |
| return 1 | |
| end | | end |
| result = rat.as_float(equave)^(tonumber(steps)/tonumber(size))
| | return entropy |
| return result | |
| end | | end |
|
| |
|
| return p | | return p |