Kotlin
Kotlin binding for the Rapidly SDK, for Android apps via Maven Central.
The Kotlin binding wraps the Rapidly SDK's native C engine in an idiomatic Kotlin class, distributed via Maven Central as an Android library. The same engine runs natively on Android. See Overview for what's inside the engine and the supported Android targets.
Install
Requirements: Android minSdk 26 (Android 8.0). The library bundles the arm64-v8a ABI.
In app/build.gradle.kts:
dependencies {
implementation("io.rapidly:rapidly-sdk:1.0")
}Alternative: .aar from GitHub Release
To vendor the binary directly instead of pulling from Maven Central, download rapidly-sdk-1.0.aar from the GitHub Release into your app's libs/ folder, then:
dependencies {
implementation(files("libs/rapidly-sdk-1.0.aar"))
}Basic usage
Import the binding:
import io.rapidly.engine.RapidlyEngineModels ship as .rapidly files. On Android, place them in your app's assets/ folder and copy to context.cacheDir on first use, then pass the filesystem path:
val modelFile = File(context.cacheDir, "speech-denoise-32ms.v1.0.rapidly")
if (!modelFile.exists()) {
context.assets.open("speech-denoise-32ms.v1.0.rapidly").use { input ->
modelFile.outputStream().use { output -> input.copyTo(output) }
}
}Create an engine by specifying the model file path, channel count, and sample rate:
val engine = RapidlyEngine.create(
modelFilepath = modelFile.absolutePath,
numOfChannels = 2,
sampleRate = 48000.0,
) ?: error("Unable to create the Rapidly engine.")create is a factory that returns null only when the model file is missing or unreadable. License coverage never causes a null result.
Audio buffers must be direct so the JNI path can read them without copying:
val inputBuffer = ByteBuffer.allocateDirect(numOfSamples * 2 * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
// Interleaved format (L1, R1, L2, R2, ...)
engine.addAudioInterleaved(inputBuffer, numOfSamples)Retrieve processed audio. Processing introduces latency, so query the number of available samples first:
val pending = engine.getNumOfPendingSamples()
engine.getAudioInterleaved(outputBuffer, pending)When finished, call close() to release the underlying processor:
engine.close()To capture the processing tail caused by model latency, add silent audio (zeros) after your input stream ends.
Threading
Drive each engine from a single thread. RapidlyEngine implements AutoCloseable, so for short offline jobs wrap construction in a use block to release native resources automatically:
RapidlyEngine.create(modelFilepath, numOfChannels = 1, sampleRate = 48000.0)
?.use { engine -> /* ... */ }For real-time audio, call close() explicitly from your audio-stop path. The JVM has no deterministic finalizer, so a forgotten close leaks the native processor until process exit.
See One vs multiple engines for the universal threading rules and the stop-then-close sequence.
Licensing
Call RapidlyEngine.addLicense before constructing any engine. See Pricing for licensing options.
if (!RapidlyEngine.addLicense("lk_...")) {
error("Rapidly license could not be verified.")
}Android specifics
Audio buffers passed to addAudio* and getAudio* must be direct FloatBuffer instances created from ByteBuffer.allocateDirect(...).order(ByteOrder.nativeOrder()).asFloatBuffer(). The JNI path reads and writes directly into the native buffer, avoiding a copy across the JVM boundary.
Model files must be on the filesystem. Ship them in your app's assets/ folder and copy to context.cacheDir on first launch.
The library ships only the arm64-v8a ABI. Emulator testing requires a physical arm64 device or an arm64 emulator image.
Types
RapidlyEngine
public class RapidlyEngine : AutoCloseableThe Kotlin-native audio engine. Implements AutoCloseable for use with use { }.
RapidlyEngine.ProcessorInfo
public data class ProcessorInfo(
val sampleRate: Double, // Sample rate the model was trained on
val numOfModelChannels: Int, // Number of channels used internally
val latencyInSamples: Int, // Maximum processing latency
)The processor automatically converts sample rates and channel formats to match the model.
RapidlyEngine.Parameters
public enum class Parameters(public val value: Int) {
MAXIMUM_ATTENUATION(0x0001),
SENSITIVITY(0x0002),
MASK_EXTRAPOLATION(0x0003),
FIRST_MODEL_SENSITIVITY(0x1000),
}For stem-separation models with multiple internal models, address an individual stem by offsetting FIRST_MODEL_SENSITIVITY.value with the model index.
Methods
Licensing
addLicense
public companion object {
@JvmStatic
public fun addLicense(licenseString: String): Boolean
}Adds a license key to remove audio watermarking from the output.
| Parameter | Description |
|---|---|
licenseString | License string issued by Rapidly. |
Returns: true if the license is valid, false otherwise.
Engine lifecycle
create(modelFilepath:numOfChannels:sampleRate:)
public companion object {
@JvmStatic
public fun create(
modelFilepath: String,
numOfChannels: Int,
sampleRate: Double,
): RapidlyEngine?
}Creates an engine and loads a single model file.
| Parameter | Description |
|---|---|
modelFilepath | Filesystem path to the .rapidly model file. |
numOfChannels | Number of audio channels to process. |
sampleRate | Sample rate of the input audio. |
Returns: A valid instance on success, null when the model file is missing or unreadable.
create(modelFilepaths:numOfChannels:sampleRate:)
public companion object {
@JvmStatic
public fun create(
modelFilepaths: List<String>,
numOfChannels: Int,
sampleRate: Double,
): RapidlyEngine?
}Creates a processor that performs stem separation, loading a set of model files. The number of stems is derived from modelFilepaths.size.
close
public override fun close()Releases the underlying processor and frees its resources. Safe to call multiple times. After close, all audio methods become no-ops and read methods return false or zero.
resetProcessorState
public fun resetProcessorState()Resets the processor state and clears all internal delay lines. Call this when starting a new audio stream.
Audio I/O
addAudio
public fun addAudio(
pcmChannels: Array<FloatBuffer>,
numOfSamples: Int,
)Adds audio from separate per-channel direct buffers.
addAudioInterleaved
public fun addAudioInterleaved(
pcmChannels: FloatBuffer,
numOfSamples: Int,
)Adds audio from an interleaved direct buffer (L1, R1, L2, R2, ...).
getNumOfPendingSamples
public fun getNumOfPendingSamples(): IntReturns the number of processed samples available for retrieval.
getAudio
public fun getAudio(
pcmChannels: Array<FloatBuffer>,
numOfSamples: Int,
): BooleanRetrieves processed audio into separate per-channel direct buffers.
getAudioInterleaved
public fun getAudioInterleaved(
pcmChannels: FloatBuffer,
numOfSamples: Int,
): BooleanRetrieves processed audio into an interleaved direct buffer.
Parameters
getParameterValue
public fun getParameterValue(parameter: Parameters): FloatReturns the current value of a parameter.
setParameter
public fun setParameter(parameter: Parameters, value: Float)Sets a parameter value.
Processor info
getProcessorInfo
public fun getProcessorInfo(): ProcessorInfoReturns a ProcessorInfo describing the processor.
Output busses
The Kotlin wrapper exposes engine-wide and per-stem-model controls through Parameters. For introspection of named output busses and per-bus gain control, use the C engine's bus methods through JNI; see the equivalent functions on the C / C++ page.