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}
