%%
%% musixser.tex:  MusiXTeX serial voices package
%%
%% Copyright (C) 1999-2003  Rainer Dunker
%%
%% This document 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 document 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 document; 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\setvoice\else\endinput\fi
\immediate\write10{MusiXSERial voices 1.2\space<January 24, 2003>}
\def\musixserversion{1.2}

% 0.1  initial version
% 0.2  multiple uses of \processvoices corrected
% 0.3  \resetbarticscount introduced
% 0.4  automatic beam and slur number allocation introduced
%      patterns in \setvoice introduced
% 0.5  default spacing for undefined tics values introduced
% 1.0  synchronization of barlines and master track items rearranged
%      \thisbarcmd and \afterbar introduced
% 1.1  enabled switching off bars with \barduration{0/1}
%      \tracingvoices introduced
%      voice-independent slurs and beams introduced
%      \makeplusactive and \makeplusother introduced
% 1.1a pattern names use name space separate from ordinary macro names
% build  9 "for each" loops in event specifications
% build 10 \processbar introduced
%          "for each" loops rewritten
%          "+p" pattern header introduced
%          "for each pattern" loops introduced
% build 11 plus sign no longer an active character
% build 12 repaired mysterious fundamental malfunction (discovered
%          after years of inactivity) by replacing toks register
%          \stf@voc by a macro
% 1.2  +p and +F unified to pattern loop processing +p
%      \musixserversion introduced


\makeatletter

\def\max@int{2147483647}

\newcount\cur@staff
\newcount\cur@voice
\newcount\cur@col
\newcount\base@tics \base@tics=192
\newcount\next@delta
\newcount\prev@delta
\newcount\bar@delta \bar@delta\m@ne
\newcount\r@tval

%\newtoks\stf@voc
\newtoks\barlinecmd \barlinecmd={\bar}

\toksdef\head@=2
\toksdef\tail@=4
\toksdef\header@=6
\toksdef\collect@=8
\newif\iftail@notempty
\newif\ifevent@qualified

\newif\ifbar@pending
\newif\ifcol@empty

\newif\iftracingcolumns
\newif\iftracingtics
\newif\iftracingvoices
\newif\ifbarproc

% obsolete
\let\makeplusother\relax
\let\makeplusactive\relax

\def\setticsskip#1#2{\expandafter\def\csname notes@#1\endcsname{#2}}

\setticsskip{192}\NOTEs
\setticsskip{144}\NOTesp
\setticsskip{96}\NOTes
\setticsskip{72}\NOtesp
\setticsskip{48}\NOtes
\setticsskip{36}\Notesp
\setticsskip{24}\Notes
\setticsskip{18}\notesp
\setticsskip{12}\notes
\setticsskip{9}\notes
\setticsskip{6}\notes

% Fuer musixlyr: PMX vortaeuschen
\let\nextvoice\relax
\let\@pmx@nextvoicetrue\relax

\def\trace@col#1{\iftracingcolumns\immediate\write15{#1}\fi}
\def\trace@voc#1{\iftracingvoices \immediate\write15{#1}\fi}


\def\barduration#1{%
  \calc@tics#1/\@end
  % if = zero -> no more bars
  \ifnum\count@=\z@
   \bar@delta\m@ne
   \def\bar@tics{\m@ne}%
  \else
   \bar@delta=\count@
   \edef\bar@tics{\the\count@}%
  \fi}

\def\setvoice#1#2#3{%
  % Muss \toks-Register allokiert werden?
  \expandafter\ifx\csname stf#1voc#2\endcsname\relax
   \begingroup
    \def\@newtoks{newtoks}% durch Gruppierung lokal
    \expandafter\csname\expandafter\@newtoks\expandafter\endcsname
       \csname stf#1voc#2\endcsname
   \endgroup
  \fi
  \expandafter\def\csname delta@stf#1voc#2\endcsname{0}% Delta-Tics
  \expandafter\def\csname dbars@stf#1voc#2\endcsname{0}% Delta-Takte
  \expandafter\let\csname barproc@stf#1voc#2\endcsname\empty % Takt-Material
  \ifx\empty#3\empty % Null-Material
    \csname stf#1voc#2\endcsname={\relax}%
  \else
    %
    % analyze patterns
    \tail@notemptytrue
    \collect@={}%
    \analyze@toks#3\pat\relax\@end
    \loop
     \iftail@notempty
      \collect@=\expandafter\expandafter\expandafter
		{\expandafter\the\expandafter\collect@\the\head@}%
      \trace@pat{Analyze: sum  = \the\collect@}%
      \expandafter\analyze@toks\the\tail@
    \repeat
    \collect@=\expandafter\expandafter\expandafter
	      {\expandafter\the\expandafter\collect@\the\head@}%
    \trace@pat{Analyze: sum  = \the\collect@}%
    %
    % assign to "material storage"
    \csname stf#1voc#2\endcsname=\expandafter{\the\collect@+\end@voc}%
  \fi}

%
% analyze patterns in \setvoice's
%
\newif\iftracingpatterns

\def\analyze@toks#1\pat#2#3\@end{%
  \head@={#1}%
  \ifx#2\relax
   \tail@notemptyfalse
  \else
   \exec@pattern#2\@end
   \tail@=\expandafter{\the\toks@ #3\@end}%
  \fi
  \trace@pat{Analyze: head = \the\head@}%
  \trace@pat{Analyze: pat  = \the\toks@}%
  \trace@pat{Analyze: tail = \the\tail@}%
  }

\def\defpattern#1#2{\def@pattern#1\@middle#2\@end}
\def\def@pattern#1#2\@middle#3\@end{%
  \expandafter\def\csname pat\string#1\endcsname #2{\toks@={#3}}}

\def\exec@pattern#1#2\@end{\csname pat\string#1\endcsname #2}
\def\trace@pat#1{\iftracingpatterns\immediate\write15{#1}\fi}

%
% synchronization of master track entries with barlines
%
\def\afterbar#1{\def\after@bar{#1}}
\let\after@bar\relax

\def\thisbarcmd#1{%
  \barlinecmd=
    \expandafter{\expandafter\barlinecmd\expandafter{\the\barlinecmd}#1}}

\def\setmaster#1{\setvoice01{#1}}

%
% per-voice stuff to be processed at barlines
%
\def\barproc#1{%
  \expandafter\gdef
    \csname barproc@stf\the\noinstrum@nt voc\the\cur@voice\endcsname{#1}}
\def\onebarproc#1{%
  \expandafter\gdef
    \csname barproc@stf\the\noinstrum@nt voc\the\cur@voice\endcsname
    {#1\expandafter
	\gdef\csname barproc@stf\the\noinstrum@nt
			     voc\the\cur@voice\endcsname{}}}

% shortcuts for common purposes
\def\pauseon{\barproc{\centerbar\pause}}
\def\pauseoff{\barproc{}}
\def\onepause{\onebarproc{\centerbar\pause}}

%
% analyze time value syntax
%
\def\get@denom#1/{#1}

\def\calc@tics#1/#2\@end{%
  % Rueckgabewert in \count@
  \count@=\base@tics
  \ifx\relax#2\relax
   % Kein Zaehler gegeben:
   \divide\count@#1
  \else
   % Bruch gegeben:
   \expandafter\divide\expandafter\count@\get@denom#2\relax
   \multiply\count@#1
  \fi}

\def\calc@tics@w@bars#1b{\calc@tics#1/\@end}

\def\calc@delta#1b#2\@end{%
  % Rueckgabe:
  % \r@tval = Delta-Takte
  % \count@ = Delta-Tics
  \ifx\relax#2\relax
   % kein Takt-Delta angegeben:
   \r@tval\z@
   \calc@tics#1/\@end
  \else
   % Takt angegeben:
   \ifx\relax#1\relax \r@tval=1 % keine Taktzahl gegeben, also = 1
   \else \r@tval#1
   \fi
   \ifx b#2% keine Delta-Tics angegeben?
    \count@\z@
   \else
    \calc@tics@w@bars#2%
   \fi
  \fi}

\def\process@plusstatement+{\futurelet\event@flag\decide@eventtype}
\def\decide@eventtype{%
  \if\event@flag f\def\@next{\process@foreach}%
%   \else\if\event@flag F\def\@next{\process@Foreach}%
%   \else\if\event@flag p\def\@next{\process@pattern}%
   % +p kann auch gleich pattern loops einleiten
   \else\if\event@flag p\def\@next{\process@Foreach}%
   \else\def\@next{\process@event}%
  \fi\fi
% \fi
  \@next}

\def\process@event#1 #2+#3\end@voc{%
  % Delta-Angaben parsen:
  \calc@delta#1b\@end
  % Delta dieser Stimme festhalten:
  \trace@col{neudelta bars=\the\r@tval, tics=\the\count@}%
  \expandafter\edef\csname delta@\stf@voc\endcsname{\the\count@}%
  \expandafter\edef\csname dbars@\stf@voc\endcsname{\the\r@tval}%
  % Minimales Delta nur ermitteln, wenn keine Delta-Takte:
  \ifnum\r@tval=0
   \ifnum\count@<\next@delta \next@delta\count@ \fi
  \fi
  % Material fuer diese Spalte bereitstellen:
  \expandafter\gdef\csname @s\the\cur@staff v\the\cur@voice\endcsname{#2}%
  \iftracingvoices
   \expandafter\let\expandafter\dummy\csname @s\the\cur@staff v\the\cur@voice\endcsname
   \toks255=\expandafter{\dummy}%
   \trace@voc{Setting event for s\the\cur@staff v\the\cur@voice: \the\toks255}%
  \fi
  % Restmaterial bereitstellen:
  \ifx\relax#3\relax % nichts mehr uebrig:
   \csname\stf@voc\endcsname={\relax}%
  \else
   \csname\stf@voc\endcsname={+#3\end@voc}%
  \fi
  \event@qualifiedtrue}

\def\process@foreach f#1 #2#3+#4\end@voc{%
  % #1 Zeitangabe
  % #2 Foreach-Body
  % #3 Foreach-Liste
  % #4 Restmaterial
  \tail@notemptytrue
  \collect@={}%
  \header@={+#1 #2}%
  \analyze@foreach#3\relax\@end
  \loop
   \iftail@notempty
    \collect@=\expandafter\expandafter\expandafter
	      {\expandafter\the\expandafter\collect@\the\head@}%
    \trace@pat{Analyze foreach: sum  = \the\collect@}%
    \expandafter\analyze@foreach\the\tail@\@end
  \repeat
  \collect@=\expandafter\expandafter\expandafter
	    {\expandafter\the\expandafter\collect@\the\head@}%
  \trace@pat{Analyze: sum  = \the\collect@}%
  %
  % assign to "material storage"
  \csname\stf@voc\endcsname=\expandafter{\the\collect@+#4\end@voc}}
\def\analyze@foreach#1#2\@end{%
  % #1#2 Foreach-Liste
  \head@=\expandafter{\the\header@{#1}}%
  \trace@pat{Analyze foreach: head = \the\head@}%
  \ifx\relax#2%
   \tail@notemptyfalse
  \else
   \tail@={#2}%
   \trace@pat{Analyze foreach: tail = \the\tail@}%
  \fi}

%\def\process@Foreach F#1#2+#3\end@voc{%
% Einleitung jetzt +p
\def\process@Foreach p#1#2+#3\end@voc{%
  % #1 Pattern-Name
  % #2 Foreach-Liste
  % #3 Restmaterial
  \tail@notemptytrue
  \collect@={}%
  \analyze@Foreach#1#2,\@end
  \loop
   \iftail@notempty
    \collect@=\expandafter\expandafter\expandafter
	      {\expandafter\the\expandafter\collect@\the\toks@}%
    \trace@pat{Analyze Foreach: sum  = \the\collect@}%
    \expandafter\analyze@Foreach\expandafter#1\the\tail@\@end
  \repeat
  \collect@=\expandafter\expandafter\expandafter
	    {\expandafter\the\expandafter\collect@\the\toks@}%
  \trace@pat{Analyze: sum  = \the\collect@}%
  %
  % assign to "material storage"
  \csname\stf@voc\endcsname=\expandafter{\the\collect@+#3\end@voc}}
\def\analyze@Foreach#1,#2\@end{%
  % #1 Pattern-Name + Foreach-Head
  % #2 Foreach-Tail
  \exec@pattern#1\relax\@end
  \iftracingpatterns
   \head@={#1}%
   \trace@pat{Analyze Foreach:  head \the\head@ -> \the\toks@}%
  \fi
  \ifx\relax#2\relax%
   \tail@notemptyfalse
  \else
   \tail@={#2}%
   \trace@pat{Analyze Foreach: tail = \the\tail@}%
  \fi}


% Obsolet; \process@Foreach tut dasselbe
%\def\process@pattern p#1+#2\end@voc{%
%  % #1 Pattern-Name + Argumente
%  % #2 Restmaterial
%  \exec@pattern#1\relax\@end
%  \iftracingpatterns
%   \collect@={#1}%
%   \trace@pat{Analyze pattern: \the\collect@ -> \the\toks@}%
%  \fi
%  %
%  % assign to "material storage"
%  \csname\stf@voc\endcsname=\expandafter{\the\toks@+#2\end@voc}}

\def\process@voice{%
  \advance\cur@voice\@ne
  \edef\stf@voc{stf\the\cur@staff voc\the\cur@voice}%
  % Zeile@Stimme definiert?
  \expandafter\ifx\csname\stf@voc\endcsname\relax
   \let\pv@next\relax  % nein
  \else
   % Zeile@Stimme nicht leer (Tokenliste != {\relax})?
   \expandafter\ifx\expandafter\relax\the\csname\stf@voc\endcsname\else
    \col@emptyfalse
    %
    % evtl Delta-Takte weiterzaehlen
    %
    \ifnum\csname dbars@\stf@voc\endcsname>0 % Warten wir auf Takte?
     \ifbar@pending
      % 1 Takt runterzaehlen:
      \count@=\csname dbars@\stf@voc\endcsname
      \advance\count@\m@ne
      \expandafter\edef\csname dbars@\stf@voc\endcsname{\the\count@}%
      \trace@col{S \the\cur@col, Z \the\cur@staff, St \the\cur@voice:
	  resttakte=\the\count@}%
     \fi % Takt runterzaehlen
    \else % warten nicht auf Takte
     % Stimmdelta vermindern:
     \count@=\csname delta@\stf@voc\endcsname\relax
     \trace@col{S \the\cur@col, Z \the\cur@staff, St \the\cur@voice:
	 prevdelta=\the\prev@delta, stimmdelta=\the\count@}%
     \advance\count@ -\prev@delta
     \expandafter\edef\csname delta@\stf@voc\endcsname{\the\count@}%
    \fi % Warten wir auf Takte?
    %
    % Enthaelt Stimme Event fuer diese Spalte?
    %
    \ifnum\csname dbars@\stf@voc\endcsname=0 % kein Taktwarten ...
     \ifnum\csname delta@\stf@voc\endcsname=0 % keine Delta-Tics
      % Event verarbeiten:
      \trace@col{About to parse event}%
      % Schleife ueber Foreach-Loops, Patterns:
      \event@qualifiedfalse
      \def\fp@body{%
	\expandafter\process@plusstatement\the\csname\stf@voc\endcsname
	\ifevent@qualified \let\fp@next\relax \else \let\fp@next\fp@body \fi
	\fp@next}%
      \fp@body
      \trace@col{neudelta=\csname delta@\stf@voc\endcsname}%
     \else % doch noch Delta-Tics uebrig
      % Minimales Spaltendelta ermitteln:
      \count@=\csname delta@\stf@voc\endcsname\relax
      \ifnum\count@<\next@delta \next@delta\count@ \fi
      \trace@col{restdelta=\csname delta@\stf@voc\endcsname}%
     \fi % keine Delta-Tics
    \fi % kein Taktwarten
   \fi % Zeile@Stimme nicht leer
   \let\pv@next\process@voice
  \fi % Zeile@Stimme definiert?
  \pv@next}

\def\process@staff{%
  \cur@voice\z@ \process@voice
  % Schleife:
  \advance\cur@staff\@ne
  \ifnum\cur@staff>\nbinstruments
   \let\ps@next\relax
  \else
   \let\ps@next\process@staff
  \fi
  \ps@next}

\def\flush@voice{%
  \global\advance\cur@voice\@ne
  \xdef\stf@voc{@s\the\noinstrum@nt v\the\cur@voice}%
  \expandafter\ifx\csname\stf@voc\endcsname\relax
   \let\fv@next\relax
  \else
   \iftracingvoices
    \expandafter\let\expandafter\@dummy\csname\stf@voc\endcsname
    \toks255=\expandafter{\@dummy}%
    \trace@voc{Processing event for \stf@voc:
	       \the\toks255}%
   \fi
   % Bei mehr als einer Stimme erst ein backskip (a la \nextvoice von PMX):
   \ifnum\cur@voice>1
    \@ndstaff\advance\noport@@-1\beginstaff
    \@pmx@nextvoicetrue
   \fi
   % Material anwenden:
   \csname\stf@voc\endcsname
   % anschliessend deaktivieren:
   \global\expandafter\let\csname\stf@voc\endcsname\empty
   \let\fv@next\flush@voice
  \fi
  \fv@next}

\def\flush@staff{%
  \global\cur@voice\z@\flush@voice
  \ifnum\noinstrum@nt<\nbinstruments
   \nextinstrument
   \let\fs@next\flush@staff
  \else
   \let\fs@next\relax
  \fi
  \fs@next}

\def\process@bar@voice{%
  \advance\cur@voice\@ne
  \edef\stf@voc{barproc@stf\the\noinstrum@nt voc\the\cur@voice}%
  \expandafter\ifx\csname\stf@voc\endcsname\relax
   \let\pbv@next\relax
  \else
   % Material anwenden:
   \csname\stf@voc\endcsname
   \let\pbv@next\process@bar@voice
  \fi
  \pbv@next}

\def\process@bar@staff{%
  \cur@voice\z@\process@bar@voice
  \ifnum\noinstrum@nt<\nbinstruments
   \nextinstrument
   \let\pbs@next\process@bar@staff
  \else
   \let\pbs@next\relax
  \fi
  \pbs@next}

\def\process@column{%
  \advance\cur@col\@ne
  %
  % Takt zu Ende?
  %
  \ifnum\bar@delta>\m@ne % Ueberhaupt Takte definiert?
   \ifnum\bar@delta=0 \bar@pendingtrue \fi % Taktende vormerken
  \fi % Takte definiert
  %
  % Material fuer Spalte sammeln:
  %
  \cur@staff\z@ % nullte Zeile = Masterspur
  \next@delta=\max@int
  \col@emptytrue
  \process@staff
  % Spalte leer?
  \ifcol@empty
   % Spalte leer, Verarbeitung beenden:
   \let\pc@next\relax
   % Unverarbeitete leere Spalte nicht zählen:
   \advance\cur@col\m@ne
  \else
   %
   % Spalte verarbeiten
   %
   % zuerst Masterspur verarbeiten:
   \noinstrum@nt\z@ \cur@voice\z@ \flush@voice
   % Takt zu Ende?
   \ifbar@pending
    % Taktmaterial ggf. verarbeiten:
    \ifbarproc \processbar \fi
    % Takt setzen:
    \the\barlinecmd
    \bar@delta=\bar@tics\relax
    \bar@pendingfalse
   \fi % Takt zu Ende
   %
   % Taktdelta fortschreiben
   %
   \ifnum\bar@delta>\m@ne % Ueberhaupt Takte definiert?
    \ifnum\bar@delta<\next@delta \next@delta\bar@delta \fi
    \advance\bar@delta-\next@delta
   \fi % Takte definiert
   % Material fuer nach dem Taktstrich verarbeiten:
   \ifx\after@bar\relax\else \after@bar \let\after@bar\relax \fi
   % Spalte ausgeben. Spaltenbreite definiert?
   \expandafter\ifx\csname notes@\the\next@delta\endcsname\relax
    \errmessage{No column skip for \the\next@delta\space tics defined;
		using default spacing}%
    \def\col@command{\vnotes8\elemskip}%
   \else
    \def\col@command{\csname notes@\the\next@delta\endcsname}%
   \fi
   % Noten setzen:
   \col@command
    \iftracingtics\zchar{-5}{\the\next@delta}\fi
    \flush@staff
   \en
   \prev@delta\next@delta
   \let\pc@next\process@column
  \fi
  \pc@next}

\def\processbar{\def\atnextbar{\znotes\process@bar@staff\en}}
\def\processvoices{\prev@delta\z@ \process@column}

\def\resetbarticscount{%
  % Ausserhalb von \processvoices Taktzaehler manuell zuruecksetzen
  \ifnum\bar@delta>\m@ne % Ueberhaupt Takte definiert?
    \bar@delta=\bar@tics\relax
    \bar@pendingfalse
  \fi}

%
% automatic slur number allocation
%
\newif\iftracingslurnumbers
\newcount\free@sl@index

\def\isl{\Isl0}
\def\rsl{\Rsl0}
\def\tsl{\Tsl0}

\def\Isl#1{\i@sl{#1}{\the\noinstrum@nt}{\the\cur@voice}}
\def\Rsl#1{\r@sl{#1}{\the\noinstrum@nt}{\the\cur@voice}}
\def\Tsl#1{\t@sl{#1}{\the\noinstrum@nt}{\the\cur@voice}}

% slurs without reference to current voice
\def\genisl#1{\i@sl{#1}00}
\def\genrsl#1{\r@sl{#1}00}
\def\gentsl#1{\t@sl{#1}00}

\def\i@sl#1#2#3#4{%
  % #1: slur-per-voice number
  % #2: staff number
  % #3: voice number
  % #4: slur command
  \trace@slurnum{Initiating slur #1 for s#2v#3.}%
  \expandafter\ifx\csname s#2v#3slur#1\endcsname\relax \else
   \errmessage{Slur #1 of s#2v#3 already active}%
  \fi
  \trace@slurnum{Taking \the\free@sl@index. slur.}%
  \expandafter\ifx\csname slnum@\the\free@sl@index\endcsname\relax
   \trace@slurnum{Unused so far, set number = \the\free@sl@index.}%
   \count@\free@sl@index
  \else
   \count@=\csname slnum@\the\free@sl@index\endcsname\relax
   \trace@slurnum{Number = \the\count@.}%
  \fi
  \expandafter\xdef\csname s#2v#3slur#1\endcsname{\the\count@}%
  \edef\slur@num{{\the\count@}}%
  \global\advance\free@sl@index\@ne
  \expandafter#4\slur@num}

\def\r@sl#1#2#3#4{%
  % #1: slur-per-voice number
  % #2: staff number
  % #3: voice number
  % #4: slur command
  \trace@slurnum{Referencing slur #1 of s#2v#3.}%
  \expandafter\ifx \csname s#2v#3slur#1\endcsname\relax
   \errmessage{Slur #1 of s#2v#3 inactive}%
  \fi
  \edef\beam@num{{\csname s#2v#3slur#1\endcsname}}%
  \expandafter#4\beam@num}

\def\t@sl#1#2#3#4{%
  % #1: slur-per-voice number
  % #2: staff number
  % #3: voice number
  % #4: slur command
  \trace@slurnum{Terminating slur #1 of s#2v#3.}%
  \expandafter\ifx
    \csname s#2v#3slur#1\endcsname\relax
   \errmessage{Slur #1 of s#2v#3 inactive}%
  \fi
  \global\advance\free@sl@index\m@ne
  \trace@slurnum{Freeing \the\free@sl@index. slur.}%
  \count@=\csname s#2v#3slur#1\endcsname \relax
  \expandafter\xdef\csname slnum@\the\free@sl@index\endcsname{\the\count@}%
  \trace@slurnum{Freed slur number = \the\count@.}%
  \expandafter\global\expandafter\let \csname s#2v#3slur#1\endcsname \relax
  \edef\slur@num{{\the\count@}}%
  \expandafter#4\slur@num}

\def\trace@slurnum#1{\iftracingslurnumbers\immediate\write15{#1}\fi}

%
% automatic beam number allocation
%
\newif\iftracingbeamnumbers
\newcount\free@bm@index

\def\ibm{\Ibm0}
\def\rbm{\Rbm0}
\def\tbm{\Tbm0}

\def\Ibm#1{\i@bm{#1}{\the\noinstrum@nt}{\the\cur@voice}}
\def\Rbm#1{\r@bm{#1}{\the\noinstrum@nt}{\the\cur@voice}}
\def\Tbm#1{\t@bm{#1}{\the\noinstrum@nt}{\the\cur@voice}}

% beams without reference to current voice
\def\genibm#1{\i@bm{#1}00}
\def\genrbm#1{\r@bm{#1}00}
\def\gentbm#1{\t@bm{#1}00}

\def\i@bm#1#2#3#4{%
  % #1: beam-per-voice number
  % #2: staff number
  % #3: voice number
  % #4: beam command
  \trace@beamnum{Initiating beam #1 for s#2v#3.}%
  \expandafter\ifx \csname s#2v#3beam#1\endcsname\relax \else
   \errmessage{Beam #1 of s#2v#3 already active}%
  \fi
  \trace@beamnum{Taking \the\free@bm@index. beam.}%
  \expandafter\ifx\csname bmnum@\the\free@bm@index\endcsname\relax
   \trace@beamnum{Unused so far, set number = \the\free@bm@index.}%
   \count@\free@bm@index
  \else
   \count@=\csname bmnum@\the\free@bm@index\endcsname\relax
   \trace@beamnum{Number = \the\count@.}%
  \fi
  \expandafter\xdef\csname s#2v#3beam#1\endcsname
    {\the\count@}%
  \edef\beam@num{{\the\count@}}%
  \global\advance\free@bm@index\@ne
  \expandafter#4\beam@num}

\def\r@bm#1#2#3#4{%
  % #1: beam-per-voice number
  % #2: staff number
  % #3: voice number
  % #4: beam command
  \trace@beamnum{Referencing beam #1 of s#2v#3.}%
  \expandafter\ifx
    \csname s#2v#3beam#1\endcsname\relax
   \errmessage{Beam #1 of s#2v#3 inactive}%
  \fi
  \edef\beam@num{{\csname s#2v#3beam#1\endcsname}}%
  \expandafter#4\beam@num}

\def\t@bm#1#2#3#4{%
  % #1: beam-per-voice number
  % #2: staff number
  % #3: voice number
  % #4: beam command
  \trace@beamnum{Terminating beam #1 of s#2v#3.}%
  \expandafter\ifx \csname s#2v#3beam#1\endcsname\relax
   \errmessage{Beam #1 of s#2v#3 inactive}%
  \fi
  \global\advance\free@bm@index\m@ne
  \trace@beamnum{Freeing \the\free@bm@index. beam.}%
  \count@=\csname s#2v#3beam#1\endcsname \relax
  \expandafter\xdef\csname bmnum@\the\free@bm@index\endcsname{\the\count@}%
  \trace@beamnum{Freed beam number = \the\count@.}%
  \expandafter\global\expandafter\let \csname s#2v#3beam#1\endcsname \relax
  \edef\beam@num{{\the\count@}}%
  \expandafter#4\beam@num}

\def\trace@beamnum#1{\iftracingbeamnumbers\immediate\write15{#1}\fi}

\makeatother
