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
Metadata
Release files for pyw-music 0.0.0.post1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyw_music-0.0.0.post1.tar.gz | 8.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyw_music-0.0.0.post1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.5 kB
Release files / pyw_music-0.0.0.post1.tar.gz
| Download URL | pyw_music-0.0.0.post1.tar.gz |
|---|---|
| Size | 8.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bdc095eed7d1dca29c45ca5d42d39bd1f9f2b9f7b002da80a7d97208d96fcaeb
|
|
BLAKE2b-256 checksum How to use checksums |
dbbd85159017b50da9bbbb9c5993082ca1459ca3101e148b25e7f48632e8ea02
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.4
|
Release files / pyw_music-0.0.0.post1-py3-none-any.whl
| Download URL | pyw_music-0.0.0.post1-py3-none-any.whl |
|---|---|
| Size | 8.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f5405421c06808a0a7ef2bc4f238ca8ae2360e93baff7d833714f082cd26e76
|
|
BLAKE2b-256 checksum How to use checksums |
0e93489356bf7951f144d6e74b17dd806c1a294688e685b61efb3c3c95199e2e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.4
|