Generate backing track audio from chord charts
Project description
accompy 🎵
Generate backing track audio from chord charts in Python — like iReal Pro, but scriptable.
from accompy import generate_accompaniment
# Generate a bossa nova backing track
audio = generate_accompaniment("| Dm7 | G7 | C^7 | A7b9 |", style="bossa", tempo=140)
print(f"Generated: {audio}") # -> /tmp/xxx.wav
Features
- Simple API: One function to generate complete backing tracks
- Multiple styles: Swing, bossa nova, rock, funk, ballad, latin, waltz, blues
- Flexible chord inputs: Strings,
Score, iReal URLs, or(chord, beats)tuples - Backend selector:
backend="auto"|"mma"|"builtin"(with backwards-compatibleuse_mma) - iReal Pro compatible: Parse iReal Pro URLs directly (with optional
pyRealParser) - Multi-instrument: Drums, bass, piano with style-appropriate patterns
- Audio output: WAV, MP3, FLAC via FluidSynth
- MIDI output: Save
.middirectly (skip audio rendering) - Extensible: Add custom patterns and styles
Quick Start
Installation
pip install accompy # Coming soon to PyPI
# Or install from source:
git clone https://github.com/yourname/accompy
pip install -e accompy
System Dependencies
accompy requires FluidSynth and a SoundFont for audio rendering.
Automated Setup (Recommended)
The easiest way to get started:
# Install accompy
pip install -e .
# Run automated setup (interactive)
python -c "from accompy import verify_and_setup; verify_and_setup()"
# This will:
# - Check all dependencies
# - Offer to install missing ones (with your permission)
# - Download and configure SoundFont files
# - Verify everything works
Manual Setup
If you prefer to install manually:
# macOS
brew install fluid-synth
# FluidSynth 2.5+ comes with a bundled SoundFont
# The setup will automatically link it for you
# Ubuntu/Debian
sudo apt-get install fluidsynth fluid-soundfont-gm
# Install Python dependencies
pip install midiutil mingus
# Verify setup
python -m accompy --check-deps
Check Your Setup
# Quick check
python -c "from accompy import check_dependencies; print(check_dependencies())"
# Detailed diagnostic report
python -c "from accompy import print_diagnostic_report; print_diagnostic_report()"
Usage
Basic Usage
from accompy import generate_accompaniment
# Generate with default settings
audio = generate_accompaniment("| C | Am | F | G |")
# Specify style and tempo
audio = generate_accompaniment(
"| Dm7 | G7 | Cmaj7 | Am7 |",
style="swing",
tempo=160,
repeats=4,
output_path="my_track.wav"
)
# Generate MIDI only (skip audio rendering)
midi = generate_accompaniment(
"| Dm7 | G7 | Cmaj7 | Am7 |",
output_path="my_track.mid",
)
Using Score Objects
For more control, create a Score object:
from accompy import Score, generate_accompaniment
# Parse chord string
score = Score.from_string(
"| Dm7 | G7 | Cmaj7 | % |", # % = repeat previous chord
title="ii-V-I in C",
key="C",
time_signature=(4, 4)
)
# Generate audio
audio = generate_accompaniment(score, style="swing", tempo=120)
### Flexible Chord Inputs
`generate_accompaniment(...)` accepts several common chord progression formats.
```python
from accompy import ensure_score, generate_accompaniment
# 1) iReal-style chord strings
generate_accompaniment("| C | Am | F | G |")
# 2) iReal Pro URL strings (irealbook://... or irealb://...)
generate_accompaniment("irealbook://Autumn%20Leaves=...")
# 3) List of (chord, beats) tuples (like `accompany`)
chords = [("F#m7b5", 4), ("B7", 4), ("Em", 8)]
score = ensure_score(chords, key="E")
generate_accompaniment(score)
Backend Selection
Choose which generator to use:
from accompy import generate_accompaniment
# Auto: use MMA if available, else builtin
generate_accompaniment("| Dm7 | G7 | Cmaj7 | Am7 |", backend="auto")
# Force builtin generator
generate_accompaniment("| Dm7 | G7 | Cmaj7 | Am7 |", backend="builtin")
# Force MMA (errors if MMA isn't installed)
generate_accompaniment("| Dm7 | G7 | Cmaj7 | Am7 |", backend="mma")
### Chord Notation
accompy supports flexible chord notation:
```python
# Jazz notation (iReal Pro style)
"| C^7 | D-7 | G7 | C^7 |" # ^7=maj7, -7=min7
# Standard notation
"| Cmaj7 | Dm7 | G7 | Cmaj7 |"
# Simple notation
"| C | Dm | G | C |"
# Multiple chords per bar
"| Dm7 G7 | Cmaj7 |" # Two chords, split evenly
# Repeat symbols
"| C | G | % | F |" # % repeats G
Chord symbol reference:
| Notation | Meaning |
|---|---|
C, Cmaj |
C major |
C-, Cm, Cmin |
C minor |
C7 |
C dominant 7 |
C^7, Cmaj7 |
C major 7 |
C-7, Cm7, Cmin7 |
C minor 7 |
Co, Cdim |
C diminished |
Co7, Cdim7 |
C diminished 7 |
Ch7, Cm7b5 |
C half-diminished |
C+, Caug |
C augmented |
Csus, Csus4 |
C suspended 4th |
Styles
Available styles with characteristic patterns:
| Style | Description | Typical Tempo |
|---|---|---|
swing |
Jazz swing with walking bass | 120-200 BPM |
bossa |
Bossa nova with syncopated feel | 100-150 BPM |
rock |
Straight 8ths rock beat | 100-140 BPM |
funk |
Syncopated funk groove | 90-120 BPM |
ballad |
Slow, sustained ballad | 60-90 BPM |
latin |
Latin/salsa with clave | 100-130 BPM |
waltz |
3/4 waltz pattern | 90-150 BPM |
blues |
Blues shuffle | 80-120 BPM |
iReal Pro Integration
Parse and play iReal Pro chord charts:
from accompy import Score, generate_accompaniment
# From iReal Pro URL (copy from app or forum)
url = "irealb://6dim=Composer%20Unknown==Medium%20Swing=C=7=1r34LbKcu7QyX%2DA6XyQ%7C%23G%7CQyXG%2F6C%7CQyXFo%7CQyXE%2F6C%7CQyXoDoXyQ%7CC44T%7BXQyXQQ%7DXyQQyXQyXQyXQyXQyQXyXQyXQyXQyXQyXXyQXyyXoB%7CQyXQyXyQXyyXQyXQyXQyXQyXyQXQyXQyXQyXQyXQQXyQXQyXQyyXQyXQXyQXXQyXQyXQyXQyXQXyQyXQyXQyXQyXQyyQXyQyXQyXQXyQXyQXyQXyQXyQ%20Z%20=Jazz%2DMedium%20Up%20Swing%202=118=21]6dim"
score = Score.from_ireal_url(url)
# Generate backing track
audio = generate_accompaniment(score, style="swing", tempo=140)
Note: pyRealParser is optional. If installed, Score.from_ireal_url(...) will use it.
If not installed, accompy uses a best-effort built-in parser.
Advanced Configuration
Full control with AccompanimentConfig:
from accompy import AccompanimentConfig, generate_accompaniment
config = AccompanimentConfig(
style="swing",
tempo=160,
repeats=4,
instruments={
"drums": True,
"bass": True,
"piano": True,
"guitar": False,
},
volumes={
"drums": 0.7,
"bass": 1.0,
"piano": 0.6,
},
sample_rate=44100,
output_format="mp3", # wav, mp3, flac, midi
)
audio = generate_accompaniment(
"| Dm7 | G7 | Cmaj7 | A7 |",
config=config,
output_path="backing_track.mp3"
)
Extensibility & Custom Patterns
New in v0.2.0: accompy now supports extensive customization through a protocol-based architecture.
Custom Chord Voicings
Provide your own chord-to-notes resolver:
from accompy import set_chord_resolver, generate_accompaniment
def jazz_voicing_resolver(symbol: str) -> list[int]:
"""Custom jazz voicings with rootless chords, tensions, etc."""
# Your custom chord resolution logic
# Return list of MIDI note numbers
return [55, 59, 62, 65, 69] # Example: Dm9 voicing
# Set as default resolver
set_chord_resolver(jazz_voicing_resolver)
# Now all accompaniments use your custom voicings
audio = generate_accompaniment("| Dm7 | G7 | Cmaj7 |")
Custom Patterns
Register your own accompaniment patterns:
from accompy import register_style, DrumPattern, BassPattern, DrumHit, NoteEvent, KICK, SNARE, CLOSED_HIHAT
# Define custom drum pattern
my_drum = DrumPattern(
name="my_funk",
beats_per_bar=4,
hits=[
DrumHit(0, KICK, 110),
DrumHit(0.75, KICK, 85),
DrumHit(1, SNARE, 105),
DrumHit(2, KICK, 110),
DrumHit(3, SNARE, 105),
# ... more hits
]
)
# Define custom bass pattern
my_bass = BassPattern(
name="my_funk",
notes=[
NoteEvent(0, 0, 0.4, 110), # Root, short
NoteEvent(0.75, 0, 0.2, 80), # Root, ghostNote
NoteEvent(1.5, 7, 0.3, 90), # 5th
# ... more notes
]
)
# Register the custom style
register_style('my_funk', drums=[my_drum], bass=[my_bass], comp=[])
# Use it
audio = generate_accompaniment("| C7 | F7 | C7 | G7 |", style="my_funk")
Pattern Registry
The pattern registry is a MutableMapping, making it Pythonic and extensible:
from accompy import get_pattern_registry
registry = get_pattern_registry()
# Check available styles
print(registry.available_styles()) # ['swing', 'bossa', 'rock', ...]
# Access patterns like a dict
swing_patterns = registry['swing']
print(swing_patterns['drums']) # List of DrumPattern objects
# Add/modify styles at runtime
registry['custom_groove'] = {
'drums': [custom_drum_pattern],
'bass': [custom_bass_pattern],
'comp': [custom_comp_pattern]
}
Real-Time Event Generation
For advanced use cases (future integration with hum/pyo for real-time synthesis):
from accompy import RealtimeAccompaniment, AccompanimentConfig
# Create real-time player
config = AccompanimentConfig(tempo=120, style='swing')
player = RealtimeAccompaniment(config)
# Set chord progression
player.set_chords("| Dm7 | G7 | Cmaj7 | A7 |")
# Get event iterator (for future real-time playback)
for event in player.events():
# event.time, event.note, event.velocity, event.duration
# Future: send to real-time synth like hum/pyo
pass
Protocol-Based Architecture
All major components implement protocols for maximum flexibility:
from accompy.protocols import ChordResolver, PatternSource, SynthesizerBackend
# Implement custom components that satisfy these protocols
# See accompy/protocols.py for full definitions
# Example: Custom synthesis backend
class MySynthBackend(SynthesizerBackend):
def render_to_file(self, midi_path, output_path, *, sample_rate=44100):
# Your custom synthesis logic (e.g., using hum, pyo, etc.)
pass
@classmethod
def is_available(cls):
return True # Check if dependencies are available
# Use with dependency injection
from accompy import AccompanimentConfig, generate_accompaniment
config = AccompanimentConfig(synthesis_backend=MySynthBackend())
audio = generate_accompaniment("| C | G | Am | F |", config=config)
Command Line
# Generate backing track
python -m accompy "| C | Am | F | G |" -s bossa -t 120 -o track.wav
# Check dependencies
python -m accompy --check-deps
# Options
python -m accompy --help
How It Works
- Parse chords: Convert chord string →
Scoreobject with normalized chord symbols - Generate MIDI: Create multi-track MIDI with drums, bass, piano patterns
- Uses MMA (Musical MIDI Accompaniment) if available for realistic tracks
- Falls back to built-in pattern generator
- Render audio: Convert MIDI → WAV using FluidSynth with SoundFont
- Convert format: Optionally convert to MP3/FLAC via ffmpeg or pydub
MMA (Musical MIDI Accompaniment)
For the best quality backing tracks, install MMA:
# MMA provides 50+ professionally designed grooves
git clone https://github.com/infojunkie/mma
cd mma && python install # Follow MMA installation instructions
MMA offers extensive groove libraries with realistic fills, variations, and transitions.
Python Dependencies
Required:
midiutil— MIDI file generation
Recommended:
mingus— Music theory (better chord parsing)pyRealParser— iReal Pro URL parsingmidi2audio— Optional Python wrapper for FluidSynth (can improve portability)pydub— Audio format conversion (if no ffmpeg)
pip install midiutil mingus pyRealParser midi2audio pydub
API Reference
generate_accompaniment(chords, *, style, tempo, repeats, output_path, output_format, config, use_mma, backend)
Generate accompaniment audio from chord progression.
Parameters:
chords(str | Score | Iterable[tuple[str, int|float]] | Iterable[str] | list[list[str]]): Chord progressionstyle(str): "swing", "bossa", "rock", "ballad", "funk", "latin", "waltz", "blues"tempo(int): BPM (default: 120)repeats(int): Number of times through the form (default: 2)output_path(str | Path): Where to save audio (default: temp file)output_format(str | None): "wav", "mp3", "flac", "midi" (optional; inferred fromoutput_path)config(AccompanimentConfig): Full config (overrides style/tempo/repeats)use_mma(bool): Backwards-compatible MMA toggle (default: True)backend(str | None): "auto", "mma", "builtin" (optional)
Returns: Path to generated audio file
Score.from_string(chord_string, *, title, key, time_signature)
Parse chord string into Score object.
Score.from_ireal_url(url)
Parse iReal Pro URL into Score object.
check_dependencies()
Returns dict of available dependencies.
print_setup_instructions()
Print installation instructions for missing dependencies.
Troubleshooting
Common Issues
"No SoundFont found" Error
Problem: RuntimeError: No SoundFont found. Download FluidR3_GM.sf2 and place in ~/.fluidsynth/default_sound_font.sf2
Solutions:
-
Automated fix:
python -c "from accompy import setup_soundfont; setup_soundfont()"
-
Check if FluidSynth includes a SoundFont:
# macOS with Homebrew find /opt/homebrew/Cellar/fluid-synth -name "*.sf2"
If found, run the automated setup to link it.
-
Manual download:
mkdir -p ~/.fluidsynth # Download MuseScore General (high quality, 35MB) curl -L -o ~/.fluidsynth/default_sound_font.sf2 \ "https://ftp.osuosl.org/pub/musescore/soundfont/MuseScore_General/MuseScore_General.sf2"
-
Verify the file:
ls -lh ~/.fluidsynth/default_sound_font.sf2 # Should be several MB (not just a few bytes)
"FluidSynth not found" Error
Problem: RuntimeError: FluidSynth not found. Install with: brew install fluidsynth
Solutions:
-
macOS:
brew install fluid-synth
-
Ubuntu/Debian:
sudo apt-get update sudo apt-get install fluidsynth
-
Windows: Download from FluidSynth releases and add to PATH
-
Verify installation:
which fluidsynth fluidsynth --version
SoundFont File is Corrupted (255 bytes)
Problem: Downloaded SoundFont is tiny (255 bytes) and appears to be XML
Cause: Download URL redirected to an error page
Solution:
# Remove corrupted file
rm ~/.fluidsynth/default_sound_font.sf2
# Use automated setup
python -c "from accompy import setup_soundfont; setup_soundfont(force=True)"
# Or manually download from a reliable source
curl -L -o ~/.fluidsynth/default_sound_font.sf2 \
"https://ftp.osuosl.org/pub/musescore/soundfont/MuseScore_General/MuseScore_General.sf2"
Import Warning About Missing Dependencies
Problem: Warning on import: accompy setup incomplete - missing: fluidsynth, soundfont
Solutions:
-
Run setup:
python -c "from accompy import verify_and_setup; verify_and_setup()"
-
Temporarily disable warning:
export ACCOMPY_SKIP_SETUP_CHECK=1 python your_script.py
-
Fix manually and verify:
# Install dependencies brew install fluid-synth # or apt-get install fluidsynth pip install midiutil # Run diagnostic python -c "from accompy import print_diagnostic_report; print_diagnostic_report()"
"midiutil not found" Error
Problem: Missing Python dependency
Solution:
pip install midiutil mingus
Diagnostic Tools
Run Full Diagnostic
Get a comprehensive report of your setup:
from accompy import print_diagnostic_report
print_diagnostic_report()
This shows:
- System information
- Dependency status (✓ or ✗)
- Specific issues found
- Solutions for each issue
Check Specific Issues
from accompy import diagnose_issues
for issue, description, solution in diagnose_issues():
print(f"Issue: {issue}")
print(f"Description: {description}")
print(f"Solution: {solution}\n")
Verify Individual Dependencies
from accompy import check_dependencies
deps = check_dependencies()
print(f"FluidSynth: {deps['fluidsynth']}")
print(f"SoundFont: {deps['soundfont']}")
print(f"midiutil: {deps['midiutil']}")
print(f"mingus: {deps['mingus']}")
print(f"MMA: {deps['mma']}")
Getting Help
If you're still having issues:
-
Run diagnostic report and save output:
python -c "from accompy import print_diagnostic_report; print_diagnostic_report()" > diagnostic.txt
-
Check existing issues: GitHub Issues
-
Create a new issue with:
- Your diagnostic report
- What you tried
- Full error message
Contributing
Contributions welcome! Areas of interest:
- Additional styles/grooves
- Better drum fills and variations
- Improved chord voicings
- More instrument parts (guitar, strings, horns)
- Web interface
- Better cross-platform setup automation
License
MIT
Acknowledgments
- MMA - Musical MIDI Accompaniment by Bob van der Poel
- FluidSynth team
- pyRealParser for iReal Pro format parsing
- iReal Pro for inspiration
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file accompy-0.3.4.tar.gz.
File metadata
- Download URL: accompy-0.3.4.tar.gz
- Upload date:
- Size: 154.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af50a0f7507a1c31591a3a881fdb813c4684b47711f573e9822897c76983917b
|
|
| MD5 |
76c3d69b2cf50f8f80d3b00a73d2c54f
|
|
| BLAKE2b-256 |
87fefb3ee2487656e84eefcdc9ba423d4a5af0001b2efdef1bd0edafaa6321e5
|
File details
Details for the file accompy-0.3.4-py3-none-any.whl.
File metadata
- Download URL: accompy-0.3.4-py3-none-any.whl
- Upload date:
- Size: 66.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb6f62043ec860cca4abe4c4050ba6b7b58dc802dee0d6ea364f95756850bcd9
|
|
| MD5 |
fc4516f83946bf47a542607d4de0e7e7
|
|
| BLAKE2b-256 |
2e8fee1e999c805735cf907ac89bca13136d8bb3509002ac77bbb952f7fe234f
|