Hello,
I've discovered a buffer initialization bug in AVAudioUnitSampler that happens when loading presets with multiple zones referencing different regions in the same audio file (monolith/concatenated samples approach). Almost all zones output silence (i.e. zeros) at the beginning of playback instead of starting with actual audio data.
The Problem
Setup:
- Single audio file (monolith) containing multiple concatenated samples
- Multiple zones in an .aupreset, each with different
sample startandsample endvalues pointing to different regions of the same file - All zones load successfully without errors
Expected Behavior: All zones should play their respective audio regions immediately from the first sample.
Actual Behavior:
- Last zone in the zone list: Works perfectly - plays audio immediately
- All other zones: Output
[0, 0, 0, 0, ..., _audio_data]instead of[real_audio_data] - The number of zeros varies from event to event for each zone. It can be a couple of samples (<30) up to several buffers.
- After the initial zeros, the correct audio plays normally, so there is no shift in audio playback, just missing samples at the beginning.
Minimal Reproduction
1. Create Test Monolith Audio File
Create a single Wav file with 3 concatenated 1-second samples (44.1kHz):
- Sample 1: frames 0-44099 (constant amplitude 0.3)
- Sample 2: frames 44100-88199 (constant amplitude 0.6)
- Sample 3: frames 88200-132299 (constant amplitude 0.9)
2. Create Test Preset
Create an .aupreset with 3 zones all referencing the same file:
Pseudo code
<Zone array>
<zone 1> start : 0, end: 44099, note: 60, waveform: ref_to_monolith.wav;
<zone 2> start sample: 44100, note: 62, end sample: 88199, waveform: ref_to_monolith.wav;
<zone 3> start sample: 88200, note: 64, end sample: 132299, waveform: ref_to_monolith.wav;
</Zone array>
3. Load and Test
// Load preset into AVAudioUnitSampler
let sampler = AVAudioUnitSampler()
try sampler.loadAudioFiles(from: presetURL)
// Play each zone (MIDI notes C4=60, D4=62, E4=64)
sampler.startNote(60, withVelocity: 64, onChannel: 0) // Zone 1
sampler.startNote(62, withVelocity: 64, onChannel: 0) // Zone 2
sampler.startNote(64, withVelocity: 64, onChannel: 0) // Zone 3
4. Observed Result
- Zone 1 (C4):
[0, 0, 0, ..., 0.3, 0.3, 0.3]❌ Zeros at beginning - Zone 2 (D4):
[0, 0, 0, ..., 0.6, 0.6, 0.6]❌ Zeros at beginning - Zone 3 (E4):
[0.9, 0.9, 0.9, ...]✅ Works correctly (last zone)
What I've Extensively Tested
What DOES Work
Separate files per zone:
- Each zone references its own individual audio file
- All zones play correctly without zeros
- Problem: Not viable for iOS apps with 500+ sample libraries due to file handle limitations
What DOESN'T Work (All Tested)
1. Different Audio Formats:
- CAF (Float32 PCM, Int16 PCM, both interleaved and non-interleaved)
- M4A (AAC compressed)
- WAV (uncompressed)
- SF2 (SoundFont2)
- Bug persists across all formats
2. CAF Region Chunks:
- Created CAF files with embedded region chunks defining zone boundaries
- Set zones with no
sampleStart/sampleEndin preset (nil values) - AVAudioUnitSampler completely ignores CAF region metadata
- Bug persists
3. Unique Waveform IDs:
- Gave each zone a unique waveform ID (268435456, 268435457, 268435458)
- Each ID has its own file reference entry (all pointing to same physical file)
- Hypothesized this might trigger separate buffer initialization
- Bug persists - no improvement
4. Different Sample Rates:
- Tested: 44.1kHz, 48kHz, 96kHz
- Bug occurs at all sample rates
5. Mono vs Stereo:
- Bug occurs with both mono and stereo files
Environment
- macOS: Sonoma 14.x (tested across multiple minor versions)
- iOS: Tested on iOS 17.x with same results
- Xcode: 16.x
- Frameworks: AVFoundation, AudioToolbox
- Reproducibility: 100% reproducible with setup described above
Impact & Use Case
This bug severely impacts professional music applications that need:
- Small file sizes: Monolith files allow sharing compressed audio data (AAC/M4A)
- iOS file handle limits: Opening 400+ individual sample files is not viable on iOS
- Performance: Single file loading is much faster than hundreds of individual files
- Standard industry practice: Monolith/concatenated samples are used by EXS24, Kontakt, and most professional samplers
Current Impact:
- Cannot use monolith files with AVAudioUnitSampler on iOS
- Forced to choose between: unusable audio (zeros at start) OR hitting iOS file limits
- No viable workaround exists
Root Cause Hypothesis
The bug appears to be in AVAudioUnitSampler's internal buffer initialization when:
- Multiple zones share the same source audio file
- Each zone specifies different
sampleStart/sampleEndoffsets
Key observation: The last zone in the zone array always works correctly.
This is NOT related to:
- File permissions or security-scoped resources (separate files work fine)
- Audio codec issues (happens with uncompressed PCM too)
- Preset parsing (preset loads correctly, all zones are valid)
Questions
-
Is this a known issue? I couldn't find any documentation, bug reports, or discussions about this.
-
Is there ANY workaround that allows monolith files to work with AVAudioUnitSampler?
-
Alternative APIs? Is there a different API or approach for iOS that properly supports monolith sample files?