App-MusicTools

 view release on metacpan or  search on metacpan

bin/ly-fu  view on Meta::CPAN

END_TMPL_HEAD

if ($Flag_Generate_Score) {
    $lilypond_input .= <<"END_TMPL_LAYOUT";
\\score {
  \\new $staff << $rel_str {
    \\accidentalStyle "neo-modern"
    \\set Staff.instrumentName = #"$instrument"
    \\tempo 4=$tempo
    $partial
    $repeat_score { \\themusic }
    $score_bar
  } >>
  \\layout { }
}
END_TMPL_LAYOUT
}

unless ($Flag_No_MIDI) {
    $lilypond_input .= <<"END_TMPL_MIDI";
\\score {
  \\new Staff << $rel_str {
    \\set Staff.midiInstrument = #"$instrument"
    $pre_art
    \\tempo 4=$tempo
    $partial
    $repeat_midi { \\themusic }
    $post_art
  } >>
  \\midi { }
}
END_TMPL_MIDI
}

if ($Flag_Show_Code) {
    print $lilypond_input;
    exit 0;
}

my $work_dir = tmpdir();
chdir $work_dir or die "ly-fu: chdir failed '$work_dir': $!\n";

# NOTE a dedicated directory for output would be safer with a shared tmp
# dir, as I am unsure of how well lilypond defends against /tmp attacks.
# (I use a TMPDIR that is not the system one.)
my $tmp_ly = File::Temp->new(
    DIR      => $work_dir,
    SUFFIX   => '.ly',
    TEMPLATE => 'ly-fu.XXXXXXXXXX',
    UNLINK   => 0,
);
$tmp_ly->print($lilypond_input);
$tmp_ly->flush;
$tmp_ly->sync;

my $ly_filename = $tmp_ly->filename;
( my $score_filename = $ly_filename ) =~ s/\.ly/\.pdf/;
( my $midi_filename  = $ly_filename ) =~ s/\.ly/\.midi/;
close $tmp_ly;

say $ly_filename if $Flag_Generate_Score;

# lilypond is noisy by default
my ( $stdout, $stderr, $status ) = capture {
    system @Lilypond_Cmd, $ly_filename;
};
if ( $status != 0 ) {
    print STDERR $stderr;
    exit 1;
}
print STDERR $stderr if $Flag_Verbose;

if ($Flag_Show_Score) {
    local $SIG{CHLD} = 'IGNORE';
    my $pid = fork();
    die "ly-fu: could not fork score reader: $!\n" unless defined $pid;
    unless ($pid) {
        # a vague effort at daemonization; may be necessary if the PDF
        # view being open holds ly-fu open which then prevents a text
        # editor from moving on
        open( STDIN,  '<', '/dev/null' );
        open( STDOUT, '>', '/dev/null' );
        ( setsid() == -1 ) and die "ly-fu: setsid failed: $!\n";
        open( STDERR, '>&', STDOUT );
        exec( @Score_Reader, $score_filename )
          or die "ly-fu: could not exec score reader '@Score_Reader': $!\n";
    }
}

unless ($Flag_No_MIDI) {
    if ($Flag_Generate_Score) {
        # we're keeping the files, so there's nothing more this script
        # needs to do
        exec( @MIDI_Player, $midi_filename )
          or die
          "ly-fu: could not exec MIDI player '@MIDI_Player $midi_filename': $!\n";
    } else {
        system( @MIDI_Player, $midi_filename ) == 0
          or die
          "ly-fu: could not run MIDI player '@MIDI_Player $midi_filename': $!\n";
    }
}

if ($Flag_Generate_Score) {
    # the files might be shared, so open up the permissions
    chmod 0644, $ly_filename, $midi_filename, $score_filename;
} else {
    # Preview.app got increasingly slower to actually start over time,
    # hence this kluge. Eventually I switched to mupdf, and eventually
    # the 2009 macbook died in late 2022.
    sleep $Flag_Sleep_Kluge if $Flag_Sleep_Kluge > 0;
    unlink $ly_filename, $midi_filename, $score_filename;
}

########################################################################
#
# SUBROUTINES

sub emit_help {
    warn <<"END_HELP";
Usage: $0 [options] "lilypond code ..."



( run in 1.036 second using v1.01-cache-2.11-cpan-524268b4103 )