Skip to main content

Music processing bundle (music21 + musicparser)

Project description

pyw-music 🎵

PyPI CI License

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

  1. Choose component: Decidi quale componente migliorare
  2. Setup: git clone + poetry install + poetry shell
  3. Code: Sviluppa seguendo type hints e testing
  4. Cross-test: Verifica compatibilità con altri componenti
  5. Bundle test: Test integration nell'intero bundle
  6. 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:

Community:

Music21 resources:

© pythonWoods — MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyw_music-0.0.0.post1.tar.gz (8.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyw_music-0.0.0.post1-py3-none-any.whl (8.9 kB view details)

Uploaded Python 3

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

Hashes for pyw_music-0.0.0.post1.tar.gz
Algorithm Hash digest
SHA256 bdc095eed7d1dca29c45ca5d42d39bd1f9f2b9f7b002da80a7d97208d96fcaeb
MD5 435b08ea3281929c41a9665f6cb1453a
BLAKE2b-256 dbbd85159017b50da9bbbb9c5993082ca1459ca3101e148b25e7f48632e8ea02

See more details on using hashes here.

File details

Details for the file pyw_music-0.0.0.post1-py3-none-any.whl.

File metadata

File hashes

Hashes for pyw_music-0.0.0.post1-py3-none-any.whl
Algorithm Hash digest
SHA256 6f5405421c06808a0a7ef2bc4f238ca8ae2360e93baff7d833714f082cd26e76
MD5 c93797adbe5469a33707e53424194503
BLAKE2b-256 0e93489356bf7951f144d6e74b17dd806c1a294688e685b61efb3c3c95199e2e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page