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
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2025, TEAMuP-dev
Copyright (c) 2026, TEAMuP-dev

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![HARP Repo](https://github-readme-stats.vercel.app/api/pin/?username=TEAMuP-dev&repo=HARP)](https://github.com/TEAMuP-dev/HARP)
[![HARP](https://gh-card.dev/repos/TEAMuP-dev/HARP.svg)](https://github.com/TEAMuP-dev/HARP)

PyHARP is a **companion package** for [HARP](https://github.com/TEAMuP-dev/HARP), an application which enables the seamless integration of machine learning models into Digital Audio Workstations (DAWs). This repository provides a lightweight wrapper to embed **arbitrary Python code** for audio processing into [Gradio](https://www.gradio.app) endpoints accessible through HARP. In this way, HARP supports offline remote processing with algorithms or models that may be too resource-hungry to run on common hardware. HARP can be run as a standalone or from within DAWs that support external sample editors (_e.g._, [REAPER](https://www.reaper.fm), [Logic Pro X](https://www.apple.com/logic-pro/), or [Ableton Live](https://www.ableton.com/en/live/)). Please see [our website](https://harp-plugin.netlify.app/content/supported_os.html) for more information and instructions on how to install and run HARP with various operating systems and DAWs.
PyHARP is a **companion package** for [HARP](https://github.com/TEAMuP-dev/HARP), an application which enables the seamless integration of machine learning models into Digital Audio Workstations (DAWs). This repository provides a lightweight wrapper to embed **arbitrary Python code** for audio processing into [Gradio](https://www.gradio.app) endpoints accessible through HARP. In this way, HARP supports offline remote processing with algorithms or models that may be too resource-hungry to run on common hardware. HARP can be run as a standalone or from within DAWs that support external sample editors (_e.g._, [REAPER](https://www.reaper.fm), [Logic Pro X](https://www.apple.com/logic-pro/), or [Ableton Live](https://www.ableton.com/en/live/)). Please see [our website](https://harp3.netlify.app/content/supported_os.html) for more information and instructions on how to install and run HARP with various operating systems and DAWs.

## Table of Contents
* **[Usage](#usage)**
Expand Down Expand Up @@ -31,7 +31,7 @@ Note that PyHARP depends on [Gradio](https://www.gradio.app/). We recommend inst

# PyHARP Apps
## Examples
We provide several examples of how to create a PyHARP app under the `examples/` directory. You can also find a list of models already deployed as PyHARP apps on [our website](https://harp-plugin.netlify.app/content/usage/models.html).
We provide several examples of how to create a PyHARP app under the `examples/` directory. You can also find a list of models already deployed as PyHARP apps on [our website](https://harp3.netlify.app/content/usage/models.html).

In order to run an app, you will need to install its corresponding dependencies, including `gradio` and `pyharp`. For example, to install the dependences for our [pitch shifter](https://github.com/TEAMuP-dev/pyharp/tree/main/examples/pitch_shifter) example:

Expand Down Expand Up @@ -221,7 +221,7 @@ with gr.Blocks() as demo:
Note that by default PyHARP uses the [symusic](https://github.com/Yikai-Liao/symusic) package to load and save MIDI, but any standard method will work.

## Output Labels
In order to display output labels in HARP, you must define an output JSON component and return our custom `LabelList` object in `process_fn`:
In order to display output labels in HARP, you must define an output [JSON](https://www.gradio.app/docs/gradio/json) component and return our custom `LabelList` object in `process_fn`:
```python
from pyharp import LabelList, AudioLabel, MidiLabel, OutputLabel, ...

Expand Down Expand Up @@ -398,4 +398,4 @@ For more information, please refer to the offical document from Hugging Face abo
## Accessing Within HARP
PyHARP apps deployed to HuggingFace will begin running at `https://huggingface.co/spaces/<USERNAME>/<SPACE_NAME>`. The shorthand `<USERNAME>/<SPACE_NAME>` can also be used within HARP to reference the endpoint. The two deployment methods above produce identical UIs and functionality.

PyHARP apps can be accessed from within HARP through the local or forwarded URL corresponding to their active Gradio endpoints ([see above](#examples)), or the URL corresponding to their dedicated hosting service ([see above](#hosting-endpoints-huggingface-spaces))), if applicable.
PyHARP apps can be accessed from within HARP through the local or forwarded URL corresponding to their active Gradio endpoints ([see above](#examples)), or the URL corresponding to their dedicated hosting service ([see above](#hosting-endpoints-huggingface-spaces)), if applicable.
29 changes: 23 additions & 6 deletions examples/ui_tester/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def download_file(url):
# Define the process function
def process_fn(
input_audio_path, # unused
generic_file_path,
slider_1_time_sleep,
slider_2,
slider_3,
Expand All @@ -70,9 +71,8 @@ def process_fn(
checkbox_3,
text_control
) -> Tuple[str, str, LabelList]:

# Paths to files to use for output
audio_url = f"https://github.com/TEAMuP-dev/HARP/blob/main/resources/media/test.wav"
audio_url = "https://github.com/TEAMuP-dev/HARP/blob/main/resources/media/test.wav"
midi_url = "https://github.com/TEAMuP-dev/HARP/blob/main/resources/media/test.mid"

# Download audio and MIDI file
Expand All @@ -94,6 +94,12 @@ def process_fn(
output_audio_path = save_audio(audio)
output_midi_path = save_midi(midi)

if generic_file_path is None:
generic_file_path = get_default_path(".txt")

with open(generic_file_path, "w") as f:
f.write("generic file output")

# Create an empty label list
output_labels = LabelList()

Expand Down Expand Up @@ -197,7 +203,7 @@ def process_fn(
# Delay return for chosen amount of time
time.sleep(int(slider_1_time_sleep))

return output_audio_path, output_midi_path, output_labels
return output_audio_path, output_midi_path, output_labels, generic_file_path


# Build Gradio endpoint
Expand All @@ -208,6 +214,13 @@ def process_fn(
label="Optional AudioInp")
.harp_required(False)
.set_info('This is an optional input track that has no effect on the output.'),
gr.File(
type="filepath",
label="Generic Config File",
file_types=[".txt", ".csv", ".json", ".nam"]
)
.set_info("Select a generic file input. HARP should show this as a GUI file picker, not an input track.")
.harp_required(False),
gr.Slider(
minimum=0,
maximum=100,
Expand Down Expand Up @@ -269,12 +282,17 @@ def process_fn(
output_components = [
gr.Audio(type="filepath",
label="Output Audio")
.set_info("The selected audio file."),
.set_info("Audio file."),
gr.File(type="filepath",
label="Output Midi",
file_types=[".mid", ".midi"])
.set_info("The fixed MIDI file."),
.set_info("MIDI file."),
gr.JSON(label="Output Labels"),
gr.File(
type="filepath",
label="Output File"
)
.set_info("Generic file."),
]

# Build a HARP-compatible endpoint
Expand All @@ -285,5 +303,4 @@ def process_fn(
process_fn=process_fn,
)


demo.queue().launch(share=True, show_error=False, pwa=True)
28 changes: 21 additions & 7 deletions pyharp/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class HarpMidiTrack(HarpComponent):
required: bool
type: str = "midi_track"

@dataclass
class HarpFileComponent(HarpComponent):
required: bool
file_types: List[str]
type: str = "generic_file"

@dataclass
class HarpSlider(HarpComponent):
minimum: float
Expand Down Expand Up @@ -115,15 +121,23 @@ def get_harp_component(gr_cmp: Component) -> HarpComponent:
info=gr_cmp.info,
required=gr_cmp.is_harp_required
)
elif isinstance(gr_cmp, gr.File) \
and('.mid' in gr_cmp.file_types or '.midi' in gr_cmp.file_types):
elif isinstance(gr_cmp, gr.File):
assert gr_cmp.type == "filepath", \
f"File input must be of type filepath, not {gr_cmp.type}"
harp_cmp = HarpMidiTrack(
label=gr_cmp.label,
info=gr_cmp.info,
required=gr_cmp.is_harp_required
)

if gr_cmp.file_types is not None and ('.mid' in gr_cmp.file_types or '.midi' in gr_cmp.file_types):
harp_cmp = HarpMidiTrack(
label=gr_cmp.label,
info=gr_cmp.info,
required=gr_cmp.is_harp_required
)
else:
harp_cmp = HarpFileComponent(
label=gr_cmp.label,
info=gr_cmp.info,
required=gr_cmp.is_harp_required,
file_types=gr_cmp.file_types if gr_cmp.file_types is not None else []
)
elif isinstance(gr_cmp, gr.Slider):
harp_cmp = HarpSlider(
minimum=gr_cmp.minimum,
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

setup(
name='pyharp',
version='0.3.0',
version='0.3.1',
url='https://github.com/TEAMuP-dev/pyharp',
author='Frank Cwitkowitz, Christodoulos Benetatos, Hugo Flores García, Patrick O\'Reilly, Nathan Pruyne, and Aldo Aguilar',
author='TEAMuP',
author_email='fcwitkow@ur.rochester.edu',
description='',
packages=find_packages(),
Expand Down