Skip to content

Repository files navigation

AcoustiRust

Simulateur d'acoustique de salle en 2.5D par lancer de rayons, générateur de réponses impulsionnelles et écoute binaurale en temps réel, écrit en Rust.

Dessinez une pièce en plan, donnez-lui une hauteur, un sol et un plafond, placez une source et une tête d'écoute, puis écoutez. La réverbération, l'atténuation avec la distance et le son qui traverse les cloisons se recalculent dès que vous relâchez un mur ou la source. L'IR obtenue s'exporte en .wav pour une réverbe à convolution ou un moteur de jeu.

Rust 1.95+ Licence MIT / Apache-2.0 316 tests Aucun unsafe

Pièce en L : rayons, échos, métriques et réponse impulsionnelle

Capture de la version 2D : pièce en L sans vue directe entre la source (rouge) et l'auditeur (bleu), métriques par bande, courbe de Schroeder et IR stéréo.


Nouveautés de la version 2.5D

  • Hauteur, sol et plafond : chaque pièce est un plan extrudé, avec ses matériaux de sol et de plafond. Les réverbérations deviennent réalistes : ≈ 0,5 s pour une chambre, ≈ 2 s pour une salle de concert aux murs ornementés, ≈ 5 s pour une nef d'église (≈ 20 s en 2D).
  • Distance : décroissance en 1/r² et niveau d'écoute calibré. Le son direct perd 6 dB à chaque doublement de distance.
  • Transmission à travers les murs : isolation par bande pour chaque paroi. Une source de la pièce voisine s'entend, étouffée.
  • HRTF mesurées (SADIE II, tête Neumann KU100) : repérage avant / arrière et élévation, avec une bascule A/B vers le modèle de tête sphérique.
  • Scènes de la version 2D migrées automatiquement à l'ouverture.

Sommaire

Fonctionnalités

Simulation

  • Lancer de rayons 3D multithreadé (rayon) dans des pièces extrudées. Les murs vont du sol au plafond ; le sol et le plafond sont facultatifs (champ libre, ciel ouvert) et bornés à l'emprise des murs.
  • Trois bandes d'octave (125–500 Hz, 500 Hz–2 kHz, 2–8 kHz), absorption de l'air par bande.
  • Réflexions spéculaires et lambertiennes selon le coefficient de diffusion.
  • Transmission à travers les parois par bande, sans biais (dédoublement borné, roulette russe) et sans allocation.
  • Émission uniforme en angle solide (spirale de Fibonacci), oreilles sphériques, occlusion par les murs, le sol et le plafond.
  • Noyau géométrique robuste en f64 : aucun rayon perdu aux arêtes et aux coins mur / sol / plafond. Accélération BVH au-delà de 32 murs, résultats identiques au bit près.

Écoute et DSP

  • Écoute binaurale en temps réel par HRTF SADIE II : réflexions précoces avec HRIR à phase minimale, queue diffuse par bande, correction d'ITD issue de la mesure. Repli automatique sur l'ombre de tête (Brown & Duda).
  • Niveau calibré (source de puissance 1 à 1 m → −18 dBFS), niveau de source en dB, badge de saturation.
  • Convolution partitionnée (Partitioned Overlap-Add, rustfft), sans allocation dans le callback audio ; changement d'IR sans clic pendant la lecture.
  • Signaux de test intégrés (clic, bruit bref, balayage de Farina, caisse claire) ou glisser-déposer d'un .wav sec.

Analyse

  • Échogramme, courbe de Schroeder, EDT / T20 / T30 par bande, niveau du son direct.
  • RT60 théorique d'Eyring 3D (« champ diffus »), avec un avertissement quand le champ est probablement non diffus (pièces plates ou peu diffusantes).

Éditeur

  • Dessin des murs avec accrochage, annuler / rétablir.
  • Hauteur sous plafond, sol et plafond (présents ou absents), hauteur z de la source et de l'auditeur, isolation de chaque mur par bande.
  • 11 matériaux : béton banché, placo, parquet, vitrage, mousse acoustique, rideau lourd, moquette, carrelage, dalles acoustiques de plafond, public assis, béton brut rugueux.
  • 12 pièces préconfigurées : studio, chambre, salon, salle de bain, classe, couloir, pièce en L, salle de concert, nef d'église, parking souterrain, deux pièces voisines, champ libre.
  • Scènes en JSON versionné (v2), migration automatique des scènes v1.
  • Export de l'IR en un clic : .wav stéréo 24 bits / 48 kHz.

Couloir ouvert : les rayons s'échappent par l'ouverture

Capture de la version 2D : couloir ouvert sur l'extérieur, 99 % des rayons s'échappent. En 2.5D, le sol et le plafond s'arrêtent à l'emprise des murs : une pièce ouverte laisse toujours sortir les rayons.

Démarrage rapide

Prérequis

  • Rust 1.95 ou plus récent.

  • Linux : bibliothèques ALSA et pilotes graphiques Vulkan ou OpenGL (pour wgpu).

    sudo apt install pkg-config libasound2-dev

L'application a été développée et testée sous Linux (Wayland). cpal et wgpu prennent en charge macOS et Windows, mais ces plateformes n'ont pas été testées.

Lancer l'application

git clone https://github.com/Dr1mS/AcoustiRust.git
cd AcoustiRust
cargo run -p acousti_ui --release

La première compilation prend plusieurs minutes (pile graphique eframe / wgpu).

Générer une IR sans interface

cargo run -p acousti_dsp --release --example render_ir
# → impulse_response.wav dans le répertoire courant

Utilisation

  1. Choisissez une pièce : Fichier → Nouvelle scène depuis un preset…
  2. Réglez la pièce dans l'inspecteur : Pièce (hauteur, sol, plafond), Hauteur z de la source et de l'auditeur (« assis 1.2 m » / « debout 1.6 m »), Isolation (dB) des murs.
  3. Mettez un casque, choisissez une Source sonore, laissez Niveau calibré et HRTF (SADIE II) cochés, puis cliquez sur Lecture.
  4. Déplacez la source ou les murs : la nouvelle réverbération arrive dès le relâchement (0,15 à 1,15 s selon la pièce).
  5. Exporter l'IR (WAV)… pour l'utiliser ailleurs.
Action Commande
Outil sélection / outil mur V / W
Déplacer un objet glisser
Panoramique glisser dans le vide ou clic droit glissé
Zoom molette
Recadrer la scène F
Simuler maintenant R
Inverser l'accrochage pendant le tracé Maj
Orientation de l'auditeur poignée jaune (Maj : pas de 15°)
Supprimer le mur sélectionné Suppr
Annuler / Rétablir Ctrl+Z / Ctrl+Maj+Z ou Ctrl+Y
Nouveau / Ouvrir / Enregistrer / Enregistrer sous Ctrl+N / Ctrl+O / Ctrl+S / Ctrl+Maj+S

Architecture

Crate Rôle Interdit
acousti_core Types partagés, géométrie 2.5D, lancer de rayons 3D, transmission, BVH audio, fenêtrage
acousti_dsp Hits → IR 48 kHz, HRTF, convolution temps réel, moteur cpal, WAV UI
acousti_bench Métriques RT60 / EDT, lois de réverbération 2D et 3D, carte SPL, benchmarks UI, DSP
acousti_ui Application egui / eframe (wgpu) —

tools/hrtf/ contient la conversion hors ligne de SADIE II en table embarquée (Python + numpy).

flowchart LR
    UI["acousti_ui<br/>éditeur egui"] -- "Scene, Source, Listener" --> CORE["acousti_core<br/>lancer de rayons 3D"]
    CORE -- "AcousticHit (azimut, élévation)" --> DSP["acousti_dsp<br/>HRTF + convolution"]
    CORE -- "SimulationResult" --> BENCH["acousti_bench<br/>RT60, EDT, carte SPL"]
    BENCH -- "métriques" --> UI
    DSP -- "audio 48 kHz" --> OUT(("casque"))
    DSP -- "impulse_response.wav" --> DAW[("DAW / moteur de jeu")]
Loading

La simulation, la synthèse de l'IR et sa préparation FFT tournent dans des threads de travail : le thread de l'interface ne fait que soumettre l'IR prête au moteur audio.

Règles du code : aucun unsafe (lint deny, tests compris), aucun unwrap hors des tests (clippy::unwrap_used = deny), erreurs typées avec thiserror, validation des entrées avant les boucles de calcul. Contrat entre crates : ARCHITECTURE.md.

Modèle physique

  • Géométrie : murs = segments du plan extrudés sur [0, H] ; sol et plafond analytiques, bornés à la boîte englobante des murs.
  • Propagation : énergie initiale puissance × directivité / N par bande. À chaque impact, réfléchi 1 − α, transmis τ (τ ≤ α), dissipé α − τ. Direction lambertienne avec une probabilité égale au coefficient de diffusion, spéculaire sinon. Air en e^(−m·d).
  • Transmission : une branche transmise hérite du compteur de rebonds et de la distance du rayon parent. Quand la pile est pleine, les branches sont fusionnées sans biais ; le trajet primaire ne traverse jamais un mur.
  • Récepteur : deux sphères de 10 cm écartées de 18 cm. ITD géométrique, corrigé par l'ITD mesuré de la HRTF ; directions de la HRTF prises depuis le centre de la tête.
  • Niveau : gain fixe calibré sur le son direct à 1 m en champ libre, fraction captée (1 − cos β)/2.
  • Réponse impulsionnelle : histogrammes d'énergie à 48 kHz par bande et par oreille, réflexions précoces (80 ms) filtrées par HRIR, queue diffuse par bande.

Dérivations : crates/acousti_bench/THEORY.md. Décisions et mesures du sprint : docs/SPRINT_2_5D.md.

Validation

Vérification Résultat
RT60 3D (T20 / T30) contre Kuttruff 3D (γ² mesuré), α = 0,1 à 0,3, avec et sans air écart ≤ 1,72 %
RT60 3D contre Eyring 3D, ᾱ ≤ 0,2 +2,1 % à +5,0 % (biais attendu)
Libre parcours moyen contre 4V/S (5 prismes) écart ≤ 0,12 %
Capture d'une sphère contre (1 − cos β)/2 écart ≤ 0,14 % ; −6,02 dB par doublement
Champ réverbéré stationnaire contre Hopkinson 3D écart ≤ 1,06 %
Isolement entre deux pièces diffuses contre TL + 10·log(A₂/S) − ΔL écart −0,13 dB
Écoute calibrée, son direct de 1 m à 2 m (HRTF) −6,17 / −6,09 dB (G / D)
ITD de l'IR synthétisée contre la table SADIE II (±90°, 0°) à ±1 échantillon
Endurance : 100 000 rayons × 1 000 rebonds, 20 prismes de 1 cm à 1 km, décalage de 1e6 m, diffusion 0 / 0,5 / 1 0 rayon échappé et 0 segment hors du prisme sur 60 passes
Lecture audio avec déplacements et changements d'IR 0 erreur de flux
Coût CPU de la convolution (IR stéréo de 3 s) 6,7 % d'un cœur en régime

Réactivité (release, du relâchement à l'IR acceptée par le moteur, avec HRTF) :

Preset Délai RT60 mesuré (T20, médium)
Salon 0,15 s ≈ 0,9 s
Deux pièces voisines 0,55 s ≈ 1,4 s
Salle de concert 0,67 s 1,7 à 2,3 s
Nef d'église 0,79 s 5,0 à 5,8 s
Parking souterrain 1,15 s 4,5 à 5,0 s
cargo test --workspace --release        # 316 tests
cargo clippy --workspace --all-targets --all-features -- -D warnings

Export et compatibilité

L'IR est écrite en WAV stéréo 24 bits / 48 kHz avec un en-tête WAVE_FORMAT_PCM (tag 1), et non WAVE_FORMAT_EXTENSIBLE : Godot 4.3 à 4.5 refuse tout autre format que les tags 1 et 3. L'en-tête est vérifié octet par octet et relu par un décodeur RIFF indépendant.

Le fichier est destiné aux réverbes à convolution (Reaper ReaVerb, Ableton Convolution Reverb, FL Convolver…) et aux moteurs audio de jeu (Godot, FMOD, Wwise, Unreal).

Données HRTF

Les HRTF proviennent du SADIE II Database (Université d'York), sujet D1 (Neumann KU100), distribué sous licence Apache 2.0 (Zenodo, record 12092466, version 2-2). AcoustiRust embarque une œuvre dérivée : une table de ~2 000 directions, convertie en phase minimale, avec énergies par bande et ITD. Elle se trouve dans crates/acousti_dsp/data/, avec la licence (SADIE_II_LICENSE.txt) et la liste des modifications (ATTRIBUTION.md). L'attribution est aussi affichée dans Aide → À propos d'AcoustiRust…

C. Armstrong, L. Thresh, D. Murphy et G. Kearney, « A Perceptual Evaluation of Individual and Non-Individual HRTFs: A Case Study of the SADIE II Database », Applied Sciences, 8(11), 2029, 2018. DOI : 10.3390/app8112029.

Limites connues

  • Tous les murs vont du sol au plafond : pas de mobilier bas ni de voitures.
  • Le sol et le plafond couvrent la boîte englobante des murs : dans une pièce en L ouverte, l'encoche extérieure a elle aussi un « toit ».
  • Champ non diffus (pièces plates, murs parallèles peu diffusants) : le RT60 réel dépasse Eyring, jusqu'à ×2. L'application le signale, et le RT60 mesuré fait alors référence.
  • Distance interaurale fixe (18 cm) ; ITD quantifié à ~20,8 µs à 48 kHz ; deux réflexions arrivant à la même oreille à moins de 1 ms d'intervalle sont fusionnées.
  • Coût par rebond sur une petite scène opaque : +18 % par rapport à la version 2D consolidée (+6,5 % à 64 murs). Les presets transmissifs se calculent en revanche 5 à 7 fois plus vite qu'au début du sprint.
  • Carte SPL calculée (acousti_bench::field), pas encore affichée dans l'application.

Feuille de route

  • Affichage de la carte SPL (coupe à hauteur d'écoute).
  • Obstacles de hauteur partielle (mobilier), géométrie 3D quelconque.
  • Réduction du surcoût par rebond sur les petites scènes.

Documentation

Licence

Code : au choix Apache License 2.0 (LICENSE-APACHE) ou MIT License (LICENSE-MIT). Sauf mention contraire explicite, toute contribution soumise pour inclusion est placée sous cette double licence, sans condition supplémentaire.

Données HRTF SADIE II : Apache 2.0 (voir Données HRTF).

Remerciements

Construit avec glam, rayon, egui / eframe, wgpu, cpal, rustfft, hound, rtrb et criterion. HRTF : projet SADIE, Université d'York.

Développé avec Claude Code, en sessions multi-agents (une session par crate, coordonnées par une session d'architecture).

About

Simulateur d'acoustique de salle par lancer de rayons, générateur de réponses impulsionnelles et écoute binaurale temps réel, en Rust

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages