aspiers / ly2video

generating videos from LilyPond projects
GNU General Public License v3.0
155 stars 23 forks source link

Work better with Windows #120

Open jstma opened 9 months ago

jstma commented 9 months ago

Using ly2video on Windows seems hard. I've only tried it via Wine.

I know github can package python projects into an exe, but I figured I'd try it locally first. Eventually, it could become a github action to ease the pain of using it on windows. The same could be done for linux if it made sense.

In a new wineprefix, I installed python, ly2video requirements, and auto-py-to-exe (pyinstaller). This created an executable from ly2video.git that ran under wine. That was easy and doesn't require the end user to have python installed

However, the external dependencies, lilypond, ffmpeg, and timidity, are a bit of a pain.

Neither lilypond or ffmpeg, come with installers. That means you have to place them somewhere and tell ly2video where they are via the PATH variable. Then timidity has the same problem, but doesn't come with any soundfonts.

On Ubuntu anyway, you can just "apt-get install tmidity" and it will play midi right out of the box. On Windows, it's a different story.

On Ubuntu timidity uses the FluidR3_GM.sf2 soundfont. It's available in various places.

Since timidity is a bear to install on windows (for someone less savvy), it would be nice to provide a working zip file with timidity and the soundfont ready to go. I don't know if it's in the scope of ly2video to host that soundfont. There is another project that has the soundfont in a sister repo where they are added as Release artefacts. Because they are too big to commit to github:

https://github.com/pianobooster/fluid-soundfont/releases

It's a one time operation. Then I guess a github action could wrap them into a zip file.

To make timidity work on Windows, I borrowed the timidity.cfg from my machine with slight modification. Running ly2video in wine produces a video file with sound. So it works, but there's also an error message at the end:

Traceback (most recent call last):
  File "ly2video\cli.py", line 1657, in <module>
  File "ly2video\cli.py", line 1650, in main
  File "shutil.py", line 516, in rmtree
  File "shutil.py", line 404, in _rmtree_unsafe
  File "shutil.py", line 402, in _rmtree_unsafe
PermissionError: [WinError 32] Sharing violation: 'C:\\users\\notme\\Temp\\ly2video4r_l02rv'
[205] Failed to execute script 'cli' due to unhandled exception!

The temp directory is deleted so I don't know what that error means yet.

I think some solutions might involve telling ly2video where lilypond and ffmpeg are installed, like is done for timidity. And then providing a way to install timidity along with ly2video. It might also be a good idea to add a config file and look for it in the directory where ly2video is. Then ly2video could be deployed as a bundle, pulling from the release builds of lilypond, ffmpeg, and timidity. Maybe this is done in a sister repo.

Lastly, it might be easier to let the user make the audio file however they want and then pass that file in through a command line argument. Is there any reason this can't be done?

jstma commented 9 months ago

ffmpeg and timidity both have location variables, so only one more would be needed to find lilypond.

I forgot to mention above that I had to take the version string out of my .ly file because it couldn't find convert-ly.py. Even though it found lilypond just fine. The error was this:

Version in test.ly: 2.2.0
Will convert to: 2.24.3
Path not found.

Generating PNG and MIDI files ...
------------------------------------------------------------
GNU LilyPond 2.24.3 (running Guile 2.2)
005b:err:combase:RoGetActivationFactory Failed to find library for L"Windows.Management.Deployment.PackageManager"
warning: cannot find file: `C:\users\notme\Temp\ly2videoijevlt7g\converted.ly'
fatal error: failed files: "C:\\users\\notme\\Temp\\ly2videoijevlt7g\\converted.ly"

It exists in the same lilypond/bin directory as lilypond.exe, but I suppose it doesn't work because file associations aren't set up. There is python.exe in that directory (with lilypond and convert-ly.py) and

python convert-ly.py

works from the command line. The python command works everywhere when lilypond's path is in the path.

A flag of some kind to indicate whether to call convert-ly.py or python convert-ly.py would be good. Or maybe test for the first and if it fails also try the second?

jstma commented 9 months ago

@aspiers I pushed a few more commits. Please review and comment.

Remaining issues:

  1. running python convert-ly.py on windows systems (only tested in wine)
    warning: cannot find file: `C:\users\notme\Temp\ly2videor45e0q3n\converted.ly'
    fatal error: failed files: "C:\\users\\notme\\Temp\\ly2videor45e0q3n\\converted.ly"`

    The command is:

    os.system("python %sconvert-ly.py '%s' >> '%s'"  % (lilypond, lyFile, newLyFile))

    and generates:

    python C:\lilypond-2.24.3\bin\convert-ly.py 'test.ly' >> 'C:\users\me\Temp\ly2videor32mcslp\converted.ly'

    And if I run that on the command line (in wine) then it works without issue with C:\lilypond-2.24.3\bin in the path. There is a python.exe in C:\lilypond-2.24.3\bin.

From ly2video it doesn't work. It runs convert-ly, but the part that redirects it to the temp file doesn't work. I wonder if it's related to the next problem.

  1. shutil.rmtree(tmpPath()) causes PermissionError: [WinError 32] Sharing violation

    ------------------------------------------------------------
    Traceback (most recent call last):
    File "ly2video\cli.py", line 1697, in <module>
    File "ly2video\cli.py", line 1690, in main
    File "shutil.py", line 516, in rmtree
    File "shutil.py", line 404, in _rmtree_unsafe
    File "shutil.py", line 402, in _rmtree_unsafe
    PermissionError: [WinError 32] Sharing violation: 'C:\\users\\me\\Temp\\ly2videom61slofj'
    [210] Failed to execute script 'cli' due to unhandled exception!

    Not sure what is causing this.

  2. Windows/WINE Errors

    00fe:err:winediag:SECUR32_initNTLMSP ntlm_auth was not found or is outdated. Make sure that ntlm_auth >= 3.0.25 is in your path. Usually, you can find it in the winbind package of your distribution.

    sudo apt-get install winbind

LilyPond was found.
C:\users\me\Temp\_MEI1862\cli.py:1134: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.

The above only occurs once when ly2video starts. Cause unknown. It doesn't seem to cause harm.

GNU LilyPond 2.24.3 (running Guile 2.2)
0068:err:combase:RoGetActivationFactory Failed to find library for L"Windows.Management.Deployment.PackageManager"

The above occurs twice when lilypond starts. It happens without ly2video. Cause unknown. It doesn't seem to cause harm.

jstma commented 9 months ago

This is a full log of running on wine. The avi was generated and played back as it should.

ly2video -i test.ly
LilyPond was found.
C:\users\me\Temp\_MEI1862\cli.py:1134: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
FFmpeg was found.
TiMidity++ was found.
------------------------------------------------------------
Version in test.ly: 2.20.0
Will convert to: 2.24.3
WARNING: Convert of input file has failed. This could cause some problems.
------------------------------------------------------------
Generating PNG and MIDI files ...
------------------------------------------------------------
GNU LilyPond 2.24.3 (running Guile 2.2)
00cb:err:combase:RoGetActivationFactory Failed to find library for L"Windows.Management.Deployment.PackageManager"
Processing `C:/users/me/Temp/ly2videom61slofj/unconverted.ly'
Parsing...
Interpreting music...
Preprocessing graphical objects...
Interpreting music...
MIDI output to `unconverted.midi'...
Finding the ideal number of pages...
Fitting music on 1 page...
Drawing systems...
Layout output to `unconverted.preview.eps'...
Converting to PNG...
Success: compilation successfully completed
------------------------------------------------------------
Generated PNG and MIDI files
Looking for staff lines in unconverted.preview.png
First staff line found at (0, 14)
Found 5 staff lines
Margins in mm: left=46 top=83 right=46 bottom=83
Margins in px: left=200 top=360 right=200 bottom=360
Wrote sanitised version of C:\users\me\Temp\ly2videom61slofj\unconverted.ly into C:\users\me\Temp\ly2videom61slofj\sanitised.ly
Generating PNG and MIDI files ...
------------------------------------------------------------
GNU LilyPond 2.24.3 (running Guile 2.2)
00cc:err:combase:RoGetActivationFactory Failed to find library for L"Windows.Management.Deployment.PackageManager"
Processing `C:/users/me/Temp/ly2videom61slofj/sanitised.ly'
Parsing...
Interpreting music...
Preprocessing graphical objects...
Interpreting music...
MIDI output to `sanitised.midi'...
Converting to PNG...
Success: compilation successfully completed
------------------------------------------------------------
Generated PNG and MIDI files
------------------------------------------------------------
MIDI resolution (ticks per beat) is 384
------------------------------------------------------------
MIDI: Parsing MIDI file has ended.
------------------------------------------------------------
sync points found:    12
             from:    12 original indices
              and:    13 original ticks
   last tick used:    12
    ticks skipped:     0
------------------------------------------------------------
SYNC: ly2video will generate approx. 360 frames at 30.000 frames/sec.
Writing frames ...
A dot is displayed for every 10 frames generated.
------------------------------------------------------------
Running TiMidity++ on C:\users\me\Temp\ly2videom61slofj\sanitised.midi to generate .wav audio ...
Playing sanitised.midi
MIDI file: sanitised.midi
Format: 1  Tracks: 2  Divisions: 384
Text: creator: 
Text: LilyPond 2.24.3               
Output sanitised.wav
Playing time: ~16 seconds
Notes cut: 0
Notes lost totally: 0

------------------------------------------------------------
Generating video with animated notation

Auto-detecting top margin; this may take a while ...
      Video height:   720 pixels
      Image height:  1286 pixels
Auto-detecting top margin; this may take a while ...
   Top margin size:   366 pixels
Bottom margin size:   837 pixels (y=449)
Visible content is formed of 83 non-white rows of pixels
Centre of visible content is 408 pixels from top
Will crop from y=48 to y=768
First staff line found at (199, 380)
.................................------------------------------------------------------------
Generating silent video C:\users\me\Temp\ly2videom61slofj\initial-padding.mpg, duration 1.000000s

...------------------------------------------------------------
Generating silent video C:\users\me\Temp\ly2videom61slofj\final-padding.mpg, duration 1.000000s

...------------------------------------------------------------
Joining videos:
  C:\users\me\Temp\ly2videom61slofj\initial-padding.mpg
  C:\users\me\Temp\ly2videom61slofj\notes.mpg
  C:\users\me\Temp\ly2videom61slofj\final-padding.mpg

ffmpeg version N-112922-gebfd3912e9-20231206 Copyright (c) 2000-2023 the FFmpeg developers
  built with gcc 13.2.0 (crosstool-NG 1.25.0.232_c175b21)
  configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libharfbuzz --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libaribcaption --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --enable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-ldexeflags= --extra-libs=-lgomp --extra-version=20231206
  libavutil      58. 32.100 / 58. 32.100
  libavcodec     60. 35.100 / 60. 35.100
  libavformat    60. 18.100 / 60. 18.100
  libavdevice    60.  4.100 / 60.  4.100
  libavfilter     9. 14.100 /  9. 14.100
  libswscale      7.  6.100 /  7.  6.100
  libswresample   4. 13.100 /  4. 13.100
  libpostproc    57.  4.100 / 57.  4.100
Input #0, avi, from 'concat:C:\users\me\Temp\ly2videom61slofj\initial-padding.mpg|C:\users\me\Temp\ly2videom61slofj\notes.mpg|C:\users\me\Temp\ly2videom61slofj\final-padding.mpg':
  Metadata:
    software        : Lavf60.18.100
  Duration: 00:00:01.04, start: 0.000000, bitrate: 9821 kb/s
  Stream #0:0: Video: mpeg4 (Simple Profile) (FMP4 / 0x34504D46), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 30 tbn
  Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, fltp, 128 kb/s
Output #0, avi, to 'Z:\home\me\personal\git\ly2video.git\wine\output\test.avi':
  Metadata:
    software        : Lavf60.18.100
    ISFT            : Lavf60.18.100
  Stream #0:0: Video: mpeg4 (Simple Profile) (FMP4 / 0x34504D46), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 30 tbr, 30 tbn
  Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, fltp, 128 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
[avi @ 00000000005958c0] Switching to NI mode, due to poor interleaving
[out#0/avi @ 00000000005bf380] video:896kB audio:236kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.835239%
size=    1164kB time=00:00:15.07 bitrate= 632.8kbits/s speed= 550x    
------------------------------------------------------------
Traceback (most recent call last):
  File "ly2video\cli.py", line 1697, in <module>
  File "ly2video\cli.py", line 1690, in main
  File "shutil.py", line 516, in rmtree
  File "shutil.py", line 404, in _rmtree_unsafe
  File "shutil.py", line 402, in _rmtree_unsafe
PermissionError: [WinError 32] Sharing violation: 'C:\\users\\me\\Temp\\ly2videom61slofj'
[210] Failed to execute script 'cli' due to unhandled exception!
aspiers commented 9 months ago

I don't use Windows so I can't help with the 2nd or 3rd issues you describe - I recommend trying Google / StackOverflow / ChatGPT etc.

For the first issue, I suspect there may be some issue with running a UNIX (POSIX) shell command via os.system(...) on a Windows machine, as I doubt that whichever shell Windows uses to execute the command inside os.system(...) behaves identically to (say) bash on Linux. It could be an issue with quoting, or with fd direction, or possibly even the use of >> for appending when AFAIK there is no good reason to allow appending and > should have been used instead.

Whatever the cause, most likely that os.system call should be replaced by something from the subprocess module, e.g. see https://docs.python.org/3.11/library/subprocess.html#replacing-os-system