Write the music
Read the episode's timing, write a score as a song file, check it, and play it into a music track on your computer.
Your agent writes the music as a short Python script. The script saves a song file, which is data: instrument names, notes and times in seconds. MiniCut checks the song file and plays it with the instruments it brings. MiniCut never runs your script.
Before you start, sign in and make a project with a shot sheet for the episode, episodes/ep01/shots.md. See Shot sheet. The script needs Python 3.9 or newer. To play a song, run minicut setup once. It installs the music tools and the instrument samples. The samples are about 396 MB. Run the commands in the project folder, ~/.minicut/projects/rain-shop here.
Read the timing
- List the shots, the cuts and the spoken lines of the episode, in seconds:
minicut music cuts episodes/ep01~/.minicut/projects/rain-shop/episodes/ep01: 15.0 s, 3 shot(s), 2 cut(s)
C01 0.00 to 5.00 s street sound: rain
C02 5.00 to 11.00 s shop sound:
C03 11.00 to 15.00 s shop SILENT sound: silence
cut 5.00 s into C02 scene change
cut 11.00 s into C03 into silence
line 5.00 to 11.00 s Lin: Are you open?
lines from: shots.md Line (speaker) cells (whole row, rough)The spoken lines come from the Line (speaker) column of shots.md, rough to the whole shot. When the episode has a transcript.json, they come from its word times. Add --json to get the same facts as JSON.
- List the instruments:
minicut music instrumentsIt prints one line for each instrument with its note range, then the knobs and the reverb presets. A drum instrument lists its pieces instead of notes.
Write the score
- Print the import lines for your script:
minicut music api- Make the file
episodes/ep01/music/score.py. Paste the two lines the command printed at the top. Then write the score. Every time is in seconds.
# Paste the two lines that minicut music api printed here.
ep = read_episode("episodes/ep01")
song = Song(length_s=ep["length_s"], title="ep01 score", tempo=72)
strings = song.track("violins", volume_db=-8)
strings.chord(chord("D3", "minor"), at=0, length=4, velocity=60)
drum = song.track("timpani")
for cut in ep["cuts"]:
if cut["scene_change"]:
drum.hit("low", at=cut["t"], velocity=110)
song.duck_under(ep["lines"], db=-8)
song.save("episodes/ep01/music/score.song.json")duck_under turns the score down under each spoken line. save checks the song and writes it. On a problem it writes nothing, prints each problem and exits with code 5.
- Run the script with your own Python:
python3 episodes/ep01/music/score.pyWrote episodes/ep01/music/score.song.json: 15.0 s, 2 track(s), 4 note(s). Next: minicut music render episodes/ep01/music/score.song.jsonA song is up to 15 minutes long and has up to 64 tracks.
Check and play the song
- Check that the song file can be played:
minicut music check episodes/ep01/music/score.song.jsonPASS: 15.0 s, 2 track(s), 4 note(s). Next: minicut music render ~/.minicut/projects/rain-shop/episodes/ep01/music/score.song.jsonIf it fails, it prints each problem and FAIL, and exits with code 5. Fix the script, run it again and check again.
- Play the song into audio files:
minicut music render episodes/ep01/music/score.song.jsonIt writes score.wav, score.mp3, score.beats.json, score-waveform.png and score.report.json beside the song file.
- Optional: to play one stretch while you work on it, add
--from 9 --to 12. To also write each instrument as its own file, add--stems. To skip the.mp3, add--no-mp3. - Measure the result against the episode:
minicut music measure episodes/ep01/music/score.wav --episode episodes/ep01It reports loudness, peaks, hits on the cuts and the music level under the spoken lines. Change the script and play again until the numbers fit the shot sheet.
Optional: start from a MIDI file
- Write a map file that says which instrument plays each MIDI track. A key is
TRACK:CHANNELor the track's name. Adrumskey maps a MIDI note toINSTRUMENT/PIECE.
{
"tracks": { "0:0": { "instrument": "piano", "volume_db": -6 } }
}- Turn the MIDI file into a song file:
minicut music from-midi episodes/ep01/music/theme.mid --map episodes/ep01/music/map.jsonIt prints Wrote with the path of the new .song.json file, its length, tracks and notes, and the next command to run.
A track or drum note that is not in the map is left out, and the command prints left out: with its name. Then check and play the song file as above.
Check it worked
score.wav and score.mp3 are in episodes/ep01/music, and the measure numbers match what the shot sheet asks for. The waveform picture score-waveform.png shows where the music is loud and quiet.
If a step fails
| Message | What to do |
|---|---|
shots.md is missing | Write the shot sheet first. See Shot sheet |
no Python found. Run: minicut setup | Run minicut setup, then run the command again |
the music tools are not set up (...). Run: minicut setup | Run minicut setup, then run the command again |
no instrument samples in .... Run: minicut setup (about 396 MB, once). Nothing was rendered. | Run minicut setup, then render again |
FAIL: N problem(s). | Fix the problems printed above it in your script, then run it again |
the song file is over 32 MB | Make the song smaller |
Stopped: it ran past the time limit. | Render a shorter part with --from and --to |