Skip to content

Commit faac823

Browse files
authored
refactor(core): overhaul audio engine and device architecture (#72)
This commit introduces a major architectural refactoring to move away from a singleton-based (`AudioEngine.Instance`) model to a device-centric, instance-based architecture. This fundamental change enables true multi-device input and output, allowing applications to manage and switch between multiple playback and capture devices simultaneously and independently. This refactor also includes several new features, performance improvements, and critical bug fixes that are built upon the new architecture. ### Key Changes & Features - **Multi-Device Architecture**: The global `AudioEngine.Instance` and `Mixer.Master` have been removed. The new design introduces `AudioPlaybackDevice`, `AudioCaptureDevice`, and `FullDuplexDevice` abstractions, each managing its own audio graph and `MasterMixer`. - **Explicit Context**: Core components now receive `AudioEngine` and `AudioFormat` context via their constructors, removing implicit dependencies on global state. - **Device Switching API**: A new, robust `Engine.SwitchDevice()` API allows for seamless hot-swapping of active audio devices while preserving their state (e.g., attached components or event subscribers). - **New `VoiceIsolationEffect`**: Adds an experimental modifier that acts as a band-pass filter to help isolate human speech frequencies. - **New `MultiEngines` Sample**: A new sample project is included to demonstrate and test the new multi-device capabilities. ### Fixes & Performance Improvements - **fix(network)**: Refactored `NetworkDataProvider` to use a chunked streaming and decoding model, resolving excessive memory usage. Memory consumption for a 15-minute audio file is reduced from ~1GB to ~20MB. - **fix(recording)**: Corrects a critical audio format conversion bug that produced garbled audio when recording to formats other than F32. - **refactor(native)**: Unified the FFT implementations in `MathHelper` for Scalar, SSE, and AVX paths to ensure consistent behavior. The SIMD paths are now toggleable via static properties for easier debugging. - **refactor(interop)**: The native device configuration layer now uses a comprehensive DTO, allowing for more granular control over backend-specific settings (WASAPI, ALSA, etc.). BREAKING CHANGE: This is a fundamental architectural change that affects the entire public API. - `AudioEngine.Instance` is removed. An `AudioEngine` must now be instantiated (e.g., `new MiniAudioEngine()`). - Audio is no longer played by adding components to `Mixer.Master`. Users must first initialize a device (e.g., `engine.InitializePlaybackDevice(...)`) and then add components to the device's `MasterMixer`. - Constructors for nearly all `SoundComponent`, `ISoundDataProvider`, `SoundModifier`, and `AudioAnalyzer` derivatives have changed. They now require an `AudioEngine` and/or `AudioFormat` instance to be passed in. - The global `AudioEngine.OnAudioProcessed` event is removed. Events for processed audio are now available on a per-device basis (e.g., `AudioCaptureDevice.OnAudioProcessed`). - The previous `SwitchDevice` API is replaced with new, more explicit methods on the `AudioEngine` instance that return a new device object.
1 parent 8393338 commit faac823

File tree

144 files changed

+5713
-3685
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+5713
-3685
lines changed

.github/workflows/build.yml

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -285,19 +285,19 @@ jobs:
285285
if: matrix.platform == 'Linux'
286286
run: |
287287
sudo apt-get update
288-
sudo apt-get install -y cmake gcc g++
288+
sudo apt-get install -y cmake gcc g++ file binutils
289289
290290
- name: Install Dependencies (Android)
291291
if: matrix.platform == 'Android'
292292
uses: android-actions/setup-android@v2
293-
293+
294294
- name: Install Cross-Compilation tools (Linux)
295295
if: matrix.platform == 'Linux' && (matrix.arch == 'armv7l' || matrix.arch == 'aarch64')
296296
run: |
297297
sudo apt-get update
298298
sudo apt-get install -y qemu-user-static
299299
if [ "${{ matrix.arch }}" == "armv7l" ]; then
300-
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
300+
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf
301301
elif [ "${{ matrix.arch }}" == "aarch64" ]; then
302302
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
303303
fi
@@ -389,44 +389,70 @@ jobs:
389389
fi
390390
391391
# Dependency analysis
392-
- name: Analyze Dependencies (Windows)
392+
- name: Analyze Dependencies and Exports (Windows)
393393
if: matrix.platform == 'Windows'
394394
shell: powershell
395395
run: |
396-
Write-Host "Dependencies for Windows:"
397-
& "$env:DUMPBIN_PATH\dumpbin.exe" /DEPENDENTS "runtimes/${{ matrix.rid }}/native/miniaudio.dll"
396+
$libPath = "runtimes/${{ matrix.rid }}/native/miniaudio.dll"
397+
Write-Host "--- Dependencies for $libPath ---"
398+
& "$env:DUMPBIN_PATH\dumpbin.exe" /DEPENDENTS "$libPath"
399+
Write-Host "--- Exports for $libPath ---"
400+
& "$env:DUMPBIN_PATH\dumpbin.exe" /EXPORTS "$libPath"
398401
399-
- name: Analyze Dependencies (iOS)
402+
- name: Analyze Dependencies and Exports (iOS)
400403
if: matrix.platform == 'iOS'
401404
shell: bash
402405
run: |
403-
FRAMEWORK_BINARY="runtimes/${{ matrix.rid }}/native/miniaudio.framework/miniaudio"
404-
echo "Dependencies for iOS:"
405-
otool -L "$FRAMEWORK_BINARY"
406+
LIB_PATH="runtimes/${{ matrix.rid }}/native/miniaudio.framework/miniaudio"
407+
echo "--- Dependencies for iOS ---"
408+
otool -L "$LIB_PATH"
409+
echo "--- Symbols ---"
410+
nm -g "$LIB_PATH" | grep " T "
406411
407-
- name: Analyze Dependencies (Android)
412+
- name: Analyze Dependencies and Exports (Android)
408413
if: matrix.platform == 'Android'
409414
shell: bash
410415
run: |
411416
LIB_PATH="runtimes/${{ matrix.rid }}/native/libminiaudio.so"
412-
echo "Dependencies for Android:"
417+
echo "--- Dependencies for Android ---"
413418
readelf -d "$LIB_PATH"
419+
echo "--- Symbols ---"
420+
nm -g "$LIB_PATH" | grep " T "
414421
415-
- name: Analyze Dependencies (Linux)
422+
- name: Analyze Dependencies and Exports (Linux)
416423
if: matrix.platform == 'Linux'
417424
shell: bash
418425
run: |
419426
LIB_PATH="runtimes/${{ matrix.rid }}/native/libminiaudio.so"
420-
echo "Dependencies for Linux (${{ matrix.arch }}):"
421-
readelf -d "$LIB_PATH" || echo "Analysis failed - binary may be invalid"
427+
echo "=== Library Information ==="
428+
file "$LIB_PATH"
429+
430+
echo -e "\n=== Dependencies ==="
431+
if [[ "${{ matrix.arch }}" == "x86_64" ]]; then
432+
ldd "$LIB_PATH" || true
433+
else
434+
readelf -d "$LIB_PATH" | grep "NEEDED" || true
435+
fi
436+
437+
echo -e "\n=== Symbols ==="
438+
if [[ "${{ matrix.arch }}" == "x86_64" || "${{ matrix.arch }}" == "aarch64" ]]; then
439+
nm -g "$LIB_PATH" | grep " T " || true
440+
else
441+
arm-linux-gnueabihf-nm -g "$LIB_PATH" | grep " T " || true
442+
fi
443+
444+
echo -e "\n=== SONAME ==="
445+
readelf -d "$LIB_PATH" | grep "SONAME" || true
422446
423-
- name: Analyze Dependencies (macOS)
447+
- name: Analyze Dependencies and Exports (macOS)
424448
if: matrix.platform == 'macOS'
425449
shell: bash
426450
run: |
427451
LIB_PATH="runtimes/${{ matrix.rid }}/native/libminiaudio.dylib"
428-
echo "Dependencies for macOS:"
452+
echo "--- Dependencies for macOS ---"
429453
otool -L "$LIB_PATH"
454+
echo "--- Symbols ---"
455+
nm -g "$LIB_PATH" | grep " T "
430456
431457
- name: Upload Artifact
432458
uses: actions/upload-artifact@v4

0 commit comments

Comments
 (0)