Loading Audio

Learn how to load and manage audio sources in flutter_soloud

Overview

flutter_soloud provides multiple ways to load audio content:

  • ๐Ÿ“‚ Local files
  • ๐Ÿ“ฆ Assets
  • ๐ŸŒ Network URLs
  • ๐Ÿ’พ Memory buffers
  • ๐Ÿ”€ Stereo buffer joining (joinTwoSources)
  • ๐ŸŒŠ Generated waveforms

Audio Source Management

Each loaded sound returns an AudioSource that must be managed:

dart
// Load and store the audio source
final sound = await SoLoud.instance.loadFile('path/to/sound.mp3');

// Use the sound multiple times
final handle1 = await SoLoud.instance.play(sound);
final handle2 = await SoLoud.instance.play(sound);

// Clean up when no longer needed
await SoLoud.instance.disposeSource(sound);

Listening for Handle Events

You can listen for events related to playback handles using the sound.soundEvents stream. This allows you to react to changes such as when a sound finishes playing (or stopped) or is disposed.

dart
sound.soundEvents.listen((event) {
  debugPrint('Sound event: $event');
});

Each event is a record containing the following:

  • SoundEventType โ€“ the type of event (see below)
  • AudioSource โ€“ the source associated with the event
  • SoundHandle โ€“ the handle for the specific playback instance

The SoundEventType enum includes:

dart
/// Types of sound events
enum SoundEventType {
  /// The handle has reached the end of playback and is no longer valid
  handleIsNoMoreValid,

  /// The audio source has been disposed
  soundDisposed,
}

Listen for all handles to finish and cleanup

Listen to allInstancesFinished to automatically dispose when all instances complete:

dart
final sound = await SoLoud.instance.loadFile('path/to/sound.mp3');
sound.allInstancesFinished.first.then((_) {
  SoLoud.instance.disposeSource(sound);
});
await SoLoud.instance.play(sound);

Automatic Disposal

All load* methods support an autoDispose parameter that automatically disposes the audio source when all its handles have finished playing. This eliminates the need to manually call disposeSource.

dart
// This sound will be automatically disposed when playback finishes
final sound = await SoLoud.instance.loadFile(
  'path/to/sound.mp3',
  autoDispose: true,
);
await SoLoud.instance.play(sound);
// No need to call disposeSource - it happens automatically!

Querying Source and Temporary File Paths

You can inspect the loaded source identifier and any temporary file path directly from the AudioSource:

  • sound.soundPath: Stores the parameter used to load the audio:
    • For loadFile(), loadMem(), and joinTwoSources(): the path argument.
    • For loadAsset(): the asset key (e.g. 'assets/sound.mp3').
    • For loadUrl(): the network url (e.g. 'https://example.com/sound.mp3').
    • For generated sources (loadWaveform(), speechText()): an empty string ''.
  • sound.tempFilePath: Stores the path of the temporary file created on disk when loading an asset or URL on native platforms. For loadFile(), loadMem(), generated sources, or on the Web platform, this is an empty string ''.
dart
final sound = await SoLoud.instance.loadAsset('assets/audio/laser.mp3');

// Prints the asset key
debugPrint('Loaded asset: ${sound.soundPath}'); // assets/audio/laser.mp3

// Prints the local temporary cached file path (on native platforms)
debugPrint('Temp cache file: ${sound.tempFilePath}');

Loading Methods

You can load audio in several ways, depending on your source and platform requirements. Below are the available methods:

From Files

Load audio directly from a file path.

dart
final sound = await SoLoud.instance.loadFile(
  '/path/to/sound.mp3',
  mode: LoadMode.memory, // Default
);

Memory modes:

  • LoadMode.memory โ€“ Loads the entire file into RAM (better performance for small files)
  • LoadMode.disk โ€“ Streams from disk (lower memory usage, suitable for large files)

From Memory

Load audio from a byte buffer, such as data read from a file, asset, network or self-made wav file.

dart
final bytes = await File('sound.mp3').readAsBytes();
final sound = await SoLoud.instance.loadMem(
  'reference_name.mp3',
  bytes,
  mode: LoadMode.memory,
);

From Assets

Load audio from bundled assets in your Flutter project.

dart
final sound = await SoLoud.instance.loadAsset(
  'assets/sound.mp3',
  mode: LoadMode.memory,
  assetBundle: rootBundle, // Optional
);

From Network

Load audio directly from a network URL.

dart
final sound = await SoLoud.instance.loadUrl(
  'https://example.com/sound.mp3',
  mode: LoadMode.memory,
  httpClient: client, // Optional custom client
);

Joining Two Buffers into Stereo (joinTwoSources)

You can load two separate audio byte buffers and join them into a single stereo AudioSource in memory.

dart
final leftBytes = await File('left_track.wav').readAsBytes();
final rightBytes = await File('right_track.wav').readAsBytes();

final stereoSound = await SoLoud.instance.joinTwoSources(
  'reference_name_stereo',
  leftBytes,
  rightBytes,
  autoDispose: false, // Optional: auto-dispose when playback completes
);

final handle = SoLoud.instance.play(stereoSound);

Key behavior of joinTwoSources():

  • Mono conversion: If either buffer contains non-mono channels, it is converted to mono on the native side before joining.
  • Engine resampling: Both audio buffers are automatically resampled to the player engine's sample rate, eliminating any real-time resampling during mixer playback.
  • Length matching: If the buffers have different lengths, the resulting audio length matches the longer buffer, and the shorter buffer is automatically padded with silence.
  • Memory mode: Always loads completely into RAM (LoadMode.memory).

Format Support

Supported audio formats:

FormatExtensionDescription
MP3.mp3Most common compressed format
WAV.wavUncompressed PCM audio
OGG.oggFree compressed format
FLAC.flacLossless compression

Best Practices

Memory Management

  • Reuse loaded sounds instead of loading multiple times
  • Dispose sounds when no longer needed
  • Use LoadMode.disk for large background music files
  • Use LoadMode.memory for sound effects needing quick access

Performance

  • Load frequently used sounds at app startup
  • Consider memory constraints when loading multiple files
  • Use appropriate load modes based on usage patterns
  • Implement proper error handling for all load operations

When you need to load multiple audio files at once, it is recommended to use the wait method in a Future list, which will load 20 to 40% faster.

dart
final sounds = await [
  SoLoud.instance.loadAsset('your/asset/sound1.mp3'),
  SoLoud.instance.loadAsset('your/asset/sound2.mp3'),
  SoLoud.instance.loadAsset('your/asset/sound3.mp3'),
  [...]
].wait;

Error Handling

dart
try {
  final sound = await SoLoud.instance.loadFile('path/to/sound.mp3');
} on SoLoudNotInitializedException {
  print('Initialize SoLoud first');
} on SoLoudFileLoadFailedException {
  print('Could not load audio file');
} catch (e) {
  print('Unexpected error: $e');
}