LilyPond: извлечение названий высоты звука из музыки - PullRequest
6 голосов
/ 07 декабря 2010

Я использую LilyPond для создания партитур и этюдов. Я выяснил, как разрешить ввод заметки в нотации Moveable Do solfege и иметь шаблон (см. Ниже), который поддерживает отображение символов Solfege в виде текста под примечаниями. В настоящее время я должен вручную извлечь текст из разметки плюс разметка, которая генерирует музыку. Я смог частично автоматизировать это с помощью некоторого кода на python и vim (здесь не показан), но это все еще несколько неудовлетворительно.

Мне кажется, что лучшим решением было бы использование встроенного в LilyPond интерпретатора Scheme для извлечения названий основного тона во время обработки файла. Я сделал несколько попыток использовать карту с ly: note-pitchname, но пока безуспешно. Вероятно, потому что я знаю, как приседать в Scheme, особенно в том смысле, как он используется в скриптах LilyPond.

% 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"                 

Ответы [ 2 ]

3 голосов
/ 09 декабря 2010

Я получил полезную информацию от Валентина Вилленаве на форуме пользователей LilyPond, который привел к следующему работоспособному решению:

LilyPond предоставляет гравер NoteNames, который автоматически печатает названия шагов, например. "c d e" как текст под примечаниями, но есть давняя ошибка, которая заставляет NoteNames возвращаться к названиям ноты голландского тона. Обходной путь Валентина состоит в том, чтобы создать ассоциативный массив и использовать его в качестве поиска в лямбда-функции, которая вызывается при печати каждого шага. Подставляя записи из массива, печатаются нужные имена тонов.

Чтобы сделать решение полностью работоспособным, мне также пришлось добавить второй блок партитуры, чтобы отделить генерацию MIDI-вывода от печати партитуры. Это необходимо для предотвращения выдачи миди-выводом гравером NoteNames.

Я протестировал это решение с помощью файла гораздо большего размера, используя полный набор имен хроматических сольфежей. Это работает очень хорошо. Единственная оставшаяся проблема заключается в том, что было бы неплохо иметь возможность настраивать свойства шрифта на выходе NoteNames, чтобы отличить сольфадж от обычной лирики. До сих пор я не смог этого сделать.

% 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: Оказывается, что свойствами шрифта можно управлять с помощью функции разметки , например, путем изменения

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

до

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

Возможно, есть другие способы сделать то же самое, но это просто и делает то, что мне нужно. На данный момент, я считаю этот вопрос ответом. Обратите внимание, что будущая версия LilyPond может исправить ошибку NoteNames и устранить необходимость использования схемы для этой цели.

0 голосов
/ 03 декабря 2015

Ответ помог очень близко к моей необходимости. Просто пропустите, как получить некоторую точку выше или ниже числа для моей практики по гармонике и скрипке.

Я перестроил вещи так, чтобы они больше походили на будущий включенный скрипт, а также для генерации чисел, английского, а не 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
r r g4 | 
c c d8 e8 | c4 c e8 f8 | \break
g4 g a | f2 d8 e8 | \break
f4 f g | e e c8 e8 | \break
d4 a c | b2 g4 | \break
c c d8 e8 | c4 c e8 f8 | \break
g4 g a | f2 d8 e8 | \break
f4 f g | e e c8 e8 | \break
d4 a b | c2. | \break }


mymelodyC = \transpose c c  { \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 /3684028/lilypond-izvlechenie-nazvanii-vysoty-zvuka-iz-muzyki

%% === 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 {

    } 
}
...