Module:ED intro

From Xenharmonic Wiki
Revision as of 05:07, 29 January 2024 by Ganaram inukshuk (talk | contribs) (Comments)
Jump to navigation Jump to search
Module documentation[view] [edit] [history] [purge]
This module should not be invoked directly; use its corresponding template instead: Template:ED intro.

This module automatically fills in an introduction for an equal-step tuning. It has presets for the most common equivalences (octave, tritave, and perfect fifth) and also supports arbitrary equivalences and arithmetic pitch sequences such as 88cET.

Introspection summary for Module:ED intro 
Functions provided (3)
Line Function Params
22 parse_ed (unparsed)
94 ed_intro (ed)
165 ed_intro_frame (invokable) (frame)
Lua modules required (3)
Variable Module Functions used
ord Module:Ordinal _ordinal
rat Module:Rational dependency not used
utils Module:Utils _gcd
_round_dec
_round

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


local ord = require('Module:Ordinal')
local utils = require('Module:Utils')
local rat = require('Module:Rational')
local p = {}

-- Module for creating an intro for an equal-division tuning.
-- Supported types: edo, edt, edf, edh, edr, edc (for octave, tritave/twelfth,
-- fifth, arbitrary harmonic h, arbitrary ratio r, and arbitrary cents c).

-- Notes:
-- - Edo and edt are technically edh's, and edf an edr; these are their own
--   types because their intros have specific wording.
-- - Edh is a special case of edr, where the ratio is h/1.
-- - Under harmonotonic tuning, edc and edr are also called ASp and APSp
--   (ambitonal sequence and arithmetic pitch sequence, respectively). These
--   were formerly called equal-step tunings but were reclassified as 1ed.
-- - Equal divisions of irrational constants (such as pi and e) are not very
--   common, but can be denoted as equal divisions of arbitrary cent values if
--   needed.

-- Parse ed function
function p.parse_ed(unparsed)
	local unparsed = unparsed or "12edo"
	
	-- If the unparsed ed is only a numeric value, default to edo
	if tonumber(unparsed) ~= nil then
		unparsed = unparsed .. "edo"
	end
	
	-- Parse
	local steps, suffix, equave = unparsed:match('^(%d+)([Ee][Dd](.+))$')
	steps = tonumber(steps)
	
	-- If the equave is text, then the equave is:
	-- o: octave, 2/1 (2nd harmonic)
	-- t: tritave or twelfth, 3/1 (3rd harmonic)
	-- f: fifth, 3/2
	-- Make sure these have the correct equave and suffix
	local ratio = "n/a"
	local cents = 0
	local ed_type = ""
	if equave == "o" or equave == "O" or equave == "2" or equave == "2/1" then
		equave = "2"
		ratio = "2/1"
		cents = 1200
		suffix = "edo"
		ed_type = "edo"
	elseif equave == "t" or equave == "T" or equave == "3" or equave == "3/1" then
		equave = "3"
		ratio = "3/1"
		cents = math.log(3) * 1200 / math.log(2)
		suffix = "edt"
		ed_type = "edt"
	elseif equave == "f" or equave == "F" or equave == "3/2" then
		equave = "3/2"
		ratio = "3/2"
		cents = math.log(3/2) * 1200 / math.log(2)
		suffix = "edf"
		ed_type = "edf"
	end
	
	-- For equaves not 2/1, 3/1, or 3/2
	if suffix ~= "edo" and suffix ~= "edt" and suffix ~= "edf" then
		-- If the equave is a number or ratio, convert it to cents
		-- If the equave is already a cent value, extract it
		local is_cents = string.match(equave, '^.+c$') ~= nil
		local is_harmonic = string.match(equave, '^%d+$') ~= nil
		local is_ratio = string.match(equave, '^%d+/%d+$') ~= nil
		
		if is_cents then
			ed_type = "edc"
			cents = tonumber(equave:match('^(.+)c$'))
		elseif is_harmonic then
			ed_type = "edh"
			local harmonic = tonumber(string.match(equave, '^%d+$'))
			cents = math.log(harmonic) * 1200 / math.log(2)
			ratio = string.format("%d/1", harmonic)
		elseif is_ratio then
			ed_type = "edr"
			local num, den = equave:match('^(%d+)/(%d+)$')
			local gcd = utils._gcd(num, den)
			num = num / gcd
			den = den / gcd
			cents = math.log(num / den) * 1200 / math.log(2)
			equave = string.format("%d/%d", num, den)
			ratio = equave
		end
	end

	return { ['cents'] = cents, ['equave'] = equave, ['ratio'] = ratio, ['steps'] = steps, ['suffix'] = suffix, ['type'] = ed_type }
end

-- Primary function
function p.ed_intro(ed)
	local ed = ed or "12edo"
	
	local parsed_ed = p.parse_ed(ed)
	local ed_type = parsed_ed['type']
	
	-- Intro formats for each possible case
	-- - Common abbrevs: edo, edt, edf; these have specially written intros
	-- - General harmonic: edh (h-th harmonic)
	-- - Arbitrary JI ratio: edr (ratio of p/q)
	-- - Arbitrary constant: edc
	-- - [[equal]]-step tunings: 1edo, 1edt, 1edf, 1edh, 1edp/q, 1edc
	local intro_text = ""
	if parsed_ed['steps'] == 1 then
		if ed_type == "edo" then
			intro_text = "'''1 [[equal]] division of the octave''' (abbreviated '''1edo''' or '''1ed2'''), also called '''1-tone equal temperament''' ('''1tet'''), or '''1 equal temperament''' ('''1et''') when viewed under a [[regular temperament]] perspective, is the [[tuning system]] where adjacent pitches are one [[octave]], or exactly/about ''s'' [[¢]], from each other."
		elseif ed_type == "edt" then
			intro_text = "'''1 [[equal]] division of the tritave''' (abbreviated '''1edt''' or '''1ed3''') is the [[non-octave]] [[tuning system]] where adjacent pitches are one tritave ([[3/1]]), or exactly/about ''s'' [[¢]], apart from each other."
		elseif ed_type == "edf" then
			intro_text = "'''1 [[equal]] division of the fifth''' (abbreviated '''1edf''' or '''1ed3/2''') is the [[non-octave]] [[tuning system]] where adjacent pitches are one perfect fifth ([[3/2]]), or exactly/about ''s'' [[¢]], apart from each other."
		elseif ed_type == "edh" then
			intro_text = "'''1 [[equal]] division of the ''hth'' harmonic''' (abbreviated '''1ed''h''''') is the [[non-octave]] [[tuning system]] where adjacent pitches are one interval of [[''h''/1]], or exactly/about ''s'' [[¢]], apart from each other."
		elseif ed_type == "edr" then
			intro_text = "'''1 [[equal]] division of ''p''/''q''''' (abbreviated '''1ed''p''/''q'''''), also called '''ambitonal sequence of ''p''/''q''''' ('''AS''p''/''q''''') or '''''p''/''q'' [[equal]]-step tuning''', is the [[non-octave]] [[tuning system]] where adjacent pitches are one interval of [[''p''/''q'']], or exactly/about ''s'' [[¢]], apart from each other."
		elseif ed_type == "edc" then
			intro_text = "'''1 [[equal]] division of ''c''¢''' (abbreviated '''1ed''c''c'''), also called '''arithmetic pitch sequence of ''c''¢''' ('''APS''c''¢'''), is the [[non-octave]] [[tuning system]] where adjacent pitches are exactly/about ''s'' [[¢]] apart from each other."
		end
	else
		if ed_type == "edo" then
			intro_text = "'''''k'' [[equal]] divisions of the octave''' (abbreviated '''''k''edo''' or '''''k''ed2'''), also called '''''k''-tone equal temperament''' ('''''k''tet'''), or '''''k'' equal temperament''' ('''''k''et''') when viewed under a [[regular temperament]] perspective, is the [[tuning system]] that divides the [[octave]] into ''k'' [[equal]] parts of exactly/about ''s'' [[¢]] each. Each step of ''k''edo represents a [[frequency ratio]] of 2<sup>1/''k''</sup>, or the ''kth'' root of 2."
		elseif ed_type == "edt" then
			intro_text = "'''''k'' [[equal]] divisions of the tritave''' (abbreviated '''''k''edt''' or '''''k''ed3''') is the [[non-octave]] [[tuning system]] that divides the interval [[3/1]] – also called the [[tritave]] or perfect twelfth – into ''k'' [[equal]] parts of exactly/about ''s'' [[¢]] each. Each step of ''k''edt represents a [[frequency ratio]] of 3<sup>1/''k''</sup>, or the ''kth'' root of 3."
		elseif ed_type == "edf" then
			intro_text = "'''''k'' [[equal]] divisions of the fifth''' (abbreviated '''''k''edf''' or '''''k''ed3/2''') is the [[non-octave]] [[tuning system]] that divides the interval [[3/2]], or perfect fifth, into ''k'' [[equal]] parts of exactly/about ''s'' [[¢]] each. Each step of ''k''edf represents a [[frequency ratio]] of (3/2)<sup>1/''k''</sup>, or the ''kth'' root of 3/2."
		elseif ed_type == "edh" then
			intro_text = "'''''k'' [[equal]] divisions of the ''hth'' harmonic''' (abbreviated '''''k''ed''h''''') is the [[non-octave]] [[tuning system]] that divides the interval [[''h''/1]], or the ''hth'' harmonic, into ''k'' [[equal]] parts of exactly/about ''s'' [[¢]] each. Each step of ''k''ed''h'' represents a [[frequency ratio]] of ''h''<sup>1/''k''</sup>, or the ''kth'' root of ''h''."
		elseif ed_type == "edr" then
			intro_text = "'''''k'' [[equal]] divisions of ''p''/''q''''' (abbreviated '''''k''ed''p''/''q''''') is the [[non-octave]] [[tuning system]] that divides the interval [[''p''/''q'']] into ''k'' [[equal]] pieces of exactly/about ''s'' [[¢]] each. Each step of ''k''ed''p''/''q'' represents the [[frequency ratio]] of (''p''/''q'')<sup>1/''k''</sup>, or the ''kth'' root of ''p''/''q''."
		elseif ed_type == "edc" then
			intro_text = "'''''k'' [[equal]] divisions of ''c''¢''' (abbreviated '''''k''ed''c''c''') is the [[non-octave]] [[tuning system]] that divides the interval of ''c'' [[¢]] into ''k'' [[equal]] pieces of exactly/about ''s'' [[¢]] each."
		end
	end
	
	-- Produce a table of key-value pairs of text to replace
	-- - ''k'': number of steps in ed
	-- - ''s'': size of a step
	-- - ''p''/''q'': equave as a ratio
	-- - ''h'': equave as a harmonic
	-- - ''c'': equave as a cent value
	-- - ''hth'': harmonic as an ordinal
	-- - ''kth'': step count as an ordinal
	local step_size = parsed_ed['cents'] / parsed_ed['steps']
	local text_replace_map = {
		["''k''"] = parsed_ed['steps'],
		["''s''"] = utils._round_dec(step_size, 3),
		["''c''"] = utils._round_dec(parsed_ed['cents'], 3),
		["''p''/''q''"] = parsed_ed['ratio'],
		["''h''"] = parsed_ed['equave'],
		["''hth''"] = ord._ordinal(parsed_ed['equave']),
		["''kth''"] = ord._ordinal(parsed_ed['steps']),
		["exactly/about"] = (utils._round(step_size, 3) == step_size and "exactly" or "about")
	}
	
	for key, value in pairs(text_replace_map) do
		intro_text = string.gsub(intro_text, key, value)
	end
	
	return intro_text
end

-- Wrapper function; for use with a template
function p.ed_intro_frame(frame)
	local ed = frame.args['ED']

	return p.ed_intro(ed)
end

return p