SonixMixer

Multi-track audio mixer with synchronized playback.

Quick Start

Kotlin

val mixer = SonixMixer.create()
mixer.addTrack("backing", "/path/to/backing.mp3") // Auto-decodes
mixer.addTrack("vocal", "/path/to/vocal.mp3")
mixer.play()

// Control individual tracks
mixer.setTrackVolume("vocal", 0.5f) // Reduce vocal volume
mixer.fadeTrackVolume("vocal", 0f, 2000) // Fade out over 2 seconds

// Release when done
mixer.release()

Swift

let mixer = SonixMixer.create(
config: .default,
audioSession: .playback
)
await mixer.addTrack(name: "backing", filePath: "/path/to/backing.mp3")
await mixer.addTrack(name: "vocal", filePath: "/path/to/vocal.mp3")
mixer.play()

// Control individual tracks
mixer.setTrackVolume(name: "vocal", volume: 0.5)
mixer.fadeTrackVolume(name: "vocal", targetVolume: 0, durationMs: 2000)

// Release when done
mixer.release()

Builder Pattern (Advanced)

Kotlin

val config = SonixMixerConfig.Builder()
.loopCount(3)
.onPlaybackComplete { println("All loops done!") }
.onLoopComplete { index -> println("Completed loop $index") }
.build()
val mixer = SonixMixer.create(config)

StateFlows

StateFlowTypeDescription
currentTimeLongCurrent playback time in ms
isPlayingBooleanTrue while playing
errorSonixError?Error state

Platform Notes

iOS

  • Uses AVAudioEngine for synchronized playback

  • Automatically configures audio session

Android

  • Uses AudioTrack with synchronized playback

  • Automatically configures audio focus

Common Pitfalls

  1. addTrack is suspend: Call from coroutine or use addTrack(name, data, rate, channels)

  2. Forgetting to release: Call release() when done

  3. Track names must be unique: Adding a track with same name replaces it

  4. Different sample rates: Tracks are automatically resampled to match

See also

For single-file playback

For click track playback

For configuration options

Types

Link copied to clipboard
object Companion
Link copied to clipboard

Listener interface for playback events.

Properties

Link copied to clipboard

This mixer as a PlaybackInfoProvider for recorder sync.

Link copied to clipboard

Number of completed loop iterations.

Link copied to clipboard
open override val currentTime: StateFlow<Long>

Current playback time in milliseconds.

Link copied to clipboard

Total duration in milliseconds (based on longest track).

Link copied to clipboard
val error: StateFlow<SonixError?>

Error state, null if no error.

Link copied to clipboard
open override val isPlaying: StateFlow<Boolean>

Whether playback is currently active.

Link copied to clipboard

Current loop count setting.

Link copied to clipboard

Pitch shift in semitones (tempo-preserving), applied to every track.

Functions

Link copied to clipboard
suspend fun addTrack(name: String, filePath: String): Boolean

Add track from file path (auto-decodes).

fun addTrack(name: String, data: ByteArray, sampleRate: Int, channels: Int): Boolean

Add track from raw PCM data (for advanced use cases).

Link copied to clipboard
open override fun audibleTimeMsAtWallNanos(wallNanos: Long): Long

Audible playback position (ms since playback start) at the given monotonic-nanoseconds wall moment, or -1L during pre-play / transient seek states. Same clock as currentTime; see the time contract above.

Link copied to clipboard
fun fadeTrackVolume(name: String, targetVolume: Float, durationMs: Long)

Fade a track's volume smoothly from current to target.

fun fadeTrackVolume(name: String, startVolume: Float, endVolume: Float, durationMs: Long)

Fade a track's volume smoothly from start to end value.

Link copied to clipboard

Get names of all loaded tracks.

Link copied to clipboard
fun hasTrack(name: String): Boolean

Check if a track is loaded.

Link copied to clipboard
open override fun pause()

Pause playback of all tracks.

Link copied to clipboard
open override fun play()

Start playback of all tracks.

Link copied to clipboard
open override fun release()

Release all resources.

Link copied to clipboard
fun removeTrack(name: String)

Remove a track from the mixer.

Link copied to clipboard
fun reset()

Reset playback position to the beginning without stopping.

Link copied to clipboard
open override fun seek(positionMs: Long)

Seek all tracks to a specific position.

Link copied to clipboard

Set a listener for playback events.

Link copied to clipboard

Designate the track whose DAC-presentation clock drives currentTime and audibleTimeMsAtWallNanos — typically the reference/lesson track a live evaluator scores against. Accompaniment tracks then ride the same shared clock. Without one, time falls back to a wall-clock estimate.

Link copied to clipboard
fun setTrackVolume(name: String, volume: Float)

Set volume for a specific track.

Link copied to clipboard
fun stop()

Stop playback and reset to beginning.