\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{octave}
[2017/10/31 Octave designations in Helmholtz or traditional style]

% Copyright 2017 Andrew A. Cashner, andrewacashner@gmail.com

% This work may be distributed and/or modified under the 
% conditions of the LaTeX Project Public License, either
% version 1.3 of this license or (at your option) any 
% later version.
% The latest version of this license is in 
%    http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions
% of LaTeX version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
% The Current Maintainer of this work is Andrew A. Cashner.
% This work consists of the package file octave.sty
% and the documentation file octave.tex.

% CHANGE LOG
% 2017-10-31 Spelling corrections
% 2017-08-21 First version on CTAN

\newif\if@OctaveNumber
\@OctaveNumbertrue % Use Helmholtz numbers by default

\DeclareOption{prime}  {\@OctaveNumberfalse}
\DeclareOption{number} {\@OctaveNumbertrue}

\ProcessOptions\relax

\RequirePackage{xparse}

% Allow user to switch styles mid-document
\NewDocumentCommand{\octaveprimes}  {}{\@OctaveNumberfalse}
\NewDocumentCommand{\octavenumbers} {}{\@OctaveNumbertrue}

%****************************************************************************
% Main user command to enter pitch
% example: middle C is \pitch{c}{4}, semitone up is \pitch{C}[\sh]{4}
% #1 Pitch letter (can be lower or uppercase)
% #2 Optional accidental (e.g., $\flat$, or \fl{} from semantic-markup package)
% #3 Octave number (Helmholtz numbers, middle C = 4)
\NewDocumentCommand{\pitch}{ m o m }{%
    \if@OctaveNumber
        {\pitchfont{\MakeUppercase{#1}%
        \IfValueTF{#2}{#2}{}\textsubscript{#3}}}%
    \else
        {\pitchfont{%
            \@GetOctaveTick{#1}[#2]{#3}%
        }}%
    \fi
}

% Font for pitch and octave designation, default italics for prime style
% User can change with \renewcommand
\NewDocumentCommand{\pitchfont}{}{%
    \if@OctaveNumber\mdseries%
    \else\itshape%
    \fi
}

%***************************************************************************
% If using ticks, determine the right letter and octave symbols to print
%
% Octave  Designation
%      0  C''
%      1  C'
%      2  C
%      3  c
%      4  c'
%      5  c''
% 
% The input octave number can be less than zero or more than 5; this will just
% produce a lot of tick marks (e.g., \pitch{c}{8} => c'''''

% Mnemonic for selecting upper or lowercase letters, 
% used as argument to \@PrintLetter
\NewDocumentCommand{\@OctaveUpper}{}{1}
\NewDocumentCommand{\@OctaveLower}{}{0}

% Get the letter of the proper case and the right number of ticks.
% #1 Pitch letter
% #2 Optional accidental
% #3 Pitch number in Helmholtz notation
\newcount\@OctaveNum
\NewDocumentCommand{\@GetOctaveTick}{ m o m }{%
    \@OctaveNum = #3
    \ifnum\@OctaveNum < 3 
    % Octave < 3: Letter lowercase + (-OctaveNum + 2)ticks
        \@PrintLetter{\@OctaveUpper}{#1}%
        \multiply\@OctaveNum by -1 
        \advance\@OctaveNum by 2 
    \else
    % Octave >= 3: Letter uppercase + (OctaveNum - 3)ticks
        \ifnum\@OctaveNum > 2
            \@PrintLetter{\@OctaveLower}{#1}%
            \advance\@OctaveNum by -3
        \fi
    \fi
    % Print accidental if there is one
    \IfValueTF{#2}{\@SpacedAccidental{#2}}{}%
    % Print ticks; No need to do so if octave 2 or 3
    \ifnum\@OctaveNum > 0
        \kern1pt\@PrintTicks{\@OctaveNum}%
    \fi
}

% Accidental with spacing around it
%  #1 accidental symbol code
\NewDocumentCommand{\@SpacedAccidental}{ m }{%
    \kern0.4pt#1\kern-0.4pt%
}
% Print letter in proper case
% #1 \@OctaveUpper (=1) or \@OctaveLower (=0)
% #2 Character to print
\NewDocumentCommand{\@PrintLetter}{ m m }{%
    \ifnum #1 = \@OctaveLower
        \MakeLowercase{#2}%
    \else
        \MakeUppercase{#2}%
    \fi
}
        
% Print sequence of tick marks
\newcount\@TickNum
\NewDocumentCommand{\@PrintTicks}{ m }{%
   \@TickNum = #1%
   \loop
        \@Tick{}%
    \advance\@TickNum by -1
    \ifnum\@TickNum > 0
    \repeat
}
\NewDocumentCommand{\@Tick}{}{\ensuremath{'}}

%*******************************************
% Octave comparison table for demonstration
\newcounter{@TableOctave}
\NewDocumentCommand{\octavetable}{}{%
    \def\@TablePitchNames{}%
    \loop
    \edef\@TablePitchNames{%
        \@TablePitchNames
        {\octaveprimes \pitch{C}{\the@TableOctave}} & 
        {\octavenumbers \pitch{C}{\the@TableOctave}}\tabularnewline
    }%
    \stepcounter{@TableOctave}%
    \ifnum\value{@TableOctave} < 8
    \repeat
    %
    \begin{tabular}{ll}
        \@TablePitchNames
    \end{tabular}%
}

\endinput