Sonix Mixer
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
| StateFlow | Type | Description |
|---|---|---|
currentTime | Long | Current playback time in ms |
isPlaying | Boolean | True while playing |
error | SonixError? | Error state |
Platform Notes
iOS
Uses AVAudioEngine for synchronized playback
Automatically configures audio session
Android
Software-mixes all tracks into a single AudioTrack (sample-locked by construction)
Automatically configures audio focus
Common Pitfalls
addTrack is suspend: Call from coroutine or use
addTrack(name, data, rate, channels)Forgetting to release: Call
release()when doneTrack names must be unique: Adding a track with same name replaces it
Different sample rates: Tracks are automatically resampled to match
See also
For single-file playback
For click track playback
For configuration options
Types
Properties
This mixer as a PlaybackInfoProvider for recorder sync.
Number of completed loop iterations.
Current playback time in milliseconds.
Error state, null if no error.
The route this mixer's audio is currently going out on.
Functions
Audible player time for a wall moment, with the output-latency compensation for the live outputRoute subtracted (SonixPlayer.compensationForRoute) — identical to SonixPlayer.audibleTimeMsAtWallNanos. Both PlaybackController impls must apply it: the live-eval scorer anchors student frames through whichever one plays the reference, and practice plays the reference in this mixer (accompaniment + reference + shruti shift). Compensating only the bare player left the mixer path — i.e. every real practice take — uncompensated.
Fade a track's volume smoothly from current to target.
Fade a track's volume smoothly from start to end value.
Get names of all loaded tracks.
Remove a track from the mixer.
Set a listener for playback events.
Designate the reference track — typically the lesson track a live evaluator scores against. While one is set, currentTime and audibleTimeMsAtWallNanos ride the DAC-presentation clock of its playback (on Android the single mix sink all tracks share; on iOS the reference player node), so accompaniment and evaluation live on one clock. Without one, time falls back to a wall-clock estimate.
Set volume for a specific track.