Skip to main content

Lesson Bundles

A reference bundle is a directory of pre-computed reference-lesson features (audio, pitch contour, HPCP chroma, phrases) produced offline and loaded at runtime. LessonBundle.load turns a bundle directory into a LessonMaterial you hand straight to CalibraLiveEval / CalibraMelodyEval, with no pitch/chroma DSP at load time (the features are already computed).

This page is the API reference for the runtime flow. For the on-disk file contract see the Bundle Format reference; for producing bundles with the CLI see the Lesson Authoring guide.

Loading a bundle

LessonBundle.load(directoryPath) reads the manifest, validates its format version, decodes the audio at the manifest's sample rate, and reconstructs the pre-computed pitch contour and HPCP frames into a LessonMaterial.

Kotlin

import com.musicmuni.voxatrace.calibra.LessonBundle

// 1. Load a bundle directory -> LessonMaterial (features pre-computed)
val reference = LessonBundle.load("/path/to/bundle-dir")

// 2. Hand it to evaluation. The student recording is a separate LessonMaterial.
val extractor = PitchDetection.createContourExtractor(ContourExtractorConfig.SCORING)
val result = CalibraMelodyEval.evaluate(reference, student, extractor)
extractor.release()

Swift

let reference = LessonBundle.shared.load(directoryPath: "/path/to/bundle-dir")

let extractor = PitchDetection.createContourExtractor(config: .scoring)
let result = CalibraMelodyEval.evaluate(
reference: reference,
student: student,
contourExtractor: extractor
)
extractor.release()

Because the bundle ships pre-computed pitchContour and hpcpFrames, the evaluator skips contour extraction and HPCP analysis for the reference side: the loaded LessonMaterial is the fast-path input described in CalibraMelodyEval.

Load Method

object LessonBundle {
fun load(directoryPath: String): LessonMaterial
}
ParameterTypeDescription
directoryPathStringPath to the bundle folder.
ReturnsDescription
LessonMaterialReference material with pitchContour and hpcpFrames populated.
ThrowsWhen
IllegalArgumentExceptiondirectoryPath is blank, the bundle audio cannot be decoded, or the bundle's format version is newer than this SDK supports.

File-not-found / malformed-manifest surface as the underlying I/O or serialization exception.

Bundle layout

A bundle directory contains exactly these five files (all names are literal). All five are required.

FileContents
reference-meta.jsonManifest: tonic (keyHz), geometry (sampleRate / hopSize / frameSize / hpcpSize), lessonType, optional tempo.
reference-16k-mono.wavReference audio for playback (16 kHz mono 16-bit PCM WAV).
reference-pitch.tsvPre-computed pitch contour (looked up by time).
reference-hpcp.binPre-computed HPCP chroma frames (indexed by absolute frame number).
reference-phrases.jsonPhrase boundaries + note-level transcription; the segment source of truth.

The manifest's geometry must match the consuming session (ADR-017): the live evaluator indexes HPCP frames by absolute frame number, so hopSize / frameSize / sampleRate are load-bearing, not cosmetic.

lessonType (authoritative)

lessonType in the manifest is the authoritative lesson mode, and it drives how reference-phrases.json is interpreted into segments:

  • "singalong" — one phrase object per phrase; the student sings along with the reference.
  • "singafter" — each phrase is a teacher_vocal / student_vocal pair, cross-linked so the evaluator knows the expected-response window.

Producing bundles from your own code

The CLI is the usual authoring path (see the Lesson Authoring guide), but you can produce the same features from your own JVM/app code with ReferenceExtractor. It computes the reference side of a lesson into a LessonMaterial; you then serialize its pieces and write the five files above.

import com.musicmuni.voxatrace.calibra.ReferenceExtractor

val extractor = PitchDetection.createContourExtractor(
ContourExtractorConfig(algorithm = PitchAlgorithm.MELODIA) // octave-robust
)
val material = ReferenceExtractor.extract(
samples = referenceSamples, // mono; resampled to 16 kHz internally
sampleRate = 44100,
segments = phraseSegments,
keyHz = 196f,
contourExtractor = extractor
)
extractor.release()
// material.pitchContour and material.hpcpFrames are now populated.
// Serialize with SonixWriter.formatPitchString / formatHpcp / formatTransString,
// write reference-meta.json + reference-16k-mono.wav, and you have a bundle.

Extract Method

fun extract(
samples: FloatArray,
sampleRate: Int,
segments: List<Segment>,
keyHz: Float,
contourExtractor: PitchContourExtractor,
config: ReferenceExtractorConfig = ReferenceExtractorConfig.DEFAULT
): LessonMaterial
ParameterTypeDescription
samplesFloatArrayReference audio, mono. Resampled to 16 kHz internally (ADR-017).
sampleRateIntSample rate of samples in Hz.
segmentsList<Segment>Phrase boundaries + lyrics for the lesson. Must be non-empty.
keyHzFloatTonic frequency in Hz.
contourExtractorPitchContourExtractorPitch contour extractor; caller owns the lifecycle and must release() when done.
configReferenceExtractorConfigHPCP frame geometry. Must match the consuming session.

It is an authoring helper only: it produces a LessonMaterial, never consumes one. The HPCP frames are computed at config geometry, the form the live evaluator indexes by absolute frame number.

Versioning

The bundle format is versioned independently of the SDK (held by BundleManifest.FORMAT_VERSION and stamped into every bundle the SDK writes).

  • LessonBundle.load accepts a bundle iff 1 <= version <= FORMAT_VERSION.
  • A bundle authored by a newer VoxaTrace (version > FORMAT_VERSION) is rejected with a clear error: upgrade the SDK to read it.
  • Older bundles remain readable.

Next Steps