Acouvero
Herunterladen
TECHNICAL DOC · v0.4.0

Raumakustik,
von der Messung
zum Plan.

Acouvero ist ein Werkzeug zur Raumakustik-Analyse und Maßnahmenplanung für iPhone / iPad. Dieses Dokument richtet sich an Leser mit Interesse an Akustik-Engineering oder Client-Implementierung — Kernalgorithmen, Geometriesystem, Messmethoden, Empfehlungssystem und Engineering-Hinweise.

Oktavbänder
6Bänder
Raumformen
4Geometrien
Reflexionen
1–3Ordnungen
§ 01

Überblick

Eingabe: Der Nutzer gibt Raummaße / Form / Materialien, Lautsprecher- und Hörposition ein — oder die Geometrie wird mit dem AR-Maßband (ohne LiDAR) oder per LiDAR-Scan (RoomPlan) erfasst.

Ausgabe
  • Lokalisierung früher Reflexionen
  • RT60 (gemessen + simuliert) plus EDT / C50 / C80 / D50 (aus der simulierten RIR abgeleitet)
  • Liste der Raummoden-Frequenzen
  • Panel-Layout (Position, Anzahl, Produkt-SKU)
  • 3D-Visualisierung + Reflexionsenergie-Heatmap
  • PDF-Export in Montagehandbuch-Qualität
  • Messung über das iPhone-Mikrofon (Sweep / Klatschen)

Rechteckige, L-, U-förmige und beliebige einfache Polygon-Räume werden unterstützt; Reflexionen 1. Ordnung sowie Flächen-/Enthaltensein-Berechnung nutzen das echte Polygon; Ordnung 2/3 und Raummoden nähern über die Bounding Box (siehe §9).

§ 02

Akustikmodell

2.1 Sabine RT60

Die klassische Sabine-Formel:

SABINE · RT60 $$ RT_{60} = \frac{0.161 \cdot V}{\sum_i S_i \alpha_i} $$
$V$
Raumvolumen (m³); bei Polygonen Shoelace-Fläche × Höhe, abzüglich Hindernissen (Stützen / Träger).
$\sum_i S_i \alpha_i$
Fläche × Absorptionsgrad je Fläche. Koeffizienten über 6 Oktavbänder (125 / 250 / 500 / 1k / 2k / 4k Hz).
$0.161$
= 24·ln(10)/c, mit c = 343 m/s (20 °C).

Die App liefert 4 Ausstattungs-Presets (leerer harter Raum / typisch harte Oberflächen / Möbel / bereits behandelt), je mit Absorptionskurve pro Band; die Einzelwert-RT60-Schätzung und das Panel-Budget nutzen einen Mittel-Hochton-Durchschnittskoeffizienten, die 6-Band-Sabine-Kurve speist die Bandanzeige. Auch das Ziel-RT60 ist eine 6-Band-Kurve, passend zu Normen wie EBU Tech 3276 / THX, die einen längeren Tiefbass-Nachhall zulassen.

2.2 Image-Source-Methode (ISM)

Erste Reflexionen per Spiegelung: Quelle an der Wand spiegeln; der Schnittpunkt der Strecke „Spiegelquelle → Hörer“ mit der Wand ist der Reflexionspunkt.

  • Rechteckiger Raum: Spiegelung an allen 6 Ebenen — geschlossene Lösung.
  • Nicht rechteckig (PolygonReflectionCalculator): jedes Wandsegment aus RoomPolygon.walls() spiegeln und Parameter s ∈ [0, 1] prüfen (Boden-/Decken-Reflexionen erfordern zusätzlich Reflexions-XY im Polygon); Pfade 1. Ordnung durchlaufen zudem einen 2D-Verdeckungstest — kreuzt ein Abschnitt Quelle→Punkt→Hörer ein anderes Wandsegment, wird der Pfad verworfen.

Mehrfachreflexionen (Ordnung 1–3) implementiert MultiOrderReflectionCalculator nach dem rekursiven Ansatz von pyroomacoustics:

  1. Alle Wandsequenzen [s₁, …, sₙ] aufzählen, benachbarte Wände verschieden
  2. Spiegelquellen-Iteration: S₀ = Quelle, Sₖ = mirror(Sₖ₋₁, sₖ)
  3. Rückverfolgung vom Hörer: Sₙ → Hörer trifft sₙ in Pₙ; Sₙ₋₁ → Pₙ trifft sₙ₋₁ in Pₙ₋₁; rekursiv zurück
  4. Jeder Schnittpunkt muss im gültigen Wandbereich liegen und t ∈ (0, 1)
NÄHERUNG Bei nicht rechteckigen Räumen nutzt Multi-Order die Bounding-Box-Näherung („Geisterreflexionen“ nahe konkaven Ecken). Die Analyse verwirft jeden Pfad, dessen Reflexionspunkt > 0,3 m von jedem echten Wandsegment entfernt ist; nur gültige Pfade gehen in die Flutter-/Slapback-Erkennung.

2.3 Pfadenergie

Breitband-Energie als Funktion von Reflexionsanzahl und Distanzdämpfung:

PATH ENERGY $$ E_{rel} = (1 - \bar{\alpha})^N \cdot \frac{d_{direct}^2}{d_{total}^2} $$
  • α wird auf [0, 0.99] begrenzt, damit α = 1 kein log(0) oder pow(negativ, N) = NaN erzeugt
  • Distanzdämpfung folgt der sphärischen Ausbreitung 1/r²
  • Umrechnung in dB über 10·log₁₀ (Energiedomäne)

Die Energie pro Band wird für die 6 Oktavbänder separat berechnet (Koeffizient aus finishProfile.absorptionByBand).

2.4 RT60-Schätzung (gemessen)

ImpulseResponseEstimator:

  • Matched Filtering: der aufgenommene 0,45-s-Sweep wird invers gefiltert (ESS / Farina) zu einem Impuls, ~+32 dB effektiver SNR
  • rmsEnvelope: gleitende RMS-Hüllkurve
  • Schroeder-Rückwärtsintegration: E_back(t) = ∫ₜ^∞ s²(τ) dτ, mit 10·log₁₀ normiert ergibt die EDC-Kurve
  • Lineare Steigungsregression: bevorzugt T30 [−5, −35 dB] je SNR, sonst T20 [−5, −25] oder T10 [−5, −15]
  • RT₆₀ = −60 / Steigung

RT60 pro Band: auf den gefilterten Samples Bandpass an ISO-Oktavmitten (250 / 500 / 1k / 2k / 4k), Q = √2, dann Schroeder je Band.

2.5 RIR-Simulation

SimulatedRIRGenerator wandelt Mehrfachreflexionspfade in diskrete Impulse in einem 8 kHz × 0,5 s PCM-Puffer:

SimulatedRIRGeneratorpseudocode
for path in reflectionPaths:
    t   = path.totalDistance / speedOfSound
    amp = 10^(path.relativeEnergyDB / 20)
    impulse[round(t * sampleRate)] += amp

Den Direktschall-Impuls hinzufügen, dann Schroeder-Integration für EDT / RT60 / C50 / C80 / D50.

Vorher- / Nachher-Vergleich Jeder Pfad wird durch die Panels der berührten Wände gedämpft — ein „behandelter“ RIR. Die UI schaltet A/B um, zeigt die EDT-/C50-Verbesserung, und AVAudio faltet ein trockenes Signal zum hörbaren Vergleich.

2.6 Raummoden

Modale Frequenzen eines rechteckigen Raums:

ROOM MODES $$ f_{n_x, n_y, n_z} = \frac{c}{2} \sqrt{\left(\frac{n_x}{L_x}\right)^2 + \left(\frac{n_y}{L_y}\right)^2 + \left(\frac{n_z}{L_z}\right)^2} $$

Klassifiziert nach Anzahl der von null verschiedenen nₓ, n_y, n_z: 1 = axial, 2 = tangential, 3 = schräg.

Die Enumeration deckt n ≤ 4 pro Achse bis 300 Hz ab. Nicht rechteckige Räume schätzen Moden über die Bounding Box (exakte Moden brauchen FEM); in der UI ausgewiesen.

§ 03

Geometriesystem

3.1 Unterstützte Formen

  • Rechteck — Breite × Länge × Höhe
  • L-Form — eine nw × nl-Kerbe an einer Ecke entfernen
  • U-Form — eine nw × nl-Kerbe mittig an einer Wand entfernen
  • Benutzerdefiniert — beliebiges einfaches Polygon (≥ 3, ≤ 24 Ecken)

Alle nicht rechteckigen Formen werden über RoomPolygon.from(shape:, bboxWidth:, bboxLength:) zur CCW-Eckenliste. Reflexionen 1. Ordnung, Fläche / Umfang und Enthaltensein nutzen diese Ecken direkt; ein ungültiges eigenes Polygon (< 3 / > 24 Ecken, selbstschneidend, Fläche nahe null) fällt still auf das umschließende Rechteck zurück.

3.2 Polygon-Geometrie-Werkzeuge

  • Fläche — Shoelace-Formel
  • Umfang — Summe der Kantenlängen
  • contains(x, y) — Ray-Casting mit Rand-Epsilon (verhindert Fehler an Ecken)
  • clamped(point) — Rechtecke nutzen den schnellen Pfad [0, w] × [0, l]; andere das echte [minₓ, maxₓ] × [min_y, max_y] aus polygon.boundingBox, prüfen polygon.contains und Binärsuche zum Bbox-Zentrum, falls außerhalb
  • walls() — zerlegt das Polygon in nach Innennormalen klassifizierte Segmente (leftWall / rightWall / frontWall / backWall), sodass der rechteckige Panel-Empfehler wiederverwendet wird
  • PolygonValidator.isSimple — prüft ein nicht selbstschneidendes einfaches Polygon

3.3 RoomPlan-Scan

RoomCaptureSession (iOS-16+-API; die App schaltet das Scannen erst ab iOS 17 frei) wird genutzt; CapturedRoomMapper bildet den Scan auf ScannedRoom ab (wallSegments + openings + furniture). Koordinaten-Mapping:

ARKit (x, y, z) → y ist vertikal App (x, y, z) → z ist vertikal Wand-Endpunkte (z=0 Boden) App.x = ARKit.x App.y = ARKit.z App.z = 0 Öffnung / Möbel-Zentrum  App.x = ARKit.x App.y = ARKit.z App.z = ARKit.y

Scans werden nach Wandanzahl klassifiziert: genau 4 Segmente gelten direkt als Rechteck; alles andere durchläuft RectangularRoomSimplifier.polygonShapeFromScan, das wallSegments zu Polygon-Ecken verkettet. RoomPlan-Endpunkte haben typ. 3–8 cm Fehler; eine 12-Segment-Schleife kann 5 cm akkumulieren, daher 12 cm Schließ-Epsilon. Schließt die Kette nicht, Rückfall auf die Bounding Box und Aufforderung zum erneuten Scan.

3.4 AR-Maßband

Ohne LiDAR übernimmt ARTapeMeasureView (RealityKit-ARView mit World-Tracking): Fadenkreuz auf die Wand richten und per Doppeltipp Start / Ende setzen, nacheinander Breite → Länge → Höhe, dann bestätigen — mit Kamera-Berechtigungsführung und Tracking-Fehler-Hinweisen.

3.5 Freier Vertex-Editor

FreeVertexEditorView erlaubt das Ziehen von Ecken auf einem SwiftUI-Canvas:

  • Langes Drücken zum Löschen (bei > 3 Ecken, damit ≥ 3 bleiben)
  • Jeder Zieh-Frame wird mit isSimple validiert; eine selbstschneidende Position wird schlicht nicht übernommen (die Ecke bleibt stehen). Tippen auf leere Fläche fügt eine Ecke auf der nächsten Kante ein; dazu kommen ein numerischer Editor je Ecke und ein Reset auf das umschließende Rechteck
  • 0,05-m-Raster-Einrastung
  • Ein Rand von max(0,5, bbox × 0,2) m außerhalb der Bbox erlaubt das Ziehen über die Bbox hinaus (die Elternansicht vergrößert room.width / length automatisch)
§ 04

Hörzonen & Multi-Listener

AcousticConfiguration.listeners unterstützt 1..N Hörpositionen (bei 0 Hörern wird eine Standard-Primärposition samt Warnung synthetisiert; bei 0 Lautsprechern übernehmen die Vorlagen aus §5.2). Die Analyse führt die Image-Source-Methode je Hörer aus und fügt Reflexionspunkte in ein Array zusammen (primärer Hörer zuerst). Der Empfehler gewichtet jede Wand nach Punktanzahl (cap = max(6, speakerCount × listenerCount)); mehrere Sitze an einer Wand treiben sie ans Budgetlimit.

UI-Darstellung
  • In 3D nutzen sekundäre Hörer Opacity 0,45 + Scale 0,75
  • Draufsicht (RoomPlanView): primäre Punkte volle Farbe r=5, sekundäre Opacity 0,45 r=3
  • Die Liste (RecommendationView) zeigt nur primäre Punkte; Fußnote „+ N Reflexionen bereits berücksichtigt“

Mehrfachreflexionen / RIR / Heatmap werden weiterhin einmal für den primären Hörer berechnet (O(speakers × surfaces³) je Hörer ist zu schwer, RIR ist eine Einzelpunkt-Metrik).

§ 05

Empfehlungssystem

PanelPlacementRecommender liefert [PanelRecommendation], je mit: Position (links / rechts / Decke / vorn / hinten / Ecke), Anzahl, Priorität (essenziell / stark / empfohlen / optional), effectivenessMultiplier, targetReflectionPointId.

5.1 Proportionale Zuteilung (größter Rest)

Das alte gierige add() ließ Wände verhungern: linke Wand verbrauchte das Budget → rechte 0; bei knappem Budget auch Decke / vorn / hinten. Neu: Methode des größten Rests:

  • Raw-Desired je Wand berechnen (Punktanzahl + Raumtiefe + Anwendungsfall)
  • floor(raw × budget / total) als Anfangszuteilung
  • Wände mit raw &gt; 0 erhalten ≥ 1 Panel; nur wenn das Budget kleiner ist als die Zahl nachgefragter Wände, werden Flächen genullt, niedrigste Priorität zuerst
  • falls Summe &gt; Budget, vom kleinsten Bruchrest aufwärts kürzen
  • Links/Rechts-Symmetrie: bei raw[0] == raw[1] alloc[0] == alloc[1] erzwingen
  • Restbestand nach größtem Bruchteil umverteilen

5.2 Anwendungsfall-Vorlagen

Ohne platzierte Lautsprecher gelten anwendungsspezifische Vorlagen:

  • Besprechungsraum: Decke 35 % + Rückwand 20 % + je Seitenwand 12 %
  • Podcast: direkt vor dem Mikrofon 25 % + je Seite 18 % + Decke 20 %
  • Studio: symmetrische Vier-Wand-Dämpfung + bis zu 4 Eck-Bassfallen im Budget (der echte Budget-Bypass greift nur auf dem Pfad dichter Tieftonmoden aus §5.3)
  • Allgemeines Hören: symmetrische Basis + Hinweis, Lautsprecher hinzuzufügen

5.3 Physikalische Muss-Maßnahmen umgehen das Budget

Eck-Bassfallen werden bei dichten 80–150-Hz-Moden auf 4 erzwungen und umgehen das totalPanel-Limit. Grund: In Ecken ist der Schalldruck am höchsten, Bassfallen dort ~1,5× effizienter — physikalische Notwendigkeit.

5.4 Hörnahe Gewichtung

Ein Nachlauf markiert Empfehlungen innerhalb 1,5 m eines Hörers als .nearListener, setzt effectivenessMultiplier ×1,15 und vermerkt dies in Titel / Begründung.

§ 06

Messung

6.1 ESS-Sweep

Nach Farinas Methode:

  • Logarithmischer Sweep 180 Hz → 4 kHz, 0,45 s
  • Inversfilter (makeInverseSweep) = Zeitumkehr + Amplitudenhüllkurve mit +6 dB/Oktave (mit der Frequenz steigend, gegen das rosa ESS-Spektrum)
  • Aufnahme via AVAudioRecorder als verlustfreies Linear PCM (16-bit Mono .caf, ~96 dB Dynamik — perceptual Codecs gehören nicht in die Impulsmessung; die Abtastrate folgt der Audio-Session — 44,1 kHz am internen Mikrofon, native 48 kHz bei USB-Messmikrofonen)
  • Zurücklesen → Matched Filter → analyzeImpulse
Abtastraten-Angleichung Sweep-WAV, inverser Sweep und Aufnahme werden alle mit der realen Abtastrate der Audio-Session erzeugt (makeInverseSweep(sampleRate:) ist parametrisiert) — das Matched Filtering ist damit immer aktiv, bei 44,1 kHz (internes Mikrofon) wie bei 48 kHz (USB-Messmikrofone).

6.2 Klatsch-Impuls

Ohne Wiedergabe — der Nutzer klatscht einmal kräftig in einem 1-s-Fenster; insgesamt 4,5 s aufgenommen (~3,5 s Ausklang). Direkt zu analyzeImpulse (kein Matched Filter nötig; ein Klatschen ist bereits ein schmaler Impuls). Deckt das 125-Hz-Band ab, das der Sweep (ab 180 Hz) verfehlt.

6.3 Gemessen vs. simuliert

MeasuredVsSimulatedCard nimmt das letzte gemessene RT60 und zeigt die Abweichung zum simulierten RT60:

< 15%Modell und Messung stimmen überein
15–30%gewisse Abweichung (nicht modellierte Möbel / Materialien)
> 30%große Abweichung — Geometrie / Materialien prüfen

6.4 Umgebungsrauschen & Kalibrierung

AmbientNoiseEstimator nimmt 3 s Stille auf (je 100 ms an den Enden beschnitten) für das Grundrauschen: Breitband-Mittel / -Spitze in dBFS + 5-stufige Ruhebewertung (dBFS nur relativ, bis eine SPL-Kalibrierung dB SPL liefert). Die Nahfeld-Latenzkalibrierung nutzt denselben ESS-Sweep: Telefon ≤ 30 cm vor den Lautsprecher, Verzögerung Aufnahmestart → Impulsspitze (inkl. bewusstem 250-ms-Vorlauf), idealerweise 2–3 Läufe — Streuung der letzten 3 Messungen < 5 ms = hohe, < 20 ms = mittlere Konfidenz. Die Latenz ist an das aktuelle Paar „Eingang + Ausgaberoute“ gebunden, verfällt bei jeder Änderung und wird bei Fernmessungen automatisch abgezogen.

6.5 USB-Messmikrofone & Ausgaberouting

Die Eingangsauswahl der Messseite listet internes Mikrofon und class-compliant USB-Eingänge (z. B. miniDSP UMIK-1 / UMIK-2); ein routeChangeNotification-Listener fällt aufs interne Mikrofon zurück, wenn das externe verschwindet. Aufnahme- und Sweep-Raten folgen der Session (UMIK-1 = 48 kHz). REW-.txt-Kalibrierdateien lassen sich direkt importieren (Auswertung von Sens Factor / SERNO, lineare Interpolation in Log-Frequenz, Endpunkt-Clamp; 90°-Datei für Raummessungen empfohlen) — die Korrektur verschiebt nur die Bandpegel-Anzeige, nie die RT60-Abklingsteigung.

Einmalige SPL-Kalibrierung: Schallpegelkalibrator (Standard 94 dB @ 1 kHz) aufs Mikrofon, die App tastet 3 s Pegel ab und leitet den dBFS → SPL-Offset ab — danach zeigen Messwerte echte dB SPL. Die Kalibrierung (Kurve + Offset) ist an die UID des Eingangsports gebunden und wird in ~/Library/Application Support/mic_calibration.json persistiert; bei Eingangswechsel warnt die UI in Orange, dass die Kalibrierung nicht gilt — neu importieren und kalibrieren.

Die Wiedergabe läuft über den System-Routenwähler (AVRoutePickerView-Wrapper, auf den Karten für Sweep / Nahfeld-Kalibrierung); die Session erlaubt AirPlay / Bluetooth A2DP / HFP für Testsignale über externe Lautsprecher, ohne externe Ausgabe wird der Lautsprecher erzwungen. Der Aufnahmeeingang ist immer explizit auf die Nutzerwahl gepinnt (USB-Mikrofon oder intern), damit das Mikrofon eines Bluetooth-Geräts während der Wiedergabe nicht den Eingang kapert und die Messung verunreinigt.

§ 07

Visualisierung & Ausgabe

7.1 3D-Ansicht

Room3DController rendert mit SceneKit: Wände / Boden / Decke / Lautsprecher (dünnes Gehäuse + Akzent + Kanal-Pille) / Hörer (FE-Glyph + Stiel) / Hindernisse (transluzente SCNBox) / empfohlene Panels / Mehrfachreflexions-Pfadsegmente / Reflexionsenergie-Overlay.

DESIGN · TECHNISCHE ZEICHNUNG „Technische-Zeichnung“-Stil (feine Kanten, konstante Beleuchtung, kein PBR), bewusst anders als fotorealistisches 3D.

7.2 Reflexionsenergie-Heatmap

ReflectionEnergyMapGenerator akkumuliert die Energie jedes Pfads auf das uCells × vCells-Raster der Wand (Standard 12×6). Eine Karte je Wand, in 3D als Energie-Farbschicht (Blau → Cyan → Grün → Gelb → Rot).

EnergyHeatmapRenderer wandelt das Raster in ein UIImage: Block-Zellen à 16 px (keine Interpolation zwischen Zellen, damit Rasterkanten lesbar bleiben; die Glättung an der Wand übernimmt SceneKits bilineare Texturfilterung) + eigener 5-Stufen-Farbverlauf (Blau → Cyan → Grün → Gelb → Rot) + Alpha linear von 0,20 bis 0,85 nach Energieposition auf fester −30…0-dB-Skala (−∞ voll transparent).

7.3 RIR-Faltungs-Vorschau

RIRPreviewPlayer (AVAudioEngine + AVAudioPlayerNode) faltet ein prozedural synthetisiertes Trockensignal (gezupfte Saite / Klatsch-Burst / vokalartige Sprache — keine mitgelieferten Samples) mit dem simulierten RIR — hörbar „unbehandelt vs. behandelt“.

Zeitbereichs-Faltung RIRConvolver.convolve(dry:rir:) direkt O(N × M) (N = trockene Samples, M = RIR), Peak-normiert auf 0,9 gegen Clipping.

7.4 PDF-Montagehandbuch

ReportExporter rendert ein A4-PDF (595 × 842 pt) via UIGraphicsPDFRenderer:

  • Raumübersicht + 3D-Schnappschuss
  • 6-Band-RT60-Balkendiagramm Sabine-Schätzung vs. Ziel (gemessenes RT60 fließt nicht ins PDF)
  • Reflexionspunkt-Tabelle + Moden-Tabelle + Risikoübersicht
  • Empfohlene-Panel-Tabelle (die BOM-Einkaufsliste erscheint in der App, nicht im PDF)
  • Geist-Schrift + PingFangSC-Fallback (CoreText cascadeList, damit CJK nicht als □□□ erscheint)

7.5 Projekt-Persistenz

ProjectStore (Actor) schreibt ~/Library/Application Support/Acouvero/projects.json: [RoomProject], je mit Room + Lautsprechern + Hörern + Empfehlungen + panelCountOverrides. Beim ersten Start migrieren Daten automatisch aus dem alten Verzeichnis FindEcho/ (FindEcho ist der interne Codename vor der Umbenennung, in Codesymbolen bewusst beibehalten).

MeasurementStore (Actor) schreibt measurements.json: [MeasurementResult], per roomId mit dem Projekt verknüpft.

Beide nutzen elementweise Decode-Wiederherstellung (Throwable<T>-Wrapper) — ein defekter Datensatz lässt nicht die ganze Liste scheitern.

MicCalibrationStore schreibt ~/Library/Application Support/mic_calibration.json (Wurzelverzeichnis, kein Unterordner): REW-Kalibrierkurve + SPL-Offset, an die Eingangsport-UID gebunden — bei Eingangswechsel ist erneutes Importieren / Kalibrieren nötig.

§ 08

Engineering-Hinweise

8.1 SwiftUI + @Observable

Das ViewModel (FindEchoViewModel) nutzt Swift 5.9 @Observable — Statusfelder direkt beobachtet, kein Combine. AcousticAnalysis-Ergebnisse werden per Equatable-Vergleich von AcousticConfiguration gecacht:

FindEchoViewModel.analysisswift
var analysis: AcousticAnalysis {
    let cfg = configuration
    if let cached = cachedAnalysis, cachedConfiguration == cfg {
        return cached
    }
    let result = analysisService.analyze(cfg)
    cachedConfiguration = cfg
    cachedAnalysis = result
    return result
}

8.2 Actor-Isolation

ProjectStore und MeasurementStore sind actors, die IO / Async natürlich serialisieren; RoomPlanService ist eine @MainActor-Klasse. Die UI nutzt async / await; der Hauptthread wird nie durch Disk-IO blockiert.

8.3 AVAudio-Lebenszyklus

AudioSessionManager zentralisiert die Session-Kategorie (.playback für RIR-Vorschau, .playAndRecord für Messung). Unterbrechungsschutz gibt es auf beiden Pfaden: messseitig lauscht ein InterruptionMonitor in AudioMeasurementService auf AVAudioSession.interruptionNotification — ein Anruf / Siri während Sweep, Klatschen oder Umgebungsrauschen verwirft das Ergebnis mit Fehler; vorschauseitig hört RIRPreviewPlayer ebenfalls zu und stoppt den Player-Node, isPlaying wird gelöscht. Auch ein Routenwechsel mitten in der Messung verwirft den Lauf.

8.4 Task-Abbruch

Die Faltungs-Wiedergabe ist ein Hintergrund-Task; schnelle Taps lösen pendingPlayTask?.cancel() plus Task.isCancelled-Doppelprüfung aus, um Out-of-order-MainActor-Schreibvorgänge zu verhindern.

8.5 Testabdeckung

AllShapesAndUseCasesTests nutzt das Swift-Testing-Framework für die volle Matrix — jede Form × jeder Anwendungsfall (ein Hörer; Lautsprecher je nach Fall als Stereopaar oder einzeln mittig) — und prüft:

  • analysis.reflectionPaths.count >= 1
  • analysis.warnings enthält den Näherungshinweis für nicht rechteckige Räume
  • die empfohlene Panel-Summe ist nicht negativ (totalPanelCount ≥ 0; keine Budget-Assertion)
  • selbstschneidende eigene Polygone fallen sicher zurück (kein Crash, Degradierung zum Rechteck)
  • Ecken &lt; 3 und weitere Randfall-Rückfälle

8.6 Plattform & Lokalisierung

Deployment-Target iOS 17.0, iPhone + iPad; null Drittanbieter-Abhängigkeiten (keine SPM- / CocoaPods-Pakete) — nur System-Frameworks (SwiftUI / SceneKit / ARKit / RoomPlan / AVFoundation / Accelerate). Lokalisierung per .xcstrings-Katalog: Chinesisch als Quellsprache plus English / Français / Deutsch / Español / Português (Brasil) — 6 Sprachen, in der App oder systemfolgend umschaltbar.

§ 09

Bekannte Grenzen

  1. Multi-Order in nicht rechteckigen Räumen via Bounding Box — Flutter-/Slapback-Risiko 2./3. Ordnung nahe konkaven Ecken kann abweichen. Erste Ordnung nutzt das echte Polygon.
  2. Raummoden in nicht rechteckigen Räumen via Bounding Box geschätzt — exakte Moden brauchen FEM.
  3. Messung mit iPhone-Mikrofon — unkalibriert; nicht-flacher Frequenzgang / Empfindlichkeit. Zuverlässigkeit immer .low, als Quervergleich zur geometrischen Schätzung. Mit einem USB-Messmikrofon (miniDSP UMIK-1 / UMIK-2) und geladener REW-Kalibrierdatei werden die Bandpegel gemäß Kalibrierkurve korrigiert; eine einmalige 94-dB-SPL-Referenz zeigt danach Umgebungs- und Messpegel als absolute dB SPL (vorher nur dBFS).
  4. Einzelquellen-ISM-Annahme — ignoriert Gehäusebeugung, Horn-Richtwirkung u. a.
  5. Keine Bassfallen-Modellierung — Probleme unter 80 Hz liegen außerhalb des Sabine-Modells und brauchen dedizierte Tieftonbehandlung.
  6. AR-Scan-Genauigkeit — RoomPlan-Endpunkte typ. 3-8 cm Fehler; 12-Segment-Schleife kann 5+ cm akkumulieren. Wanddicke nicht modelliert.
§ 10

Referenzen

  1. Sabine, W. C. (1922). Collected Papers on Acoustics. Harvard University Press.
  2. Allen, J. B., & Berkley, D. A. (1979). Image method for efficiently simulating small-room acoustics. JASA, 65(4), 943–950.
  3. Schroeder, M. R. (1965). New method of measuring reverberation time. JASA, 37(3), 409–412.
  4. Farina, A. (2000). Simultaneous measurement of impulse response and distortion with a swept-sine technique. Audio Engineering Society Convention 108.
  5. Scheibler, R., Bezzam, E., & Dokmanić, I. (2018). Pyroomacoustics: A Python package for audio room simulation and array processing algorithms. ICASSP 2018.
  6. EBU Tech 3276. Listening conditions for the assessment of sound programme material.
  7. ITU-R BS.1116. Methods for the subjective assessment of small impairments in audio systems.
  8. BB93 — Acoustic design of schools (UK).
  9. THX Pro Cinema Certification requirements.
Lieber die einfache Version?

„Warum dein Raum die Musik umschreibt“

Deep Read lesen