Skip to main content

SonixLessonSynthesizer

Synthesize audio lessons from note sequences (e.g. Sa Re Ga in Indian classical practice), each with its own audio recording.

Quick Start

Kotlin

val notes = listOf(
LessonNote(
noteName = "Sa",
noteLabel = "S",
noteAudioFilePath = "/path/to/sa.wav",
numBeats = 2,
numSamplesConsonant = 100
),
LessonNote(
noteName = "Re",
noteLabel = "R",
noteAudioFilePath = "/path/to/re.wav",
numBeats = 2,
numSamplesConsonant = 100
)
)

val synth = SonixLessonSynthesizer.create(
notes = notes,
beatLengthMs = 500
)

if (synth.loadAudioSync()) {
val audioData: AudioRawData? = synth.synthesize()
// audioData is ready to play or save
}

synth.release()

Swift

let notes = [
LessonNote(
noteName: "Sa",
noteLabel: "S",
noteAudioFilePath: "/path/to/sa.wav",
numBeats: 2,
numSamplesConsonant: 100
),
LessonNote(
noteName: "Re",
noteLabel: "R",
noteAudioFilePath: "/path/to/re.wav",
numBeats: 2,
numSamplesConsonant: 100
)
]

let synth = SonixLessonSynthesizer.create(
notes: notes,
beatLengthMs: 500
)

if await synth.loadAudio() {
if let audioData = synth.synthesize() {
// audioData is ready to play or save
}
}

synth.release()

Configuration

Factory Method

ParameterTypeDefaultDescription
notesList<LessonNote>Note sequence (required)
beatLengthMsIntBeat duration in milliseconds (required)

Builder

For advanced configuration:

Kotlin

val synth = SonixLessonSynthesizer.Builder()
.notes(noteList)
.beatLengthMs(500)
.silenceBeats(start = 2, end = 2)
.sampleRate(44100)
.onError { error -> println("Error: $error") }
.build()

Builder Parameters

MethodTypeDefaultDescription
notesList<LessonNote>Note sequence (required)
beatLengthMsIntBeat duration in ms (required)
silenceBeatsstart: Int, end: Int2, 2Silence beats at start/end
sampleRateInt16000Output sample rate in Hz
onError(String) -> UnitError callback

Workflow

The synthesis process has two steps:

1. Load Audio

Load note audio files into memory:

// Suspending (preferred)
val success = synth.loadAudio()

// Synchronous (blocking)
val success = synth.loadAudioSync()

2. Synthesize

Generate the lesson track:

val audioData: AudioRawData? = synth.synthesize()
if (audioData != null) {
// Play it
val player = SonixPlayer.createFromPcm(
data = audioData.audioData,
sampleRate = audioData.sampleRate,
channels = audioData.numChannels
)
player.play()
}

Observing State

Kotlin (StateFlow)

synth.isLoading.collect { loading ->
progressBar.isVisible = loading
}

synth.isLoaded.collect { loaded ->
synthesizeButton.isEnabled = loaded
}

synth.error.collect { error ->
error?.let { showError(it.message) }
}

Swift (Observers)

let loadingTask = synth.observeIsLoading { loading in
self.isLoading = loading
}

let loadedTask = synth.observeIsLoaded { loaded in
self.isReady = loaded
}

let errorTask = synth.observeError { error in
if let error = error { self.showError(error.message) }
}

Swift (Combine)

synth.isLoadingPublisher
.receive(on: DispatchQueue.main)
.sink { self.isLoading = $0 }
.store(in: &cancellables)

StateFlows

StateFlowTypeDescription
isLoadingStateFlow<Boolean>Whether audio files are being loaded
isLoadedStateFlow<Boolean>Whether ready for synthesis
errorStateFlow<SonixError?>Error state

Properties

PropertyTypeDescription
beatLengthMsIntBeat duration in milliseconds
silenceBeatsStartIntSilence beats at the start
silenceBeatsEndIntSilence beats at the end
sampleRateIntOutput sample rate

LessonNote

Each note in the sequence is defined by:

PropertyTypeDescription
noteNameStringFull name (e.g., "Sa", "Re")
noteLabelStringShort label (e.g., "S", "R")
noteAudioFilePathStringPath to audio recording
numBeatsIntDuration in beats
numSamplesConsonantIntConsonant samples for crossfading

Method Summary

MethodReturnsDescription
loadAudio()BooleanLoad audio files (suspend / async)
loadAudioSync()BooleanLoad audio files (blocking)
synthesize()AudioRawData?Generate lesson audio
release()Release resources

Next Steps