1/* Part of plumdrum
    2	Copyright 2012-2015 Samer Abdallah (Queen Mary University of London; UCL)
    3	 
    4	This program is free software; you can redistribute it and/or
    5	modify it under the terms of the GNU Lesser General Public License
    6	as published by the Free Software Foundation; either version 2
    7	of the License, or (at your option) any later version.
    8
    9	This program is distributed in the hope that it will be useful,
   10	but WITHOUT ANY WARRANTY; without even the implied warranty of
   11	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12	GNU Lesser General Public License for more details.
   13
   14	You should have received a copy of the GNU Lesser General Public
   15	License along with this library; if not, write to the Free Software
   16	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
   17*/
   18
   19:- module(kern,
   20		[	kern_duration/2
   21		,	kern_pitch/2
   22		,	kern_rest/1
   23		]).

Kern spine format for Humdrum objects

This defines hooks into the humdrum module to enable it to parse Kern format spines. The predicates exported are hum_data_hook//2 and hum_duration_hook/3. */

   32:- use_module(library(dcg_core)).   33:- use_module(library(dcg_macros)).   34:- use_module(library(humdrum)).   35:- use_module(library(humdrum/humutils)).   36:- use_module(library(apply_macros)).   37
   38:- set_prolog_flag(double_quotes,codes).   39
   40% hooks to enable humdrum module to interpret kern data
   41humdrum:hum_data_hook(kern,Sigs) --> !, seqmap(kern,Sigs).
   42
   43humdrum:hum_duration_hook(kern,tok(E),D) :- !, kern_duration(E,D).
   44humdrum:hum_duration_hook(kern,sub(EX),D) :- !,
   45	(	maplist(dur_token(D),EX) -> true
   46	;	throw(kern_semantics(subtoken_duration_mismatch(EX)))
   47	).
   48
   49dur_token(Dur,Token) :- (kern_duration(Token,Dur) -> true; Dur=none).
 kern_duration(+S:data, -D:rational) is det
Determines the duration of a given Kern data term.
   53kern_duration(S,0) :- member(grace(Gr),S), (Gr=acciaccatura;Gr=appoggiatura), !.
   54kern_duration(S,R) :- member(recip(D),S), !, recip_to_rational(D,R).
   55kern_duration(_,0).
 kern_pitch(+S:data, -P:pitch) is nondet
True when P is one of the pitches contained in a Kern data term.
   59kern_pitch(Sigs,Pitch) :- member(pitch(Note,Oct),Sigs), !, oct_note_pitch(Oct,Note,Pitch).
 kern_rest(+S:data) is nondet
True when Kern data term S signifies a rest.
   63kern_rest(Sigs) :- memberchk(rest,Sigs).
   64
   65oct_note_pitch(4,Note,Note)      :- !.
   66oct_note_pitch(5,Note,Note*oct)  :- !.
   67oct_note_pitch(3,Note,Note/oct)  :- !.
   68oct_note_pitch(O1,Note,Note*(oct^O)) :- O1>5, !, O is O1-4.
   69oct_note_pitch(O1,Note,Note/(oct^O)) :- O1<3, !, O is 4-O1.
   70
   71% --------------- signifier and signifier components -----------------
   72
   73kern(P) --> {kern(P)}, P.
   74
   75% all the phrase that can occur in a kern data token
   76kern(recip(_)).
   77kern(pitch(_,_)).
   78kern(rest).
   79kern(articulation(_)).
   80kern(ornament(_)).
   81kern(grace(_)).
   82kern(par(_,_)).
   83kern(beam(_)).
   84kern(stem(_)).
   85kern(editorial).
   86kern(undefined(_)).
   87
   88rest --> "r";"rr".
   89
   90% articulation and phrasing (kern)
   91par(open,tie)   --> "[".
   92par(cont,tie)   --> "_".
   93par(close,tie)  --> "]".
   94par(open,slur-0)  --> "(".
   95par(close,slur-0) --> ")".
   96par(open,phrase-0)   --> "{".
   97par(close,phrase-0)  --> "}".
   98par(open,glissando)   --> "H".
   99par(close,glissando)  --> "h".
  100par(Op,Type-N) --> peek("&"), rep_shared(N,"&"), par(Op,Type-0).
  101
  102articulation(staccato)  --> "'".
  103articulation(spiccato)  --> "s".
  104articulation(pizzicato) --> "\"".
  105articulation(attacca)   --> "`".
  106articulation(tenuto)    --> "~".
  107articulation(accent)    --> "^".
  108articulation(generic)   --> "I".
  109articulation(harmonic)  --> "o".
  110articulation(sordino)   --> "U".
  111articulation(sforzando) --> "z".
  112articulation(down_bow)  --> "u".
  113articulation(up_bow)    --> "v".
  114articulation(arpeggio)  --> ":".
  115articulation(pause)     --> ";".
  116articulation(breath)    --> ",".
  117
  118ornament(turn) --> "S".
  119ornament(wagnerian_turn) --> "$".
  120ornament(trill(whole)) --> "T".
  121ornament(trill(semi)) --> "t".
  122ornament(mordent(whole)) --> "M".
  123ornament(mordent(semi)) --> "m".
  124ornament(inv_mordent(whole)) --> "W".
  125ornament(inv_mordent(semi)) --> "w".
  126ornament(ending_turn) --> "R".
  127ornament(generic) --> "O".
  128
  129
  130grace(acciaccatura)      --> "q".
  131grace(appoggiatura)      --> "P".
  132grace(groupetto)         --> "Q".
  133grace(post_appoggiatura) --> "p".
  134
  135/*
  136	relevant only to score typesetting
  137
  138	k	partial beam extending leftward
  139	kk	two partial beams extending leftward
  140	J	end beam
  141	JJ	end two beams
  142	K	partial beam extending rightward
  143	KK	two partial beams extending rightward
  144	L	start beam
  145	LL	start two beams
  146
  147	/	up-stem
  148	\	down-stem
  149*/
  150
  151beam(B) --> ("kk";"k";"JJ";"J";"KK";"K";"LL";"L")//list(Codes), {atom_codes(B,Codes)}.
  152stem(S) --> ("/";"\\")//list(Codes), {atom_codes(S,Codes)}.
  153
  154/*
  155	x	editorial interpretation; immediately preceding signifier is interpreted
  156	xx	editorial interpretation; entire data token is interpreted
  157	X	editorial intervention; immediately preceding signifier is an editorial addition; see also x
  158	XX	editorial intervention; entire data token is an editorial addition
  159	y	editorial mark: invisible symbol; unprinted note, rest, or
  160	Y	editorial mark: sic marking; information is encoded
  161	?	editorial mark: immediately preceding signifier has footnote in an ensuing comment
  162	??	editorial mark: entire preceding data token has footnote in an ensuing comment
  163*/
  164editorial --> "xx";"x";"y";"XX";"X";"Y";"??";"?".
  165
  166% !!!RDF**piano: X=hands cross, left over right
  167
  168undefined(XX) --> [X], {member(X,"VijlNZ@+|<>"), char_code(XX,X)}.
  169undefined('%') --> "%".
  170
  171
  172prolog:message(kern_semantics(subtoken_duration_mismatch(Terms))) -->
  173	{ maplist(dur_token,Durs,Terms) },
  174	[ 'Subtoken duration mismatch in **kern spine'-[], nl,
  175		'Subtokens are ~w'-[Terms], nl,
  176		'Durations are ~w'-[Durs], nl ]