Re: Emacs: lilypond-ts-mode and the future of lilypond-mode
David Kastrup <[email protected]>
| Newsgroups | gmane.comp.gnu.lilypond.devel |
|---|---|
| Message-ID | <[email protected]> |
Saul Tobin <[email protected]> writes: > Hi all, > > I'd like to get folks' thoughts on the future of LilyPond official Emacs > support. > > My project lilypond-ts-mode > (https://github.com/shevvek/lilypond-ts-mode) is nearing the end of > alpha, and is relatively stable and feature complete. No interface to a PDF viewer and point-and-click? > In short, my pitch is that it's time to move towards retiring > lilypond-mode in favor of lilypond-ts-mode. I think that handling a viewer is kind of essential. I just threw some random file at it (adding an EPS file for compilability as attachment) that is mostly hand-indented (with a referral to scheme-mode for some parts). Running indent-region on that seems mostly ok-ish (not a mean feat compared to what LilyPond-mode does when given this task) but gets weird at the end (for example) and has a few strange decisions. At any rate, load the original file and then do C-x h C-M-\ M-x ediff-current-file RET and then leaf through the changes with SPC. Things to note are a change from chordmap = #(define-music-function ... to chordmap = #(define-music-function ... which costs indentation. Then there is $@(map (lambda (p) (let ((idx (car p)) (m (cdr p))) #{ << \context Staff = "hi" << \new Voice \with \tv-one \transpose c c' $m \new Voice \with \tv-two { <>_\markup #idx $m } >> \context Staff = \bass-staff << \new Voice \with \bv-one \transpose c c' $bass \new Voice \with \bv-two { $bass } >> >> #})) accp) which changes to $@(map (lambda (p) (let ((idx (car p)) (m (cdr p))) #{ << \context Staff = "hi" << \new Voice \with \tv-one \transpose c c' $m \new Voice \with \tv-two { <>_\markup #idx $m } >> \context Staff = \bass-staff << \new Voice \with \bv-one \transpose c c' $bass \new Voice \with \bv-two { $bass } >> >> #})) accp) and a few other such changes. Shortly before the end, there is the rather weird change of \markup \fill-line \general-align #Y #UP { \override #'(line-width . 45) \justify { Two sliders \bass-desc enable lower and upper bass reed sets. One slider (stem up, diamond heads) enables upper baritone reed set. The lower baritone reed set \bari-low-desc is not optional. Independent of the enabled reed sets is the chord note selection: a tutti slider (resulting chords marked with “*”) may be engaged. Otherwise a chord root slider with positions 1–20 is consulted. Each chord in the diagram is marked either with “*” or with the range of slider positions producing it. } \epsfile #X #85 #"bassbuttons.eps" } to \markup \fill-line \general-align #Y #UP { \override #'(line-width . 45) \justify { Two sliders \bass-desc enable lower and upper bass reed sets. One slider (stem up, diamond heads) enables upper baritone reed set. The lower baritone reed set \bari-low-desc is not optional. Independent of the enabled reed sets is the chord note selection: a tutti slider (resulting chords marked with “*”) may be engaged. Otherwise a chord root slider with positions 1–20 is consulted. Each chord in the diagram is marked either with “*” or with the range of slider positions producing it. } \epsfile #X #85 #"bassbuttons.eps" } where indentation goes really bonkers. And at the end, we have a change from \markuplist \override-lines #'(word-space . 4) \wordwrap-lines #(concatenate (stats-list)) to \markuplist \override-lines #'(word-space . 4) \wordwrap-lines #(concatenate (stats-list)) which is not a win either. Now make no mistake: this file was hand-indented rather than worked on by LilyPond-mode (apart from the Scheme passages mostly dealt with in Scheme-mode). So it's more looking at how it fares against a capable indenter (one should probably try Frescobaldi) than against the unspeakable LilyPond-mode. But not being able to start a viewer is certainly a drawback. -- David Kastrup
another.ly
(text/x-lilypond, 6.6 KB)
\version "2.19.22"
\paper {
ragged-last = ##f
}
#(define (number-or-pitch? a) (or (integer? a) (ly:pitch? a)))
bass-staff = "lo"
bass-clef = "bass"
bass-desc = \markuplist { }
bari-low-desc = \markuplist { (stem down, solid heads) }
bv-one = { \voiceOne \harmonicsOn }
bv-two = { \voiceTwo \harmonicsOn }
tv-one = { \voiceOne \harmonicsOn }
tv-two = \voiceTwo
sv-one = { \voiceOne \harmonicsOn }
sv-two = \voiceTwo
%%{
bass-staff = "hi"
bass-clef = "treble"
bass-desc = \markuplist { (stem down, diamond heads) }
bari-low-desc = \markuplist { (stem up, solid heads) }
bv-one = { \voiceFour \harmonicsOn }
bv-two = { \voiceTwo \harmonicsOn }
tv-one = { \voiceOne \harmonicsOn }
tv-two = \voiceThree
sv-one = { \voiceOne \harmonicsOn }
sv-two = \voiceTwo
%}
#(define stats (make-hash-table 20))
#(define (add-to-stats pitch chordname count)
(let ((p (hashv-create-handle! stats count '()))
(num (modulo (ly:pitch-semitones (ly:pitch-diff pitch #{ a #})) 12)))
(set-cdr! p (cons (cons num chordname) (cdr p)))))
#(define (stats-list)
(define (sort-pairs lst)
(map cdr
(sort-list lst car<)))
(map (lambda (e)
#{ \markuplist \override-lines #'(word-space . 1) \wordwrap-lines
#(cons (format #f "~d reeds:" (car e))
(fold-right
(lambda (next lst)
(cons (string-append next (if (null? lst) "." ",")) lst))
'() (sort-pairs (reverse (cdr e))))) #})
(sort-list (hash-table->alist stats) car<)))
chordmap =
#(define-music-function (start width music)
(number-or-pitch? index? ly:music?)
(if (ly:pitch? start) (set! start (ly:pitch-semitones start)))
(map-some-music
(lambda (m)
(and
(music-is-of-type? m 'event-chord)
(begin
(set! (ly:music-property m 'elements)
(append-map
(lambda (x)
(let ((p (ly:music-property x 'pitch)))
(if (ly:pitch? p)
(let loop ((n (ly:make-pitch
(- (ly:pitch-octave p)
(floor (/ (- (ly:pitch-semitones p) start)
12)))
(ly:pitch-notename p)
(ly:pitch-alteration p)))
(l '()))
(if (< (ly:pitch-semitones n)
(+ start width))
(loop (ly:pitch-transpose (ly:make-pitch 1 0 0) n)
(cons (music-clone x 'pitch n) l))
l))
(list x))))
(ly:music-property m 'elements)))
m)))
music))
#(define (conflate keys vals)
(define (folder k v res)
(if (or (null? res)
(not (equal? v (cdar res))))
(cons (cons (list k) v) res)
(cons (cons (cons k (caar res)) (cdar res)) (cdr res))))
(fold-right folder '() keys vals))
#(define (one-set start count music)
(map (lambda (kv)
(let ((keys (car kv)) (m (cdr kv)))
(cons (if (null? (cdr keys))
(format "~d" (car keys))
(format "~d–~d" (car keys) (last keys)))
m)))
(conflate (iota count 1)
(map
(lambda (i) #{ \chordmap #i #12 $music #})
(iota count (ly:pitch-semitones start))))))
#(define (bass-format-set pitch name)
(let ((bass #{ \chordmap e,, 12 < $pitch >4 #})
(accf #{ \chordmap a, 41 < $pitch >4 #})
(accp (one-set #{ a, #} 20 #{ < $pitch >4 #})))
(add-to-stats pitch (string-upcase name) (+ 2 (* 2 (length (ly:music-property accf ' elements)))))
#{ << \context Staff = "hi"
<< \new Voice \with \tv-one
{ \tempo \markup \caps #name \transpose c c' $accf }
\new Voice \with \tv-two { <>_"*" $accf } >>
\context Staff = \bass-staff
{ \clef \bass-clef \key $pitch \major
<< \new Voice \with \bv-one \transpose c c' $bass
\new Voice \with \bv-two { $bass } >>
}
>>
$@(map (lambda (p)
(let ((idx (car p)) (m (cdr p)))
#{ << \context Staff = "hi"
<< \new Voice \with \tv-one \transpose c c' $m
\new Voice \with \tv-two { <>_\markup #idx $m } >>
\context Staff = \bass-staff
<< \new Voice \with \bv-one \transpose c c' $bass
\new Voice \with \bv-two { $bass }
>>
>> #}))
accp)
#}))
#(define (chord-format-set pitch chord name)
(let ((accf #{ \chordmap a, 41 $chord #})
(accp (one-set #{ a, #} 20 chord)))
(add-to-stats pitch name (* 2 (length (ly:music-property accf 'elements))))
#{ << \new Voice \with \sv-one { \tempo \markup #name \transpose c c' $accf }
\new Voice \with \sv-two { <>_"*" $accf }
>>
$@(map (lambda (p)
(let ((idx (car p)) (m (cdr p)))
#{ << \new Voice \with \sv-one \transpose c c' $m
\new Voice \with \sv-two { <>_\markup #idx $m }
>>
#}))
accp)
#}))
#(define (score-format-set pitch name)
#{ \score { \new Staff = "hi"
{ \key $pitch \major \cadenzaOn
$(bass-format-set pitch name) \bar "|"
$@(map
(lambda (c t)
#{ \once \accidentalStyle forget
$(chord-format-set pitch c (string-append name t))
\bar "|"
#})
(ly:music-property
(ly:music-property
(ly:music-property
#{ \transpose c $pitch
\chordmode { c4 c:m c:7^5 c:dim7^5 } #}
'element)
'element)
'elements)
'("" "m" "7" "°"))
}
\layout {
indent = 0
\context {
\Staff
\remove "Time_signature_engraver"
\override TextScript.self-alignment-X = #CENTER
\override VerticalAxisGroup.outside-staff-placement-directive
= #'right-to-left-greedy
}
}
}
#})
#(set-global-staff-size 16)
\markup \fill-line { \huge "Morino Sonderkonstruktion 100811, \"M. Thöni\"" }
\markup \vspace #2
\markup \fill-line
\general-align #Y #UP
{ \override #'(line-width . 45) \justify {
Two sliders \bass-desc
enable lower and upper bass reed sets. One slider (stem
up, diamond heads) enables upper baritone reed set. The
lower baritone reed set \bari-low-desc is not optional.
Independent of the enabled reed sets is the chord note selection: a
tutti slider (resulting chords marked with “*”) may be engaged. Otherwise
a chord root slider with positions 1–20 is consulted.
Each chord in the diagram is marked either with
“*” or with the range of slider positions producing it. }
\epsfile #X #85 #"bassbuttons.eps" }
\markup \vspace #3
$@(map
(lambda (p n)
(score-format-set p n))
(event-chord-pitches #{ <des as es bes f c g d a e b fis> #})
#{ \markuplist { d♭ a♭ e♭ b♭ f c g d a e b f♯ } #})
\markup { Maximum number of reeds sounding with “*” slider engaged: }
\markuplist \override-lines #'(word-space . 4)
\wordwrap-lines #(concatenate (stats-list))
bassbuttons.eps
(application/postscript, 361.4 KB) - not displayed