質問
練習譜や練習曲の作成にはLilyPondを使用しています。Moveable Do ソルフェージュ記譜法で音符の入力を許可する方法と、音符の下にソルフェージュ記号を歌詞として表示することをサポートするテンプレート (以下を参照) を用意する方法を考え出しました。現時点では、音楽を生成する記譜法とマークアップから歌詞を手動で抽出する必要があります。いくつかの 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"
解決
LilyPond ユーザー フォーラムで Valentin Villenave から有益な情報を受け取りました。これにより、次の実行可能な解決策が得られました。
LilyPond は、ピッチ名を自動的に印刷する NoteNames エングレーバーを提供します。音符の下に歌詞として「c d e」が表示されますが、NoteName がオランダ語の音名に戻ってしまうという長年のバグがあります。Valentin 氏の回避策は、連想配列を作成し、それを各ピッチが出力されるときに呼び出されるラムダ関数のルックアップとして使用することです。配列のエントリを置き換えることにより、希望の音名が出力されます。
ソリューションを完全に実行可能にするために、MIDI 出力生成をスコア印刷から分離するために 2 番目のスコア ブロックも追加する必要がありました。これは、NoteNames エングレーバーが MIDI 出力を生成しないようにするために必要です。
私は、半音階ソルフェージュ名の完全なセットを使用して、はるかに大きなファイルでこのソリューションをテストしました。とてもうまくいきます。唯一残っている問題は、ソルフェージュを通常の歌詞と区別できるように 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"
アップデート:フォントのプロパティは次のコマンドで制御できることがわかりました。 マークアップ機能, たとえば、変更することによって
(ly:grob-set-property! grob 'text new-name)
に
(ly:grob-set-property! grob 'text (markup #:italic #:smaller new-name))
おそらく、同じことを達成する他の方法はありますが、これはシンプルで、必要なことを実現します。この時点で、この質問は答えられたと思います。LilyPond の将来のバージョンでは NoteNames のバグが修正され、この目的で Scheme を使用する必要がなくなる可能性があることに注意してください。
他のヒント
その答えは私のニーズに非常に近いものでした。ハーモニカとヴァイオリンの練習で、数字の上または下にドットを取得する方法を見逃してください。
将来的に組み込まれるスクリプトのようになり、OPドレミではなく数字、英語を生成するように再構築しました。
% 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 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 {
}
}