Files
pmomusic/pmoaudio/REFACTORING_SUMMARY.md

343 lines
9.0 KiB
Markdown

# 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:**
```rust
pub struct AudioChunk {
stereo: Arc<[[i32; 2]]>,
sample_rate: u32,
bit_depth: BitDepth,
}
```
**Après:**
```rust
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: u32``BitDepth`
- 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`](examples/audio_chunk_api.rs) pour une démonstration complète.
### Création rapide
```rust
// 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
```rust
// Via méthodes
let chunk_f32 = audio_chunk.to_f32();
// Via From/Into
let chunk_i32: Arc<AudioChunkData<i32>> = (&*chunk_i16).into();
```
### Macros
```rust
// 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
```rust
// 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
```bash
# 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:**
```rust
let chunk = AudioChunk::new(stereo, 48000, BitDepth::B32);
let gain = chunk.gain_linear();
```
**Après:**
```rust
let chunk_data = AudioChunkData::new(stereo, 48000, 0.0);
let chunk = AudioChunk::I32(chunk_data);
let gain = chunk.gain_linear(); // Toujours disponible
```
### AudioSegment
**Avant:**
```rust
segment.chunk.sample_rate
```
**Après:**
```rust
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