1/* lilypond.pl
    2Author: Gimenez, Christian.
    3
    4Copyright (C) 2025 Gimenez, Christian
    5
    6This program is free software: you can redistribute it and/or modify
    7it under the terms of the GNU General Public License as published by
    8the Free Software Foundation, either version 3 of the License, or
    9at your option) any later version.
   10
   11This program is distributed in the hope that it will be useful,
   12but WITHOUT ANY WARRANTY; without even the implied warranty of
   13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14GNU General Public License for more details.
   15
   16You should have received a copy of the GNU General Public License
   17along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18
   192025-10-14
   20*/
   21
   22:- module(lilypond, [
   23              notelily//1,
   24              lily//1,
   25              write_lily/1,
   26              write_lily/2
   27          ]).

lilypond: generate or parse Lilypond code.

Parse Prolog note representations from Lilypond code. Or generate Lilypond code from Prolog notes. This is achieved by DCG rules.

Examples

Generating Lilypond code:

?- phrase(lily([c, d, e, f, g]), L, []), format('~s', [L]).
c d e f g

Parsing from Lilypond code:

?- phrase(lily(L1), `c cis   d dis e`, R).
L1 = [c, cs, d, ds, e],
R = [].
author
- Christian Gimenez
license
- GPLv3 */
   54:- license(gplv3).   55
   56:- use_module(library(dcg/basics)).
Parse a Prolog note representation from a Lilypond note. Or generate Lilypond code from a Prolog note.
Arguments:
Note- An atom with the note name or a Note-Octave-Duration term.
   65notelily(cs) --> `cis`,
   66               % sharp notes must be before natural notes!
   67               % this allows recognising them because of the string length.
   68               !. 
   69notelily(c) --> `c`, !.
   70notelily(ds) --> `dis`, !.
   71notelily(d) --> `d`, !.
   72notelily(e) --> `e`, !.
   73notelily(fs) --> `fis`, !.
   74notelily(f) --> `f`, !.
   75notelily(gs) --> `gis`, !.
   76notelily(g) --> `g`, !.
   77notelily(as) --> `ais`, !.
   78notelily(a) --> `a`, !.
   79notelily(b) --> `b`, !.
   80notelily(r) --> `r`, !.
   81            
   82notelily(Note-Octave-Duration) --> notelily(Note), octavelily(Octave), number(Duration).
 octavelily(+Number:integer)//
Convert the octave number to a Lilypond phrase.
To be done
- Implement octavelily//1
   89octavelily(_) --> [].
Parse Prolog notes from Lilypond code, or generate Lilypond code from Prolog notes.
Arguments:
Notes- A list of the following elements:
  • an atom with the note name or,
  • a Note-Octave-Duration term.
  100lily([Note|Rest]) -->
  101    % Case: parsing Lilypond string with multiple blanks. But cannot be used to
  102    % generate Lilypond strings, because blank//0 and blanks//0 will fail.
  103    notelily(Note), blank, blanks, !, lily(Rest). 
  104lily([Note|Rest]) -->
  105    % Case: useful to generate Lilypond strings.
  106    notelily(Note), ` `, !, lily(Rest).
  107lily([Note]) --> notelily(Note), !.
  108lily([]) --> [].
 write_lily(+Notes:list) is det
Write to stdout the Lilypond representation of Notes.
  113write_lily(Notes) :-
  114    write_lily(current_output, Notes).
  115
  116write_lily(Stream, Notes) :-
  117    phrase(lily(Notes), Str, []),
  118    format(Stream, '~s', [Str])