Hello, Jinxy

I took a course on film and animation scoring at New York University in 2024. The course’s assignments consisted of videos for which you had to write music, and the innocuously named “Jinxy Jenkins” assignment was somewhat notoriously the most demanding of the course. That assignment was to re-score the animated short film Jinxy Jenkins, Lucky Lou (2014). I got a little obsessed with it.

The coursework version of Jinxy was originally distributed by CINE (Council on International Nontheatrical Events) for a Marvin Hamlisch Film Scoring Contest, not for public viewing. However, Jinxy has been freely available on Vimeo since its release. It’s a bit of work, but it’s possible to share my re-scored film with the help of some free tools.

First, you’ll need to install Homebrew, a widely used package manager for macOS (and Linux). Then, install FFmpeg (a video processor) and yt-dlp (a video downloader) by entering:

brew install ffmpeg yt-dlp

To download Jinxy, enter:

yt-dlp https://vimeo.com/92471917

This should download a file named “Jinxy Jenkins, Lucky Lou [92471917].mp4”. In theory, all one should have to do is overwrite the audio in this file, but when I did this, I went down a minor rabbit hole with video frame rates.

If you run ffprobe (part of FFmpeg) to get the frame rate of the video—

ffprobe \
  -v error \
  -select_streams v:0 \
  -show_entries stream=r_frame_rate \
  -of default=noprint_wrappers=1:nokey=1 \
  'Jinxy Jenkins, Lucky Lou [92471917].mp4'

—the output is 24/1, meaning 24 fps. However, running the same thing with the CINE video outputs 24000/1001, about 23.976 fps. This may seem minor, but here’s what happens after 240 seconds (about the length of Jinxy). At 24 fps, you’ll see

24 frames1 second×240 seconds=5,760 frames\frac{24\text{ frames}}{1\text{ second}} \times 240\text{ seconds} = 5,760\text{ frames}

And at 23.976 fps:

24,000 frames1,001 seconds×240 seconds5,754 frames\frac{24,000\text{ frames}}{1,001\text{ seconds}} \times 240\text{ seconds} \approx 5,754\text{ frames}

That’s a difference of 6 frames, and something like a cut to black that occurs 6 frames before the corresponding music will look out of sync.

It should be possible to fix this by using FFmpeg to slow the 24 fps video down to 23.976 fps, but I couldn’t make this work for the life of me. Thankfully, another way to fix this is to speed up the audio so that it fits in the 24 fps video. I did this using Rubber Band, which includes a convenient command line utility. The audio I’m sharing is already sped up, so you don’t have to do any of this, but here’s how this works. First, install Rubber Band:

brew install rubberband

Now you can run the Rubber Band utility, but you have to tell Rubber Band how much you want to speed up (or slow down) your audio. The speed-up/slow-down amount is expressed as a factor of time, not speed, so if you want audio to play twice as fast, the factor is 0.5, not 2 (audio that plays twice as fast takes half the time). Rather than compute the time factor manually, you can let the computer do it for you. The frame rate of the CINE video is:

original_fps=24000/1001

The frame rate we want is:

new_fps=$( \
ffprobe \
  -v error \
  -select_streams v:0 \
  -show_entries stream=r_frame_rate \
  -of default=noprint_wrappers=1:nokey=1 \
  'Jinxy Jenkins, Lucky Lou [92471917].mp4' \
)

This is enough to run Rubber Band:

rubberband \
  --time "$(python -c "print(($original_fps) / ($new_fps))")" \
  --fine \
  --ignore-clipping \
  'Jinxy Jenkins soundtrack (CINE).wav' \
  Jinxy-Jenkins-soundtrack.wav

Python is doing the actual computation; yt-dlp depends on Python, so Python should already be installed.

Here’s the resulting audio:

And now we can use FFmpeg to add this audio to the video:

ffmpeg \
  -i 'Jinxy Jenkins, Lucky Lou [92471917].mp4' \
  -i Jinxy-Jenkins-soundtrack.wav \
  -c:v copy \
  -map 0:v:0 -map 1:a:0 \
  'Jinxy Jenkins, Lucky Lou (new soundtrack).mp4'

If you just want to listen:

(There’s about 5 seconds of silence at the beginning for Jinxy’s title card.)