tab-agent-pro / app.py
Tab Agent Bot
bind to 0.0.0.0 for HF proxy
57fbca7
Raw
History Blame Contribute Delete
11.5 kB
"""
Tab Agent - Hugging Face Gradio Interface (MVP)
AI-powered guitar/bass tablature transcription using Basic Pitch
This is the web UI for the Tab Agent transcription system.
Optimized for Zero GPU deployment with Basic Pitch model.
"""
import os
import sys
import tempfile
import zipfile
from pathlib import Path
from datetime import datetime
import gradio as gr
import numpy as np
# Zero GPU support for faster processing
try:
import spaces
GPU_AVAILABLE = True
except ImportError:
GPU_AVAILABLE = False
print("โš ๏ธ Running without Zero GPU support")
# Import Tab Agent modules
from agents import SplitterAgent, EarAgent, TabAgent
from main import export_tab_to_txt, export_tab_to_json
# Configuration
TEMP_DIR = tempfile.gettempdir()
OUTPUT_DIR = Path(TEMP_DIR) / "tab_agent_outputs"
OUTPUT_DIR.mkdir(exist_ok=True)
# Default tunings
GUITAR_TUNING = [40, 45, 50, 55, 59, 64] # E2-A2-D3-G3-B3-E4
BASS_TUNING = [23, 28, 33, 38, 43] # B0-E1-A1-D2-G2
# Apply Zero GPU decorator if available
if GPU_AVAILABLE:
@spaces.GPU
def process_audio(
audio_file,
instrument_type="Guitar",
include_midi=True,
include_tab=True,
include_json=True,
progress=gr.Progress()
):
"""
Process audio file and generate tablature.
Args:
audio_file: Path to uploaded audio file
instrument_type: "Guitar" or "Bass"
include_midi: Export MIDI files
include_tab: Export ASCII tab files
include_json: Export JSON files
progress: Gradio progress callback
Returns:
Tuple of (status_message, output_files_zip)
"""
return _process_audio_impl(audio_file, instrument_type, include_midi,
include_tab, include_json, progress)
else:
def process_audio(
audio_file,
instrument_type="Guitar",
include_midi=True,
include_tab=True,
include_json=True,
progress=gr.Progress()
):
"""Process audio file and generate tablature (CPU-only)."""
return _process_audio_impl(audio_file, instrument_type, include_midi,
include_tab, include_json, progress)
def _process_audio_impl(
audio_file,
instrument_type,
include_midi,
include_tab,
include_json,
progress
):
"""
Internal implementation of audio processing.
"""
if audio_file is None:
return "โŒ Please upload an audio file", None
try:
# Create unique output directory
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
session_dir = OUTPUT_DIR / f"session_{timestamp}"
session_dir.mkdir(exist_ok=True)
# Get file info
audio_path = Path(audio_file)
song_name = audio_path.stem
progress(0.1, desc="๐ŸŽต Initializing agents...")
# Initialize agents (auto-detects GPU via Zero GPU)
splitter = SplitterAgent(output_dir=str(session_dir / "stems"))
ear = EarAgent(device="auto") # Auto-detect: GPU if available, else CPU
# Stage 1-3: Stem separation and processing
progress(0.2, desc="๐ŸŽต Separating audio stems (Demucs)...")
stems = splitter.separate_stems(str(audio_path))
progress(0.3, desc="๐ŸŽธ Processing guitar stems...")
if instrument_type == "Guitar":
guitar_stems = splitter.process_guitars(stems['guitar'])
processed_stems = {
"lead": guitar_stems['lead'],
"rhythm_l": guitar_stems['left'],
"rhythm_r": guitar_stems['right']
}
else: # Bass
bass_clean = splitter.process_bass(stems['bass'])
processed_stems = {"bass": bass_clean}
# Stage 4: Transcription
progress(0.5, desc="๐ŸŽธ Transcribing to MIDI (Basic Pitch)...")
results = {}
for stem_name, stem_path in processed_stems.items():
progress(0.5 + (0.3 / len(processed_stems)),
desc=f"๐ŸŽธ Transcribing {stem_name}...")
# Transcribe
notes_raw = ear.transcribe_stem(
stem_path,
target=instrument_type
)
notes_clean = ear.humanize_and_clean(
notes_raw,
is_bass=(instrument_type == "Bass")
)
# Export MIDI
if include_midi:
midi_path = session_dir / f"{song_name}_{stem_name}.mid"
ear.export_midi(notes_clean, str(midi_path))
results[stem_name] = notes_clean
# Stage 5: Tablature generation
progress(0.8, desc="๐Ÿ“ Generating tablature...")
if instrument_type == "Guitar":
tab_agent = TabAgent(tuning=GUITAR_TUNING, num_frets=24)
else:
tab_agent = TabAgent(tuning=BASS_TUNING, num_frets=24)
for stem_name, notes in results.items():
tab_data = tab_agent.generate_tab(notes)
# Export tab files
if include_tab:
tab_path = session_dir / f"{song_name}_{stem_name}.tab"
export_tab_to_txt(
tab_data,
str(tab_path),
instrument=f"{instrument_type} - {stem_name}"
)
if include_json:
json_path = session_dir / f"{song_name}_{stem_name}.json"
export_tab_to_json(
tab_data,
str(json_path),
instrument=f"{instrument_type} - {stem_name}"
)
# Create ZIP archive
progress(0.9, desc="๐Ÿ“ฆ Creating download package...")
zip_path = session_dir / f"{song_name}_tablature.zip"
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for file in session_dir.rglob("*"):
if file.is_file() and file != zip_path:
arcname = file.relative_to(session_dir)
zipf.write(file, arcname)
progress(1.0, desc="โœ… Complete!")
# Generate status message
file_count = len(list(session_dir.glob("*.*"))) - 1 # Exclude zip
status_msg = f"""
โœ… **Transcription Complete!**
- **Song**: {song_name}
- **Instrument**: {instrument_type}
- **Files Generated**: {file_count}
- **Formats**: {', '.join([
'MIDI' if include_midi else '',
'Tab' if include_tab else '',
'JSON' if include_json else ''
]).strip(', ')}
๐Ÿ“ฅ **Download the ZIP file below to get all outputs!**
"""
return status_msg, str(zip_path)
except Exception as e:
import traceback
error_msg = f"โŒ **Error during processing:**\n\n```\n{str(e)}\n\n{traceback.format_exc()}\n```"
return error_msg, None
# Create Gradio interface
def create_ui():
"""Create Gradio UI interface."""
with gr.Blocks(
title="Tab Agent - AI Tablature Transcription",
theme=gr.themes.Soft()
) as demo:
gr.Markdown("""
# ๐ŸŽธ Tab Agent - AI Tablature Transcription (MVP)
AI-powered transcription for guitar and bass using **Basic Pitch** (Spotify's proven model).
## Features
- ๐ŸŽต **Multi-stage pipeline**: Demucs stem separation + spatial processing
- ๐Ÿค– **Basic Pitch AI**: Production-ready transcription model (Spotify)
- ๐ŸŽธ **Multi-track support**: Lead guitar, rhythm guitars (L/R), bass
- ๐Ÿ“ **Multiple formats**: MIDI, ASCII tablature, JSON
- ๐ŸŽฏ **Optimal fingering**: Dynamic programming for playable tabs
- โœจ **Technique detection**: Slides, hammer-ons, pull-offs
- โšก **Zero GPU**: Faster processing with Hugging Face Zero GPU
---
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Upload Audio")
audio_input = gr.Audio(
label="Audio File",
type="filepath",
sources=["upload"],
)
instrument_type = gr.Radio(
label="Instrument Type",
choices=["Guitar", "Bass"],
value="Guitar"
)
gr.Markdown("### Export Options")
with gr.Group():
export_midi = gr.Checkbox(label="MIDI Files", value=True)
export_tab = gr.Checkbox(label="ASCII Tablature", value=True)
export_json = gr.Checkbox(label="JSON Data", value=True)
transcribe_btn = gr.Button(
"๐ŸŽธ Transcribe to Tablature",
variant="primary",
size="lg"
)
with gr.Column(scale=1):
gr.Markdown("### Results")
status_output = gr.Markdown(
value="Upload an audio file and click 'Transcribe' to begin.",
label="Status"
)
download_output = gr.File(
label="Download Results (ZIP)",
interactive=False
)
# Examples
gr.Markdown("### Example Audio Files")
gr.Examples(
examples=[
["examples/guitar_solo.wav", "Guitar"],
["examples/bass_groove.wav", "Bass"],
],
inputs=[audio_input, instrument_type],
)
# Information
with gr.Accordion("โ„น๏ธ How It Works", open=False):
gr.Markdown("""
### Processing Pipeline
1. **Stem Separation (Demucs)**: Isolates guitar/bass from full mix
2. **Spatial Processing**: Separates lead and rhythm guitars using mid-side technique
3. **AI Transcription (Basic Pitch)**: Converts audio to MIDI notes with proven accuracy
4. **Tablature Generation**: Dynamic programming finds optimal fingering
5. **Technique Detection**: Identifies slides, hammer-ons, pull-offs
### Output Formats
- **MIDI**: Import into DAWs (Reaper, Ableton, Logic, etc.)
- **ASCII Tab**: Human-readable tablature for printing
- **JSON**: Programmatic access for custom applications
### Tips for Best Results
- Use high-quality audio (WAV/FLAC preferred)
- Isolate guitar/bass tracks if possible
- Shorter clips (< 60 seconds) process faster
- Clean recordings work better than live/noisy audio
""")
with gr.Accordion("๐Ÿ”— Links & Resources", open=False):
gr.Markdown("""
- **GitHub**: [Tab-Agent Repository](https://github.com/YOUR_USERNAME/Tab-Agent)
- **ReaPack**: [Install for Reaper](https://github.com/YOUR_USERNAME/Tab-Agent#reaper-integration)
- **Documentation**: [Full Guide](https://github.com/YOUR_USERNAME/Tab-Agent/blob/main/README.md)
- **Basic Pitch**: [Spotify Research](https://github.com/spotify/basic-pitch)
**License**: MIT | **Python**: 3.10+ | **Model**: Basic Pitch | **Acceleration**: Zero GPU
""")
# Connect event handlers
transcribe_btn.click(
fn=process_audio,
inputs=[
audio_input,
instrument_type,
export_midi,
export_tab,
export_json
],
outputs=[status_output, download_output]
)
return demo
# Main entry point
if __name__ == "__main__":
demo = create_ui()
demo.queue() # Enable queuing for progress tracking
demo.launch(server_name="0.0.0.0")