Files
pmomusic/pmoaudio/REFACTORING_SUMMARY.md

9.0 KiB

PMOAudio - Refactoring Summary

Vue d'ensemble

Refactoring complet du système audio pour supporter plusieurs types de samples (entiers et flottants) avec une architecture générique optimisée pour le temps réel.

Architecture

Option choisie: Générique + Enum plat

  • AudioChunkData<T: Sample>: Structure générique pour factoriser le code
  • AudioChunk: Enum plat avec 6 variants (I8, I16, I24, I32, F32, F64)
  • Sample trait: Interface unifiée pour tous les types de samples

Nouveaux fichiers créés

1. src/sample_types.rs

Définition du trait Sample et du type I24 (24-bit audio).

Features principales:

  • Type I24 wrapper sur i32 avec validation de plage (±2^23)
  • Trait Sample implémenté pour: i8, i16, I24, i32, f32, f64
  • Conversions normalisées vers/depuis f64 et f32
  • Tests unitaires complets

2. src/conversions.rs

Module complet de conversions entre tous les types audio.

Features principales:

  • Conversions Int → Int: Utilise bitdepth_change_stereo avec SIMD
  • Conversions Int → Float: Utilise i32_stereo_to_pairs_f32 avec SIMD
  • Conversions Float → Int: Utilise pairs_f32_to_i32_stereo avec SIMD
  • Conversions Float → Float: Direct avec cast
  • 34 implémentations From/Into pour conversions ergonomiques
  • Tests de round-trip et validation

Point clé: Les conversions I32 ↔ F32/F64 n'ont pas besoin de paramètre BitDepth car le type définit lui-même sa résolution (I32 = ±2^31).

3. src/macros.rs

Macros pour simplifier la manipulation des AudioChunk et AudioSegment.

Macros disponibles:

  • extract_chunk_data!(chunk, TYPE) - Extrait les données typées
  • match_chunk!(chunk, data => expr) - Pattern matching unifié
  • map_chunk!(chunk, data => transform) - Transformation préservant le type
  • is_chunk_type!(chunk, TYPE) - Prédicat de type
  • extract_audio_chunk!(segment) - Extrait AudioChunk d'un segment
  • extract_sync_marker!(segment) - Extrait SyncMarker d'un segment
  • match_segment!(segment, chunk => ..., marker => ...) - Match sur segment

Tests: 7 tests unitaires

Fichiers modifiés

1. src/audio_chunk.rs - Refactoring complet

Avant:

pub struct AudioChunk {
    stereo: Arc<[[i32; 2]]>,
    sample_rate: u32,
    bit_depth: BitDepth,
}

Après:

pub struct AudioChunkData<T: Sample> {
    stereo: Arc<[[T; 2]]>,
    sample_rate: u32,
    gain_db: f64,  // Toujours en dB
}

pub enum AudioChunk {
    I8(Arc<AudioChunkData<i8>>),
    I16(Arc<AudioChunkData<i16>>),
    I24(Arc<AudioChunkData<I24>>),
    I32(Arc<AudioChunkData<i32>>),
    F32(Arc<AudioChunkData<f32>>),
    F64(Arc<AudioChunkData<f64>>),
}

Nouvelles méthodes:

  • AudioChunk::to_f32(), to_f64(), to_i32() - Conversions de type
  • AudioChunk::set_gain_db() - Modification du gain
  • AudioChunk::type_name() - Nom du type runtime
  • Implémentations spécialisées pour i32, f32, f64

Tests: 4 tests unitaires

2. src/audio_segment.rs - Helpers ergonomiques

Nouvelles méthodes d'accès:

  • as_chunk() - Récupère le AudioChunk
  • as_sync_marker() - Récupère le SyncMarker
  • as_track_metadata() - Extrait les métadonnées de track
  • as_error() - Récupère le message d'erreur

Helpers de conversion:

  • to_f32_chunk() - Convertit vers F32
  • to_i32_chunk() - Convertit vers I32

Helpers de propriétés:

  • sample_rate() - Sample rate du chunk
  • frame_count() - Nombre de frames
  • gain_db() - Gain en dB
  • chunk_type_name() - Type du chunk

Manipulation du gain:

  • with_gain_db(gain_db) - Nouveau segment avec gain absolu
  • adjust_gain_db(delta_db) - Nouveau segment avec gain relatif

Tests: 4 tests unitaires

3. src/dsp/int_float.rs - Simplification

Changements:

  • Suppression du trait BitDepthType obsolète
  • Suppression des types Bit8, Bit16, Bit24, Bit32
  • Utilisation de l'enum BitDepth du module principal
  • Fonctions SIMD préservées et optimisées
  • Paramètres runtime au lieu de génériques

4. src/dsp/resampling.rs - Mise à jour BitDepth

Changements:

  • Type ResamplingError créé (remplace AudioError manquant)
  • Resampler.bit_depth: u32BitDepth
  • Match sur les variants d'enum au lieu de valeurs numériques
  • Qualité de resampling adaptée au bit depth (VeryHigh pour 24/32-bit)

5. src/lib.rs - Exports et organisation

Ajouts:

  • mod macros avec #[macro_use]
  • pub use sample_types::{I24, Sample}
  • pub use audio_segment::_AudioSegment (pour les macros)
  • pub mod conversions

Temporairement désactivé:

  • mod nodes (commenté)

Statistiques de tests

Tests réussis: 35/35

Répartition:

  • audio_chunk: 4 tests
  • audio_segment: 4 tests
  • conversions: 12 tests
  • macros: 7 tests
  • sample_types: 5 tests
  • events: 3 tests

Couverture des conversions

From/Into implémentations: 34 au total

  • Wrapper conversions (6): AudioChunkData → AudioChunk
  • I16 ↔ I32 (2)
  • I24 ↔ I32 (2)
  • I32 ↔ F32 (2)
  • I32 ↔ F64 (2)
  • F32 ↔ F64 (2)
  • Et toutes les autres combinaisons...

Optimisations

Performance temps réel

  • Objectif: Audio 192kHz/24-bit stéréo en temps réel
  • SIMD: Toutes les conversions critiques utilisent les fonctions SIMD du module DSP
  • Zero-copy: Partage via Arc<[[T; 2]]>
  • Lazy evaluation: Le gain n'est appliqué que lors de la lecture des frames

Harmonisation du gain

  • Tous les gains en dB (décibels)
  • Helpers de conversion: db_to_linear(), linear_to_db()
  • Plus d'interfaces linéaires (sauf helpers de conversion)

Exemple d'utilisation

Voir examples/audio_chunk_api.rs pour une démonstration complète.

Création rapide

// Chunk I32
let chunk = AudioChunkData::new(
    vec![[1000i32, 2000i32]],
    48000,
    0.0
);

// Segment avec gain
let segment = AudioSegment::new_chunk_with_gain_db(
    0, 0.0,
    vec![[1000i32, 2000i32]],
    48000,
    BitDepth::B32,
    6.0  // +6 dB
);

Conversions

// Via méthodes
let chunk_f32 = audio_chunk.to_f32();

// Via From/Into
let chunk_i32: Arc<AudioChunkData<i32>> = (&*chunk_i16).into();

Macros

// Type checking
if is_chunk_type!(&chunk, I32) {
    // ...
}

// Pattern matching universel
match_chunk!(&chunk, data => {
    println!("{} frames", data.len());
});

// Transformation
let with_gain = map_chunk!(&chunk, data => {
    data.set_gain_db(6.0)
});

Helpers AudioSegment

// Accès ergonomique
if let Some(sr) = segment.sample_rate() {
    println!("Sample rate: {}", sr);
}

// Manipulation du gain
let louder = segment.adjust_gain_db(3.0)?;

// Conversion
let f32_chunk = segment.to_f32_chunk()?;

Points clés de design

1. Type = Résolution

Chaque type définit sa propre résolution:

  • I8 = ±2^7 (128)
  • I16 = ±2^15 (32,768)
  • I24 = ±2^23 (8,388,608)
  • I32 = ±2^31 (2,147,483,648)
  • F32 / F64 = normalisé [-1.0, 1.0]

Conséquence: Pas besoin de paramètre BitDepth pour les conversions I32 ↔ Float.

2. Gain toujours en dB

  • Plus de gains linéaires dans l'API principale
  • Conversions disponibles via helpers si nécessaire
  • Évaluation paresseuse du gain

3. Immutabilité

  • Toutes les modifications créent de nouvelles instances
  • Partage efficace via Arc
  • Pas de copy-on-write nécessaire pour les données audio

4. Stéréo strict

  • Format fixe: [[T; 2]] (gauche, droite)
  • Pas de support multicanal pour l'instant
  • Optimisé pour le cas d'usage principal

Compilation et tests

# Build
cargo build --package pmoaudio

# Tests
cargo test --package pmoaudio --lib

# Exemple
cargo run --package pmoaudio --example audio_chunk_api

Statut: Compilation sans erreur, tous les tests passent

Travail futur (optionnel)

Les tâches suivantes ont été identifiées mais ne sont pas critiques:

  1. Benchmark temps réel 192kHz/24-bit

    • Valider les performances en conditions réelles
    • Mesurer l'overhead des conversions
  2. Macros avancées

    • Macros procédurales pour génération de code
    • DSL pour pipelines audio
  3. Support multicanal

    • Format [[T; N]] générique
    • Gestion des configurations surround
  4. Réactivation des Nodes

    • Mise à jour avec la nouvelle API
    • Tests d'intégration complets

Notes de migration

Pour le code existant utilisant l'ancienne API:

AudioChunk

Avant:

let chunk = AudioChunk::new(stereo, 48000, BitDepth::B32);
let gain = chunk.gain_linear();

Après:

let chunk_data = AudioChunkData::new(stereo, 48000, 0.0);
let chunk = AudioChunk::I32(chunk_data);
let gain = chunk.gain_linear();  // Toujours disponible

AudioSegment

Avant:

segment.chunk.sample_rate

Après:

segment.sample_rate().unwrap()  // Avec helper
// ou
segment.as_chunk().unwrap().sample_rate()  // Direct

Date: 2025-11-01 Version: PMOAudio 0.1.0 Status: Refactoring complet, tous les tests passent