Hello Knute,

so you are using books to allow specification of the midi filename. This is 
probably a fine usecase, but it still seems like a bit of an abuse of the book 
mechanic to me. Rather I’d adapt the midi output name logic itself.

This code adapts the internal function responsible for writing out the midi 
performances (scm/midi.scm:write-performances-midis) in such a way that

A) If we have multiple midi outputs all outputs are numbered starting with 1 
(instead of the first not being numbered and the next one starting with 1)
B) The numbering is padded to an equal length (so if you’ve got less than 10 
midis you number 1, 2, 3, ..., under 100 01, 02, 03, ...)
C) The midi performance title (if set midititle else title else "") (if set) 
is used as suffix.
D) The header property midiOutputSuffix may be used to override this suffix
E) The header property midiOutputFile may be used to override the full midi 
file name

This has the advantage over abusing Books that it specifies the names at the 
relevant position, not at a higher position.

Cheers,
Valentin

Am Dienstag, 27. Juni 2023, 16:39:53 CEST schrieb Knute Snortum:
> On Tue, Jun 27, 2023 at 2:35 AM Valentin Petzel <[email protected]> wrote:
> > Hello Knute,
> > 
> > I do not think this behaviour is particularly weird, rather the input is
> > weird.
> 
> Thanks for your replies.  Here is my slightly convoluted use-case.  Maybe
> there's a better way to do it.
> 
> I am engraving collections of pieces, such as Bach's 15 two-part
> inventions.  I want to be able to create a "book" with all the pieces in
> one PDF, but also to be able to print each piece individually.  And I want
> to be able to tweak the MIDI output, so I use \keepWithTag to do that.  So
> I have an "include" file something like this:
> 
> inventionOneMusic =
> \score {
>   \keepWithTag layout
>   % Notes
>   \layout {}
> }
> 
> inventionOneMidi =
> \score {
>   \keepWithTag midi
>   % Notes
>   \midi {}
> }
> 
> So now I can have a file called "invention-one.ly" that looks like this:
> 
> \inventionOneMusic
> \inventionOneMidi
> 
> ...and another that is the "book" called "15-two-part-inventions.ly" like
> this:
> 
> \inventionOneMusic
> \inventionTwoMusic
> % etc
> 
> \inventionOneMidi
> \inventionTwoMidi
> % etc
> 
> But now there's a problem.  I want one PDF but also the individual MIDI
> files named correctly.  As it stands I get files named like this:
> 
> 15-two-part-inventions.pdf
> 15-two-part-inventions.midi
> 15-two-part-inventions-1.midi
> etc
> 
> It's hard to tell which MIDI file belongs to which invention.  What I want
> is:
> 
> 15-two-part-inventions.pdf
> invention-one.midi
> invention-two.midi
> etc
> 
> The only way I could think of doing that is to wrap the MIDI score in a
> book and use \bookoutputFile:
> 
> inventionOneMidi =
> \book {
>   \bookOutputFile "invention-one"
>   \score {
>     \keepWithTag midi
>     % Notes
>     \midi {}
>   }
> }
> 
> So that's my use-case.  Maybe that isn't the best solution and one of you
> can come up with a better one.  Thanks for reading this long post.

%%% Create a binding to current module so we can get back there
#(module-define! (resolve-module '(lily)) 'mod (current-module))

%%% Change to lily module
#(set-current-module (resolve-module '(lily)))

% New convenience function to obtain midiOutputFile property from header
#(define (midi-filename-from-headers headers)
   (let ((f (ly:modules-lookup headers 'midiOutputFile)))
     (if f (markup->string f) #f)))

% New convenience function to obtain midiOutputSuffix property from header
#(define (midi-suffix-from-headers headers)
   (let ((f (ly:modules-lookup headers 'midiOutputSuffix)))
     (if f (markup->string f) #f)))

#(define-public (write-performances-midis performances basename . rest)
  (let* ((midi-ext (ly:get-option 'midi-extension))
         (n (length performances))                                      ; change: calculate highest number of digits
         (ndigits (1+ (floor (log10 n)))))                              ; used for padding counts
    (let
        loop
      ((perfs performances)
       (count (if (null? rest) 0 (car rest))))
      (if (pair? perfs)
          (let* ((perf (car perfs))
                 (performance-name (performance-name-from-headers       ; change: previously done directly in format,
                                    (ly:performance-headers perf)))     ; now we need this multiple times
                 (midi-filename (midi-filename-from-headers             ; this is new
                                 (ly:performance-headers perf)))
                 (midi-suffix (midi-suffix-from-headers                 ; this is new
                                 (ly:performance-headers perf)))
                 (suffix (or midi-suffix performance-name)))            ; this is new
            (ly:performance-write
             perf
             (if midi-filename                                          ; New case if midiOutputFile is specified            
                 (format #f "~a.~a" midi-filename midi-ext)             ; new branch then use this given file
                 (if (> n 1)                                            ; change from (> count 0) (so first file will also get count)
                     (if (equal? suffix "")                             ; New case if suffix is not specified
                         ((@ (ice-9 format) format)                     ; change: use ice-9 format to allow for variable padding
                          #f "~a-~v,'0d.~a" basename ndigits (1+ count) midi-ext) ; change: use ice-9 format to allow for variable padding, start count with 1
                         ((@ (ice-9 format) format)                     ; New branch if suffix is specified use suffix
                          #f "~a-~v,'0d-~a.~a"
                          basename ndigits (1+ count) suffix midi-ext))
                     (format #f "~a.~a" basename midi-ext)))
             performance-name)
            (loop (cdr perfs) (1+ count)))))))

%%% Done, change back to correct module
#(set-current-module mod)

%%% ...-1-Movement 1.midi
\score {
  \header {
    midititle = "Movement 1"
  }
  c
  \midi { }
}

%%% ...-2-Movemet 2.midi
\score {
  \header {
    title = "Movement 2"
  }
  d
  \midi { }
}

%%% completelyDifferentFile.midi
\score {
  \header {
    midiOutputFile = "completelyDifferentFile"
  }
  d
  \midi { }
}

%%% ...-4-mmt3.midi
\score {
  \header {
    title = "Movement 3"
    midiOutputSuffix = "mmt3"
  }
  d
  \midi { }
}

%%% ...-5.midi
\score {
  \header {
    title = "Movement 4"
    midiOutputSuffix = ""
  }
  d
  \midi { }
}

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to