Module:Infobox ET: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Move special properties to the last, move octave before fifth. Add "dual" marker to sharp and flat fifths
Category sorting of "prime edo"
Line 63: Line 63:
prime = " (prime)"
prime = " (prime)"
if rat.eq(et.equave, 2) then
if rat.eq(et.equave, 2) then
categories = categories .. '[[Category:Prime EDO]]'
categories = categories .. '[[Category:Prime EDO|' .. string.rep ('#', string.len (et.size)) .. ']]'
end
end
end
end

Revision as of 16:45, 22 January 2023

Module documentation[view] [edit] [history] [purge]
This module should not be invoked directly; use its corresponding template instead: Template:Infobox ET.

This module automatically fills in information about a specified equal temperament tuning.

Introspection summary for Module:Infobox ET 
Functions provided (1)
Line Function Params
43 infobox_ET (invokable) (frame)
Lua modules required (6)
Variable Module Functions used
ET Module:ET approximate
cents
parse
is_zeta
is_highly_composite
why_zeta
infobox Module:Infobox build
i Module:Interval _to_cents
l Module:Limits consistency_limit
rat Module:Rational eq
new
converges
as_float
as_table
as_ratio
u Module:Utils _round
is_prime
_prime_factorization

No function descriptions were provided. The Lua code may have further information.


local p = {}
local i = require('Module:Interval')
local u = require('Module:Utils')
local rat = require('Module:Rational')
local l = require('Module:Limits')
local ET = require('Module:ET')
local infobox = require('Module:Infobox')

-- towards is one of: -1 (floor), 0 (nearest), 1 (ceil)
local function approximation(et, interval, towards, precomputed_approx)
	local approx = precomputed_approx or ET.approximate(et, interval, towards or 0)
	
	local tuning = et.size
	if not rat.eq(et.equave, 2) then
		tuning = tuning .. et.suffix
	end
	
	local ratio = rat.new(approx, et.size)
	
	local convergement_notice = ''
	local converges = rat.converges(ratio, math.log(interval) / math.log(rat.as_float(et.equave)))
	if converges then
		convergement_notice = '<br/>(' .. converges .. ')'
	end
	
	if rat.as_table(ratio)[1] ~= approx then
		convergement_notice = ''
		local link = rat.as_table(ratio)[2] .. et.suffix
		ratio = ' (→[[' .. link .. '|' .. rat.as_ratio(ratio, '\\')
		if not rat.eq(et.equave, 2) then
			ratio = ratio .. et.suffix
		end
		ratio = ratio .. ']])'
	else
		ratio = ''
	end
	
	local cents = u._round(ET.cents(et, approx), 6)
	
	return approx .. '\\' .. tuning .. ' (' .. cents .. '¢)' .. ratio .. convergement_notice
end

function p.infobox_ET(frame)
	-- debug mode
	local debug_mode = frame.args['debug'] ~= nil
	local categories = ''
	
	local tuning = frame.args['tuning']
	local et = ET.parse(tuning) or ET.parse('12edo')
	
	-- category of the main article
	categories = categories .. '[[Category:' .. tuning .. '| ]]'
	-- category of the equal division
	if rat.eq(et.equave, 2) then
		categories = categories .. '[[Category:Equal divisions of the octave|' .. string.rep ('#', string.len (et.size)) .. ']]'
	else
		categories = categories .. '[[Category:' .. et.suffix .. '|' .. string.rep ('#', string.len (et.size)) .. ']]'
	end
	
	-- prime test
	local prime = ""
	if u.is_prime(et.size) then
		prime = " (prime)"
		if rat.eq(et.equave, 2) then
			categories = categories .. '[[Category:Prime EDO|' .. string.rep ('#', string.len (et.size)) .. ']]'
		end
	end
	
	-- zeta test
	local zeta_override = frame.args['Zeta']
	local zeta_switch = nil
	if type(zeta_override) == 'string' and #zeta_override > 0 then
		zeta_switch = not zeta_override:match('^[Nn][Oo]$')
	else
		zeta_switch = rat.eq(et.equave, 2) and ET.is_zeta(et)
	end
	
	local prev_one = ''
	if et.size > 0 then
		prev_one = '[[' .. (et.size - 1) .. et.suffix .. '|← ' .. (et.size - 1) .. et.suffix .. ']]'
	end
	local next_one = '[[' .. (et.size + 1) .. et.suffix .. '|' .. (et.size + 1) .. et.suffix .. ' →]]'
	
	local step_size = ET.cents(et, 1)
	local note_12edo = ''
	if rat.eq(et.equave, 2) and et.size == 12 then
		note_12edo = '<sup>by definition</sup>'
	end
	
	local octave = ET.approximate(et, 2)
	local twelfth = ET.approximate(et, 3)
	
	local fifth = -octave + twelfth -- 3/2 = [-1 1>
	local fifth_error = ET.cents(et, fifth) - i._to_cents(3/2)
	local dual_fifth = math.abs(fifth_error) > step_size / 3

	local A1 = -11 * octave + 7 * twelfth -- 2187/2048 = [-11 7>
	local m2 = 8 * octave - 5 * twelfth -- 256/243 = [8 -5>
	local A1_cents = u._round(ET.cents(et, A1), 4)
	local m2_cents = u._round(ET.cents(et, m2), 4)

	local infobox_data = {}
	table.insert(infobox_data, {
		'Prime factorization',
		u._prime_factorization(et.size) .. prime
	})

	table.insert(infobox_data, {
		'Step size',
		u._round(step_size, 6) .. '¢' .. note_12edo
	})

	if not rat.eq(et.equave, 2) then
		table.insert(infobox_data, {
			'Octave',
			approximation(et, 2)
		})
	end
	
	if not rat.eq(et.equave, rat.new(3, 2)) then
		table.insert(infobox_data, {
			'Fifth',
			approximation(et, 3/2)
		})
	end

	table.insert(infobox_data, {
		'Semitones (A1:m2)',
		A1 .. ':' .. m2 .. ' (' .. A1_cents .. '¢ : ' .. m2_cents .. '¢)'
	})

	if dual_fifth and et.size > 0 then
		table.insert(infobox_data, {
			'Dual sharp fifth',
			approximation(et, 3/2, 1)
		})
		table.insert(infobox_data, {
			'Dual flat fifth',
			approximation(et, 3/2, -1)
		})
		local sharp = ET.approximate(et, 3/2, 1)
		local flat = ET.approximate(et, 3/2, -1)
		table.insert(infobox_data, {
			'Dual major 2nd',
			approximation(et, 9/8, 0, sharp + flat - octave)
		})
	end
	
	local consistency = tonumber(frame.args['Consistency'])
	if consistency == nil then
		consistency = l.consistency_limit(et, false, 43)
	end
	if consistency == nil then
		consistency = 'at least 43'
	end
	if consistency ~= nil then
		table.insert(infobox_data, {
			'Consistency limit',
			consistency
		})
	end
	local distinct_consistency = tonumber(frame.args['Distinct consistency'])
	if distinct_consistency == nil then
		distinct_consistency = l.consistency_limit(et, consistency or true, 43)
	end
	if distinct_consistency == nil then
		distinct_consistency = 'at least 43'
	end
	if distinct_consistency ~= nil then
		table.insert(infobox_data, {
			'Distinct consistency limit',
			distinct_consistency
		})
	end

	-- special properties
	if ET.is_highly_composite(et) or zeta_switch then
		local text = ''
		if ET.is_highly_composite(et) then
			text = text .. '[[Highly composite equal division|highly composite]]'
			if rat.eq(et.equave, 2) then
				categories = categories .. '[[Category:Highly composite EDO|' .. string.rep ('#', string.len (et.size)) .. ']]'
			end
		end
		if zeta_switch then
			if #text > 0 then text = text .. '<br>' end
			if not (type(zeta_override) == 'string' and #zeta_override > 0) then
				text = text .. ET.why_zeta(et)
			else
				text = text .. zeta_override
			end
			categories = categories .. '[[Category:Zeta|' .. string.rep ('#', string.len (et.size)) .. ']]'
		end
		table.insert(infobox_data, {
			'Special properties',
			'<div style="max-width: 270px;">' .. text .. '</div>'
		})
	end

	result = infobox.build(
		'[[' .. et.suffix .. '|' .. tuning .. ']]',
		infobox_data,
		prev_one,
		next_one
	)
	if not debug_mode then
		result = result .. categories
	end
	return result
end

return p