3

Some time ago, I reached out to the lil mailing list seeking assistance with creating a Csound to LilyPond converter. The goal was to improve the readability and presentation of Csound scores using LilyPond.

For context, the Csound score format I'm dealing with is relatively straightforward and consists of the following fields: instrument_name, onset, duration, dynamic, frequency (at least).

\context Staff = MY_INSTR \new Voice \after 4*##eMY_ONSET { MY_NOTE 4*##eMY_DUR \- _"MY_CENT¢" } <>

It works well, but as I'm working on more complex compositions, I've encountered some inconsistencies.

The first system doesn't display bar lines marking the seconds in this code. Bar lines also do not appear in the last measure of the system.

I'm wondering if this approach is the right one to achieve the desired result. Any guidance or suggestions would be greatly appreciated!

\version "2.24.0"

\paper {
#(set-paper-size "a4landscape")
print-page-number = ##t
system-separator-markup = \slashSeparator
}

\layout {
\context {
\Score
proportionalNotationDuration = #(ly:make-moment 1/48)
\override SpacingSpanner.uniform-stretching = ##t
\override TimeSignature.stencil = ##f
\override TextScript.font-size = #-9
}
\context {
\Voice
\remove Stem_engraver
\remove Dots_engraver
\override NoteHead.duration-log = 2
}
}

<<
%===================================
\new RhythmicStaff = timeline
\new Staff = "org"
\new Staff = "senot"
\cadenzaOn
%===================================
\context Staff = "org" \new Voice \after 4*##e0.333 { f,, 4*##e1.324 _"+1.96¢" } <>
\context Staff = "org" \new Voice \after 4*##e0.333 { \clef "bass_8" } <>
\context Staff = "org" \new Voice \after 4*##e0.663 { cis,, 4*##e1.318 _"-11.73¢" } <>
\context Staff = "org" \new Voice \after 4*##e13.655 { bes,, 4*##e1.112 _"+3.91¢" } <>
\context Staff = "org" \new Voice \after 4*##e13.655 { \clef "bass_8" } <>
\context Staff = "org" \new Voice \after 4*##e13.933 { cis,, 4*##e1.108 _"-11.73¢" } <>
\context Staff = "org" \new Voice \after 4*##e13.933 { \clef "bass_8" } <>
\context Staff = "org" \new Voice \after 4*##e14.21 { f,, 4*##e1.105 _"+1.96¢" } <>
\context Staff = "org" \new Voice \after 4*##e14.21 { \clef "bass_8" } <>
\context Staff = "org" \new Voice \after 4*##e14.487 { c, 4*##e1.101 _"0.0¢" } <>
\context Staff = "org" \new Voice \after 4*##e14.487 { \clef "bass_8" } <>
\context Staff = "org" \new Voice \after 4*##e14.762 { fis,, 4*##e1.097 _"-9.78¢" } <>
\context Staff = "org" \new Voice \after 4*##e14.762 { \clef "bass_8" } <>
\context Staff = "org" \new Voice \after 4*##e15.036 { f,, 4*##e1.094 _"+1.96¢" } <>
\context Staff = "org" \new Voice \after 4*##e15.036 { \clef "bass_8" } <>
\context Staff = "senot" \new Voice \after 4*##e14.486 { bes, 4*##e1.101 _"+3.91¢" } <>
\context Staff = "senot" \new Voice \after 4*##e14.486 { \clef "bass_8" } <>
\context Staff = "senot" \new Voice \after 4*##e14.762 { f,, 4*##e1.097 _"+1.96¢" } <>
\context Staff = "senot" \new Voice \after 4*##e14.762 { \clef "bass_8" } <>
\context Staff = "senot" \new Voice \after 4*##e15.036 { cis,, 4*##e1.094 _"-11.73¢" } <>
\context Staff = "senot" \new Voice \after 4*##e15.036 { \clef "bass_8" } <>
\context Staff = timeline \new Voice \after 4*##e1 { s1 ^\markup"1" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e2 { s1 ^\markup"2" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e3 { s1 ^\markup"3" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e4 { s1 ^\markup"4" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e5 { \break } <>
\context Staff = timeline \new Voice \after 4*##e6 { s1 ^\markup"6" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e7 { s1 ^\markup"7" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e8 { s1 ^\markup"8" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e9 { s1 ^\markup"9" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e10 { \break } <>
\context Staff = timeline \new Voice \after 4*##e11 { s1 ^\markup"11" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e12 { s1 ^\markup"12" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e13 { s1 ^\markup"13" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e14 { s1 ^\markup"14" \bar "!"  } <>
\context Staff = timeline \new Voice \after 4*##e15 { \break } <>
\context Staff = timeline \new Voice \after 4*##e16 { s1 ^\markup"16" \bar "!"  } <>
>>

1 Answer 1

3

You are not getting some barlines as

s1^"text" \bar "!"

will insert the bar line after the skip, which is in your case in a random position later. Rather do

\bar "!" s1^"text"

to have the bar line at the exact position you specify. Alternatively you may do

<>^"text" \bar "!"

or

\bar "!" <>^"text"

Some more details:

\new Staff \new Staff ...

creates contexts within contexts. I’d rather do

\new Staff $(empty-music)

instead to create an empty context.

Also \after x m1 m2 is equivalent to << m2 sx m1>>. So instead of

\after 4*##e0.333 { f,, 4*##e1.324 _"+1.96¢" } <>

you can directly do

s4*##e0.333 f,, 4*##e1.324 _"+1.96¢"

etc.

So this could look like this:

\version "2.24.0"

\paper {
  #(set-paper-size "a4landscape")
  print-page-number = ##t
  system-separator-markup = \slashSeparator
}

\layout {
  \context {
    \Score
    proportionalNotationDuration = #(ly:make-moment 1/48)
    \override SpacingSpanner.uniform-stretching = ##t
    \override TimeSignature.stencil = ##f
    \override TextScript.font-size = #-9
  }
  \context {
    \Voice
    \remove Stem_engraver
    \remove Dots_engraver
    \override NoteHead.duration-log = 2
  }
}

<<
  %===================================
  \new RhythmicStaff = "timeline" $(empty-music)
  \new Staff = "org" $(empty-music)
  \new Staff = "senot" $(empty-music)
  \cadenzaOn
  %===================================
  \context Staff = "org" \new Voice { s4*##e0.333 f,, 4*##e1.324 _"+1.96¢" }
  \context Staff = "org" \new Voice { s4*##e0.333 \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e0.663  cis,, 4*##e1.318 _"-11.73¢" }
  \context Staff = "org" \new Voice { s4*##e13.655  bes,, 4*##e1.112 _"+3.91¢" }
  \context Staff = "org" \new Voice { s4*##e13.655  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e13.933  cis,, 4*##e1.108 _"-11.73¢" }
  \context Staff = "org" \new Voice { s4*##e13.933  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e14.21  f,, 4*##e1.105 _"+1.96¢" }
  \context Staff = "org" \new Voice { s4*##e14.21  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e14.487  c, 4*##e1.101 _"0.0¢" }
  \context Staff = "org" \new Voice { s4*##e14.487  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e14.762  fis,, 4*##e1.097 _"-9.78¢" }
  \context Staff = "org" \new Voice { s4*##e14.762  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e15.036  f,, 4*##e1.094 _"+1.96¢" }
  \context Staff = "org" \new Voice { s4*##e15.036  \clef "bass_8" }
  \context Staff = "senot" \new Voice { s4*##e14.486  bes, 4*##e1.101 _"+3.91¢" }
  \context Staff = "senot" \new Voice { s4*##e14.486  \clef "bass_8" }
  \context Staff = "senot" \new Voice { s4*##e14.762  f,, 4*##e1.097 _"+1.96¢" }
  \context Staff = "senot" \new Voice { s4*##e14.762  \clef "bass_8" }
  \context Staff = "senot" \new Voice { s4*##e15.036  cis,, 4*##e1.094 _"-11.73¢" }
  \context Staff = "senot" \new Voice { s4*##e15.036  \clef "bass_8" }
  \context Staff = "timeline" \new Voice { s4*##e1  <> ^\markup"1" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e2  <> ^\markup"2" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e3  <> ^\markup"3" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e4  <> ^\markup"4" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e5  \break }
  \context Staff = "timeline" \new Voice { s4*##e6  <> ^\markup"6" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e7  <> ^\markup"7" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e8  <> ^\markup"8" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e9  <> ^\markup"9" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e10  \break }
  \context Staff = "timeline" \new Voice { s4*##e11  <> ^\markup"11" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e12  <> ^\markup"12" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e13  <> ^\markup"13" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e14  <> ^\markup"14" \bar "!"  }
  \context Staff = "timeline" \new Voice { s4*##e15  \break }
  \context Staff = "timeline" \new Voice { s4*##e16  <> ^\markup"16" \bar "!"  }
>>

But I wouldn’t really do the counters as separate markups in the first place, but add them to the bar line stencil, e.g. do something like

\new RhythmicStaff = "timeline" \with {
  \override BarLine.stencil =
  #(grob-transformer
    'stencil
    (lambda (grob orig)
      (let ((text (ly:text-interface::print grob)))
        (ly:stencil-add
         orig
         (ly:stencil-translate text '(0.6 . 0.6))))))
  \override BarLine.font-size = #-8
  \override BarLine.font-series = #'bold
} $(empty-music)

and then

\context Staff = "timeline" \new Voice { s4*##e1  \once\override Staff.BarLine.text = "1" \bar "!"  }

(a similar effect could be achieved by doing \override Score.BarNumber.break-visibility = ##(#t #t #t)).

But this number could be derived automatically from the current bar number if we do not use \cadenzaOn:

\version "2.24.0"

\paper {
  #(set-paper-size "a4landscape")
  print-page-number = ##t
  system-separator-markup = \slashSeparator
}

\layout {
  \context {
    \Score
    proportionalNotationDuration = #(ly:make-moment 1/48)
    \override SpacingSpanner.uniform-stretching = ##t
    \override TimeSignature.stencil = ##f
    \override TextScript.font-size = #-9
    measureBarType = "!"
  }
  \context {
    \Voice
    \remove Stem_engraver
    \remove Dots_engraver
    \override NoteHead.duration-log = 2
  }
}

#(define (bar-number-engraver context)
   (make-engraver
    (acknowledgers
     ((bar-line-interface engraver grob source-engraver)
      (ly:grob-set-property!
       grob
       'text
       (number->string (1- (ly:context-property context 'currentBarNumber))))))))

<<
  %===================================
  \new RhythmicStaff = "timeline" \with {
    \consists #bar-number-engraver
    \override BarLine.stencil =
    #(grob-transformer
      'stencil
      (lambda (grob orig)
        (let ((text (ly:text-interface::print grob)))
          (ly:stencil-add
           orig
           (ly:stencil-translate
            (ly:stencil-aligned-to text X RIGHT) '(-0.6 . 0.6))))))
    \override BarLine.font-size = #-8
    \override BarLine.font-series = #'bold
  } $(empty-music)
  \new Staff = "org" $(empty-music)
  \new Staff = "senot" $(empty-music)
  \time 1/4
  %===================================
  \context Staff = "org" \new Voice { s4*##e0.333 f,, 4*##e1.324 _"+1.96¢" }
  \context Staff = "org" \new Voice { s4*##e0.333 \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e0.663  cis,, 4*##e1.318 _"-11.73¢" }
  \context Staff = "org" \new Voice { s4*##e13.655  bes,, 4*##e1.112 _"+3.91¢" }
  \context Staff = "org" \new Voice { s4*##e13.655  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e13.933  cis,, 4*##e1.108 _"-11.73¢" }
  \context Staff = "org" \new Voice { s4*##e13.933  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e14.21  f,, 4*##e1.105 _"+1.96¢" }
  \context Staff = "org" \new Voice { s4*##e14.21  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e14.487  c, 4*##e1.101 _"0.0¢" }
  \context Staff = "org" \new Voice { s4*##e14.487  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e14.762  fis,, 4*##e1.097 _"-9.78¢" }
  \context Staff = "org" \new Voice { s4*##e14.762  \clef "bass_8" }
  \context Staff = "org" \new Voice { s4*##e15.036  f,, 4*##e1.094 _"+1.96¢" }
  \context Staff = "org" \new Voice { s4*##e15.036  \clef "bass_8" }
  \context Staff = "senot" \new Voice { s4*##e14.486  bes, 4*##e1.101 _"+3.91¢" }
  \context Staff = "senot" \new Voice { s4*##e14.486  \clef "bass_8" }
  \context Staff = "senot" \new Voice { s4*##e14.762  f,, 4*##e1.097 _"+1.96¢" }
  \context Staff = "senot" \new Voice { s4*##e14.762  \clef "bass_8" }
  \context Staff = "senot" \new Voice { s4*##e15.036  cis,, 4*##e1.094 _"-11.73¢" }
  \context Staff = "senot" \new Voice { s4*##e15.036  \clef "bass_8" }
  \context Staff = "timeline" \new Voice { s4*##e5  \break }
  \context Staff = "timeline" \new Voice { s4*##e10  \break }
  \context Staff = "timeline" \new Voice { s4*##e15  \break }
>>

Finally we could automatize a lot of the stuff going on, essentially storing the content as a table of context, time and something to do. This can then be nicely parsed into music by a function:

\version "2.24.0"

#(define (bar-number-engraver context)
   (make-engraver
    (acknowledgers
     ((bar-line-interface engraver grob source-engraver)
      (ly:grob-set-property!
       grob
       'text
       (number->string (1- (ly:context-property context 'currentBarNumber))))))))

parseTable =
#(define-music-function (table) (list?)
   (define (impl t)
     (if (null? t)
         '()
         (let* ((line (car t))
                (ctx (first line))
                (time (second line))
                (what (third line))
                (args (cdddr line)))
           (cons
            #{
              \context Staff = #ctx
              \new Voice
              { s4*$time
                #(cond ((ly:music? what) (ly:music-deep-copy what))
                       ((procedure? what) (apply what args))
                       (else (begin
                              (ly:warning
                               (format #f "Unknown argument at time ~a" time))
                              (empty-music))))
              }
            #}
            (impl (cdr t))))))
   (make-music 'SimultaneousMusic 'elements (impl table)))

makeNote =
#(define-music-function (p dur alt)
   ((lambda (p) (or (ly:pitch? p) (string? p))) number? (markup? #f))
   (if (string? p)
       (set! p (ly:parse-string-expression (ly:parser-clone) p)))
   (if alt
       #{ $p 4*$dur _$alt #}
       #{ $p 4*$dur #}))

table =
#(list
  (list "org"       #e0.333 makeNote "f,," #e1.324 "+1.96¢")
  (list "org"       #e0.333 clef "bass_8")
  (list "org"       #e0.663 makeNote "cis,," #e1.318 "-11.73¢")
  (list "org"      #e13.655 makeNote "bes,," #e1.112 "+3.91¢")
  (list "org"      #e13.655 clef "bass_8")
  (list "org"      #e13.933 makeNote "cis,," #e1.108 "-11.73¢")
  (list "org"      #e13.933 clef "bass_8")
  (list "org"      #e14.21  makeNote "f,," #e1.105 "+1.96¢")
  (list "org"      #e14.21  clef "bass_8")
  (list "org"      #e14.487 makeNote "c," #e1.101 "0.0¢")
  (list "org"      #e14.487 clef "bass_8")
  (list "org"      #e14.762 makeNote "fis,," #e1.097 "-9.78¢")
  (list "org"      #e14.762 clef "bass_8")
  (list "org"      #e15.036 makeNote "f,," #e1.094 "+1.96¢")
  (list "org"      #e15.036 clef "bass_8")
  (list "senot"    #e14.486 makeNote "bes," #e1.101 "+3.91¢")
  (list "senot"    #e14.486 clef "bass_8")
  (list "senot"    #e14.762 makeNote "f,," #e1.097 "+1.96¢")
  (list "senot"    #e14.762 clef "bass_8")
  (list "senot"    #e15.036 makeNote "cis,," #e1.094 "-11.73¢")
  (list "senot"    #e15.036 clef "bass_8")
  (list "timeline"  #e5     break)
  (list "timeline" #e10     break)
  (list "timeline" #e15     break)
)


\paper {
  #(set-paper-size "a4landscape")
  print-page-number = ##t
  system-separator-markup = \slashSeparator
}

\layout {
  \context {
    \Score
    proportionalNotationDuration = #(ly:make-moment 1/48)
    \override SpacingSpanner.uniform-stretching = ##t
    \override TimeSignature.stencil = ##f
    \override TextScript.font-size = #-9
    measureBarType = "!"
  }
  \context {
    \Voice
    \remove Stem_engraver
    \remove Dots_engraver
    \override NoteHead.duration-log = 2
  }
}

<<
  %===================================
  \new RhythmicStaff = "timeline" \with {
    \consists #bar-number-engraver
    \override BarLine.stencil =
    #(grob-transformer
      'stencil
      (lambda (grob orig)
        (let ((text (ly:text-interface::print grob)))
          (ly:stencil-add
           orig
           (ly:stencil-translate
            (ly:stencil-aligned-to text X RIGHT) '(-0.6 . 0.6))))))
    \override BarLine.font-size = #-8
    \override BarLine.font-series = #'bold
  } $(empty-music)
  \new Staff = "org" $(empty-music)
  \new Staff = "senot" $(empty-music)
  \time 1/4
  %===================================
  \parseTable \table
>>
1
  • Thank you very much!! That's amazing it's really clear and it works like a charm. Can I ask you where did u study lilypond. I struggle a bit finding a good way to deeply understand basis.
    – cordelia
    Commented Oct 6, 2023 at 8:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.