MidiJamSession / README.md
adricl's picture
Setup for processing via transformers
ef96802
---
tags: [gradio-custom-component, File, MIDI, LLM]
title: gradio_midijamsession
short_description: Human AI Jam Sessions with Music LLMs
colorFrom: blue
colorTo: yellow
sdk: docker
pinned: false
app_file: space.py
---
# `gradio_midijamsession`
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
Human AI Jam Sessions with Music LLMs
## Installation
```bash
pip install gradio_midijamsession
```
## Usage
```python
"""
Demo app for MidiJamSession component.
Transposes all incoming MIDI notes by +2 semitones.
"""
import gradio as gr
from gradio_midijamsession import MidiJamSession
import io
from processor import transpose_midi
# Create the Gradio interface
with gr.Blocks(title="MIDI Jam Session Demo") as demo:
gr.Markdown("""
# 🎹 MIDI Jam Session Demo
This demo shows the MidiJamSession component in action:
1. **Select your MIDI input device** - Connect your MIDI keyboard or controller
2. **Select your MIDI output device** - Choose where to send the processed MIDI
3. **Play some notes** - The component will record your input
4. **Wait 5 seconds** - After inactivity, the recording is sent for processing
5. **Listen to the result** - Notes are transposed up by 2 semitones and played back
## How it works
- The frontend uses the **Web MIDI API** to capture live MIDI input
- After 5 seconds of inactivity, the recording is converted to a MIDI file using **@tonejs/midi**
- The backend receives the MIDI file and uses **mido** to transpose all notes by +2 semitones
- The processed MIDI is sent back and played on your selected output device
""")
midi_session = MidiJamSession(
label="MIDI Jam Session",
bpm=120,
interactive=True,
)
# Connect the processing function
midi_session.change(
fn=transpose_midi,
inputs=midi_session,
outputs=midi_session,
)
if __name__ == "__main__":
demo.launch()
```
## `MidiJamSession`
### Initialization
<table>
<thead>
<tr>
<th align="left">name</th>
<th align="left" style="width: 25%;">type</th>
<th align="left">default</th>
<th align="left">description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>value</code></td>
<td align="left" style="width: 25%;">
```python
str | bytes | Callable | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">Default MIDI file to display, given as a str file path, URL, or bytes.</td>
</tr>
<tr>
<td align="left"><code>bpm</code></td>
<td align="left" style="width: 25%;">
```python
int
```
</td>
<td align="left"><code>value = 120</code></td>
<td align="left">The tempo to use when creating MIDI files from recorded messages. Defaults to 120.</td>
</tr>
<tr>
<td align="left"><code>label</code></td>
<td align="left" style="width: 25%;">
```python
str | I18nData | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">The label for this component.</td>
</tr>
<tr>
<td align="left"><code>every</code></td>
<td align="left" style="width: 25%;">
```python
Timer | float | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">Continuously calls `value` to recalculate it if `value` is a function.</td>
</tr>
<tr>
<td align="left"><code>inputs</code></td>
<td align="left" style="width: 25%;">
```python
Component | Sequence[Component] | set[Component] | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">Components that are used as inputs to calculate `value` if `value` is a function.</td>
</tr>
<tr>
<td align="left"><code>show_label</code></td>
<td align="left" style="width: 25%;">
```python
bool | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">If True, will display label.</td>
</tr>
<tr>
<td align="left"><code>container</code></td>
<td align="left" style="width: 25%;">
```python
bool
```
</td>
<td align="left"><code>value = True</code></td>
<td align="left">If True, will place the component in a container.</td>
</tr>
<tr>
<td align="left"><code>scale</code></td>
<td align="left" style="width: 25%;">
```python
int | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">Relative size compared to adjacent Components.</td>
</tr>
<tr>
<td align="left"><code>min_width</code></td>
<td align="left" style="width: 25%;">
```python
int
```
</td>
<td align="left"><code>value = 160</code></td>
<td align="left">Minimum pixel width.</td>
</tr>
<tr>
<td align="left"><code>height</code></td>
<td align="left" style="width: 25%;">
```python
int | str | float | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">The height of the component.</td>
</tr>
<tr>
<td align="left"><code>interactive</code></td>
<td align="left" style="width: 25%;">
```python
bool | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">If True, will allow users to interact with MIDI devices.</td>
</tr>
<tr>
<td align="left"><code>visible</code></td>
<td align="left" style="width: 25%;">
```python
bool | Literal['hidden']
```
</td>
<td align="left"><code>value = True</code></td>
<td align="left">If False, component will be hidden.</td>
</tr>
<tr>
<td align="left"><code>elem_id</code></td>
<td align="left" style="width: 25%;">
```python
str | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">An optional string that is assigned as the id of this component in the HTML DOM.</td>
</tr>
<tr>
<td align="left"><code>elem_classes</code></td>
<td align="left" style="width: 25%;">
```python
list[str] | str | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">An optional list of strings that are assigned as the classes of this component.</td>
</tr>
<tr>
<td align="left"><code>render</code></td>
<td align="left" style="width: 25%;">
```python
bool
```
</td>
<td align="left"><code>value = True</code></td>
<td align="left">If False, component will not render in the Blocks context.</td>
</tr>
<tr>
<td align="left"><code>key</code></td>
<td align="left" style="width: 25%;">
```python
int | str | tuple[int | str, ...] | None
```
</td>
<td align="left"><code>value = None</code></td>
<td align="left">In a gr.render, Components with the same key across re-renders are treated as the same component.</td>
</tr>
<tr>
<td align="left"><code>preserved_by_key</code></td>
<td align="left" style="width: 25%;">
```python
list[str] | str | None
```
</td>
<td align="left"><code>value = "value"</code></td>
<td align="left">A list of parameters from this component's constructor to preserve across re-renders.</td>
</tr>
</tbody></table>
### Events
| name | description |
|:-----|:------------|
| `change` | Triggered when the value of the MidiJamSession changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
| `upload` | This listener is triggered when the user uploads a file into the MidiJamSession. |
| `clear` | This listener is triggered when the user clears the MidiJamSession using the clear button for the component. |
### User function
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
- When used as an Input, the component only impacts the input signature of the user function.
- When used as an output, the component only impacts the return signature of the user function.
The code snippet below is accurate in cases where the component is used as both an input and an output.
- **As output:** Is passed, the MIDI file contents as bytes.
- **As input:** Should return, mIDI data as a file path (str/Path) or raw bytes.
```python
def predict(
value: bytes| None
) -> str| bytes| pathlib.Path| None:
return value
```