Using TikZ to depict intonation
Following up on Matthew Leingang's answer, here's the same approach tied up with some syntactic sugar. It messes around with \catcode
stuff, so care needs to be taken.
\documentclass{standalone}
\usepackage{tikz}
\newcount\contourmarkcount
\newdimen\contourraise
{\catcode`\|=13
\gdef\installbarmark#1\ignorespaces{%
#1\ignorespaces%
\catcode`\|=13%
\global\contourmarkcount=0\relax%
\global\def\lastmarkshift{0}%
\let|=\marktext}%
}
\def\star{*}
\newcommand\marktext[1][*]{%
\def\markshift{#1}%
% When not followed by the optional argument
% the contour mark is set at the previous height.
\ifx\markshift\star
\let\markshift=\lastmarkshift%
\fi
\global\advance\contourmarkcount by1\relax%
\xdef\tmpmark{\the\contourmarkcount}%
\tikz[remember picture, overlay, y=\pgfkeysvalueof{/tikz/contour scale}]
\path [yshift=\contourraise, shift={(0,\markshift)}]
coordinate (\contourmarkprefix-\tmpmark);%
\global\contourmarkcount=\tmpmark\relax%
\global\let\lastmarkshift=\markshift%
}
\tikzset{
intonation contour/.style={%
execute at begin node={%
\installbarmark%
},
append after command={%
\pgfextra{%
\ifnum\contourmarkcount>1
\draw [contour] (\contourmarkprefix-1)
\foreach \y in {2,...,\the\contourmarkcount}{ -- (\contourmarkprefix-\y) };
\fi
}
}
},
% How far above the base line of the text,
raise contour/.code=\pgfmathsetlength\contourraise{#1},
% The `scale' for the values in the contour height specification
contour scale/.initial=3pt,
% The prefix for the contour marks.
contour mark prefix/.code=\xdef\contourmarkprefix{#1},
contour mark prefix=intonation contour,
contour/.style={
draw,
rounded corners=1ex,
}
}
\begin{document}
\begin{tikzpicture}[remember picture]
\node [intonation contour, raise contour=0.5cm]
{|[10]Where |[3]are |[3]you |[5]go|[2]ing|[0]?};
\end{tikzpicture}
\begin{tikzpicture}[remember picture]
\node [intonation contour, raise contour=0.5cm, contour mark prefix=my contour]
{|[2]I |am |[7]fina|lly |[4]go|ing |[2]home|[0].};
\path [draw=red, ->] ([yshift=0.25cm]my contour-2) -- ([yshift=0.25cm]my contour-3)
node [midway, left] {\tiny rising};
\path [draw=red, ->] ([yshift=0.25cm]my contour-4) -- ([yshift=0.25cm]my contour-5)
node [midway, right] {\tiny falling};
\end{tikzpicture}
\end{document}
And just for fun, here's a version that doesn't use remember picture
so doesn't need two compilations. Also there is no fooling around with category codes. It is, unfortunately, a bit more involved, and the letters are not typeset ideally as they are all in separate boxes.
EDIT A bit more versatility has been implemented, but as a result it is a bit more complex.
\documentclass{standalone}
\usepackage{tikz}
\newdimen\contourraise
\tikzset{
% How far above the base line of the text,
raise contour/.code=\pgfmathsetlength\contourraise{#1},
% The `scale' for the values in the contour height specification
contour scale/.initial=3pt,
% The prefix for the contour marks.
contour mark prefix/.code=\xdef\contourmarkprefix{#1},
contour mark prefix=contour,
% The style for the contour path
contour/.style={
draw,
rounded corners=1ex,
},
% The style for the token nodes
contour token/.style={
anchor=base west,
inner sep=0pt,
text depth=0.6ex, % controls underline depth
},
contour underline/.style={
draw
},
% The character to insert a mark (use with care)
contour mark character/.store in=\contourmarkchar,
contour mark character=|
}
\makeatletter
\def\at@{@}
\newcount\lasttokennumber
\newcount\currenttokennumber
\newcount\contourmarkcount
\newcount\contourtokenunderlinestate
\newcommand\contour[2][]{%
\begin{scope}[#1]
\coordinate (token-0);
\currenttokennumber=0\relax%
\lasttokennumber=0\relax%
\contourmarkcount=0\relax%
\def\lastcontourheight{0}%
\contourtokenunderlinestate=0\relax%
\@contour#2@%
}
% Must check for a spaces
\def\@contour{\futurelet\@token\@checkforspace}
\def\@uscore{_}
\def\@checkforspace{%
\ifx\@token\@sptoken%
\let\@next=\@replacespace%
\else%
\if\@token\contourmarkchar%
\let\@next=\@contour@insertmark
\else%
\if\@token\@uscore
\let\@next=\@contourtoggleunderline%
\else%
\let\@next=\@@contour%
\fi%
\fi%
\fi%
\@next%
}
\def\@contourtoggleunderline#1{%
\advance\contourtokenunderlinestate by1\relax
\ifnum\contourtokenunderlinestate>3\relax%
\contourtokenunderlinestate=0\relax%
\fi%
\@contour%
}
\def\@contour@insertmark{%
\afterassignment\@@contour@insertmark\let\@token=%
}
\def\@@contour@insertmark{%
\futurelet\@token\@@@contour@insertmark}%
\def\@@@contour@insertmark{%
\if\@token[%
\let\@next=\@@@@contour@insertmark%
\else%
\let\currentcontourheight=\lastcontourheight%
\let\@next=\@@@@@contour@insertmark%
\fi%
\@next%
}
\def\@@@@contour@insertmark[#1]{%
\def\@tmp{#1}%
\ifx\@tmp\@empty%
\let\currentcontourheight=\lastcontourheight%
\else%
\def\currentcontourheight{#1}%
\fi%
\@@@@@contour@insertmark}
\def\@@@@@contour@insertmark{%
\advance\contourmarkcount by1\relax%
% Code for inserting mark
\coordinate (\contourmarkprefix-\the\contourmarkcount)
at ([yshift=\contourraise, y=\pgfkeysvalueof{/tikz/contour scale},
shift={(0,\currentcontourheight)}]token-\the\currenttokennumber.base east);
%
\let\lastcontourheight=\currentcontourheight
\@contour}
\def\customspace{{\hbox to 1ex{\hfill}}}
\def\@replacespace#1{%
\@contour\customspace#1%
}
\def\@@contour#1{%
\def\@token{#1}%
\if\@token\at@
\let\@next=\@@@contour%
\else%
\lasttokennumber=\currenttokennumber%
\advance\currenttokennumber by1%
% Code for typesetting token
\node [contour token/.try] at (token-\the\lasttokennumber.base east) (token-\the\currenttokennumber) {\@token};
% Manage underline state
\ifnum\contourtokenunderlinestate=1\relax%
\coordinate (underline start) at (token-\the\currenttokennumber.south west);
\contourtokenunderlinestate=2\relax%
\else
\ifnum\contourtokenunderlinestate=3\relax%
\coordinate (underline end) at (token-\the\currenttokennumber.south west);
\draw (underline start) -- (underline end);
\contourtokenunderlinestate=0\relax
\fi%
\fi%
\let\@next=\@contour
%
\fi%
\@next%
}
\def\@@@contour{%
\ifnum\contourmarkcount>1
% Code for drawing contour
\draw [contour] (\contourmarkprefix-1)
\foreach \y in {2,...,\the\contourmarkcount}{ -- (\contourmarkprefix-\y) };
%
\fi%
\end{scope}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[baseline={(0,-0.25)}]
\contour[raise contour=0.5cm]
{|[10]Where |[3]are |[3]_you_ |[5]go|[2]ing|[0]?}
\end{tikzpicture}
\begin{tikzpicture}[baseline={(0,-0.25)}]
\contour[
raise contour=0.5cm,
contour mark prefix=my contour,
contour/.style={
thick,
rounded corners=1mm,
line cap=round,
dotted},
contour mark character=*]
{*[2]I *am *[7]_{fi}na*lly_ *[4]go*ing *[2]home*[0].};
\path [draw=red, ->] ([yshift=0.25cm]my contour-2) -- ([yshift=0.25cm]my contour-3)
node [midway, left] {\tiny rising};
\path [draw=red, ->] ([yshift=0.25cm]my contour-4) -- ([yshift=0.25cm]my contour-5)
node [midway, right] {\tiny falling};
\path (0,-0.25);
\end{tikzpicture}
\end{document}
EDIT: enhanced version which hopefully covers all the use cases given above.
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{fit}
\newdimen\contourraise
\newdimen\contourspacetokenwidth
\newcount\lasttokennumber
\newcount\currenttokennumber
\newcount\contourmarkcount
\newcount\contourtokenunderlinestate
\newbox\contourbox
\tikzset{
tight fit/.style={
inner sep=0pt,
outer sep=0pt,
},
%
%
% How far above the reference anchor of the text,
contour raise/.code=\pgfmathsetlength\contourraise{#1},
contour reference anchor/.store in=\contourreferenceanchor,
contour reference anchor=base east,
% The `scale' for the values in the contour height specification
contour scale/.store in=\contourscale,
contour scale=3pt,
% The prefix for the contour marks.
contour mark prefix/.store in=\contourmarkprefix,
contour mark prefix=contour,
% The style for the contour path
contour/.style={
draw,
rounded corners=1ex,
},
% The style for the token nodes
every contour token/.style={
anchor=base west,
inner sep=0pt,
},
contour underline/.style={
draw
},
% The character to insert a mark (use with care)
contour mark character/.store in=\contourmarkchar,
contour mark character=|,
% Want to change the code for contour marks? Use this key.
contour mark code/.store in=\contourmarkcode,
% Want to change the code for tokens? Use this key.
contour token code/.store in=\contourtokencode,
% Want to change the code for drawing the contour? Use this key.
contour code/.store in=\contourcode,
%
% Default stuff
contour mark code={%
\coordinate (\contourmarkprefix-\the\contourmarkcount)
at ([yshift=\contourraise, y=\contourscale,
shift={(0,\currentcontourheight)}]token-\the\currenttokennumber.\contourreferenceanchor);
},
contour token code={%
\node [every contour token/.try] at
(token-\the\lasttokennumber.base east)
(token-\the\currenttokennumber) {\token};
},
contour code={
\draw [contour] (\contourmarkprefix-1)
\foreach \y in {2,...,\the\contourmarkcount}{ --
(\contourmarkprefix-\y) };
},
%
% Don't draw the contour.
tokens only/.style={
contour code={}
},
%
% Only draw the contour (but the space is still used for the tokens)
contour only/.style={
every contour token/.append style={
execute at begin node={\setbox\contourbox=\hbox\bgroup},
execute at end node=\egroup\phantom{\box\contourbox}%
},
underline/.style={
draw=none
}
},
%
% Make tokens follow the contour marks.
tokens follow contour/.style={
tokens only,
contour token code={%
\node [every contour token/.try, y=\contourscale] at
(token-\the\lasttokennumber.base east |-
0,\currentcontourheight)
(token-\the\currenttokennumber) {\token};
},
},
% What style to use when drawing underline
underline/.style={
draw
},
% The underline is drawn along the south side of a node which
% takes this style.
underline token/.style={
inner ysep=1pt
},
% When grouping tokens (e.g., for putting box around)
% this style is applied to a node that is fitted around the group
token group/.style={
inner xsep=1pt,
inner ysep=2pt,
rounded corners=2pt
},
% Draw boxes around tokens groups.
box tokens/.style={
token group/.append style={
draw
}
},
% Change the width of the spaces.
space token width/.code=\pgfmathsetlength\contourspacetokenwidth{#1},
space token width=0.125cm
}
\makeatletter
\def\at@{@}
\newcommand\contour[2][]{%
\begin{scope}[#1]
\coordinate (token-0);
\currenttokennumber=0\relax%
\lasttokennumber=0\relax%
\contourmarkcount=0\relax%
\def\lastcontourheight{0}%
\contourtokenunderlinestate=0\relax%
\@contour#2@%
}
% Must check for a spaces
\def\@contour{\futurelet\@token\@checkforspace}
\def\@uscore{_}
\def\@checkforspace{%
\ifx\@token\@sptoken%
\let\@next=\@replacespace%
\else%
\if\@token\contourmarkchar%
\let\@next=\@contour@insertmark
\else%
\if\@token\@uscore
\let\@next=\@contourtoggleunderline%
\else%
\let\@next=\@@contour%
\fi%
\fi%
\fi%
\@next%
}
\def\@contourtoggleunderline#1{%
\advance\contourtokenunderlinestate by1\relax
\ifnum\contourtokenunderlinestate>3\relax%
\contourtokenunderlinestate=0\relax%
\fi%
\@contour%
}
\def\@contour@insertmark{%
\afterassignment\@@contour@insertmark\let\@token=%
}
\def\@@contour@insertmark{%
\futurelet\@token\@@@contour@insertmark}%
\def\@@@contour@insertmark{%
\if\@token[%
\let\@next=\@@@@contour@insertmark%
\else%
\let\currentcontourheight=\lastcontourheight%
\let\@next=\@@@@@contour@insertmark%
\fi%
\@next%
}
\def\@@@@contour@insertmark[#1]{%
\def\@tmp{#1}%
\ifx\@tmp\@empty%
\let\currentcontourheight=\lastcontourheight%
\else%
\def\currentcontourheight{#1}%
\fi%
\@@@@@contour@insertmark}
\def\@@@@@contour@insertmark{%
\advance\contourmarkcount by1\relax%
% Code for inserting mark
\contourmarkcode%
\let\lastcontourheight=\currentcontourheight%
\@contour}
\def\contourspacetoken{{\hbox to \contourspacetokenwidth{\hfill}}}
\def\@replacespace#1{%
\@contour\contourspacetoken#1%
}
\def\@@contour#1{%
\def\@token{#1}%
\if\@token\at@%
\@contourdounderline%
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{}{%
\node [tight fit, fit={(tokengroup)}, token group/.try] {};
\global\let\pgf@sh@ns@tokengroup=\relax%
}%
\let\@next=\@@@contour%
\else%
\lasttokennumber=\currenttokennumber%
\advance\currenttokennumber by1%
\let\token=\@token%
% Code for typesetting token
\contourtokencode%
% Manage underline state
\@contourdounderline%
\def\@@token{\contourspacetoken}%
\ifx\@token\@@token%
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{}{%
\pgfutil@ifundefined{pgf@sh@ns@underline}{}{%
\node [tight fit, fit={(tokengroup) (underline)}]
(tokengroup)
{};}%
\node [tight fit, fit={(tokengroup)}, token group/.try] {};
\global\let\pgf@sh@ns@tokengroup=\relax%
}%
\else
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{%
\node [tight fit,
fit={(token-\the\currenttokennumber)}]
(tokengroup) {};
}{%
\node [tight fit,
fit={(token-\the\currenttokennumber)
(tokengroup)}]
(tokengroup){};
}%
\fi%
\let\@next=\@contour
%
\fi%
\@next%
}
\def\@contourdounderline{%
\ifcase\contourtokenunderlinestate%
\or
\node [tight fit, fit={(token-\the\currenttokennumber)}]
(underline) {};
\contourtokenunderlinestate=2\relax%
\or%
\node [tight fit,fit={(token-\the\currenttokennumber) (underline)}]
(underline) {};
\or%
\node [tight fit, fit={(underline)}, underline token/.try]
(underline) {};
\draw [underline/.try]
(underline.south west) -- (underline.south east);
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{}{%
\node [tight fit, fit={(tokengroup) (underline)}]
(tokengroup) {};%
\node [tight fit, fit={(tokengroup)}, token group/.try] {};
\global\let\pgf@sh@ns@tokengroup=\relax%
\global\let\pgf@sh@ns@underline=\relax%
}
\contourtokenunderlinestate=0\relax
\fi%
}
\def\@@@contour{%
\ifnum\contourmarkcount>1
% Code for drawing contour
\contourcode%
\fi%
\end{scope}%
}
\makeatother
\begin{document}
\begin{tabular}{c}
\\
\begin{tikzpicture}
\contour[tokens follow contour]
{|[10]_Where_ |[3]are you |[6]_go_|[1]ing?|[0]}
\end{tikzpicture}
\\[0.5cm]
\begin{tikzpicture}
\contour[tokens follow contour, box tokens, space token width=0.2cm]
{|[10]_Where_ |[3]are you |[6]_go_ |[1]ing?|[0]}
\end{tikzpicture}
\\[0.5cm]
\begin{tikzpicture}
\contour[contour raise=0.5cm]
{|[10]_Where_ |[3]are you |[6]_go_|[1]ing?|[0]}
\end{tikzpicture}
\\[0.5cm]
\begin{tikzpicture}
\contour[contour raise=0.5cm]
{|[10]Where |[3]are |[3]_you_ |[5]go|[2]ing?|[0]}
\contour[contour raise=0.5cm, contour only, contour/.append style={dashed}]
{|[0]Where |[2]are |[8]you |[2]go|[2]ing?|[1]}
\end{tikzpicture}
\\[1cm]
\begin{tikzpicture}
\contour[tokens follow contour,
contour mark character=*]
{*[2]I *am *[7]_{fi}na*lly_ *[4]go*ing *[2]_home_*[0]};
\end{tikzpicture}
\\[0.5cm]
\begin{tikzpicture}
\contour[
contour raise=0.5cm,
contour mark prefix=my contour,
contour/.style={
thick,
rounded corners=1mm,
line cap=round,
dotted},
contour mark character=*]
{*[2]I *am *[7]_{fi}na*lly_ *[4]go*ing *[2]home*[0].};
\path [draw=red, ->] ([yshift=0.25cm]my contour-2) -- ([yshift=0.25cm]my
contour-3)
node [midway, left] {\tiny rising};
\path [draw=red, ->] ([yshift=0.25cm]my contour-4) -- ([yshift=0.25cm]my
contour-5)
node [midway, right] {\tiny falling};
\end{tikzpicture}
\end{tabular}
\end{document}
I would use the famous \tikzmark
macro and combine it with intersection coordinates. Here is the code:
\documentclass{standalone}
\usepackage{tikz}
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture,baseline] \node [anchor=base] (#1) {};}%
\tikzstyle{intonation}=[rounded corners=2mm,yshift=1.5ex]
\begin{document}
\begin{tikzpicture}[remember picture]
\node{\tikzmark{w}Where \tikzmark{a}are \tikzmark{y}you \tikzmark{g}go\tikzmark{i}ing\tikzmark{q}?};
\draw[intonation] (w |- 0,1) -- (a |- 0,0.2) -- (y |- 0,0.2) -- (g |- 0,0.6) -- (q |- 0,0);
\end{tikzpicture}
\end{document}
The \tikzmark
macro saves the coordinates of the point of the document at which it is called. So the node text \tikzmark{w}Where \tikzmark{a}are...
saves coordinates called w
, a
, etc., at various points in the sentence.
If A
and B
are TikZ nodes or coordinates, then (A |- B)
is the intersection of a vertical line through A
and a horizontal line through B
. So (w |- 0,1)
has as its x coordinate the baseline-left point of the w in where, and y coordinate 1. You can change this y coordinate as you wish for the other coordinate names.
Here is the result:
You might be able to design a macro that specifies/marks the text and defines the y-values in the same argument. But this is a possible implementation.
I'm not sure I put the coordinates on the right places (and reused \zzb
in two points) but something like
%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode
\documentclass[a4paper,12pt, oneside]{article}
\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text, Scale=MatchLowercase}
\setmainfont{Charis SIL}
\makeatletter
\def\savecoordinate#1#2{\sbox0{#2}\edef#1{\strip@pt\wd0}}
\makeatother
\usepackage{tikz}
\begin{document}
\savecoordinate\zza{Where }
\savecoordinate\zzb{Where are you}
\savecoordinate\zzc{Where are you going?}
\begin{table}[hbtp]
\begin{tabular}{l}
\tikz[x=1pt,y=1mm,rounded corners=2mm] \draw[very thick, gray](0,10)--(\zza,2)--(\zzb,2)--(\zzb,6)--(\zzc,0); \\
\mbox{Where are you going?}
\end{tabular}
\end{table}
\end{document}