diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-12 23:46:03 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-12 23:46:03 +0000 |
commit | 873660d1a83ece926fe7206288dda9c36b349c1b (patch) | |
tree | a48f77125c309a355b5d0eb58d6b24446abe9d62 /Master/texmf-dist/tex/generic/musixlyr | |
parent | 2939242967231097459df0fc3150fabc2f639111 (diff) |
generic 1
git-svn-id: svn://tug.org/texlive/trunk@613 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic/musixlyr')
-rw-r--r-- | Master/texmf-dist/tex/generic/musixlyr/musixlyr.tex | 1102 |
1 files changed, 1102 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/musixlyr/musixlyr.tex b/Master/texmf-dist/tex/generic/musixlyr/musixlyr.tex new file mode 100644 index 00000000000..2143d8c5190 --- /dev/null +++ b/Master/texmf-dist/tex/generic/musixlyr/musixlyr.tex @@ -0,0 +1,1102 @@ +%% +%% musixlyr.tex: Convenient lyrics handling for MusiXTeX T.52 or later +%% +%% Copyright (C) 1996-2001 Rainer Dunker +%% +%% This program is free software; you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published by +%% the Free Software Foundation; either version 2 of the License, or +%% any later version. +%% +%% This program is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%% GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public License +%% along with this program; if not, write to the Free Software +%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +%% +%% Author: +%% Rainer Dunker +%% Wachtelweg 31 +%% 85591 Vaterstetten +%% Germany +%% +%% E-mail: rainer.dunker@web.de +%% +\ifx\undefined\lyr\else\endinput\fi +\immediate\write10{MusiXLYRics 2.0c\space<December 06, 2001>} + +\makeatletter + +%%%%%%%%%% +% +% register allocation +% +%%%%%%%%%% +\newtoks\alle@texte + +% internal parameters for setting text +\let\evtl@klein\empty +\let\evtl@komma\empty +\let\evtl@punktweg\empty +\let\evtl@offset\empty +\let\evtl@next@lyr\empty +\newif\if@strich +\newif\iflyr@processing +\newif\if@pmx@nextvoice +\newif\if@lyrmode +\newif\if@hyphen +\newif\ifaux@active +\newif\if@single@token +\newdimen\lyr@shift +\newbox\lyr@box +\newbox\lyr@hyphen@box +\newbox\lyr@linkbox +\newbox\lyr@linkdepthbox +\def\ma@sw{lyr@m} % "main/aux switch" + +% helpers for shuffling data around +\newtoks\@rohtext +\newtoks\@textvar + +\let\text@name\empty + +% public parameters +\newif\ifleftlyr +\newif\ifforcelyrhyphens +\newif\ifshowlyrshift +\newdimen\minlyrrulelength \minlyrrulelength=2mm +\newdimen\minmulthyphens \minmulthyphens=1.5cm +\newdimen\minlyrspace \minlyrspace=3pt +\def\lyrhyphenchar{-} +\newbox\lyrstrutbox + +\def\lyrlog#1{\immediate\write16{#1}} % just for debugging convenience + +% for testing token lists for emptyness with \ifx +\def\emp@tst{\empty@test@errmsg} +\def\empty@test@errmsg{% + \errmessage{This shouldn't happen; you have found a musixlyr bug}} + +%%%%%%%%%% +% +% lyrics definition +% +%%%%%%%%%% +% set up text completely +\def\setlyrics#1#2{% iterative variant + % Parameter: + % #1 - lyrics line name + % #2 - text + \@rohtext={#2 -}% + \@textvar={}% + %\lyrlog{setlyrics{#1}, raw text: \the\@rohtext}% + \loop + \expandafter\ifx\expandafter\emp@tst\the\@rohtext\emp@tst % no more text + \let\@weiter n\else \let\@weiter j% + \fi + \ifx\@weiter j% + \expandafter\split@lyr@by@hyphens\the\@rohtext\@end + \repeat + \expandafter\xdef\csname dertext@#1\endcsname{\the\@textvar}% + \expandafter\xdef\csname nochtext@#1\endcsname{\the\@textvar}% + %\lyrlog{setlyrics{#1}: \the\@textvar}% + \initialize@verse{#1}} + +% separate hyphens from syllables +\def\split@lyr@by@hyphens#1-#2\@end{% + % #1: text before first hyphen + % #2: text after first hyphen; may be empty + \ifx\emp@tst#2\emp@tst % -> no hyphen present + \@textvar=\expandafter{\the\@textvar#1}% + \else % -> hyphen present + \@textvar=\expandafter{\the\@textvar#1 @}% + \fi + \@rohtext={#2}% + %\lyrlog{splitlyrics 1: \the\@textvar}% + %\lyrlog{splitlyrics 2: \the\@rohtext}% + } + +% copy whole text under different name +\def\copylyrics#1#2{% + % #1 - existing text name + % #2 - new text name + % text still undefined? + \expandafter\ifx\csname dertext@#1\endcsname\relax + \errmessage{Trying to copy undefined verse "#1" to "#2"}% + \setlyrics{#2}{UNDEFINED}% + \else + \expandafter\let\expandafter\text@copy\csname dertext@#1\endcsname + \global\expandafter\let\csname dertext@#2\endcsname\text@copy + \global\expandafter\let\csname nochtext@#2\endcsname\text@copy + \initialize@verse{#2}% + \fi} + +% at 1st definition of a text name +\def\initialize@verse#1{% + % test whether lyrics line name already defined + \expandafter\ifx\csname stp@#1\endcsname\relax + \expandafter\gdef\csname stp@#1\endcsname{0pt}% tracks horizontal progress + \global\expandafter\let\csname cont@#1\endcsname\relax% context stuff + \expandafter\gdef\csname zwr@#1\endcsname{0}% flag for hyphen/rule status + % for layout definitions + \global\expandafter\let\csname llay@#1\endcsname\relax + % switch on auto-text + {\def\text@name{#1}\lyricson}% + % insert in list of all defined text names + \global\alle@texte=\expandafter{\the\alle@texte#1,}% + \fi} + +% just for more elegance ... +\def\if@multistaff{\ifnum\st@ffs>1 } + +\def\set@texte#1#2{% + % assign assigned lyrics lines to \@texte + % or \empty in case they are empty + % #1: instrument number + % #2: staff number of instrument + \expandafter\let\expandafter\@texte\csname\ma@sw#1-#2\endcsname + \ifx\@texte\relax\let\@texte\empty\fi} + +\def\set@texte@current#1{% + % apply \set@texte to current context + % using PMX, automatically switch to aux lyrics where required + \switch@pmx@aux{% + % get the verses + \ifnum\st@ffs>1 % multi-staff instrument + \set@texte{\the\noinstrum@nt}{\the\noport@@}% + \else + \set@texte{\the\noinstrum@nt}{1}% + \fi + % perform given action + #1}} + +\def\loop@texte#1\@repeat{% + % assumption: \@texte is already set properly, may be empty + % #1: action to be executed + \ifx\@texte\empty\else + \expandafter\loop@texte@step\@texte\@end{#1}% + \fi} + +\def\loop@texte@step#1,#2\@end#3{% + % assumption: text list is not empty, #1 contains list head + % #1: text list head + % #2: text list tail + % #3: action to be executed + % + % perform action on first text + \def\text@name{#1}% + #3\relax + % + % prepare iteration + \ifx\emp@tst#2\emp@tst % list tail empty + \let\@iterate \empty % stop looping + \let\text@name\empty % reset working environment + \else + \def\@iterate{\loop@texte@step#2\@end{#3}}% + \fi + \@iterate} + +% assign text name to staff +\def\assignlyrics#1{% for single-staff instruments + % #1: instrument number + \assignlyricsmulti{#1}1} + +\def\assignlyricshere#1{% assign lyrics to current instrument/staff context + % #1: comma-separated list of text names + \switch@pmx@aux{% + \ifnum\st@ffs>1 % multi-staff instrument + \assignlyricsmulti{\the\noinstrum@nt}{\the\noport@@}{#1}% + \else + \assignlyrics{\the\noinstrum@nt}{#1}% + \fi}} + +\def\assignlyricsmulti#1#2#3{% + % #1: instrument number + % #2: staff number of instrument + % #3: comma-separated list of text names + % gather farthest right current position + % of currently assigned lyrics lines + \y@v=0pt + \set@texte{#1}{#2}% + \loop@texte + % starting position greater than retrieved so far? + \ifdim\csname stp@\text@name\endcsname > \y@v + \y@v=\csname stp@\text@name\endcsname % advance maximum + \fi + \@repeat + % + % new text names list non-empty -> append comma + \ifx\emp@tst#3\emp@tst + \expandafter\global\expandafter\let\csname\ma@sw#1-#2\endcsname\relax + \else + \expandafter\gdef\csname\ma@sw#1-#2\endcsname{#3,}% + \fi + % set parameters according to newly assigned lyrics lines + \set@texte{#1}{#2}% + \loop@texte + % check for existence + \expandafter\ifx\csname stp@\text@name\endcsname\relax + \errmessage{Trying to assign undefined verse "\text@name"}% + \expandafter\setlyrics\expandafter{\text@name}{EMPTY}% + \fi + \reset@params + \@repeat} + + +\def\reset@params{% + \expandafter\xdef\csname stp@\text@name\endcsname{\the\y@v}% + \expandafter\gdef\csname zwr@\text@name\endcsname{0}} + + +% +% reset horizontal positioning parameters of all lyrics lines +% +\def\resetlyrics{% + \edef\@texte{\the\alle@texte}% + \y@v=0pt + \loop@texte \reset@params \@repeat} + + +%%%%%%%%%% +% +% process lyrics verse-wise +% +%%%%%%%%%% +% same action for all assigned verses +\def\forall@verses#1{% + % #1: action to be executed + \ifx\text@name\empty + % perform action for all assigned verses + \set@texte@current{% + \ifx\@texte\empty\else + \vplace@lyrics{\loop@texte \hbox{\lyr@strut #1}\@repeat}% + \fi}% + \else + % text name already selected -> perform action for this one only + #1% + \fi} + + +% specify separate actions per verse +\def\verses#1{% + % #1: comma-separated list of actions (from top to bottom) + \set@texte@current{% + \def\@param{#1}% running variable for per-text actions + \vplace@lyrics{% + \loop@texte \expandafter\one@verse\@param,\@end \@repeat}}} + +\def\one@verse#1,#2\@end{% + % #1: action list head = action for current verse + % #2: action list tail = actions for remaining verses + \def\@param{#2}% + % perfrom action + \hbox{\lyr@strut #1}} + + +%%%%%%%%%% +% +% line spacing for multiple verses +% +%%%%%%%%%% +\def\lyr@strut{\copy\lyrstrutbox} +\def\setlyrstrut{% set up strut according to currently active font + \setbox0=\hbox{()}% + \setbox\lyrstrutbox=\hbox{\vrule height 1.1\ht0 depth 1.1\dp0 width\z@}} +\setlyrstrut % initialize + + +%%%%%%%%%% +% +% retrieve text by syllable +% +%%%%%%%%%% +\def\next@lyr{% + \expandafter\let\expandafter\@nochtext\csname nochtext@\text@name\endcsname + %\show\@nochtext + \ifx\@nochtext\empty + % no more text + \@hyphenfalse\@lyric{???}% + \else + \@textvar=\expandafter{\@nochtext}% + \expandafter\next@syllable\the\@textvar\relax\relax + \fi} + +\def\next@syllable#1 #2#3\relax{% + % #1 - first syllable + % #2 - either hyphenation symbol @ + % or \relax (if text ends after #2) + % or 1st char/group of rest text + % #3 - rest text, may be empty + \parse@melisma{#2}{#3}#1_\@end} + +\def\test@single@token#1#2\@end{% + % #2 is empty if argument consists of a single token + \ifx\emp@tst#2\emp@tst + \@single@tokentrue + \else + \@single@tokenfalse + \fi} + +\def\parse@melisma#1#2#3_#4\@end{% parse trailing underscores + % #1: either hyphenation indicator @ + % or \relax (if text ends after #1), + % or 1st char/group of rest text + % #2: rest text, may be empty + % #3: current syllable; may be empty if melisma pending + % #4: trailing underscores, if any, or + % melisma notes number followed by single underscore, or + % empty if no melisma + % + % evaluate hyphenation sign + \ifx @#1% + \@hyphentrue + \@textvar={#2}% may be empty + \else + \@hyphenfalse + % decide rest text (#1 was no hyphen sign) + \ifx\relax#1% current syllable is final syllable + \@textvar={}% + \else + \test@single@token#1\@end % #1 may have been grouped + \if@single@token + \@textvar={#1#2}% + \else + \@textvar={{#1}#2}% + \fi + \fi + \fi + % + % melisma pending? + \ifx\emp@tst#4\emp@tst % no melisma + \let\melisma@spec\empty + \@lyric{\evtl@klein{\evtl@punktweg{#3}}\evtl@komma}% + \else % melisma + \ifx\emp@tst#3\emp@tst % syllable empty, d.i. in mid-melisma + \parse@melisma@tail#4\@end + \ifx\melisma@spec\empty % final melisma note + \lyrruleend + \fi + \else % syllable non-empty, d.i. at melisma start + \leftlyrtrue\@strichtrue + \parse@melisma@start#4\@end + \@lyric{\evtl@klein{\evtl@punktweg{#3}}\evtl@komma}% + \fi % at melisma start + \fi % in melisma + % + % set remaining text + \expandafter\xdef + \csname nochtext@\text@name\endcsname{\melisma@spec\the\@textvar}} + +\def\parse@melisma@start#1_\@end{% + % Cut trailing underscore and attach it at argument head. + % For underscore sequences, the effect is void. + % For numbers, it converts "num_" to "_num". + % Moreover, append a single space. + \def\melisma@spec{_#1 }} + +\def\parse@melisma@tail#1_\@end{% + % #1: either trailing underscores minus one + % or melisma notes number + % or empty + \ifx\emp@tst#1\emp@tst % no more underscores + \let\melisma@spec\empty + \else + \parse@melisma@tail@ii#1\@end + \fi} + +\def\parse@melisma@tail@ii#1#2\@end{% helper for deciding melisma spec type + % #1#2: either trailing underscores minus one + % or melisma notes number + \if#1_% % underscore sequence given + \def\melisma@spec{#1#2 }% + \else % number given + \ifnum#1#2>1 % more melisma notes pending + \count@=#1#2 + \advance\count@\m@ne + \edef\melisma@spec{_\the\count@\space}% + \else % no more melisma notes + \let\melisma@spec\empty + \fi + \fi} + +\def\@lyric#1{% + % #1: Text + \evtl@offset + % Alles Folgende ist Argument fuer obiges \evtl@offset: + {\csname llay@\text@name\endcsname% Layoutkontext abrufen + \lyr@processingtrue + \setbox\lyr@box=\hbox{#1}% + \setbox\lyr@hyphen@box=\hbox{\lyrhyphenchar}% + % Zwischenraum zu voriger Silbe ermitteln: + \get@lyrspace + \ifleftlyr\else + % Silbe zentriert -> Zwischenraum entspr. kleiner: + \advance\y@v -0.5\wd\lyr@box + \advance\y@v 0.5\qn@width % halbe Notenkopfbreite dazu + \fi + % Bindestrich von voriger Silbe anhaengig? + \expandafter\ifnum\csname zwr@\text@name\endcsname=1 + % Minimalzwischenraum entsprechend aendern: + \ifforcelyrhyphens + % Min. Zw.-R. mindestens so breit wie Bindestrich: + \ifdim\minlyrspace < \wd\lyr@hyphen@box + \minlyrspace=\wd\lyr@hyphen@box + \fi + \else + \minlyrspace=0pt % % kein Zwischenraum noetig + \fi + \fi + \ifdim\y@v < \minlyrspace % Zwischenraum zu klein? + \lyr@shift=\minlyrspace % Silbe um Differenz nach rechts verschieben + \advance\lyr@shift -\y@v + \y@v=\minlyrspace % Zwischenraumbreite = geg. Minimum + \else + \expandafter\ifnum\csname zwr@\text@name\endcsname=1 % Bindestrich anhaengig? + \ifforcelyrhyphens\else % Bindestrich nicht erzwungen? + \ifdim\y@v < \wd\lyr@hyphen@box % Zwischenraum zu schmal? + \advance\lyr@shift -\y@v % => Zw.raum ganz wegnehmen + % Dank an Sebastian Clauss fuer diese Verbesserung + \fi + \fi + \fi + \fi + \rlap{% + \hskip\lyr@shift + {\ifleftlyr + \aftergroup\rlap % linksbuendig + \else + \aftergroup\qlrlap % zentriert + \fi}% + % Alles Folgende ist Argument fuer obiges \qlrlap bzw. \rlap: + {% Ist von voriger Silbe noch ein Bindestrich anhaengig? + \expandafter\ifnum\csname zwr@\text@name\endcsname=1 + % Bindestrich nur setzen, wenn Platz genug vorhanden: + \ifdim\y@v < \wd\lyr@hyphen@box\else + \print@hyphen + \fi + \fi + \ifshowlyrshift + % Mit Rechteck Wortverschiebung zeigen: + \llap{\vrule width \lyr@shift height \ht\strutbox}% + \fi + \unhcopy\lyr@box % Wort setzen + % Startposition des nachfolgenden Zwischenraums festhalten: + \getcurpos + \advance\y@v by \lyr@shift + \ifleftlyr + \advance\y@v \wd\lyr@box + \else + \advance\y@v 0.5\wd\lyr@box + \advance\y@v 0.5\qn@width % halbe Notenkopfbreite dazu + \fi + \expandafter\xdef\csname stp@\text@name\endcsname{\the\y@v}% Startposition setzen + \if@hyphen % Bindestrich gefordert? + \expandafter\gdef\csname zwr@\text@name\endcsname{1}% + \else + \if@strich % Verlaengerungs-Strich gefordert? + \expandafter\gdef\csname zwr@\text@name\endcsname{2}% + \else % nichts gefordert + \expandafter\gdef\csname zwr@\text@name\endcsname{0}% + \fi + \fi}}}} + +\def\print@hyphen{% + \llap{\hbox to \y@v{% + % Zwischenraum mit "Strich-Kette" ausfuellen: + \loop + \hfil\lyrhyphenchar\hss% rechter Raum darf am Systemende negativ werden + \advance\y@v by -\minmulthyphens + \ifdim\y@v > 0pt% + \repeat}}} + +\def\get@lyrspace{% + \getcurpos + \advance\y@v by -\csname stp@\text@name\endcsname + \relax} + +% Verlaengerungs-Striche abschliessen: +\def\lyrruleend{\forall@verses\lyrrule@end} + +\def\lyrrule@end{% + \expandafter\ifcase\csname zwr@\text@name\endcsname + % 0 -> Bindestrich von vorigem System anhaengig (nur bei Melisma; + % wurde bei Systemende zurückgesetzt) + % -> Einstellung fuer Bindestrich-Einfuegen an nächster Note setzen: + \expandafter\gdef\csname zwr@\text@name\endcsname{1}% + \or + % 1 -> Bindestrich anhaengig -> nichts tun + \or + % 2 -> Strich anhaengig: + \roff{% Zum rechten Notenkopf-Rand + \get@lyrspace\print@lyr@rule + % Zwischenraum-Startposition festhalten, wenn Wort nicht nach + % rechts darueber hinausragt: + \getcurpos + \ifdim\csname stp@\text@name\endcsname < \y@v + \expandafter\xdef\csname stp@\text@name\endcsname{\the\y@v}% + \fi}% + % Einstellung zuruecksetzen: + \expandafter\gdef\csname zwr@\text@name\endcsname{0}% + \fi} + +\def\print@lyr@rule{% + % Kleiner Zwischenraum zur vorherigen Silbe: + \advance\y@v by -2pt% + \ifdim \y@v > \minlyrrulelength + \llap{\vrule\@width\y@v\@height\lthick\@depth0pt}% + \fi} + + +%%%%%%%%%% +% +% Textstellen per Label anspringen +% +%%%%%%%%%% +\def\llabel#1{}% Damit Kennzeichnung bei der Ausgabe ohne Effekt bleibt + +\def\golyr#1{\forall@verses{\@golyr{#1}}} + +\def\@golyr#1{{% + \expandafter\let\expandafter\@nochtext\csname dertext@\text@name\endcsname + \def\query@label{#1}% + \loop + \expandafter\find@llabel\@nochtext\ende + \ifx\query@label\cur@label\let\@weiter n\else \let\@weiter j\fi + \if\@weiter j\repeat + \expandafter\global\expandafter\let + \csname nochtext@\text@name\endcsname\@nochtext}} + +\def\find@llabel#1\llabel#2#3\ende{% + % #1 - Text vor erstem \llabel + % #2 - naechstfolgender \llabel-Name + % #3 - Resttext + \def\cur@label{#2}% + \def\@nochtext{#3}} + + +%%%%%%%%%% +% +% Offene Silbentrennungen und -verlaengerungen am Systemende abschliessen +% +%%%%%%%%%% +\let\@orig@z@suspend\z@suspend +\def\z@suspend{% + \znotes\sysend@lyrics\empty\en + \znotes\sysend@lyrics\auxlyr\en + \@orig@z@suspend} + +\def\sysend@verse{% + % Flag auswerten: + \expandafter\ifcase\csname zwr@\text@name\endcsname + % 0 -> fertig; + \or + % 1 -> Bindestrich anhaengig: + \csname llay@\text@name\endcsname% Layoutkontext abrufen + \get@lyrspace + \print@hyphen + % Einstellung zuruecksetzen + % (-> Bindestrich wird nicht im nächsten System fortgesetzt, + % außer bei \lyrrule@end am Melisma-Ende): + \expandafter\gdef\csname zwr@\text@name\endcsname{0}% + \or + % 2 -> Verlaengerungs-Strich anhaengig: + % Platz zum rechten Systemrand, damit Strich nicht in Taktstrich ragt: + \loffset{0.3}{\get@lyrspace\print@lyr@rule}% + \fi + % Startposition fuer naechstes System zuruecksetzen: + \expandafter\gdef\csname stp@\text@name\endcsname{0pt}} + +\def\sysend@lyrics#1{% + % #1: \auxlyr or \empty + #1{\let\switch@pmx@aux\empty \forall@verses\sysend@verse}% + \if@multistaff + % loop over staves of instrument + \ifnum \noport@@ < \st@ffs + \def\@next{\nextstaff\sysend@lyrics#1}% + \else % staves of instrument finished; continue with next instrument + \sysend@lyrics@instrum@loop#1% + \fi + \else % single-staff instrument + \sysend@lyrics@instrum@loop#1% + \fi + % iterate + \@next} + +\def\sysend@lyrics@instrum@loop#1{% + % prepare instruments loop + \ifnum \noinstrum@nt < \nbinstruments + \def\@next{\nextinstrument\sysend@lyrics#1}% + \else % \noinstrum@nt >= \nbinstruments + \let\@next\empty + \fi} + + +%%%%%%%%%% +% +% Zeilenspezifisches Layout festlegen +% +%%%%%%%%%% +\def\lyrlayout#1{% + \forall@verses{% + \expandafter\gdef\csname llay@\text@name\endcsname{#1}% + % Wenn gerade Text verarbeitet wird, Kontext sofort abrufen: + \iflyr@processing #1\fi}} + +% +% Kontextbehandlung fuer Textnamen: +% +% Aktion zu Kontext hinzufuegen: +\def\add@context#1{% + \toks@=\expandafter\expandafter\expandafter + {\csname cont@\text@name\endcsname #1}% + \expandafter\xdef\csname cont@\text@name\endcsname{\the\toks@}} + +% Kontext abrufen: +\def\@context{% + \expandafter\let\expandafter\der@kontext\csname cont@\text@name\endcsname + \clear@context + \der@kontext} + +% Kontext loeschen: +\def\clear@context{% + \global\expandafter\let\csname cont@\text@name\endcsname\empty} + + +%%%%%%%%%% +% +% Zusaetzliche Textzeilen oberhalb der Notenzeile (auxiliary lyrics) +% +%%%%%%%%%% +\let\enableauxlyrics\empty % just for backward compatibility + +% Befehle auf auxlyrics beziehen: +\def\auxlyr#1{{% + \def\ma@sw{lyr@a}% + \aux@activetrue + #1}} + + +%%%%%%%%%% +% +% vertical lyrics positioning +% +%%%%%%%%%% +\def\lyrraise#1{% + % #1: instrument number + \lyrraisemulti{#1}1} + +\def\lyrraisehere#1{% + % #1: position/offset + \switch@pmx@aux{% + \ifnum\st@ffs>1 % multi-staff instrument + \lyrraisemulti{\the\noinstrum@nt}{\the\noport@@}{#1}% + \else + \lyrraise{\the\noinstrum@nt}{#1}% + \fi}} + +\def\lyrraisemulti#1#2#3{% + % #1: instrument number + % #2: staff of instrument + % #3: position/offset + \toks@=\expandafter{\csname l@raise#1-#2\endcsname}% + \expandafter\ifx\the\toks@\relax + % raise parameter still unset + \expandafter\lyrraise@init\the\toks@ + \fi + % now set raise parameter + \expandafter\expandafter\expandafter + \lyr@raise@multii\the\toks@\@end{#1}{#2}{#3}% + %\lyrlog{raise #1-#2: \expandafter\empty\the\toks@}% +} + +\def\lyr@raise@multii#1@#2\@end#3#4#5{% + % #1: current main position/offset + % #2: current aux position/offset + % #3: instrument number + % #4: staff of instrument + % #5: new position/offset + \expandafter\xdef\csname l@raise#3-#4\endcsname{% + \ifaux@active #1@#5\else #5@#2\fi}} + +% be backward compatible +\let\setsongraise@orig\setsongraise +\def\setsongraise#1#2{\setsongraise@orig{#1}{#2}\lyrraise{#1}{b#2}} +\def\auxsetsongraise#1#2{\auxlyr{\lyrraise{#1}{b#2}}} + + +\def\lyrraise@init#1{% + % #1: control sequence to be set to default value + \gdef#1{b0pt@a0pt}} + + +% vertically place lyrics columns +% replaces MusiXTeX's \C@tx +\def\vplace@lyrics#1{% + % find out applicable positioning settings + \edef\placelyr@staff{\ifnum\st@ffs>1 \the\noport@@ \else 1\fi}% + \toks@=\expandafter + {\csname l@raise\the\noinstrum@nt-\placelyr@staff\endcsname}% + % eventually initialize lyrraise setting first + \expandafter\ifx\the\toks@\relax % lyrraise still unset + \expandafter\lyrraise@init\the\toks@ + \fi + \expandafter\expandafter\expandafter\vplace@lyricsii\the\toks@\@end{#1}} + +\def\vplace@lyricsii#1#2@#3#4\@end#5{% + % #1: main lyrics positioning switch (a/b) + % #2: main lyrics raise value + % #3: aux lyrics positioning switch (a/b) + % #4: aux lyrics raise value + % #5: lyrics material to be issued + % + % decice main/aux context + % + \ifaux@active \let\lyr@ab#3\toks@={#4}% + \else \let\lyr@ab#1\toks@={#2}% + \fi + % + % decide placement situation: above/below/in-mid of system or instrument + % + \if\lyr@ab a% above staff + \ifnum\placelyr@staff<\st@ffs % non-highest staff of multiple staves + \vplaceLyricsAboveMultistaff{#5}% + \else % single or highest staff of instrument + \ifnum\noinstrum@nt<\nbinstruments % lyrics go above instrument + \vplaceLyricsAboveInstrument{#5}% + \else % lyrics go into top margin + \vplaceLyricsTopMargin{#5}% + \fi + \fi + \else % below staff + \ifnum\placelyr@staff>1 % non-lowest staff of multiple staves + \vplaceLyricsBelowMultistaff{#5}% + \else % single or lowest staff of instrument + \ifnum\noinstrum@nt>1 % lyrics go below instrument + \vplaceLyricsBelowInstrument{#5}% + \else % lyrics go into bottom margin + \vplaceLyricsBottomMargin{#5}% + \fi + \fi + \fi} + +% +% user-supersedable placement calculations +% +\def\vplaceLyricsBelowMultistaff#1{% + % #1: lyrics material + % reduced \C@Tx algorithm + \y@iv=\the\toks@\relax + \C@Inter % compute \stem@skip (?) + \advance\y@iv -0.5\stem@skip + \raise\y@iv\vbox\@to\z@{\vss\offinterlineskip#1\vss}} + +\def\vplaceLyricsAboveMultistaff#1{% + % #1: lyrics material + % reduced \C@Tx algorithm + \y@iv=\the\toks@\relax + \C@Inter % compute \stem@skip (?) + \advance\y@iv -0.5\stem@skip + % add height difference to base line of upper staff + \advance\y@iv \interportee + \raise\y@iv\vbox\@to\z@{\vss\offinterlineskip#1\vss}} + +\def\vplaceLyricsBottomMargin#1{% + % #1: lyrics material + % based on \C@tx + \y@iv=\the\toks@\relax + \advance\y@iv -\staffbotmarg + \raise\y@iv\vbox\@to\z@{\vss\offinterlineskip#1\vss}} + +\def\vplaceLyricsTopMargin#1{% + % #1: lyrics material + % based on \C@tx, "mirrored" bottom margin situation + \y@iv=\the\toks@\relax + \advance\y@iv \stafftopmarg + \Comp@High \advance\y@iv\y@v % \y@v = total height of instrument + \advance\y@iv \altitude % for multi-staff: + \advance\y@iv-\altportee % reduce by base hight of current staff + \raise\y@iv\vbox\@to\z@{\vss\offinterlineskip#1\vss}} + +\def\vplaceLyricsBelowInstrument#1{% + % #1: lyrics material + % assumption: \noinstrum@nt > 1 + % based on \C@tx + \y@iv=\the\toks@\relax + \multiply\y@iv 2 % balance division by 2 below + \advance\noinstrum@nt\m@ne + \advance\y@iv -\csname interinstrument\romannumeral\noinstrum@nt\endcsname + \C@Inter % compute \stem@skip (?) + \advance\y@iv -\stem@skip + \divide\y@iv\tw@ + \advance\noinstrum@nt\@ne + \raise\y@iv\vbox\@to\z@{\vss\offinterlineskip#1\vss}} + +\def\vplaceLyricsAboveInstrument#1{% + % #1: lyrics material + % assumption: \noinstrum@nt < \nbinstruments + % analogous to \C@tx, but refers to upper instrument instead + \y@iv=\the\toks@\relax + \multiply\y@iv 2 % balance division by 2 below + \advance\y@iv -\csname interinstrument\romannumeral\noinstrum@nt\endcsname + \C@Inter % compute \stem@skip (?) + \advance\y@iv -\stem@skip + \divide\y@iv\tw@ + % add height difference to base line of upper instrument + \begingroup + \advance\y@iv-\altportee \advance\noinstrum@nt\@ne \s@l@ctinstr + \advance\y@iv \altitude + \raise\y@iv\vbox\@to\z@{\vss\offinterlineskip#1\vss}% + \endgroup} + + +%\def\C@tx{% +% \ifnum\noinstrum@nt=\@ne +% \y@iv\staffbotmarg +% \else +% \advance\noinstrum@nt\m@ne +% \y@iv\csname interinstrument\romannumeral\noinstrum@nt\endcsname +% \C@Inter % compute \stem@skip +% \advance\y@iv\stem@skip +% \divide\y@iv\tw@ +% \advance\noinstrum@nt\@ne +% \fi +% \advance\y@iv-\csname T@R\romannumeral\noinstrum@nt\endcsname +% \lower\y@iv\uplap} +%\def\uplap#1{\vbox\@to\z@{\vss#1}} + + +%%%%%%%%%% +% +% Textsatz-Automatik +% +%%%%%%%%%% +% Text automatisch unter alle "spacing"-Noten eines Systems: +\let\orig@writ@note\writ@note +\def\writ@note{% + \ifnum\n@i<\@c % Bedingung fuer's Notenschreiben in \writ@note (warum?) +% \ifx\st@m\beamst@m +% \uptext{\csname s@bl\balken@nr\endcsname}% +% \else + \decide@lyrmode + \main@aux@or@not{\forall@verses{\@context\evtl@next@lyr}}% +% \fi + \fi + \orig@writ@note} + +\def\lyrmode@no {\def\main@aux@or@not##1{}} +\def\lyrmode@main{\def\main@aux@or@not##1{##1}} +\def\lyrmode@aux {\let\main@aux@or@not\auxlyr} +\let\pmx@auxmode\lyrmode@aux + +% Feststellen, ob Haupt- oder Nebentext oder gar nichts gesetzt werden soll: +\ifx\nextvoice\undefined % ohne PMX + \def\decide@lyrmode{% + \call@lyrmode + \if@lyrmode \decide@stem@direction % Notenhals-Automatik + \else % manuell, nur "spacing"-Noten + \ifadvance \lyrmode@main + \else \lyrmode@no + \fi + \fi} + \def\decide@stem@direction{% + \ifx\st@m\upst@m \lyrmode@aux \else + \ifx\st@m\up@flag \lyrmode@aux \else + \ifx\st@m\downst@m \lyrmode@main\else + \ifx\st@m\down@flag\lyrmode@main\else + \ifx\st@m\setst@m \lyrmode@no \else % kein Hals + \ifx\st@m\resetst@m\lyrmode@no \else + \ifx\st@m\beamst@m + \expandafter\ifx\csname s@bl\balken@nr\endcsname o\lyrmode@aux + \else\lyrmode@main + \fi + \else\errmessage{invalid \string\st@m\space setting}% + \fi\fi\fi\fi\fi\fi\fi} +\else % mit PMX + \def\decide@lyrmode{% + \ifadvance % nur "spacing"-Noten + \call@lyrmode + \if@pmx@nextvoice % Oberstimme + \if@lyrmode\lyrmode@main \else\pmx@auxmode \fi + \else % Unterstimme + \if@lyrmode\pmx@auxmode \else\lyrmode@main \fi + \fi + \else + \lyrmode@no % non-spacing Note + \fi} + \let\orig@nextvoice\nextvoice % \nextvoice erweitern + \def\nextvoice{\orig@nextvoice\@pmx@nextvoicetrue} +\fi + +\def\call@lyrmode{% activate lyrmode setting of current staff/instrument + \ifnum\st@ffs>1 % multi-staff instrument + \csname zlm@\the\noinstrum@nt-\the\noport@@\endcsname + \else % single-staff instrument + \csname zlm@\the\noinstrum@nt-1\endcsname + \fi} + +\def\switch@pmx@aux#1{% + % using PMX, automatically activate auxlyr context for #1 after \nextvoice + \ifx\nextvoice\undefined % not using PMX + #1% + \else % using PMX + \call@lyrmode + \if@pmx@nextvoice % upper PMX voice + \if@lyrmode\lyrmode@main \else\pmx@auxmode \fi + \else % lower PMX voice + \if@lyrmode\pmx@auxmode \else\lyrmode@main \fi + \fi + \main@aux@or@not{#1}% + \fi} + + + +% lyrmode umschalten: +\def\switch@lyrmode#1#2#3{% + % #1: instrument number + % #2: staff-of-instrument number + % #3: lyrmode setting + \ifnum#1=0 % % alle Zeilen einbeziehen + \switch@lyrmode@all@instrum#3% + \else % nur 1 Zeile + \global\expandafter\let\csname zlm@#1-#2\endcsname=#3% + \fi} + +% loop over all possible instruments +\def\switch@lyrmode@all@instrum#1{% + \m@loop \switch@lyrmode@all@staves#1\repeat} + +% loop over 4 possible staves of instrument +\def\switch@lyrmode@all@staves#1{% + \begingroup + \count@=0 + \loop + \advance\count@ 1 + \switch@lyrmode{\the\noinstrum@nt}{\the\count@}#1% + \ifnum\count@<4 \repeat + \endgroup} +% ... nicht wahnsinnig effizient, zugegeben ... + + +\def\lyrmodenormal#1{\lyrmodenormalmulti{#1}1} +\def\lyrmodealter #1{\lyrmodealtermulti {#1}1} + +\def\lyrmodenormalmulti#1#2{\switch@lyrmode{#1}{#2}\@lyrmodefalse} +\def\lyrmodealtermulti #1#2{\switch@lyrmode{#1}{#2}\@lyrmodetrue } + +\def\lyrmodenormalhere{\lyrmode@here\@lyrmodefalse} +\def\lyrmodealterhere {\lyrmode@here\@lyrmodetrue } + +\def\lyrmode@here#1{% apply lyrmode to current instrument/staff context + % #1: lyrmode switch + \if@multistaff + \switch@lyrmode{\the\noinstrum@nt}{\the\noport@@}#1% + \else + \switch@lyrmode{\the\noinstrum@nt}1#1% + \fi} + +\lyrmodenormal0 % auf "normal" initialisieren + +% fuer Halsrichtungs-Automatik: Balkenlage in \s@bl<nr> vermerken +\def\balk@nlage#1{\global\expandafter\let + \csname s@bl\balken@nr\endcsname #1\relax} +\let\orig@i@bu\i@bu \def\i@bu{\balk@nlage o\orig@i@bu}% <o>ben +\let\orig@i@bl\i@bl \def\i@bl{\balk@nlage u\orig@i@bl}% <u>nten + +\let\orig@s@l@ctbeam\s@l@ctbeam +\def\s@l@ctbeam#1\relax{\orig@s@l@ctbeam#1\relax \xdef\balken@nr{\number\n@i}} + + +% Auto-Text ein- und ausschalten (innerhalb \notes...\enotes): +\def\lyricson{\forall@verses{\add@context\verse@on@context}} +\def\verse@on@context{% + \let\evtl@next@lyr\next@lyr + \add@context\verse@on@context} + +\def\lyricsoff{\forall@verses\clear@context} + +\def\lyric {\let\evtl@hyph\@hyphenfalse\futurelet\ast@risk\lyric@i} +\def\lyrich{\let\evtl@hyph\@hyphentrue \futurelet\ast@risk\lyric@i} + +\def\lyric@i{% + \ifx\ast@risk*% + \let\evtl@nolyr\relax \let\@next\lyric@ii + \else + \let\evtl@nolyr\nolyr \def\@next{\nolyr\lyric@ii*}% + \fi + \@next} + +% Silben abseits vom Haupttext ausgeben: +\def\lyric@ii*#1{\forall@verses{\@context\evtl@hyph\@lyric{#1}}\evtl@nolyr} + +% Manipulationen einzelner Haupttext-Silben: +\def\forall@context#1{\forall@verses{\add@context{#1}}} + +% 1 Silbe ausgeben: +\def\lyr{\forall@verses{\@context\next@lyr}} + +% Linksbuendig: +\def\llyr{\forall@context{\leftlyrtrue}} + +% Verlaengerungs-Strich: +\def\lyrrule{\forall@context{\@strichtrue}} + +% Horizontale Verschiebung (analog \roffset): +\def\lyroffset#1{\forall@context{\def\evtl@offset{\roffset{#1}}}} + +% Kein automatischer Text: +\def\nolyr{\forall@context{\let\evtl@next@lyr\empty}} + +% Kleinbuchstaben: +\def\lclyr{\forall@context{\let\evtl@klein\@klein}} +\def\@klein#1{\lowercase\expandafter{#1}} + +% Satzzeichen anhaengen: +\def\lyrpt#1{\forall@context{\def\evtl@komma{#1}}} + +% Punkt vom Ende abschneiden: +\def\lyrnop{\forall@context{\let\evtl@punktweg\@punktweg}} +\def\@punktweg#1{{\punktweg@rek#1\ende}} +\def\punktweg@rek#1#2\ende{% + \def\par@ii{#2}% + \ifx\par@ii\empty\else + \aftergroup#1% + \expandafter\punktweg@rek\par@ii\ende + \fi} + +% Melisma beginnen und abschliessen: +\def\beginmel{\forall@verses{\llyr\lyrrule\add@context\lyricsoff}} +\def\endmel{\forall@verses{\lyrruleend\add@context\lyricson}} + +% +% Bindebogen unter zwei Silben derselben Note: +% +\def\lyrlink {\lyr@link0} +\def\lowlyrlink{\lyr@link1} + +\def\lyr@link#1{% + % Bogen erstellen: + \setbox\lyr@linkbox=\hbox{$\smile$}% + % In Box der Breite eines Wortzwischenraums einsetzen: + \setbox\lyr@linkbox=\hbox to\the\fontdimen2\the\font{% + \hss + % Unter die Grundlinie druecken: + \lower\ht\lyr@linkbox\hbox{% + % Zusaetzlicher vertikaler Abstand zur Wortunterseite: + \lower1pt\hbox{% + \if#10\relax + \hbox{$\smile$}% + \else + % Buchstabe mit Unterlaenge -> auch darunter druecken: + \setbox\lyr@linkdepthbox=\hbox{y}% + \lower\dp\lyr@linkdepthbox\hbox{$\smile$}% + \fi}}% + \hss}% + % Keine zusaetzliche Tiefe fuer Bogen anrechnen: + \dp\lyr@linkbox=0pt + % Bogen setzen: + \box\lyr@linkbox} + +\makeatother |