Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 6 additions & 37 deletions pymusiclooper/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ def common_loop_options(f):
@click.option("--brute-force", is_flag=True, default=False, help=r"Check the entire audio track instead of just the detected beats. [dim yellow](Warning: may take several minutes to complete.)[/]")
@click.option("--disable-pruning", is_flag=True, default=False, help="Disables filtering of the detected loop points from the initial pass.")

@click.option("--tag-names", type=str, required=False, nargs=2, help="Name of the loop metadata tags to read from, e.g. --tag-names LOOP_START LOOP_END (note: values must be integers and in sample units). Default: auto-detected.")
@click.option("--tag-offset/--no-tag-offset", is_flag=True, default=None, help="Always parse second loop metadata tag as a relative length / or as an absolute length. Default: auto-detected based on tag name.")

@click.option("--read-tags/--no-read-tags", is_flag=True, default=None, help="Always determine loop points from metadata tags / from analysis. Default: use tags if present, analysis otherwise.")

@functools.wraps(f)
def wrapper_common_options(*args, **kwargs):
return f(*args, **kwargs)
Expand Down Expand Up @@ -116,9 +121,8 @@ def play(**kwargs):
handler = LoopHandler(**kwargs)

in_samples = "PML_DISPLAY_SAMPLES" in os.environ
interactive_mode = "PML_INTERACTIVE_MODE" in os.environ

chosen_loop_pair = handler.choose_loop_pair(interactive_mode=interactive_mode)
chosen_loop_pair = handler.choose_loop_pair(interactive_mode=handler.interactive_mode)

start_time = handler.format_time(chosen_loop_pair.loop_start, in_samples=in_samples)
end_time = handler.format_time(chosen_loop_pair.loop_end, in_samples=in_samples)
Expand All @@ -141,41 +145,6 @@ def play(**kwargs):
print_exception(e)


@cli_main.command()
@click.option('--path', type=click.Path(exists=True), required=True, help='Path to the audio file.')
@click.option("--tag-names", type=str, required=False, nargs=2, help="Name of the loop metadata tags to read from, e.g. --tag-names LOOP_START LOOP_END (note: values must be integers and in sample units). Default: auto-detected.")
@click.option("--tag-offset/--no-tag-offset", is_flag=True, default=None, help="Always parse second loop metadata tag as a relative length / or as an absolute length. Default: auto-detected based on tag name.")
def play_tagged(path, tag_names, tag_offset):
"""Skips loop analysis and reads the loop points directly from the tags present in the file."""
try:
if tag_names is None:
tag_names = [None, None]

looper = MusicLooper(path)
loop_start, loop_end = looper.read_tags(tag_names[0], tag_names[1], tag_offset)

in_samples = "PML_DISPLAY_SAMPLES" in os.environ

start_time = (
loop_start
if in_samples
else looper.samples_to_ftime(loop_start)
)
end_time = (
loop_end
if in_samples
else looper.samples_to_ftime(loop_end)
)

rich_console.print(f"\nPlaying with looping active from [green]{end_time}[/] back to [green]{start_time}[/]")
rich_console.print("(Press [red]Ctrl+C[/] to stop looping.)")

looper.play_looping(loop_start, loop_end)

except Exception as e:
print_exception(e)


@cli_main.command()
@common_path_options
@common_loop_options
Expand Down
22 changes: 19 additions & 3 deletions pymusiclooper/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,34 @@ def __init__(
brute_force: bool = False,
disable_pruning: bool = False,
_progressbar: Progress = None,
tag_names: Optional[List[Optional[str]]] = None,
tag_offset: Optional[bool] = None,
read_tags: Optional[bool] = None,
**kwargs,
):
self.filepath = path
self._musiclooper = MusicLooper(filepath=path)

if read_tags or read_tags is None:
try:
if tag_names is None:
tag_names = [None, None]

loop_start, loop_end = self._musiclooper.read_tags(tag_names[0], tag_names[1], tag_offset)
self.loop_pair_list = [LoopPair(_loop_start_frame_idx=None, _loop_end_frame_idx=None, note_distance=0.0, loudness_difference=0.0, loop_start=loop_start, loop_end=loop_end, score=1.0)]
self.interactive_mode = False
return
except ValueError as e:
if read_tags:
raise e

if approx_loop_position is not None:
self.approx_loop_start = approx_loop_position[0]
self.approx_loop_end = approx_loop_position[1]
else:
self.approx_loop_start = None
self.approx_loop_end = None

self.filepath = path
self._musiclooper = MusicLooper(filepath=path)

logging.info(f"Loaded \"{path}\". Analyzing...")

self.loop_pair_list = self.musiclooper.find_loop_pairs(
Expand Down