Skip to content

Commit

Permalink
Add render --dry-run flag
Browse files Browse the repository at this point in the history
* Thread new kwarg to all render helper functions
* During dry run,
  * Do not leave changed files on disk, do not upload
  * Eagerly compute result stats, before temp file is deleted
  • Loading branch information
john-kurkowski committed Dec 13, 2024
1 parent 4334349 commit 6378f3f
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 15 deletions.
17 changes: 15 additions & 2 deletions src/music/render/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@
" SOUNDCLOUD_ADDITIONAL_HEADERS."
),
)
@click.option(
"--dry-run",
default=False,
help=(
"Whether to actually write changes to disk or upload, while still"
" performing the render."
),
is_flag=True,
)
@click.option(
"--include-main",
default=None,
Expand Down Expand Up @@ -144,6 +153,7 @@
async def main(
project_dirs: list[Path],
additional_headers: str,
dry_run: bool,
include_main: SongVersion | None,
include_instrumental: SongVersion | None,
include_instrumental_dj: SongVersion | None,
Expand Down Expand Up @@ -191,6 +201,7 @@ async def main(

command = _Command(
parsed_additional_headers,
dry_run,
oauth_token,
upload,
upload_existing,
Expand All @@ -208,6 +219,7 @@ class _Command:
"""Wrap parsed command line arguments."""

additional_headers: dict[str, str]
dry_run: bool
oauth_token: str
upload: bool
upload_existing: bool
Expand Down Expand Up @@ -255,7 +267,7 @@ async def _render_project(
renders = []
uploads = []

if self.upload_existing:
if self.upload_existing and not self.dry_run:
uploads.append(
asyncio.create_task(
self.upload_process.process(
Expand All @@ -270,12 +282,13 @@ async def _render_project(
async for _, render in self.render_process.process(
project,
*self.versions,
dry_run=self.dry_run,
verbose=0,
vocal_loudness_worth=self.vocal_loudness_worth,
):
renders.append(render)

if self.upload and render.fil.is_file():
if self.upload and render.fil.is_file() and not self.dry_run:
uploads.append(
asyncio.create_task(
self.upload_process.process(
Expand Down
47 changes: 34 additions & 13 deletions src/music/render/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@


async def render_version(
project: ExtendedProject, version: SongVersion
project: ExtendedProject, version: SongVersion, *, dry_run: bool
) -> RenderResult:
"""Trigger Reaper to render the current project audio. Returns the output file.
Expand Down Expand Up @@ -71,13 +71,23 @@ async def render_version(
else:
tmp_fil = out_fil.with_stem(in_name)

rm_rf(out_fil)
shutil.move(tmp_fil, out_fil)

return RenderResult(
project, version, out_fil, datetime.timedelta(seconds=time_end - time_start)
final_fil = tmp_fil if dry_run else out_fil
result = RenderResult(
project,
version,
final_fil,
datetime.timedelta(seconds=time_end - time_start),
eager=dry_run,
)

if dry_run:
rm_rf(tmp_fil)
else:
rm_rf(final_fil)
shutil.move(tmp_fil, final_fil)

return result


def trim_silence(fil: Path) -> None:
"""Trim leading and trailing silence from the given audio file, in-place.
Expand Down Expand Up @@ -113,31 +123,33 @@ def trim_silence(fil: Path) -> None:


async def _render_main(
project: ExtendedProject, *vocals: reapy.core.Track, verbose: int
project: ExtendedProject, *vocals: reapy.core.Track, dry_run: bool, verbose: int
) -> RenderResult:
for vocal in vocals:
vocal.unsolo()
vocal.unmute()
return await render_version(project, SongVersion.MAIN)
return await render_version(project, SongVersion.MAIN, dry_run=dry_run)


async def _render_version_with_muted_tracks(
version: Literal[SongVersion.INSTRUMENTAL, SongVersion.INSTRUMENTAL_DJ],
project: ExtendedProject,
*tracks_to_mute: reapy.core.Track,
dry_run: bool,
vocal_loudness_worth: float,
verbose: int,
) -> RenderResult:
with (
adjust_master_limiter_threshold(project, vocal_loudness_worth),
mute_tracks(tracks_to_mute),
):
return await render_version(project, version)
return await render_version(project, version, dry_run=dry_run)


async def _render_a_cappella(
project: ExtendedProject,
*,
dry_run: bool,
vocal_loudness_worth: float,
verbose: int,
) -> RenderResult:
Expand All @@ -147,7 +159,7 @@ async def _render_a_cappella(
adjust_master_limiter_threshold(project, vocal_loudness_worth),
mute_tracks(tracks_to_mute),
):
out = await render_version(project, SongVersion.ACAPPELLA)
out = await render_version(project, SongVersion.ACAPPELLA, dry_run=dry_run)

trim_silence(out.fil)
return out
Expand All @@ -156,6 +168,7 @@ async def _render_a_cappella(
async def _render_stems(
project: ExtendedProject,
*vocals: reapy.core.Track,
dry_run: bool,
verbose: int,
) -> RenderResult:
for vocal in vocals:
Expand All @@ -166,7 +179,7 @@ async def _render_stems(
for track in find_stems(project):
track.select()
with toggle_fx_for_tracks([project.master_track], is_enabled=False):
return await render_version(project, SongVersion.STEMS)
return await render_version(project, SongVersion.STEMS, dry_run=dry_run)


class Process:
Expand All @@ -180,6 +193,7 @@ async def process(
self,
project: ExtendedProject,
*versions: SongVersion,
dry_run: bool,
verbose: int,
vocal_loudness_worth: float | None,
) -> AsyncIterator[tuple[SongVersion, RenderResult]]:
Expand All @@ -202,7 +216,9 @@ async def process(
results.append(
(
SongVersion.MAIN,
lambda: _render_main(project, *vocals, verbose=verbose),
lambda: _render_main(
project, *vocals, dry_run=dry_run, verbose=verbose
),
self._add_task(project, SongVersion.MAIN),
)
)
Expand All @@ -221,6 +237,7 @@ async def process(
for track in [*vocals, *find_vox_tracks_to_mute(project)]
if track
],
dry_run=dry_run,
vocal_loudness_worth=vocal_loudness_worth,
verbose=verbose,
),
Expand All @@ -243,6 +260,7 @@ async def process(
SongVersion.INSTRUMENTAL_DJ,
project,
*vocals,
dry_run=dry_run,
vocal_loudness_worth=vocal_loudness_worth,
verbose=verbose,
),
Expand All @@ -256,6 +274,7 @@ async def process(
SongVersion.ACAPPELLA,
lambda: _render_a_cappella(
project,
dry_run=dry_run,
vocal_loudness_worth=vocal_loudness_worth,
verbose=verbose,
),
Expand All @@ -267,7 +286,9 @@ async def process(
results.append(
(
SongVersion.STEMS,
lambda: _render_stems(project, *vocals, verbose=verbose),
lambda: _render_stems(
project, *vocals, dry_run=dry_run, verbose=verbose
),
self._add_task(project, SongVersion.STEMS),
)
)
Expand Down
8 changes: 8 additions & 0 deletions src/music/render/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,20 @@ def __init__(
version: SongVersion,
fil: Path,
render_delta: datetime.timedelta,
*,
eager: bool = False,
):
"""Override. Initialize."""
super().__init__(project, version)
self.fil = fil
self.render_delta = datetime.timedelta(seconds=round(render_delta.seconds))

if eager:
# Trigger computation eagerly. For example, the input file might be
# temporary and not exist later.
self.duration_delta # noqa: B018
self.summary_stats # noqa: B018

@cached_property
def duration_delta(self) -> datetime.timedelta:
"""How long the audio file is.
Expand Down

0 comments on commit 6378f3f

Please sign in to comment.