Music processing bundle (music21 + musicparser)
Project description
pyw-music 🎵
Complete music processing toolkit for the pythonWoods ecosystem – from MIDI to sheet music, everything type-safe and developer-friendly.
Overview
pyw-music è il bundle completo per l'elaborazione musicale nell'ecosistema pythonWoods. Unifica parsing, analisi, composizione e export in un'unica API coerente, trasformando Music21 in un'esperienza moderna e type-safe.
Bundle Components
| Package | Description | Version | Features |
|---|---|---|---|
| pyw-music21 | Type-safe Music21 integration | 0.0.0 |
Stubs, helpers, Pydantic models |
| pyw-musicparser | Multi-format music parsing | 0.0.0 |
MIDI, Lilypond, MusicXML → Music21 |
| pyw-music | Meta-package & unified API | 0.0.1 |
Single import, workflow tools |
Philosophy
- Format-agnostic processing – Import da qualsiasi formato musicale, lavora con un'API unificata
- Type-safe composition – Pydantic models per note, accordi, scale, progressioni
- Workflow-oriented – Tools pensati per composer, musicologist, developer
- Performance-first – Ottimizzato per librerie musicali e batch processing
- Interoperable – Compatibile con ecosistemi esistenti (music21, pretty_midi, librosa)
Quick Start
# Installa tutto l'ecosistema musicale
pip install pyw-music
# Per sviluppo con tutti gli extra
pip install pyw-music[dev,analysis,audio]
Hello World
from pyw.music import (
parse_file, quick_analysis,
export_formats, compose
)
# Parse qualsiasi formato musicale
score = parse_file("song.mid") # MIDI
score = parse_file("piece.ly") # Lilypond
score = parse_file("work.xml") # MusicXML
# Analisi immediata
analysis = quick_analysis(score)
print(f"Key: {analysis.key}, Tempo: {analysis.tempo}")
# Export in tutti i formati
export_formats(score, "output", formats=["midi", "musicxml", "png"])
# Composizione programmatica
melody = compose.melody(
notes=["C4", "D4", "E4", "F4"],
durations=[0.5, 0.5, 1.0, 1.0],
key="C major"
)
Unified API Examples
🎼 Multi-Format Processing
from pyw.music import MusicLibrary, batch_process
# Gestione libreria musicale
library = MusicLibrary("./my_music_collection/")
# Auto-discovery di tutti i formati supportati
files = library.discover()
print(f"Found {len(files)} music files:")
for file in files:
print(f" {file.path} ({file.format})")
# Batch processing con progress
results = batch_process(
files,
operations=["normalize", "analyze", "export_midi"],
parallel=True,
progress=True
)
# Statistiche della libreria
stats = library.statistics()
print(f"Genres: {stats.genres}")
print(f"Average tempo: {stats.avg_tempo}")
print(f"Key distribution: {stats.key_distribution}")
🎹 Composition Workflow
from pyw.music.compose import (
Composer, ChordProgression,
Melody, Rhythm, Arrangement
)
# Compositore intelligente
composer = Composer(style="jazz", key="Bb major")
# Progressione armonica
progression = ChordProgression.from_roman_numerals(
["IIM7", "V7", "IM7", "VIM7"],
key="Bb major"
)
# Melodia generata
melody = composer.generate_melody(
progression=progression,
length=32, # battute
style_hints=["bebop", "chromatic_approach"]
)
# Arrangiamento completo
arrangement = Arrangement(
melody=melody,
harmony=progression,
rhythm=Rhythm.swing_8ths(),
instrumentation=["piano", "bass", "drums"]
)
# Export in tutti i formati
arrangement.export("my_composition", formats=["midi", "musicxml", "pdf"])
🔍 Advanced Analysis
from pyw.music.analysis import (
StyleAnalyzer, StructureAnalyzer,
HarmonicAnalyzer, PerformanceAnalyzer
)
# Analisi stilistica avanzata
style_analyzer = StyleAnalyzer()
style = style_analyzer.identify_style("bach_invention.xml")
print(f"Style: {style.period} - {style.genre}")
print(f"Confidence: {style.confidence:.2%}")
print(f"Key features: {style.characteristic_features}")
# Analisi strutturale
structure = StructureAnalyzer().analyze("sonata.xml")
print(f"Form: {structure.form_type}")
print(f"Sections: {structure.sections}")
print(f"Modulations: {structure.key_changes}")
# Analisi armonica approfondita
harmony = HarmonicAnalyzer().analyze("jazz_standard.mid")
print(f"Chord density: {harmony.chord_density}")
print(f"Functional harmony: {harmony.functional_analysis}")
print(f"Voice leading quality: {harmony.voice_leading_score}")
# Analisi performance (da MIDI)
performance = PerformanceAnalyzer().analyze("recording.mid")
print(f"Tempo variations: {performance.tempo_flexibility}")
print(f"Dynamic range: {performance.dynamic_range}")
print(f"Articulation: {performance.articulation_style}")
🎛️ Format Conversion Pipeline
from pyw.music.conversion import ConversionPipeline
# Pipeline di conversione avanzata
pipeline = ConversionPipeline()
# Configurazione step-by-step
pipeline.add_step("normalize_tempo", target_bpm=120)
pipeline.add_step("quantize_timing", grid="16th")
pipeline.add_step("transpose", target_key="C major")
pipeline.add_step("simplify_chords", max_voices=4)
pipeline.add_step("add_chord_symbols")
# Batch conversion con pipeline
converted = pipeline.process_directory(
input_dir="./originals/",
output_dir="./processed/",
input_formats=["mid", "ly"],
output_format="musicxml"
)
# Custom pipeline per progetti specifici
jazz_pipeline = ConversionPipeline.jazz_leadsheet()
classical_pipeline = ConversionPipeline.classical_score()
pop_pipeline = ConversionPipeline.pop_chord_chart()
Specialized Workflows
🎼 Sheet Music Publisher
from pyw.music.publishing import (
ScorePublisher, LayoutEngine,
PartExtractor, TranspositionSet
)
# Publisher professionale
publisher = ScorePublisher()
# Estrazione parti automatica
full_score = parse_file("orchestra_piece.xml")
parts = PartExtractor(full_score).extract_all()
# Set di trasposizioni per strumenti traspositori
transpositions = TranspositionSet({
"Bb Clarinet": "M2", # Maggiore seconda
"F Horn": "P5", # Quinta perfetta
"Eb Alto Sax": "M6" # Sesta maggiore
})
# Layout ottimizzato per stampa
layout = LayoutEngine(
page_size="A4",
staff_size="normal",
margins="professional"
)
# Generazione parti trasposte
for instrument, part in parts.items():
if instrument in transpositions:
part = part.transpose(transpositions[instrument])
# Export con layout professionale
publisher.export_part(
part,
filename=f"{instrument}_part.pdf",
layout=layout,
include_rehearsal_numbers=True
)
🎵 Music Education Tools
from pyw.music.education import (
ExerciseGenerator, TheoryValidator,
ProgressionBuilder, EarTrainingSet
)
# Generatore esercizi automatico
generator = ExerciseGenerator(level="intermediate")
# Esercizi di armonia
harmony_exercises = generator.harmony_exercises(
topics=["ii-V-I progressions", "secondary dominants"],
keys=["C", "F", "G", "D"],
count=20
)
# Validatore teoria musicale
validator = TheoryValidator()
# Verifica progressioni studenti
student_progression = ["C", "Am", "F", "G"]
validation = validator.check_progression(
student_progression,
key="C major",
style="pop"
)
if validation.valid:
print("✅ Progressione corretta!")
print(f"Funzioni: {validation.roman_numerals}")
else:
print("❌ Errori trovati:")
for error in validation.errors:
print(f" - {error}")
# Set per ear training
ear_training = EarTrainingSet.generate(
exercise_types=["interval_recognition", "chord_quality"],
difficulty="beginner",
audio_format="wav"
)
🎹 Live Performance Integration
from pyw.music.live import (
MIDIController, RealtimeAnalyzer,
ChordDetector, PerformanceRecorder
)
# Controller MIDI in tempo reale
controller = MIDIController(device="Piano")
# Analizzatore tempo reale
analyzer = RealtimeAnalyzer(
buffer_size=1024,
analysis_rate=30 # fps
)
# Detector accordi live
chord_detector = ChordDetector(
confidence_threshold=0.8,
update_rate=4 # volte al secondo
)
# Setup callback per performance live
@controller.on_note_on
def handle_note(note, velocity, timestamp):
analyzer.add_note(note, velocity, timestamp)
# Detection accordi in tempo reale
current_chord = chord_detector.detect(analyzer.current_notes)
if current_chord:
print(f"Chord detected: {current_chord}")
# Registrazione performance
recorder = PerformanceRecorder()
recorder.start()
# ... performance ...
performance = recorder.stop()
performance.save("my_performance.mid")
# Analisi post-performance
analysis = quick_analysis(performance.to_stream())
print(f"Performance stats: {analysis}")
Development Tools
🛠️ CLI Toolkit
# Analisi rapida
pyw-music analyze song.mid --detailed --export-json
# Conversione batch
pyw-music convert *.ly --to midi --parallel --transpose P5
# Libreria musicale
pyw-music library scan ./music/ --build-index
pyw-music library stats --genre jazz --decade 1960s
# Composizione assistita
pyw-music compose --style classical --key "D major" --length 32
pyw-music harmonize melody.mid --style jazz --output full_arrangement.xml
# Validation e cleanup
pyw-music validate score.xml --strict --fix-common-errors
pyw-music optimize library/ --remove-duplicates --normalize-metadata
# Educational tools
pyw-music exercises --topic "chord progressions" --level advanced --count 10
pyw-music theory-check progression.xml --key "F major" --style "common practice"
🧪 Testing Framework
from pyw.music.testing import (
MusicTestCase, generate_test_scores,
assert_musical_correctness, MockMIDIDevice
)
class TestMyMusicProcessor(MusicTestCase):
def setUp(self):
# Generate test scores automaticamente
self.test_scores = generate_test_scores([
"major_scale", "minor_scale", "chromatic",
"simple_chord_progression", "complex_rhythm"
])
def test_harmonic_analysis(self):
score = self.test_scores["simple_chord_progression"]
analysis = my_harmonic_analyzer(score)
# Validazione musicale specifica
assert_musical_correctness(analysis.result)
self.assertValidProgression(analysis.chord_progression)
self.assertInKey(analysis.chords, key="C major")
def test_midi_processing(self):
with MockMIDIDevice() as midi:
midi.send_notes(["C4", "E4", "G4"])
processor = MyMIDIProcessor(midi)
result = processor.process()
self.assertEqual(result.detected_chord, "C major")
📊 Performance Profiling
from pyw.music.profiling import (
profile_music_processing, memory_tracker,
benchmark_suite, optimization_hints
)
# Profiling automatico
@profile_music_processing
def my_complex_analysis(score):
# Your analysis code
return result
# Memory tracking per large scores
with memory_tracker() as tracker:
large_symphony = parse_file("mahler_symphony_2.xml")
analysis = comprehensive_analysis(large_symphony)
print(f"Peak memory usage: {tracker.peak_mb:.1f} MB")
# Benchmark suite per ottimizzazioni
results = benchmark_suite([
("small_score", "simple_song.mid"),
("medium_score", "string_quartet.xml"),
("large_score", "full_orchestra.xml")
])
# Suggerimenti automatici per ottimizzazioni
hints = optimization_hints(my_analysis_function)
for hint in hints:
print(f"💡 {hint}")
Integration Examples
🎵 With Audio Processing
# Integrazione con librosa/essentia (opzionale)
from pyw.music.audio import AudioAnalyzer
# Analisi audio → sheet music
audio_file = "recording.wav"
audio_analyzer = AudioAnalyzer()
# Transcription automatica
transcription = audio_analyzer.transcribe(
audio_file,
instrument_hint="piano",
include_harmony=True
)
# Converti in score Music21
score = transcription.to_music21()
# Analisi completa
analysis = quick_analysis(score)
print(f"Transcribed key: {analysis.key}")
🌐 Web Integration
from pyw.music.web import MusicWebAPI, ScoreRenderer
# API web per servizi musicali
api = MusicWebAPI()
@api.route("/analyze")
def analyze_uploaded_score(file):
score = parse_file(file)
analysis = quick_analysis(score)
return analysis.to_json()
@api.route("/render")
def render_score(score_data):
score = parse_json(score_data)
renderer = ScoreRenderer(format="svg")
return renderer.render(score)
# Deploy con FastAPI/Flask integration
api.deploy(port=8000)
📱 Mobile/Embedded
from pyw.music.mobile import LightweightProcessor
# Processore ottimizzato per mobile
processor = LightweightProcessor(
max_memory_mb=50,
cpu_optimization=True,
battery_aware=True
)
# Analisi semplificata per devices limitati
light_analysis = processor.quick_analyze(simple_melody)
Configuration & Customization
from pyw.music.config import MusicConfig
# Configurazione globale ecosistema
config = MusicConfig(
# Default formats
preferred_import_format="auto",
preferred_export_format="musicxml",
# Analysis settings
default_analysis_depth="standard", # "basic", "standard", "comprehensive"
cache_analysis_results=True,
# Performance
parallel_processing=True,
max_workers=4,
memory_limit_mb=512,
# Audio integration (se disponibile)
enable_audio_features=True,
audio_sample_rate=44100,
# Educational features
enable_theory_validation=True,
default_notation_style="american", # vs "european"
# Export quality
pdf_resolution=300,
audio_export_quality="high"
)
# Applica configurazione
config.apply_globally()
Bundle Extras
# Installazione base
pip install pyw-music
# Con analisi audio (librosa, essentia)
pip install pyw-music[audio]
# Con generazione PDF avanzata
pip install pyw-music[pdf]
# Con supporto web
pip install pyw-music[web]
# Per sviluppo completo
pip install pyw-music[dev]
# Everything included
pip install pyw-music[all]
Migration Guides
From Music21
# Prima (Music21 puro)
from music21 import converter, analysis
score = converter.parse("file.mid")
key = analysis.discrete.analyzeStream(score, 'key')
# Dopo (pyw-music)
from pyw.music import parse_file, quick_analysis
score = parse_file("file.mid") # Auto-detect formato
analysis = quick_analysis(score) # Più informazioni
print(f"Key: {analysis.key}, Confidence: {analysis.key_confidence}")
From pretty_midi
# Prima (pretty_midi)
import pretty_midi
midi = pretty_midi.PrettyMIDI("file.mid")
# Complex conversion to music21...
# Dopo (pyw-music)
from pyw.music import parse_file
score = parse_file("file.mid") # Direct Music21 Stream
# Immediate access to all Music21 features
Advanced Topics
🎯 Custom Analysis Pipelines
from pyw.music.pipelines import AnalysisPipeline
# Pipeline personalizzata
pipeline = AnalysisPipeline()
pipeline.add_analyzer("basic_info")
pipeline.add_analyzer("harmonic_analysis", depth="comprehensive")
pipeline.add_analyzer("rhythmic_complexity")
pipeline.add_analyzer("form_analysis")
pipeline.add_custom_analyzer(MyCustomAnalyzer())
# Batch processing con pipeline
results = pipeline.process_library("./scores/", parallel=True)
🔌 Plugin Architecture
from pyw.music.plugins import MusicPlugin, register_plugin
@register_plugin("genre_classifier")
class GenreClassifierPlugin(MusicPlugin):
"""Plugin per classificazione automatica generi."""
name = "genre_classifier"
version = "1.0.0"
dependencies = ["tensorflow", "librosa"]
def classify(self, score):
# ML-based genre classification
return {"genre": "jazz", "confidence": 0.85}
# Auto-discovery e integrazione
📈 Scalability Features
from pyw.music.distributed import DistributedProcessor
# Processing distribuito per librerie enormi
processor = DistributedProcessor(
workers=["server1", "server2", "server3"],
load_balancing="round_robin"
)
# Process migliaia di file
results = processor.process_massive_library(
library_path="./10000_scores/",
operations=["analyze", "normalize", "export_midi"]
)
Roadmap
🎼 Near Term (Q3-Q4 2025)
- Complete Music21 stubs coverage
- Advanced MIDI parsing with velocity/timing preservation
- Lilypond bidirectional conversion
- PDF score generation with customizable layout
- Basic audio analysis integration
🎵 Medium Term (2026)
- AI-powered composition assistance
- Real-time performance analysis
- Advanced music theory validation
- Mobile-optimized processing
- Web service deployment tools
- Collaborative composition features
🎹 Long Term (2027+)
- Machine learning music generation
- Virtual reality score visualization
- Blockchain music rights management
- IoT instrument integration
- Advanced acoustics simulation
- Quantum computing music analysis
Performance Benchmarks
| Operation | Small (1KB) | Medium (100KB) | Large (10MB) |
|---|---|---|---|
| Parse MIDI | <1ms | 15ms | 200ms |
| Parse MusicXML | 2ms | 45ms | 800ms |
| Quick Analysis | 5ms | 100ms | 2s |
| Export PDF | 50ms | 500ms | 5s |
| Batch Process (100 files) | 2s | 45s | 8min |
Benchmarks su MacBook Pro M1, results may vary
Contributing
Il bundle pyw-music coordina lo sviluppo di multiple componenti:
🎯 Component-Specific
- pyw-music21: Stubs, type safety, Music21 helpers
- pyw-musicparser: Format parsers, conversion utilities
- pyw-music: Unified API, workflow tools, documentation
🛠️ Development Workflow
- Choose component: Decidi quale componente migliorare
- Setup:
git clone+poetry install+poetry shell - Code: Sviluppa seguendo type hints e testing
- Cross-test: Verifica compatibilità con altri componenti
- Bundle test: Test integration nell'intero bundle
- Document: Aggiorna docs sia componente che bundle
🧪 Testing Strategy
# Test singolo componente
cd pyw-music21 && pytest
# Test integration bundle
cd pyw-music && pytest --integration
# Test complete ecosystem
pytest --ecosystem --slow
📋 Contribution Areas
- Format support: Nuovi parser (ABC, Finale, etc.)
- Analysis algorithms: Algoritmi musicologici avanzati
- Performance: Ottimizzazioni per large-scale processing
- Educational tools: Strumenti per didattica musicale
- Audio integration: Bridge con audio processing libraries
- Documentation: Examples, tutorials, API reference
Happy music coding nella foresta di pythonWoods! 🎵🌲🎼
Links utili
Bundle documentation → https://pythonwoods.dev/docs/pyw-music/latest/
Component docs:
- pyw-music21 – Type-safe Music21
- pyw-musicparser – Multi-format parsing
Community:
- Issue tracker → https://github.com/pythonWoods/pyw-music/issues
- Discussions → https://github.com/pythonWoods/pyw-music/discussions
- Changelog → https://github.com/pythonWoods/pyw-music/releases
Music21 resources:
- Official docs → https://web.mit.edu/music21/doc/
- Corpus access → https://web.mit.edu/music21/doc/moduleReference/moduleCorpus.html
© pythonWoods — MIT License
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 pyw_music-0.0.0.post1.tar.gz.
File metadata
- Download URL: pyw_music-0.0.0.post1.tar.gz
- Upload date:
- Size: 8.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdc095eed7d1dca29c45ca5d42d39bd1f9f2b9f7b002da80a7d97208d96fcaeb
|
|
| MD5 |
435b08ea3281929c41a9665f6cb1453a
|
|
| BLAKE2b-256 |
dbbd85159017b50da9bbbb9c5993082ca1459ca3101e148b25e7f48632e8ea02
|
File details
Details for the file pyw_music-0.0.0.post1-py3-none-any.whl.
File metadata
- Download URL: pyw_music-0.0.0.post1-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f5405421c06808a0a7ef2bc4f238ca8ae2360e93baff7d833714f082cd26e76
|
|
| MD5 |
c93797adbe5469a33707e53424194503
|
|
| BLAKE2b-256 |
0e93489356bf7951f144d6e74b17dd806c1a294688e685b61efb3c3c95199e2e
|