Moduuli:Kitarakirja/Sointuote
Ulkoasu
Tämän moduulin ohjeistuksen voi tehdä sivulle Moduuli:Kitarakirja/Sointuote/ohje
--- Otekaavio, nuottkuva ja tabulatuuri.
local p = {}
local otekaavio = require "Moduuli:Kitarakirja/Otekaavio"
local kitaramalli = require "Moduuli:Kitarakirja/Kitaramalli"
local lily = require "Moduuli:Kitarakirja/Lily"
--- Alustaa annetunkokoisen taulukon annetulla arvolla.
--
-- @param size: taulukon koko
-- @param init: alkioihin alustettava arvo
local function init_array(size, init)
local arr = {}
for i = 1, size do
arr[i] = init
end
return arr
end
-- TODO pois
-- Nuoteista käytetyt nimitykset. Jos parametri nuotit1 tai nuotit2 on annettu korvataan
-- taulukon arvot annetuilla arvoilla. Nuotit ovat taulukossa abcdefg-järjestelmän mukaan.
-- H lisätään vasta tulostusvaiheessa.
local g_notenames1 = { "c", "c♯", "d", "d♯", "e", "f", "f♯", "g", "g♯", "a", "a♯", "b" }
local g_notenames2 = { "c", "d♭", "d", "e♭", "e", "f", "g♭", "g", "a♭", "a", "b♭", "b" }
-- Indeksit nuottinnimet-taulukoihin
local indeces = {
["c"] = 0,
["c♯"] = 1,
["c𝄪"] = 2,
["d𝄫"] = 0,
["d♭"] = 1,
["d"] = 2,
["d♯"] = 3,
["d𝄪"] = 4,
["e𝄫"] = 2,
["e♭"] = 3,
["e"] = 4,
["e♯"] = 5,
["e𝄪"] = 6,
["f𝄫"] = 3,
["f♭"] = 4,
["f"] = 5,
["f♯"] = 6,
["f𝄪"] = 7,
["g𝄫"] = 5,
["g♭"] = 6,
["g"] = 7,
["g♯"] = 8,
["g𝄪"] = 9,
["a𝄫"] = 7,
["a♭"] = 8,
["a"] = 9,
["a♯"] = 10,
["a𝄪"] = 11,
["b𝄫"] = 9,
["b♭"] = 10,
["b"] = 11,
["b♯"] = 0,
["b𝄪"] = 1,
["c𝄫"] = 10,
["c♭"] = 11,
["b𝄫 (b♭)"] = 9,
["b♭ (b)"] = 10,
["b (h)"] = 11,
["b♯ (h♯)"] = 0,
["b𝄪 (h𝄪)"] = 1,
}
--- Palauttaa tabulatuuriin tarkoitetun nuotin nimen Lilypond-notaatiolla, esim. "dis''".
-- Tässä ei tarvitse ottaa huomioon enharmonisia nuotteja vaan käytettään vain toista
-- niistä.
-- param index: nuotin absoluuttinen indeksi
function lilytabnote(index, stringno)
if index == "x" then
return ""
end
local octave = math.floor((index - (indeces["c"] + 0*12)) / 12)
local note = g_notenames1[index % 12 + 1]
return lily.lilyfy{note} .. lily.getOctaveString(octave, note) .. "\\" .. stringno
end
-- Taulukko syötteen muuttamiseen sisäiseen muotoon.
local input_to_simple = {
["b♭ (b)"] = "b♭",
["b (h)"] = "b",
["b♭ (b)"] = "b♭",
["b𝄫 (b♭)"] = "b𝄫",
["b♯ (h♯)"] = "b♯",
["b𝄪 (h𝄪)"] = "b𝄪"
}
-- Taulukko nuotinnimienm muuttamiseen sisäisestä muodosta tulostettavaan muotoon.
local internal_to_output = {
["b♭"] = "b♭<br/>(b)",
["b"] = "b<br/>(h)",
["b♭"] = "b♭<br/>(b)",
["b𝄫"] = "b𝄫<br/>(b♭)",
["b♯"] = "b♯<br/>(h♯)",
["b𝄪"] = "b𝄪<br/>(h𝄪)"
}
local function notename_to_print_format(notename)
if internal_to_output[notename] then
return internal_to_output[notename]
else
return notename
end
end
local function to_lilynote(args)
local index = args.index
local name = args.name
if index == "x" or index == nil then
return ""
end
local octave = math.floor((index - indeces["c"]) / 12)
return lily.lilyfy{name} .. lily.getOctaveString(octave, name)
end
--- Palauttaa soinnun nuotit lilypond notaatiolla.
-- @param noteindeces: taulukko, jossa on joka kielelle oma nuotti-indeksi
-- @param notenames: nuottien nimet sisäisessä muodossa (esim. "b♯")
-- @return: taulukko, jossa on joka kielelle nuotti Lilypondin käyttämässä muodossa
local function make_lilynotes(noteindeces, notenames)
local lilynotes = init_array(6, "")
for i = 1, #noteindeces do
lilynotes[i] = to_lilynote{ index = noteindeces[i], name = notenames[i] }
end
return lilynotes
end
--- Palauttaa nuottimerkinnän tuottavan Lilypond-koodin (\Staff-lohkon).
-- Jos sointuja on kaksi varianttia, on palautettavan koodilohkon aikayksikkö 2/1. Jos
-- yksi on aikayksikkö 1/1.
-- param lilynotes1: ensimmäisen sointuvariantin nuotit Lilypond-muodossa
-- param lilynotes2: toisen sointuvariantin nuotit Lilypond-muodossa
-- return: \Staff-lohkon koodi
-- return: 1 jos yksi sointu, 2 jos kaksi sointua
local function get_staff_markup(lilynotes1, lilynotes2)
local notes_str1 = table.concat(lilynotes1, " ")
local notes_str2 = table.concat(lilynotes2, " ")
if notes_str2 == notes_str1 then
notes_str2 = ""
elseif notes_str1 == "" then
notes_str1 = notes_str2
notes_str2 = ""
end
if notes_str1 == "" and notes_str2 == "" then
return "", 1
elseif notes_str1 ~= "" and notes_str2 ~= "" then
return [=[
\new Staff {
\clef "treble_8"
\once \override Staff.TimeSignature #'stencil = ##f
<]=] .. notes_str1 .. [=[>1 | <]=] .. notes_str2 .. [=[>1 |
}
]=], 2
elseif notes_str1 ~= "" then
return [=[
\new Staff {
\clef "treble_8"
\once \override Staff.TimeSignature #'stencil = ##f
<]=] .. notes_str1 .. [=[>1
}
]=], 1
end
end
--- Muotoilee TabStaff-lohkon.
-- param noteindeces: nuotinnettava sointu absoluuttisina indekseinä
-- param time: aikayksikön nimittäjä (1 tai 2)
-- return: TabStaff-lohkon koodi
local function get_tabstaff_markup(noteindeces, time)
local lilynotestab = { "", "", "", "", "", "" }
-- Haetaan nuotit, josta generoidaan tabulatuuri. Nuottien nimillä
-- (onko esim. cis vai des) ei tässä ole väliä.
lilynotestab[1] = lilytabnote(noteindeces[1], 6)
lilynotestab[2] = lilytabnote(noteindeces[2], 5)
lilynotestab[3] = lilytabnote(noteindeces[3], 4)
lilynotestab[4] = lilytabnote(noteindeces[4], 3)
lilynotestab[5] = lilytabnote(noteindeces[5], 2)
lilynotestab[6] = lilytabnote(noteindeces[6], 1)
if time == 2 then
return [=[
\new TabStaff {
\override Stem #'transparent = ##t
\override Beam #'transparent = ##t
s2 <]=] .. table.concat(lilynotestab, " ") .. [=[>1 s2
}
]=]
else
return [=[
\new TabStaff {
\override Stem #'transparent = ##t
\override Beam #'transparent = ##t
<]=] .. table.concat(lilynotestab, " ") .. [=[>1
}
]=]
end
end
local function get_lilymarkup(noteindeces, notenames1, notenames2)
local lilynotes1 = {}
local lilynotes2 = {}
local notation_markup, tabstaff_markup
local time
local success
-- Nuotit, joista generoidaan nuottimerkintä.
lilynotes1 = make_lilynotes(noteindeces, notenames1)
if #notenames2 > 0 then
lilynotes2 = make_lilynotes(noteindeces, notenames2)
end
notation_markup, time = get_staff_markup(lilynotes1, lilynotes2)
-- Nuotit, joista generoidaan tabulatuuri.
tabstaff_markup = get_tabstaff_markup(noteindeces, time)
return [=[
<<
%\override Score.BarLine.break-visibility = ##(#f #t #t)
\time ]=] .. time .. [=[/1
]=] .. notation_markup .. [=[
]=] .. tabstaff_markup .. [=[
>>
]=]
end
--- Lukee kielten soivat nauhavälit.
--
-- @param conf:
-- @param args:
-- @param fret_pos: ensimmäisen kuvattavan nauhan nauhaväli
-- @return: taulukko, jossa on jokaiselta kieleltä soiva nauhaväli. Jos kieltä painetaan useasta kohdasta palauttaa suurimman.
-- 0 tarkoittaa vapaata kieltä. Nil tarkoittaa että kieli ei soi.
local function read_played_positions(conf, args, fret_pos)
local played_frets = init_array(conf.n_strings, nil)
local s_idx = 0
local f_idx = 0
local cur
assert ( fret_pos and fret_pos >= 1, "Virheellinen parametrin fret_pos arvo" )
-- Vapaat kielet.
for s_idx = 1, conf.n_strings do
if args[s_idx]:gsub("^%s*(.-)%s*$", "%1") == "o" then
played_frets[s_idx] = 0
else
played_frets[s_idx] = "x"
end
end
local from = conf.n_strings + 1
local till = conf.n_strings * (1 + 5) -- avoimet kielet + 5 nauhaväliä
for i = from, till do
cur = args[i]:gsub("^%s*(.-)%s*$", "%1")
-- Kielen ja nauhan numero.
s_idx = ((i - 1) % conf.n_strings) + 1
if s_idx == 1 then
f_idx = f_idx + 1
end
if cur == "o" or cur == "C" or cur == "D" or cur == "H" or cur == "-" then
played_frets[s_idx] = (fret_pos - 1) + f_idx
end
end
return played_frets
end
local function get_notename_table_row(notenames)
local out = {}
out[1] = '| style="padding-left: 10px; width: 20px;" | '
.. notename_to_print_format(notenames[1])
for i = 2, #notenames - 1 do
out[i] = '| style="width: 20px;" | '
.. notename_to_print_format(notenames[i])
end
out[#notenames] = '| style="padding-right: 10px; width: 20px;" | '
.. notename_to_print_format(notenames[#notenames])
return table.concat(out, "\n")
end
--- Tekee nuotinnimistä kaavion alle tulostettavan taulukon.
local function get_notename_table(conf, notenames1, notenames2)
local row1 = get_notename_table_row(notenames1)
if not notenames2 or #notenames2 == 0 then
return [=[
{| style="border-collapse: collapse; font-size: 80%; width: ]=] .. conf.min_width .. [=[px; "
|- style="vertical-align: top;"
]=] .. row1 ..
[=[
|}
]=]
end
local row2 = get_notename_table_row(notenames2)
return [=[
{| style="border-collapse: collapse; font-size: 80%; width: ]=] .. conf.min_width .. [=[px; "
|- style="vertical-align: top;"
]=] .. row1 .. [=[
|- style="vertical-align: top;"
]=] .. row2 .. [=[
|}
]=]
end
function p.Sointuote(frame)
local n_strings = 6
local conf = {
n_strings = n_strings,
min_width = (n_strings + 1) * 20,
}
local malli = kitaramalli:new{
kitaramalli.indeces["e"] + -1*12,
kitaramalli.indeces["a"] + -1*12,
kitaramalli.indeces["d"] + 0*12,
kitaramalli.indeces["g"] + 0*12,
kitaramalli.indeces["b"] + 0*12,
kitaramalli.indeces["e"] + 1*12,
}
local nuotit1 = frame.args.nuotit1
local nuotit2 = frame.args.nuotit2
local get_notename1 = nil
local get_notename2 = nil
local luokka = ""
if not nuotit1 and not nuotit2 then
luokka = "[[Luokka:Sointuotteet, joista puuttuu nuotinnimet]]"
end
if not nuotit1 and nuotit2 then
nuotit1 = nuotit2
nuotit2 = nil
end
get_notename1 = malli:get_notename_function(mw.text.split(nuotit1, "–"))
if nuotit2 then
get_notename2 = malli:get_notename_function(mw.text.split(nuotit2, "–"))
end
local frets = read_played_positions(conf, frame.args, (tonumber(frame.args.nauhanumero) or 1))
local notenames1 = {}
local notenames2 = {}
local noteindeces = {}
if get_notename1 then
for i,fret in ipairs(frets) do
if fret == "x" then
notenames1[i] = ""
if get_notename2 then
notenames2[i] = ""
end
noteindeces[i] = "x"
else
notenames1[i] = get_notename1{ string = i, fret = fret }
if get_notename2 then
notenames2[i] = get_notename2{ string = i, fret = fret }
end
noteindeces[i] = malli:get_note_index{ string = i, fret = fret }
end
end
end
local notenames_table = ""
local score = ""
if #notenames1 > 0 then
notenames_table = get_notename_table(conf, notenames1, notenames2)
local lilyoutput = get_lilymarkup(noteindeces, notenames1, notenames2)
score = frame:extensionTag{ name = "score", content = lilyoutput }
end
return [=[
<div style="display: inline-block; text-align: center;">
<div>
]=] .. score .. [=[
</div>
<div>
]=] .. otekaavio.Otekaavio(frame) .. [=[
</div>
]=] .. notenames_table .. [=[
</div>]=] .. luokka
end
return p