% ddphonism % % (c) Celia Rubio Madrigal % %% This program can be redistributed and/or modified under the terms %% of the LaTeX Project Public License Distributed from CTAN archives %% in directory macros/latex/base/lppl.txt. \ProvidesPackage{ddphonism} [2025/05/13 v0.3 Dodecaphonic diagrams: twelve-tone matrices, clock diagrams, etc.] \RequirePackage{tikz} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Utilities \newcounter{D@size} \newcommand{\D@sizeMake}[1]{% \setcounter{D@size}{0}% \foreach \n in {#1} {\stepcounter{D@size}}% } \newcounter{D@head} \newcommand{\D@headMake}[1]{% \setcounter{D@head}{-1}% \foreach \n in {#1}% {\ifnum\theD@head=-1\setcounter{D@head}{\n}\fi}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Matrices \usetikzlibrary{matrix} \newif\ifD@matrixLines \newif\ifD@matrixO \newif\ifD@matrixI \newif\ifD@matrixV \newif\ifD@matrixH \newif\ifD@matrixTikz \pgfkeys{ /dmatrix/.is family , /dmatrix , default/.style = { lines = false, outside lines = false, inside lines = false , sep = 1, vsep = 1, hsep = 1, no tikz = false } , lines/.is if=D@matrixLines , outside lines/.is if=D@matrixO , inside lines/.is if=D@matrixI , vlines/.is if=D@matrixV , hlines/.is if=D@matrixH , sep/.estore in=\D@matrixSep , vsep/.estore in=\D@matrixVsep , hsep/.estore in=\D@matrixHsep , no tikz/.is if=D@matrixTikz } \newcommand{\D@LOH}{% outside horizontal lines \foreach \y in {0, {-0.5*\theD@size*\D@matrixSepVsep}} \draw (0,\y) -- ({\theD@size*\D@matrixSepHsep},\y);% } \newcommand{\D@LOV}{% outside vertical lines \foreach \x in {0, {\theD@size*\D@matrixSepHsep}} \draw (\x, 0) -- (\x, {-0.5*\D@matrixSepVsep*\theD@size});% } \newcommand{\D@LIH}{% inside horizontal lines \pgfmathparse{\theD@size - 1}\foreach \x in {1,...,\pgfmathresult} \draw (0,{-0.5*\x*\D@matrixSepVsep}) --% ({\theD@size*\D@matrixSepHsep},{-0.5*\x*\D@matrixSepVsep});% } \newcommand{\D@LIV}{% inside vertical lines \pgfmathparse{\theD@size - 1}\foreach \x in {1,...,\pgfmathresult} \draw ({\x*\D@matrixSepHsep},0) --% ({\x*\D@matrixSepHsep},{-\theD@size*0.5*\D@matrixSepVsep});% } \newcommand{\dmatrix}[2][]{% \pgfkeys{/dmatrix, default, #1}% \D@sizeMake{#2}\D@headMake{#2}% \pgfmathsetmacro{\D@matrixSepVsep}{\D@matrixSep*\D@matrixVsep}% \pgfmathsetmacro{\D@matrixSepHsep}{\D@matrixSep*\D@matrixHsep}% \ifD@matrixTikz\else\begin{tikzpicture}\fi% \foreach [count=\nj] \j in {#2} \foreach [count=\ni] \i in {#2} {% \pgfmathsetmacro{\D@matrixI}% {int(mod(\i - \j + \theD@head + \theD@size, \theD@size))}% \draw node at ({(\ni-0.5)*\D@matrixSepHsep},% {-0.5*(\nj-0.5)*\D@matrixSepVsep})% {\D@matrixI};% }% \ifD@matrixLines\D@LOH\D@LOV\D@LIH\D@LIV\fi% \ifD@matrixV\D@LOV\D@LIV\fi% \ifD@matrixH\D@LOH\D@LIH\fi% \ifD@matrixO\D@LOH\D@LOV\fi% \ifD@matrixI\D@LIH\D@LIV\fi% \ifD@matrixTikz\else\end{tikzpicture}\fi% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Diagrams \usetikzlibrary{shapes,arrows,decorations.markings,shapes.misc} \tikzstyle{ddiagram}=[minimum height=0pt,inner sep=0pt,outer sep=0pt,scale=0.65] \tikzset{D@invclip/.style={clip,insert path={{[reset cm] % for inverse clipping (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)}}}} \newif\ifD@diagramTikz \newif\ifD@diagramNoNum \newif\ifD@diagramNoArr \pgfkeys{ /ddiagram/.is family , /ddiagram , default/.style = { up =\empty, name =\empty, no tikz = false , no numbers = false, no arrow = false, arrow shift = 2.5 } , no tikz/.is if=D@diagramTikz , no numbers/.is if=D@diagramNoNum , no arrow/.is if=D@diagramNoArr , name/.estore in=\D@diagramName , up/.estore in=\D@diagramUp , arrow shift/.estore in=\D@diagramArrS } \newcounter{D@prev} \newcommand{\ddiagram}[2][]{% \pgfkeys{/ddiagram, default, #1}% \D@sizeMake{#2}\D@headMake{#2}% \pgfmathsetmacro{\D@up}% {int(\ifx\D@diagramUp\empty\theD@head\else\D@diagramUp\fi)}% % \ifD@diagramTikz\else\begin{tikzpicture}[ddiagram]\fi% \begin{scope}[rotate=360*\D@up/\theD@size]% \ifx\D@diagramName\empty\else% \node at (0,0) [circle] {\D@diagramName};% \begin{pgfinterruptboundingbox}% \path[D@invclip] (0,0) ellipse % ({0.02*width("\D@diagramName")} and {0.02*height("\D@diagramName")});% \end{pgfinterruptboundingbox}% \fi % \pgfmathparse{\theD@size - 1}\foreach \x in {0,...,\pgfmathresult} {% numbers \ifD@diagramNoNum\else\node at ({90-360*\x/\theD@size}:2) {\x};\fi% \coordinate (\x) at ({90-360*\x/\theD@size}:1.6);% }; \setcounter{D@prev}{-1}% \foreach \x in {#2}{% lines \ifnum\theD@prev=\theD@head% second \draw [decoration={markings,mark=at position 0.099*\D@diagramArrS with {\arrow[scale=1.25,>=triangle 45]{>}}},postaction={decorate}] (\theD@prev) -- (\x);% \else\ifnum\theD@prev>-1\draw (\theD@prev) -- (\x);\fi\fi% third onward \setcounter{D@prev}{\x}% };% \draw (\theD@prev) -- (\theD@head);% last \end{scope}% \ifD@diagramTikz\else\end{tikzpicture}\fi% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Dihedral diagrams \tikzstyle{D@dihedralArrow}= [decoration={markings,mark=at position 1 with {\arrow[scale=1.5,>=angle 60]{>}}},postaction={decorate}] \tikzstyle{ddihedral}=[inner sep=0,minimum height=18pt] \newif\ifD@dihedralTikz \pgfkeys{ /ddihedral/.is family, /ddihedral, default/.style = { t = 0, c = 0, s = 0, v = 0, no tikz=false , new t = T, new c = C, new s = S, new v = V} , t/.estore in = \D@dihedralT , c/.estore in = \D@dihedralC , s/.estore in = \D@dihedralS , v/.estore in = \D@dihedralV , new t/.estore in = \D@dihedralNewT , new c/.estore in = \D@dihedralNewC , new s/.estore in = \D@dihedralNewS , new v/.estore in = \D@dihedralNewV , no tikz/.is if=D@dihedralTikz } \newif\ifdarrowsTikz \pgfkeys{ /darrows/.is family, /darrows, default/.style = {no tikz=false}, no tikz/.is if=darrowsTikz, } \newcommand{\darrows}[2][]{% \pgfkeys{/darrows, default, #1}% \D@sizeMake{#2}% \ifdarrowsTikz\else\begin{tikzpicture}\fi% \pgfmathparse{\theD@size - 1}\foreach \x in {0,...,\pgfmathresult}% \draw ({90-360*\x/\theD@size}:2.5) node[circle] (\x) {};% \foreach \x [count=\y] in {#2}% \draw[style=D@dihedralArrow] ({90-360*(\y-1)/\theD@size}:1.25) -- (\x);% \ifdarrowsTikz\else\end{tikzpicture}\fi% } \newcommand\ddihedral[2][]{% \pgfkeys{/ddihedral, default, #1}% \D@sizeMake{#2}% % \ifD@dihedralTikz\else\begin{tikzpicture}[ddihedral]\fi% \def\D@dihedralName{% \ifodd\D@dihedralV{\D@dihedralNewV}\else% \ifnum\D@dihedralC=0% \ifodd\D@dihedralS\else% \ifnum\D@dihedralT=0{\D@dihedralNewT$^0$}% \fi\fi\fi\fi% \ifnum\D@dihedralC=0\else\D@dihedralNewC$^{\D@dihedralC}$\fi% \ifodd\D@dihedralS{\D@dihedralNewS}\fi% \ifnum\D@dihedralT=0\else\D@dihedralNewT$^{\D@dihedralT}$\fi% } \node at (0,0) [very thin,draw,circle,inner sep=1pt] {\D@dihedralName};% \begin{pgfinterruptboundingbox}% \path[D@invclip] (0,0) circle % ({0.02*width("\D@dihedralName")} and {0.02*height("\D@dihedralName")});% \end{pgfinterruptboundingbox}% \pgfmathparse{\theD@size - 1}\foreach \x in {0,...,\pgfmathresult} {% \draw ({90+(\D@dihedralT + (2*\D@dihedralS-1)*\x)*360/\theD@size}:2.5)% node[very thin,circle,draw] {\x};% \draw ({90-(\D@dihedralC+(2*\D@dihedralV-1)*\x*360/\theD@size)}:1.25)% node[very thin,circle,draw] {\x};% }% \darrows[no tikz]{#2}% \ifD@dihedralTikz\else\end{tikzpicture}\fi% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Rows \pgfkeys{ /drow/.is family, /drow, default/.style = {sep=\arraycolsep}, sep/.estore in = \D@rowSep, } \long\def\D@concat#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}} \newlength{\D@ogsep} \newcommand{\drow}[2][]{% \pgfkeys{/drow, default, #1}% \D@sizeMake{#2}% \setlength{\D@ogsep}{\arraycolsep}\setlength{\arraycolsep}{\D@rowSep}% % \ifnum\theD@size=0{\ensuremath{\left(\right)}}% \else\ifnum\theD@size=1 \ensuremath{\left(\begin{array}{*{\theD@size}c}0\\0\\\end{array}\right)}% \else% \global\def\D@firstrow{}\global\def\D@secondrow{}% \foreach \x [count=\i from 0] in {#2} {% \ifnum\i>0 \xdef\D@firstrow{\D@firstrow & \i} \xdef\D@secondrow{\D@secondrow & \x}% \else \xdef\D@firstrow{\i} \xdef\D@secondrow{\x} \fi% }% \ensuremath{\left(\begin{array}{*{\theD@size}c}% \D@firstrow \\ \D@secondrow \\ \end{array}\right)}% \fi% \setlength{\arraycolsep}{\D@ogsep}% } \endinput %% End of file `ddphonism.sty'.