Moduuli:Musiikin taulukot/Pianon sointuote
Moduuli kosketinsoitinsormitusten piirtämiseen.
Funktio SointuoteNuoteista
muokkaa- Numeroparametrit: jokainen parametri on nuottinimi tai "+". Nuotit annetaan nousevassa järjestyksessä eli jälkimmäinen nuotti tulkitaan aina edellistä ylemmäksi. Esim.:
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|c|b}}
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|c|c}}
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|c|d}}
- Plusmerkillä (+) voi hypätä ylemmäs kokonaisen oktaavin:
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|c|+|d}}
- Piirtäminen aloitetaan ja lopetetaan aina toiseen kahden valkoisen koskettimen väliin. Alku- ja loppukohta asetetaan automaattisesti ellei parametreilla alku ja pituus muuta määrätä. Nuotit c:stä e:hen aloitetaan c:stä ja f:stä b:hen f:stä:
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|f|a|c}}
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|d|f♯|a|c}}
- Alkukohdan voi pakottaa c:hen ensimmäinen-parametrilla:
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteNuoteista|f|a|c|ensimmäinen=c}}
Funktio SointuoteSormio
muokkaaParametrit:
- väri<n>: (jossa n on jokin kokonaisluku) painetun koskettimen väri muodossa <valkoisen väri>;<mustan väri>; jos värejä ei anneta, käytetään moduulissa valmiina olevaa neljää väriä
- Kaikki seuraavat parametrit annetaan muodossa <nuotinnimi><oktaavi>, jossa oktaavi on tieteellisen merkintätavan mukainen; esim. "c4" (= keski-c)
- ensimmäinen: parametrin arvo on ensimmäinen näytettävä kosketin
- viimeinen: parametrin arvo on viimeinen näytettävä kosketin
- Muut nimetyt parametrit ovat painetut nuotit, joilla parametrin arvo on nuotin väri
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteSormio|ensimmäinen=c4|viimeinen=b4|c4=1|e4=1|g4=1}}
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteSormio|ensimmäinen=c4|viimeinen=b4|c4=1|cis4=1|d4=2|dis4=2|f4=3|fis4=3|g4=4|gis4=4}}
- ensimmäinen ja viimeinen voivat olla mitä tahansa valkoisia koskettimia
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteSormio|ensimmäinen=a0|viimeinen=c8|c4=1}}
- Värit voi vaihtaa väri-parametreilla. Värit voi antaa missä tahansa Värit-moduulin tukemassa muodossa (paitsi rgba).
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteSormio|ensimmäinen=f3|viimeinen=b4|väri1=rgb(234,83,122);rgb(10,25,222)|väri2=#34f3a3;#bc98f1|g3=2|c4=1|e4=1|g4=2}}
TODO
{{#invoke:Musiikin taulukot/Pianon sointuote|SointuoteSormio|ensimmäinen=f3|viimeinen=b4|väri2=gray(0.3);gray(0.8)|g3=2|c4=1|e4=1|g4=2}}
--- Moduuli kosketinsoittimen sointuotteiden piirtämiseen. Generoi timeline-lisäosan avulla kuvan.
local p = {}
local notedata = require "Moduuli:Kitarakirja/Nuottidata"
local tekstipohja = require "Moduuli:Tekstipohja"
local hsl = require "Moduuli:Värit"
-- Valkoisen koskettimen leveys.
local KEY_W = 12
-- Vasen marginaali. Pitää olla sama kuin PlotArea left.
local LMARGIN = 0
-- Oikea marginaali. Pitää olla sama kuin PlotArea right.
local RMARGIN = 0
-- Originaali: [https://de.wikipedia.org/wiki/Vorlage:KlavierAkkord/Doku#Alte_Version_mit_Timeline]
local template = [=[
ImageSize = width:{{{WIDTH}}} height:60
PlotArea = left:0 right:0 top:1 bottom:1
TimeAxis = orientation:vertical
#AlignBars = justify
AlignBars = early
Colors =
id:s value:gray(0.0)
id:textcol value:gray(0.5)
id:w value:gray(1)
{{{COLORS
}}}
Period = from:0 till:60
Define $keyB = from:24 till:end width:6
Define $keyW = from:start till:end width:10 color:wx
Define $spalt = from:2 till:end color:black width:0.2
LineData =
# layer:front
{{{WHITE_KEYS
}}}
{{{EDGES
}}}
{{{BLACK_KEYS
}}}
at:2 color:black width:0.2
at:59 color:black width:0.2
TextData =
# pos:(11,50) textcolor:textcol fontsize:XL
pos:(7,30) textcolor:textcol fontsize:S
tabs:({{{TABS}}})
text:{{{NOTENAMES}}}
# {{{DUMMY}}}
]=]
-- Mustien ja valkoisten koskettimien sarja. Voidaan aloittaa lukeminen joko indeksistä 1 tai 6.
local pattern = { 10, 1, 0, 1, 0, 10, 1, 0, 1, 0, 1, 0 }
-- Valkoisiin koskettimiin piirrettävät ja kommentteihin (tulostettavat) nuotinnimet.
local noteNames = { "c", "c♯/d♭", "d", "d♯/e♭", "e", "f", "f♯/g♭", "g", "g♯/a♭", "a", "a♯/b♭", "b" }
-- Mahdolliset merkinnät: http://ploticus.sourceforge.net/doc/color.html
-- Parittomat ovat valkoisia, parilliset mustia. Parametrin indeksi kerrotaan 2:lla.
-- Esim. 1 tarkoittaa 1. ja 2., 2 taas 3. ja 4.
local colors = {
[1] = "rgb(0.91,0.68,0.69)",
[2] = "rgb(0.8,0.14,0.16)",
[3] = "rgb(0.74,0.8,0.9)",
[4] = "rgb(0.22,0.41,0.69)",
[5] = "rgb(0.73,0.85,0.64)",
[6] = "rgb(0.25,0.6,0.32)",
[7] = "rgb(0.94,0.79,0.64)",
[8] = "rgb(0.85,0.49,0.19)",
[9] = "rgb(0.71,0.72,0.72)",
[10] = "rgb(0.33,0.31,0.33)",
[11] = "rgb(0.75,0.65,0.8)",
[12] = "rgb(0.42,0.3,0.6)",
[13] = "rgb(0.81,0.66,0.61)",
[14] = "rgb(0.57,0.14,0.15)",
[15] = "rgb(0.91,0.89,0.75)",
[16] = "rgb(0.58,0.55,0.24)",
}
--- Muotoilee viittauksen annettuun, numerolla viitattuun väriin.
-- @param index väriparin numero
-- @param bw 'white' tai 'black'
-- @return viittaus Colors-osan taulukkoon esim. 'color3'
local function get_color(index, bw)
if index < 1 or index > math.floor(#colors / 2) then
error("Virheellinen värin indeksi: " .. tostring(index))
end
if bw == "white" then
return "color" .. tostring((index - 1) * 2 + 1)
else
return "color" .. tostring((index - 1) * 2 + 2)
end
end
--- Asettaa väriparin.
-- @param index väriparin numero
-- @param colorW painetun valkoisen väri
-- @param colorW painetun mustan väri
local function set_color(index, colorW, colorB)
colors[(index - 1) * 2 + 1] = hsl.alter_color{ color = colorW, output = "rgb0.1" }
colors[(index - 1) * 2 + 2] = hsl.alter_color{ color = colorB, output = "rgb0.1" }
end
--- Muotoilee väritaulukon (@see colors) Timelinen käyttämään muotoon.
local function format_colortable()
local out = {}
for key, val in ipairs(colors) do
table.insert(out, "id:color" .. key .. " value:" .. val)
end
return table.concat(out, "\n")
end
--- Generoi timeline-koodin.
-- @param start Ensimmäisen koskettimen kokonaislukuarvo.
-- @param length Piirrettävien koskettimien määrä.
-- @param pressed Taulukko, pituudelta length, jossa painettujen koskettimien arvona on väri muiden nil.
-- Taulukon indeksi on (nuotin kokonaislukuarvo) - start ja pituus korkeintaan length.
-- @param dummy: Tilapäinen bugin kiertoparametri, joka ei vaikuta
-- lopputulokseen muuten kuin lisäämällä tyhjää, jolloin koodi
-- poikkeaa aiemmasta ja kuva piirrettään uudellen.
-- TODO: tarviiko lengthiä
local function create_image(start, length, pressed, dummy)
local outputWhites = { }
local outputEdges = { }
local outputBlacks = { }
local outputTabs = { }
local outputNames = { }
-- 1-alkuinen indeksi pressed-taulukkoon
local pressedIndex = 1
-- Valkoisen ja mustan tai tyhjän muodostamaa kosketinparia kuvaava arvo.
local pairIndex = 0
-- 0-alkuinen mod 12 -indeksi
local ch_idx = start % 12
local octave
--assert ( length == #pressed, "length: " .. tostring(length) .. ", #pressed: " .. tostring(#pressed) )
for pressedIndex = 1, length, 1 do
ch_idx = (start + (pressedIndex - 1)) % 12
octave = math.floor((start + (pressedIndex - 1)) / 12)
local tp = pattern[ch_idx + 1]
if tp % 10 == 0 then -- Valkoinen kosketin.
table.insert(outputWhites, "# " .. noteNames[ch_idx + 1])
if pressed[pressedIndex] then
local color = get_color(tonumber(pressed[pressedIndex]), 'white')
-- Valkoinen tehdään kahdesta palkista.
table.insert(outputWhites, "$keyW atpos:" .. tostring(pairIndex * KEY_W + 4 + LMARGIN) .. " color:" .. color)
table.insert(outputWhites, "$keyW atpos:" .. tostring(pairIndex * KEY_W + 8.5 + LMARGIN) .. " color:" .. color)
--table.insert(outputWhites, "$keyW atpos:" .. tostring(pairIndex * KEY_W + KEY_W/2 + 4 + LMARGIN) .. " color:" .. color)
--table.insert(outputWhites, "$keyW atpos:" .. tostring(pairIndex * KEY_W + KEY_W/2 + 8.5 + LMARGIN) .. " color:" .. color)
else
-- Painamattomia ei tarvitse lisätä, koska tausta on valkoinen.
table.insert(outputWhites, "#$keyW atpos:" .. tostring(pairIndex * KEY_W + 4 + LMARGIN) .. " color:w")
table.insert(outputWhites, "#$keyW atpos:" .. tostring(pairIndex * KEY_W + 8.5 + LMARGIN) .. " color:w")
end
table.insert(outputWhites, "")
-- Valkosia koskettimia erottava pystyviiva.
table.insert(outputEdges, "$spalt atpos:" .. tostring(pairIndex * KEY_W + LMARGIN))
-- Nuotinnimien kohdat ja nuotinnimet.
table.insert(outputTabs, tostring(pairIndex * KEY_W + LMARGIN) .. "-center")
table.insert(outputNames, "^" .. noteNames[ch_idx + 1])
pairIndex = pairIndex + 1
-- Hypätään yksi yli mustien indekseissä, että saadaan väli kohtaan, jossa on kaksi valkoista vierekkäin.
-- Jos ollaan ensimmäisessä koskettimessa skipataan musta aloitettiin sitten mistä tahansa. Esim.
-- jos aloitetaan a:sta, jää edeltävä gis pois.
if tp == 10 or pressedIndex == 1 then
table.insert(outputBlacks, "")
end
elseif tp == 1 then -- Musta kosketin.
table.insert(outputBlacks, "# " .. noteNames[ch_idx + 1])
if pressed[pressedIndex] then
local color = get_color(tonumber(pressed[pressedIndex]), 'black')
table.insert(outputBlacks, "$keyB atpos:" .. tostring(pairIndex * KEY_W + LMARGIN) .. " color:" .. color)
--table.insert(outputBlacks, "$keyB atpos:" .. tostring(pairIndex * KEY_W - 3 + LMARGIN) .. " color:" .. color)
--table.insert(outputBlacks, "$keyB atpos:" .. tostring(pairIndex * KEY_W + 3 + LMARGIN) .. " color:" .. color)
else
table.insert(outputBlacks, "$keyB atpos:" .. tostring(pairIndex * KEY_W + LMARGIN) .. " color:s")
--table.insert(outputBlacks, "$keyB atpos:" .. tostring(pairIndex * KEY_W - 3 + LMARGIN) .. " color:s")
--table.insert(outputBlacks, "$keyB atpos:" .. tostring(pairIndex * KEY_W + 3 + LMARGIN) .. " color:s")
end
end
end
table.insert(outputEdges, "$spalt atpos:" .. tostring(pairIndex * KEY_W + LMARGIN - 1))
table.insert(outputEdges, "")
table.insert(outputTabs, tostring(pairIndex * KEY_W) .. "-left")
width = tostring(pairIndex * KEY_W + LMARGIN + RMARGIN)
return tekstipohja.korvaaMuuttujat(template, {
["WIDTH"] = width,
["WHITE_KEYS"] = table.concat(outputWhites, "\n"),
["BLACK_KEYS"] = table.concat(outputBlacks, "\n"),
["EDGES"] = table.concat(outputEdges, "\n"),
["TABS"] = table.concat(outputTabs, ","),
["NOTENAMES"] = table.concat(outputNames, ""),
["COLORS"] = format_colortable(),
["DUMMY"] = string.rep("X", tonumber(dummy or "0")) })
end
--- Palauttaa annettua merkkijonomuotoista nuottia (esim. "c4") vastaavat arvot.
-- @return Nuotin nimi, esim. "c".
-- @return Oktaavi, esim. 4.
local function parse_notestring(notestr)
local name, oct = mw.ustring.match(notestr, "([^%d]*)(%d)")
if not name or not oct then
error("Virheellinen nuotti: " .. notestr)
end
return name, tonumber(oct)
end
--- Piirtää annetun alku- ja loppukohdan välisen sormion, jossa on painettuja koskettimia.
-- @param frame
-- ['ensimmäinen'] : ensimmäinen sisällytettävä näppäin
-- ['viimeinen'] : viimeinen sisällytettävä näppäin
-- muut nimetyt :
-- (muotoa c0, c#0, d0 ... c1 ... b8) :
-- painetut nuotit. Parametrin arvo on painetun
-- koskettimen värinumero.
-- (muotoa väri1, väri2...) :
-- arvo on väri Plotibuksen käyttämässä muodossa [linkki]. Väreihin
-- viitataan nuottiparametreissa numeroilla.
function p.SointuoteSormio(frame)
local first = frame.args["ensimmäinen"] or "c1"
local last = frame.args["viimeinen"] or "b8"
-- Syötteeksi kelpaavat nuotit.
local white_keys = "cdefgab"
-- First_integer ja last_integer: Nuotit täysasteikolla kokonaislukuina esitettynä, esim. c0 = 0, c4 = 37
local first_n, first_o = parse_notestring(first)
first_integer = notedata.getNoteIndex(first_n, first_o)
if not first_n then
error("Virheellinen parametri ensimmäinen. Kelvolliset arvot ovat c, d, e, f, g ja b")
end
local last_n, last_o = parse_notestring(last)
last_integer = notedata.getNoteIndex(last_n, last_o)
if not last_n then
error("Virheellinen parametri viimeinen. Kelvolliset arvot ovat c, d, e, f, g, a ja b")
end
-- Tarkistetaan, että arvoksi on annettu valkoinen kosketin.
if not white_keys:find(first_n) then
error("Virheellinen parametrin 'ensimmäinen' arvo: " .. first)
end
if not white_keys:find(last_n) then
error("Virheellinen parametrin 'viimeinen' arvo: " .. last)
end
local length = last_integer - first_integer + 1
if length < 0 then
error("Parametrin 'viimeinen' pitää olla suurempi kuin parametrin 'ensimmäinen'.")
elseif length < 3 then
error("Pitää olla vähintään kolme kosketinta.")
end
local pressed = { }
-- Katsotaan mitkä nuotit on annettu painettuina ja merkitään ne pressed-taulukkoon.
for note, val in pairs(frame.args) do
note = note:gsub("is", "♯")
note = note:gsub("es", "♭")
if note ~= "ensimmäinen" and note ~= "viimeinen" then
local note_name, octave = parse_notestring(note)
if note_name == "väri" then
local colors = mw.text.split(val, ";", true)
if #colors ~= 2 then
error("Tarvitaan kaksi väriä: " .. note .. "=" .. val)
end
set_color(octave, colors[1], colors[2])
else
note_integer = notedata.getNoteIndex(note_name, octave)
if note_integer < first_integer or note_integer > last_integer then
error("Nuotti ei mahdu annetulle välille: " .. note)
end
pressed[note_integer - first_integer + 1] = val
end
end
end
if frame.args["nowiki"] then
return "<pre>\n" .. create_image(first_integer, length, pressed, frame.args.dummy) .. "</pre>"
else
return frame:extensionTag{ name = "timeline", content = create_image(first_integer, length, pressed, frame.args.dummy) }
end
end
function p.SointuoteNuoteista(frame)
local notes = frame.args
local octave = 0
local pressed = {}
local first_integer -- 0-alkuinen indeksi koko asteikolla
local last_integer -- 0-alkuinen indeksi koko asteikolla
local prevInteger = -1 -- 0-alkuinen indeksi koko asteikolla
local first
local last
if frame.args["nuotit"] then
notes = mw.text.split(frame.args.nuotit, "–", true)
else
notes = frame.args
end
if #notes < 3 then
--error("Liian vähän nuotteja")
end
if frame.args["ensimmäinen"] then
first_n = frame.args["ensimmäinen"]
else
local note_n = notes[1]
if notedata.getNoteIndex(note_n, 0) < 5 then
first_n = "c"
else
first_n = "f"
end
end
first_integer = notedata.getNoteIndex(first_n, 0)
prevInteger = first_integer - 1
-- Syötetaulukon pituus. Lasketaan, koska # ei toimi frame.args-taulukolla.
local n_notes = 0
for index, note in ipairs(notes) do
n_notes = n_notes + 1
note = note:gsub("is", "♯")
note = note:gsub("as", "♭")
if note == "+" then
octave = octave + 1
else
-- Oletetaan että nuotit on annettu nousevassa järjestyksessä.
local integer = notedata.getNoteIndex(note, 0)
if integer <= prevInteger then
octave = octave + 1
end
prevInteger = integer
pressed[(12 * octave + integer) - first_integer + 1] = 1
end
end
-- Viimeisen nuotin nimi. Jos käyttäjä ei anna, lopetaan e:hen tai b:hen
-- riippuen siitä onko annetun soinnun viimeinen nuotti välillä c–e vai f–b.
if frame.args["viimeinen"] then
last_n = frame.args["viimeinen"]
else
local note_n = notes[n_notes]
if notedata.getNoteIndex(note_n, 0) < 5 then
last_n = "e"
else
last_n = "b"
end
end
-- Viimeisen nuotin absoluuttinen luku.
integer = notedata.getNoteIndex(last_n, 0)
if integer < prevInteger then
octave = octave + 1
end
last_integer = 12*octave + integer
length = last_integer - first_integer + 1
if frame.args["nowiki"] then
return "<pre>\n" .. create_image(first_integer, length, pressed, frame.args.dummy) .. "</pre>"
else
return frame:extensionTag{ name = "timeline", content = create_image(first_integer, length, pressed, frame.args.dummy) }
end
end
return p