LilyPond: Extracting Sounds from Music

I use LilyPond to create practice assessments and studies. I figured out how to allow notes to be recorded in the Moveable Do solfege notation and have a template (see below) that supports the display of solfege characters as texts under the notes. Currently, I have to manually extract the lyrics from the notation plus the markup that generates the music. I was able to partially automate this with python and vim code (not shown here), but it is still somewhat unsatisfactory.

It seems to me that the best solution would be to use the built-in Scheme LilyPond interpreter to extract field names during file processing. I made several attempts to use the card with ly: note-pitchname, but so far have not achieved anything. Probably because I know squats about Scheme, especially in LilyPond scripts.

% Moveable Do as lyrics example % define some solfege pitchnames % (in practice, the full set goes into "english.ly") pitchnames = #`( (do . ,(ly:make-pitch -1 0 NATURAL)) (re . ,(ly:make-pitch -1 1 NATURAL)) (mi . ,(ly:make-pitch -1 2 NATURAL)) ) #(ly:parser-set-note-names parser pitchnames) % compose as though in C major mynotes = \relative do' {\key do \major do2 re4( mi4) } % transpose to desired key melody = \transpose do mi { \mynotes } % I WANT TO AUTOMATICALLY CREATE THE % THE PITCHNAMES IN THIS BLOCK % FROM THE CONTENTS OF \mynotes solfa = \lyricmode { \set ignoreMelismata = ##t % one syllable per note do re mi \unset ignoreMelismata % allow normal placement of other lyrics } % Produce score with solfege names as lyrics \score { << \new Voice = "myVoice" { \melody } \new Lyrics \lyricsto "myVoice" \solfa >> } \version "2.12.3" 
+6
scheme guile lilypond
source share
2 answers

I received useful information from Valentin Villenave in the LilyPond user forum, which led to the following workable solution:

LilyPond provides a NoteNames graphical editor that automatically prints tag names, for example. "cde" is like lyrics under notes, but there is a long-standing mistake that makes NoteNames revert to Dutch names. Valentan's workaround is to create an associative array and use it as a search in the lambda function, which is called when each step is ready to print. Substituting the entries from the array, the names of the desired tone are printed.

To make the solution fully functional, I also had to add a second evaluation unit to separate the generation of the midi output signal from the print points. This is to ensure that NoteNames engravers do not produce MIDI output.

I tested this solution with a much larger file using the full set of chromatic solfege names. It works very well. The only remaining problem is that it would be nice to adjust the font settings on the NoteNames output to make solfege different from the usual lyrics. So far, I have not been able to do this.

 % Moveable Do as lyrics example % define solfege pitchnames pitchnames = #`( (do . ,(ly:make-pitch -1 0 NATURAL)) (re . ,(ly:make-pitch -1 1 NATURAL)) (mi . ,(ly:make-pitch -1 2 NATURAL)) ) #(ly:parser-set-note-names parser pitchnames) % Apparently, LilyPond reverts to dutch names when % using the NoteNames context. The following % workaround was posted by V. Villenave at % http://lists.gnu.org/archive/html/lilypond-user/2010-10/msg00687.html newnames = #`(("c" . "do") ("d" . "re") ("e" . "mi")) myNoteNames = #(lambda (grob) (let* ( ;; bindings (default-name (ly:grob-property grob 'text)) (new-name (assoc-get default-name newnames)) ) ;; body (ly:grob-set-property! grob 'text new-name) (ly:text-interface::print grob) ) ) % compose as though in C major mynotes = \relative do' {\key do \major do2 re4( mi4) } % transpose to desired key melody = \transpose do mi { \mynotes } % Produce score with solfege names as lyrics \score { << \new Voice = "myVoice" { \melody } \context NoteNames \with { \override NoteName #'stencil = #myNoteNames } { \mynotes } >> } % Use a second score block to produce midi, % otherwise the NoteNames will produce a duplicate % track. \score { \new Voice = "myVoice" { \melody } %% This generates the midi file \midi { } } \version "2.12.3" 

UPDATE: It turns out that font properties can be controlled using the markup function, for example, by changing

 (ly:grob-set-property! grob 'text new-name) 

to

 (ly:grob-set-property! grob 'text (markup #:italic #:smaller new-name)) 

There may be other ways to do the same thing, but it just does what I need. At this stage, I believe that this question is answered. Please note that a future version of LilyPond may fix NoteNames error and eliminate the need to use Schema for this purpose.

+3
source share

The answer really helped me. Just skip how to get some point above or below the numbers for my practice of harmonics and violin.

I remade things so that it looks more like a future script, and also for generating a number, English, not OP do-re-mi:

 % LilyBin == template with 馬槽歌 Away in a Manger lilypond ... === % LilyBin \version "2.18.2" \include "english.ly" %% === melody ============================== mynotesC = \relative c' { \tempo 4 = 120 \key c \major \time 3/4 rr g4 | cc d8 e8 | c4 c e8 f8 | \break g4 ga | f2 d8 e8 | \break f4 fg | ee c8 e8 | \break d4 ac | b2 g4 | \break cc d8 e8 | c4 c e8 f8 | \break g4 ga | f2 d8 e8 | \break f4 fg | ee c8 e8 | \break d4 ab | c2. | \break } mymelodyC = \transpose cc  { \mynotesC } opusDef = "" opusBug = "Away in a Manger 馬槽歌 (Bug)" opusEng = "Away in a Manger 馬槽歌 (English)" opusNum = "Away in a Manger 馬槽歌  (Number)" opusNil = "Away in a Manger 馬槽歌  (No generated)" %% === default header ============================= \header { title = "Away in a Manger 馬槽歌  (Default Header)" composer = "" opus = \opusDef } %% still problem %% based on http://stackoverflow.com/questions/4378228/lilypond-extracting-pitch-names-from-music %% === engnames ====================================== engnames = #`(  ("c" . "D")  ("d" . "D")  ("e" . "E")  ("f" . "F")  ("g" . "G")  ("a" . "A")  ("b" . "B")    ("ces" . "Cb")  ("des" . "Db")  ("ees" . "Eb")  ("fes" . "Fb")  ("ges" . "Gb")  ("aes" . "Ab")  ("bes" . "Bb")    ("cis" . "C#")  ("dis" . "D#")  ("eis" . "E#")  ("fis" . "F#")  ("gis" . "G#")  ("ais" . "A#")  ("bis" . "B#")  ) myEngNames = #(lambda (grob)  (let* (     ;; bindings     (default-name (ly:grob-property grob 'text))     (new-name (assoc-get default-name engnames))     )      ;; body     (ly:grob-set-property! grob 'text new-name)     (ly:text-interface::print grob)     )  ) %% === numnames ===================================== numnames = #`(  ("c" . "1")  ("d" . "2")  ("e" . "3")  ("f" . "4")  ("g" . "5")  ("a" . "6")  ("b" . "7")    ("ces" . "1b")  ("des" . "2b")  ("ees" . "3b")  ("fes" . "4b")  ("ges" . "5b")  ("aes" . "6b")  ("bes" . "7b")    ("cis" . "1#")  ("dis" . "2#")  ("eis" . "3#")  ("fis" . "4#")  ("gis" . "5#")  ("ais" . "6#")  ("bis" . "7#")  ) myNumNames = #(lambda (grob)  (let* (     ;; bindings     (default-name (ly:grob-property grob 'text))     (new-name (assoc-get default-name numnames))     )      ;; body     (ly:grob-set-property! grob 'text new-name)     (ly:text-interface::print grob)     )  ) %% === no generated "lyrics" ================= \score {  <<  \new Voice = "myVoice" {    \mymelodyC  } %{  \context NoteNames \with {    \override NoteName #'stencil = #myNumNames  }{ \mynotesC }  %}  >> \layout{ \context {   \Score   proportionalNotationDuration = #(ly:make-moment 1/16)  } #(layout-set-staff-size 30)  indent = #0  line-width = #180  ragged-last = ##f} %% ##t} %%  \midi{} \header { opus = \opusNil } } %% === Produce score with buggy non-English names as lyrics ====== \pageBreak \score {  <<  \new Voice = "myVoice" {    \mymelodyC  }  \context NoteNames { \mynotesC }  >> \header { opus = \opusBug }   \layout{ \context {   \Score   proportionalNotationDuration = #(ly:make-moment 1/16)  } #(layout-set-staff-size 30)  indent = #0  line-width = #180  ragged-last = ##f} %% ##t} %%  \midi{} } %% ===  Produce score with English names as lyrics ============ \pageBreak \score {  <<  \new Voice = "myVoice" {    \mymelodyC  }  \context NoteNames \with {    \override NoteName #'stencil = #myEngNames  }{ \mynotesC }  >> \header { opus = \opusEng }   \layout{ \context {   \Score   proportionalNotationDuration = #(ly:make-moment 1/16)  } #(layout-set-staff-size 30)  indent = #0  line-width = #180  ragged-last = ##f} %% ##t} %%  \midi{} } %% === Page with numNames ============================ \pageBreak \score {  <<  \new Voice = "myVoice" {    \mymelodyC  }  \context NoteNames \with {    \override NoteName #'stencil = #myNumNames  }{ \mynotesC }  >> \layout{ \context {   \Score   proportionalNotationDuration = #(ly:make-moment 1/16)  } #(layout-set-staff-size 30)  indent = #0  line-width = #180  ragged-last = ##f} %% ##t} %%  \midi{} \header { opus = \opusNum } } %% === MIDI ============================================ % Use a second score block to produce midi, % otherwise the NoteNames will produce a duplicate % track. \score {  \new Voice = "myVoice" {    \mymelodyC  }   %% This generates the midi file  \midi {  } } 
0
source share

All Articles