Module:ED intro

Revision as of 01:25, 29 January 2024 by Ganaram inukshuk (talk | contribs) (Removed equal link from "equal temperament")
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
18 parse_ed (unparsed)
90 ed_intro (ed)
161 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 = {}

-- Notes on supported types:
-- - Supported types: edo, edt, edf, edh, edr, edc (for octave, tritave/twelfth,
--   fifth, arbitrary harmonic h, arbitrary ratio r, and arbitrary cents c).
-- - Note that EDs of irrational numbers (edir) aren't supported since some of
--   these constants have names (e, pi, phi) or are formatted in special ways
--   (sqrt(2)). These aren't very common and can be expressed as edc's if need
--   be (edsqrt(2) is ed600c), or as an ed of a non-integer number (ed1.41421).
-- - Also note that, under harmontonic tuning, edc and edr are the same as ASp
--   and APSp (ambitonal sequence and arithmetic pitch sequence); these were
--   recently reclassified as edr and edc, however.

-- 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 map 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