AIC_SDK_LICENSE setup. Check runtime and platform support in the compatibility matrix.
Use the shared quickstart recording to check the same input across languages, then substitute representative audio from your application.
Start with Quail Voice Focus for primary-speaker isolation before speech-to-text (STT). For human listening, use Rook Multi Speaker. The model reference explains model loading and selection.
SDK key authorization and usage reporting are distinct concerns. See authentication and telemetry before deploying. Downloading a model in advance does not by itself enable offline operation.
- Python
- Node.js
- Rust
- WebAssembly
- C++
- C
Installation
Use Python 3.11 for this example on a supported platform. The SDK package declares Python 3.10 or later. This example pinsaic-sdk 3.2.0 and NumPy 2.2.6. Create a project directory and a virtual environment:mkdir aic-python-quickstart
cd aic-python-quickstart
python3 -m venv .venv
source .venv/bin/activate
python -m pip install "aic-sdk==3.2.0" "numpy==2.2.6"
mkdir aic-python-quickstart
cd aic-python-quickstart
py -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install "aic-sdk==3.2.0" "numpy==2.2.6"
Quickstart
Prepare the key and input
Generate an SDK key on the developer platform. Set it in the terminal where you will run the example, replacingYOUR_SDK_KEY with your key. Keep it out of source control and shared terminal logs.export AIC_SDK_LICENSE="YOUR_SDK_KEY"
$env:AIC_SDK_LICENSE = "YOUR_SDK_KEY"
input.wav in aic-python-quickstart. It contains 56,080 mono PCM16 samples at 16 kHz (3.505 seconds). The fixture guide includes attribution, checksums and the aligned clean reference.For your own recording, export a short sentence with background noise as mono, 16 kHz, signed 16-bit PCM WAV. Renaming a file does not convert it.The example downloads quail-vf-2.2-l-16khz into ./models. Quail Voice Focus isolates the primary speaker for speech-to-text (STT) input. The first run needs network access for the model download and SDK key authorization. See authentication for deployment options.Save and run
Save this complete program asquickstart.py in the same directory:quickstart.py
import os
from pathlib import Path
import sys
import wave
import aic_sdk as aic
import numpy as np
def main():
license_key = os.environ.get("AIC_SDK_LICENSE")
if not license_key or license_key == "YOUR_SDK_KEY":
raise ValueError("Set AIC_SDK_LICENSE to your SDK key, then retry.")
with wave.open("input.wav", "rb") as source:
if (source.getnchannels(), source.getframerate(), source.getsampwidth()) != (1, 16000, 2):
raise ValueError("Export input.wav as mono, 16 kHz, 16-bit PCM WAV, then retry.")
frames = source.getnframes()
raw = source.readframes(frames)
if len(raw) != frames * 2:
raise ValueError("input.wav is truncated. Export the complete recording, then retry.")
audio = np.frombuffer(raw, dtype="<i2").astype(np.float32) / 32768.0
if audio.size == 0:
raise ValueError("input.wav is empty. Record speech, then retry.")
model_path = aic.Model.download("quail-vf-2.2-l-16khz", Path("models"))
model = aic.Model.from_file(model_path)
config = aic.ProcessorConfig.optimal(model, sample_rate=16000)
processor = aic.Processor(model, license_key)
try:
processor.initialize(config)
delay = processor.get_context().get_audio_delay()
# Pad the last block and flush the delayed tail with silence.
padded_size = ((audio.size + delay + config.block_size - 1) // config.block_size) * config.block_size
padded = np.zeros(padded_size, dtype=np.float32)
padded[:audio.size] = audio
output = np.empty_like(padded)
for start in range(0, padded_size, config.block_size):
end = start + config.block_size
# Python returns a new array; the input block is unchanged.
output[start:end] = processor.process(padded[start:end])
enhanced = output[delay:delay + audio.size]
if not np.isfinite(enhanced).all():
raise ValueError("Processing returned non-finite samples; no output was written.")
pcm = (np.clip(enhanced, -1.0, 32767 / 32768) * 32768).astype("<i2")
with wave.open("enhanced.wav", "wb") as destination:
destination.setnchannels(1)
destination.setsampwidth(2)
destination.setframerate(16000)
destination.writeframes(pcm.tobytes())
print(f"SDK {aic.get_sdk_version()}, model {model.get_id()}")
print(f"Processed {audio.size} samples at 16000 Hz; wrote enhanced.wav")
finally:
processor.terminate_session()
if __name__ == "__main__":
try:
main()
except Exception as error:
message = getattr(error, "message", str(error))
print(f"{type(error).__name__}: {message}", file=sys.stderr)
sys.exit(1)
aic-python-quickstart, with the virtual environment active:python quickstart.py
Check the result
The program prints the native SDK version, resolved model ID and processed sample count. It writesenhanced.wav beside input.wav at 16 kHz with the same sample count, compensating for processing delay.With the supplied fixture, the processed sample count is 56080. Verify the file headers:python -c "import wave; a=wave.open('input.wav'); b=wave.open('enhanced.wav'); assert a.getparams()[:4] == b.getparams()[:4]; print('PASS: matching channels, bit depth, sample rate and frame count'); a.close(); b.close()"
Recover from an error
| Problem | Cause and retry |
|---|---|
| Package installation fails | Check python --version and the compatibility matrix. Activate the virtual environment and rerun the pinned installation. |
Missing key or LicenseFormatInvalidError | Set AIC_SDK_LICENSE in this terminal to the complete SDK key from the developer platform, then rerun python quickstart.py. |
LicenseExpiredError or ProcessingNotAllowedError | Check key validity, account entitlement and required connectivity in authentication. Correct the cause and restart the program with a new processor. |
Missing or invalid input.wav | Save a nonempty mono, 16 kHz, signed 16-bit PCM WAV in the current directory, then rerun the program. |
| Model download or load fails | Check connectivity, write access to ./models and the exact model ID. For manual model files, check the model format version. Retry the download after fixing the cause. |
AudioConfigMismatchError | Keep every call at config.block_size samples. The example pads the final block; do not pass a short final slice with fixed block sizes. |
Adapt this example
Use one processor per independent stream and retain it between consecutive blocks. Reset its context when seeking or starting unrelated audio. Downmix stereo input or give each channel its own processor. See audio format, streams and state and the Python binding guide for async processing and lifecycle details.This example reads the full file into memory. For live audio or long files, process bounded blocks and keep file I/O, model downloads and session termination outside the audio callback. For human listening, evaluate Rook Multi Speaker.Installation
Use Node.js 22 for this example. The package declares Node.js 18 or later; see the compatibility matrix for native platform support. Create an isolated project and install the pinned SDK and WAV reader:mkdir aic-node-quickstart
cd aic-node-quickstart
npm init -y
npm install --save-exact @ai-coustics/aic-sdk@0.24.0 wavefile@11.0.0
Quickstart
Prepare the key and input
Generate an SDK key on the developer platform. Set it in the terminal where you will run the example, replacingYOUR_SDK_KEY with your key. Keep it out of source control and shared terminal logs.export AIC_SDK_LICENSE="YOUR_SDK_KEY"
$env:AIC_SDK_LICENSE = "YOUR_SDK_KEY"
input.wav in aic-node-quickstart. It contains 56,080 mono PCM16 samples at 16 kHz (3.505 seconds). The fixture guide includes attribution, checksums and the aligned clean reference.For your own recording, export a short sentence with background noise as mono, 16 kHz, signed 16-bit PCM WAV. Renaming a file does not convert it.The example downloads quail-vf-2.2-l-16khz into ./models. Quail Voice Focus isolates the primary speaker for speech-to-text (STT) input. The first run needs network access for the model download and SDK key authorization. See authentication for deployment options.Save and run
Save this complete program asquickstart.cjs. The .cjs extension makes its CommonJS module format explicit, including in projects that use "type": "module".quickstart.cjs
const fs = require("node:fs");
const { WaveFile } = require("wavefile");
const { Model, ProcessorAsync, getVersion } = require("@ai-coustics/aic-sdk");
async function main() {
const licenseKey = process.env.AIC_SDK_LICENSE;
if (!licenseKey || licenseKey === "YOUR_SDK_KEY") {
throw new Error("Set AIC_SDK_LICENSE to your SDK key, then retry.");
}
const input = new WaveFile(fs.readFileSync("input.wav"));
if (input.fmt.numChannels !== 1 || input.fmt.sampleRate !== 16000 || input.bitDepth !== "16") {
throw new Error("Export input.wav as mono, 16 kHz, 16-bit PCM WAV, then retry.");
}
if (input.data.samples.length !== input.data.chunkSize) {
throw new Error("input.wav is truncated. Export the complete recording, then retry.");
}
input.toBitDepth("32f");
const audio = input.getSamples(false, Float32Array);
if (audio.length === 0) {
throw new Error("input.wav is empty. Record speech, then retry.");
}
const modelPath = await Model.download("quail-vf-2.2-l-16khz", "./models");
const model = Model.fromFile(modelPath);
let processor;
try {
const blockSize = model.getOptimalBlockSize(16000);
processor = new ProcessorAsync(model, licenseKey);
await processor.initialize(16000, blockSize, false);
const context = await processor.getContext();
const delay = context.getAudioDelay();
// Pad the last block and flush the delayed tail with silence.
const paddedSize = Math.ceil((audio.length + delay) / blockSize) * blockSize;
const padded = new Float32Array(paddedSize);
padded.set(audio);
const output = new Float32Array(paddedSize);
for (let start = 0; start < paddedSize; start += blockSize) {
// Await each block to preserve stream order. Async processing returns a new array.
const enhanced = await processor.process(padded.subarray(start, start + blockSize));
output.set(enhanced, start);
}
const enhanced = output.subarray(delay, delay + audio.length);
if (!enhanced.every(Number.isFinite)) {
throw new Error("Processing returned non-finite samples; no output was written.");
}
const pcm = Int16Array.from(enhanced, (sample) =>
Math.trunc(Math.max(-1, Math.min(32767 / 32768, sample)) * 32768)
);
const result = new WaveFile();
result.fromScratch(1, 16000, "16", pcm);
fs.writeFileSync("enhanced.wav", result.toBuffer());
console.log(`SDK ${getVersion()}, model ${model.getId()}`);
console.log(`Processed ${audio.length} samples at 16000 Hz; wrote enhanced.wav`);
} finally {
// All processing promises above have settled before native resources are released.
if (processor) processor.dispose();
model.dispose();
}
}
main().catch((error) => {
console.error(`Error: ${error.message}`);
process.exitCode = 1;
});
aic-node-quickstart:node quickstart.cjs
Check the result
The program prints the native SDK version, resolved model ID and processed sample count. It writesenhanced.wav beside input.wav at 16 kHz with the same sample count, compensating for processing delay.With the supplied fixture, the processed sample count is 56080. Verify the file headers:node -e "const fs=require('node:fs'); const {WaveFile}=require('wavefile'); const a=new WaveFile(fs.readFileSync('input.wav')); const b=new WaveFile(fs.readFileSync('enhanced.wav')); for (const k of ['numChannels','sampleRate','bitsPerSample']) if(a.fmt[k]!==b.fmt[k]) throw Error(k+' differs'); if(a.getSamples().length!==b.getSamples().length) throw Error('sample count differs'); console.log('PASS: matching channels, bit depth, sample rate and frame count');"
Recover from an error
| Problem | Cause and retry |
|---|---|
| Native module cannot load | Check node --version and your OS/architecture against the compatibility matrix. Install in the target environment with optional dependencies enabled, then rerun node quickstart.cjs. |
| Missing or invalid SDK key | Set AIC_SDK_LICENSE in this terminal to the complete SDK key from the developer platform, then retry. |
| Processing is not allowed | Check key validity, account entitlement and required connectivity in authentication. Correct the cause and restart the program with a new processor. |
Missing or invalid input.wav | Save a nonempty mono, 16 kHz, signed 16-bit PCM WAV in the current directory, then rerun the program. |
| Model download or load fails | Check connectivity, write access to ./models and the exact model ID. For manual model files, check the model format version. Retry the download after fixing the cause. |
| Audio configuration mismatch | Keep every call at blockSize samples. The example pads the final block; do not pass a short final slice with fixed block sizes. |
Adapt this example
Use one processor per independent stream and await each operation before submitting the next block. Use separate processors for simultaneous streams;Promise.all over blocks from one stream can reorder processing. Downmix stereo input or give each channel its own processor. See audio format, streams and state and the Node.js binding guide.This example reads the full file into memory and uses synchronous file I/O. For live audio or long files, process bounded blocks and keep file I/O and model downloads outside the audio path. For human listening, evaluate Rook Multi Speaker.Installation
Use Rust with Cargo, a native linker and libclang on a supported platform. The published SDK crate declares Rust 1.88 or later. Its build script generates C bindings with libclang; install your platform’s compiler tools before building. See the released linking guide for local-library and deployment options.Create a project:cargo new aic-rust-quickstart
cd aic-rust-quickstart
Cargo.toml with the following. download-lib downloads the matching native library during the first build; it requires network access. The explicit aic-sdk-sys pin keeps the native dependency at the documented release. hound reads and writes WAV files.Cargo.toml
[package]
name = "aic-rust-quickstart"
version = "0.1.0"
edition = "2024"
[dependencies]
aic-sdk = { version = "=0.24.0", features = ["download-lib"] }
aic-sdk-sys = "=0.24.0"
hound = "=3.5.1"
Cargo.lock in your application to preserve resolved dependency versions.Quickstart
Prepare the key, model and input
Generate an SDK key on the developer platform. Set it in the terminal where you will run the program. Keep it out of source control and shared logs.export AIC_SDK_LICENSE="YOUR_SDK_KEY"
curl -fL -o model.aicmodel "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel"
$env:AIC_SDK_LICENSE = "YOUR_SDK_KEY"
Invoke-WebRequest "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel" -OutFile model.aicmodel
YOUR_SDK_KEY with your key. This pins a format-7 build of quail-vf-2.2-l-16khz. Quail Voice Focus isolates the primary speaker for speech-to-text (STT) input. Downloading the model in advance does not remove SDK key authorization requirements; see authentication.Download the noisy speech fixture and save it as input.wav in this project directory. It contains 56,080 mono PCM16 samples at 16 kHz (3.505 seconds). The fixture guide includes attribution, checksums and the aligned clean reference.For your own recording, export mono, 16 kHz, signed 16-bit PCM WAV, at most 60 seconds long. Renaming a file does not convert it.Save and run
Replacesrc/main.rs with:src/main.rs
use aic_sdk::{Model, Processor, ProcessorConfig};
use hound::{SampleFormat, WavReader, WavSpec, WavWriter};
use std::error::Error;
fn run() -> Result<(), Box<dyn Error>> {
let key = std::env::var("AIC_SDK_LICENSE")
.map_err(|_| "Set AIC_SDK_LICENSE to your SDK key, then retry.")?;
if key.is_empty() || key == "YOUR_SDK_KEY" {
return Err("Set AIC_SDK_LICENSE to your SDK key, then retry.".into());
}
let mut reader = WavReader::open("input.wav")?;
let spec = reader.spec();
if spec.channels != 1 || spec.sample_rate != 16000 || spec.bits_per_sample != 16 ||
spec.sample_format != SampleFormat::Int || reader.duration() == 0 || reader.duration() > 960000 {
return Err("Use a nonempty mono, 16 kHz, PCM16 input.wav, at most 60 seconds.".into());
}
let input: Vec<f32> = reader.samples::<i16>()
.map(|sample| sample.map(|value| value as f32 / 32768.0))
.collect::<Result<_, _>>()?;
let model = Model::from_file("model.aicmodel")?;
let config = ProcessorConfig {
sample_rate: 16000,
block_size: model.optimal_block_size(16000),
variable_block_size: false,
};
let mut processor = Processor::new(&model, &key)?.with_config(&config)?;
let delay = processor.context().audio_delay();
let padded_count = input.len().checked_add(delay)
.and_then(|n| n.checked_add(config.block_size - 1))
.ok_or("Audio buffer size overflow")? / config.block_size * config.block_size;
let mut output = vec![0.0_f32; padded_count];
output[..input.len()].copy_from_slice(&input);
for block in output.chunks_exact_mut(config.block_size) {
processor.process(block)?;
}
// Flush with silence, then omit the initial delay to align the files.
let enhanced = &output[delay..delay + input.len()];
if enhanced.iter().any(|sample| !sample.is_finite()) {
return Err("Non-finite output sample; no output written.".into());
}
let mut writer = WavWriter::create("enhanced.wav", WavSpec {
channels: 1, sample_rate: 16000, bits_per_sample: 32, sample_format: SampleFormat::Float,
})?;
for &sample in enhanced { writer.write_sample(sample)?; }
writer.finalize()?;
println!("SDK {}, model {}", aic_sdk::get_sdk_version(), model.id());
println!("Processed {} samples at 16000 Hz; wrote enhanced.wav", input.len());
// Drop releases the processor and ends its session, including on an error return.
Ok(())
}
fn main() {
if let Err(error) = run() {
eprintln!("{error}");
std::process::exit(1);
}
}
aic-rust-quickstart:cargo run --release
?. Rust drops the processor and model on a normal return or an error return from run, releasing native resources.Check the result
A successful run exits with code zero, prints the native SDK version and resolved model ID, then reportsProcessed N samples at 16000 Hz; wrote enhanced.wav, where N is your input’s sample count (56080 for the supplied fixture). Open enhanced.wav in your audio editor: it should be mono, 16 kHz and the same duration as input.wav. The output is a 32-bit float WAV; the input is PCM16.The program pads the final block, flushes the delayed tail and removes the initial processing delay, preserving the original sample count. File writes are checked; discard any incomplete file if writing fails.Listen to both files and compare them with the same STT settings to evaluate quality.Recover from an error
| Problem | Cause and retry |
|---|---|
| Build cannot find libclang or a linker | Install the platform compiler tools and libclang. Set LIBCLANG_PATH to your libclang library directory if discovery fails, then rerun cargo build --release. |
| Native library download fails | Check network access and target platform. For a preinstalled SDK, use AIC_LIB_PATH as described in the linking guide. |
| Missing or invalid SDK key | Set AIC_SDK_LICENSE in this terminal to the complete SDK key, then rerun cargo run --release. |
| Processing is not allowed or the key expired | Check key validity, entitlement and required connectivity. Correct the cause and restart the program. |
| Input file rejected | Save a nonempty mono, 16 kHz, PCM16 WAV of at most 60 seconds as input.wav, then retry. |
| Model loading fails | Run from the project directory containing model.aicmodel. Re-download the exact file above for SDK 0.24.0. |
| Audio configuration mismatch | Keep each process call at config.block_size samples. The example pads the final block before processing. |
| Output write fails | Check free space and write permission. Discard the incomplete output, correct the cause and retry. |
Adapt this example
Keep one processor per stream and process blocks in order. Reset its context on a discontinuity or before unrelated audio. Downmix stereo or use a processor per channel. See audio format and streams and state.The helper reads a short recording into memory. For long files and live audio, use bounded buffers and keep file I/O, model loading and session teardown outside the audio callback. For human-listening enhancement, evaluate Rook Multi Speaker.Installation
Use@ai-coustics/aic-sdk-wasm 0.23.0, Node.js 22 or later for the local token server and a browser with WebAssembly SIMD support. This example processes a local recording into a mono WAV; it does not use an AudioWorklet or microphone pipeline.Download the noisy speech fixture, or use a short recording you have permission to process, exported as mono PCM16 WAV at 16 kHz. The example accepts up to 60 seconds. Create an SDK key in the developer platform and put it in the server’s AIC_SDK_LICENSE environment variable. Do not put the key into HTML, browser storage or client configuration.mkdir aic-wasm-example
cd aic-wasm-example
npm init -y
npm install --save-exact @ai-coustics/aic-sdk-wasm@0.23.0
curl --fail --location \
'https://artifacts.ai-coustics.io/models/quail-vf-2-2-s-16khz/v7/quail_vf_2_2_s_16khz_gf70x7zf_v14.aicmodel' \
--output model.aicmodel
read -r -s AIC_SDK_LICENSE
export AIC_SDK_LICENSE
Quickstart
Create the local token server
Save the following asserver.mjs. This server binds to loopback and serves only the listed files. The token endpoint checks the request origin and returns no cached credentials. It decodes the SDK key on the server using the documented token flow.This is a local development server. Before production, replace it with an HTTPS backend that authenticates users, authorizes SDK access and enforces rate and usage limits. Never expose this demo server on a public interface.
server.mjs
import http from 'node:http';
import { readFile } from 'node:fs/promises';
const origin = 'http://127.0.0.1:4173';
const sdkKey = process.env.AIC_SDK_LICENSE;
if (!sdkKey) throw new Error('Set AIC_SDK_LICENSE in the server environment.');
const files = new Map([
['/', ['index.html', 'text/html']],
['/sdk.js', ['node_modules/@ai-coustics/aic-sdk-wasm/aic_sdk_wasm.js', 'text/javascript']],
['/aic_sdk_wasm_bg.wasm', ['node_modules/@ai-coustics/aic-sdk-wasm/aic_sdk_wasm_bg.wasm', 'application/wasm']],
['/model.aicmodel', ['model.aicmodel', 'application/octet-stream']],
]);
const server = http.createServer(async (req, res) => {
res.setHeader('Cache-Control', 'no-store');
res.setHeader('X-Content-Type-Options', 'nosniff');
if (req.headers.host !== '127.0.0.1:4173') {
res.writeHead(403).end('Use the loopback URL printed by the server.');
return;
}
if (req.url === '/session-token' && req.method === 'POST') {
// This is a local-only demo. Production needs authenticated users and quotas.
if (req.headers.origin !== origin || req.headers['x-aic-demo'] !== '1') {
res.writeHead(403).end('Same-origin demo request required.');
return;
}
try {
const payload = JSON.parse(Buffer.from(sdkKey.split('.')[0], 'base64').toString());
if (typeof payload.api_key !== 'string') throw new Error('Invalid SDK key');
const basic = Buffer.from(`${payload.api_key}:`).toString('base64');
const response = await fetch('https://api.ai-coustics.io/v1/sdk/tokens', {
method: 'POST', headers: { Authorization: `Basic ${basic}` },
signal: AbortSignal.timeout(10000),
});
if (!response.ok) throw new Error('Token request rejected');
const { token } = await response.json();
if (typeof token !== 'string') throw new Error('Missing token');
const { exp } = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString());
if (!Number.isFinite(exp) || exp * 1000 <= Date.now() + 120000) {
throw new Error('Token lifetime is too short for this demo');
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ token }));
} catch {
// Do not log credentials or return upstream response bodies.
res.writeHead(502).end('Token request failed. Check the server key and connectivity.');
}
return;
}
const file = files.get(req.url);
if (req.method !== 'GET' || !file) {
res.writeHead(404).end('Not found');
return;
}
try {
const bytes = await readFile(new URL(file[0], import.meta.url));
res.writeHead(200, { 'Content-Type': file[1] }).end(bytes);
} catch {
res.writeHead(404).end('File missing. Check installation and model download.');
}
});
server.listen(4173, '127.0.0.1', () => console.log(`Open ${origin}`));
Create the browser page
Save this asindex.html beside server.mjs. Audio stays in browser memory. The page loads the WASM module and model, requests a token, processes complete frames, pads the tail and removes the reported delay before creating the output file. Session authorization and usage reporting still require network access.index.html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ai-coustics WASM file example</title>
<h1>Enhance a short recording</h1>
<p>Select a mono, 16 kHz, PCM16 WAV with speech (up to 60 seconds).</p>
<label>Recording <input id="input" type="file" accept=".wav"></label>
<button id="run">Enhance</button>
<p id="status" role="status">Ready.</p>
<a id="download" hidden download="enhanced.wav">Download enhanced.wav</a>
<script type="module">
import init, { Model, Processor, getVersion } from '/sdk.js';
const input = document.querySelector('#input');
const run = document.querySelector('#run');
const status = document.querySelector('#status');
const download = document.querySelector('#download');
let outputUrl;
function readWav(bytes) {
const view = new DataView(bytes);
const text = (offset, length) => String.fromCharCode(...new Uint8Array(bytes, offset, length));
if (bytes.byteLength < 44 || text(0, 4) !== 'RIFF' || text(8, 4) !== 'WAVE') {
throw new Error('Select a RIFF WAV file.');
}
let format, data;
for (let pos = 12; pos + 8 <= bytes.byteLength;) {
const size = view.getUint32(pos + 4, true), start = pos + 8;
if (start + size > bytes.byteLength) throw new Error('Truncated WAV chunk.');
if (text(pos, 4) === 'fmt ' && size >= 16) {
format = [view.getUint16(start, true), view.getUint16(start + 2, true),
view.getUint32(start + 4, true), view.getUint16(start + 14, true)];
}
if (text(pos, 4) === 'data') data = [start, size];
pos = start + size + (size % 2);
}
if (String(format) !== '1,1,16000,16' || !data || data[1] % 2) {
throw new Error('Export mono PCM16 WAV at 16 kHz, then retry.');
}
const samples = new Float32Array(data[1] / 2);
if (!samples.length || samples.length > 16000 * 60) {
throw new Error('Use a nonempty recording of up to 60 seconds.');
}
for (let i = 0; i < samples.length; i++) samples[i] = view.getInt16(data[0] + i * 2, true) / 32768;
return samples;
}
function wavBlob(samples) {
const bytes = new ArrayBuffer(44 + samples.length * 2), view = new DataView(bytes);
const text = (offset, value) => [...value].forEach((c, i) => view.setUint8(offset + i, c.charCodeAt(0)));
text(0, 'RIFF'); view.setUint32(4, bytes.byteLength - 8, true); text(8, 'WAVE');
text(12, 'fmt '); view.setUint32(16, 16, true); view.setUint16(20, 1, true);
view.setUint16(22, 1, true); view.setUint32(24, 16000, true); view.setUint32(28, 32000, true);
view.setUint16(32, 2, true); view.setUint16(34, 16, true); text(36, 'data');
view.setUint32(40, samples.length * 2, true);
samples.forEach((x, i) => view.setInt16(44 + i * 2, Math.round(Math.max(-1, Math.min(32767 / 32768, x)) * 32768), true));
return new Blob([bytes], { type: 'audio/wav' });
}
run.onclick = async () => {
let model, processor, context;
run.disabled = true; download.hidden = true;
if (outputUrl) { URL.revokeObjectURL(outputUrl); outputUrl = undefined; }
try {
if (!input.files.length) throw new Error('Select a recording first.');
if (input.files[0].size > 3_000_000) throw new Error('Select a WAV file smaller than 3 MB.');
const samples = readWav(await input.files[0].arrayBuffer());
status.textContent = 'Loading the WASM module and model...';
await init();
const response = await fetch('/model.aicmodel', { signal: AbortSignal.timeout(30000) });
if (!response.ok) throw new Error('Model unavailable. Check the model download.');
model = Model.fromBytes(new Uint8Array(await response.arrayBuffer()));
const tokenResponse = await fetch('/session-token', {
method: 'POST', headers: { 'X-Aic-Demo': '1' }, signal: AbortSignal.timeout(15000),
});
if (!tokenResponse.ok) throw new Error('Token unavailable. Check the server key and connectivity.');
let { token } = await tokenResponse.json();
processor = new Processor(model, token);
token = undefined; // No URL, storage, console or source-code credential.
const size = model.getOptimalBlockSize(16000);
processor.initialize(16000, size, false);
context = processor.getProcessorContext();
const delay = context.getAudioDelay();
const count = Math.ceil((samples.length + delay) / size);
const processed = new Float32Array(count * size);
const deadline = performance.now() + 60000;
status.textContent = 'Processing...';
for (let block = 0; block < count; block++) {
if (performance.now() > deadline) throw new Error('Processing timed out. Use a shorter recording.');
const frame = new Float32Array(size), offset = block * size;
frame.set(samples.subarray(offset, offset + size));
processor.process(frame);
processed.set(frame, offset);
// Allow browser I/O and UI tasks to run between synchronous calls.
if (block % 10 === 0) await new Promise(resolve => setTimeout(resolve, 0));
}
const output = processed.slice(delay, delay + samples.length);
if (!output.every(Number.isFinite)) throw new Error('Non-finite output; stop and check the model.');
outputUrl = URL.createObjectURL(wavBlob(output));
download.href = outputUrl; download.hidden = false;
status.textContent = `Processed ${output.length} samples at 16000 Hz with SDK ${getVersion()}.`;
} catch (error) {
status.textContent = `Stopped: ${error.message.replace(/[.!?]+$/, '')}. Correct the problem and select Enhance to retry.`;
} finally {
context?.free();
if (processor) { processor.terminateSession(); processor.free(); }
model?.free(); run.disabled = false;
}
};
</script>
</html>
Run and check the result
node server.mjs
http://127.0.0.1:4173, select your recording and choose Enhance. On success, the page displays the number of processed samples and SDK version and exposes Download enhanced.wav. The output has the same sample count as the input, one channel and a 16 kHz sample rate. Compare both files to evaluate quality for your task.Each recording uses a fresh token with at least two minutes of remaining validity. Processing stops after one minute of wall time. These are demo bounds, not SDK limits. Stop the server with Ctrl+C, then run unset AIC_SDK_LICENSE.Recover from an error
| Problem | Cause and retry |
|---|---|
Server asks for AIC_SDK_LICENSE | Set the key in the server’s terminal and restart it. |
| Module or model file is missing | Run the installation/download commands in the same directory as server.mjs. |
| Browser cannot compile WASM | Use a browser with WebAssembly SIMD support and verify that the .wasm response is served as application/wasm. |
| Token unavailable | Check the server key, token-service connectivity and whether the credential can mint a JWT. Do not copy a long-lived key into the browser as a workaround. |
ProcessingNotAllowed | Check activation connectivity, credential expiry and authorization. Correct the cause and retry with a fresh token. Do not treat a stopped or bypassed run as enhancement. |
| Invalid WAV or empty input | Export nonempty mono PCM16 audio at 16 kHz and select the corrected file. |
| Timeout | Try a shorter recording and measure your target device’s processing budget before a live integration. |
Adapt this example
Use one processor per independent audio stream.Processor.process() mutates its Float32Array in place and runs synchronously. Move sustained processing off the main UI thread and design buffering around the audio format and latency contracts.For a long-running stream, refresh a JWT through your authenticated backend before expiry and update the existing context:// context came from processor.getProcessorContext().
// freshToken came from your authenticated backend.
context.updateBearerToken(freshToken);
Installation
Use a C++11 compiler, Git and CMake 3.24 or later on a supported platform. On Windows, use a Visual Studio developer terminal with the C++ build tools installed. Create an empty project directory:mkdir aic-cpp-quickstart
cd aic-cpp-quickstart
Quickstart
Prepare the key, model and input
Generate an SDK key on the developer platform. Set it in the terminal where you will run the program. Keep it out of source control and shared logs.export AIC_SDK_LICENSE="YOUR_SDK_KEY"
curl -fL -o model.aicmodel "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel"
$env:AIC_SDK_LICENSE = "YOUR_SDK_KEY"
Invoke-WebRequest "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel" -OutFile model.aicmodel
YOUR_SDK_KEY with your key. This pins a format-7 build of quail-vf-2.2-l-16khz. Quail Voice Focus isolates the primary speaker for speech-to-text (STT) input. Downloading the model in advance does not remove SDK key authorization requirements; see authentication.Download the noisy speech fixture and save it as input.wav in this project directory. It contains 56,080 mono PCM16 samples at 16 kHz (3.505 seconds). The fixture guide includes attribution, checksums and the aligned clean reference.For your own recording, export mono, 16 kHz, signed 16-bit PCM WAV, at most 60 seconds long. Renaming a file does not convert it.Add WAV file handling
The example uses dr_wav 0.14.4 for file I/O. Download its pinned single header into the project directory:curl -fL -o dr_wav.h "https://raw.githubusercontent.com/mackron/dr_libs/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59/dr_wav.h"
Invoke-WebRequest "https://raw.githubusercontent.com/mackron/dr_libs/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59/dr_wav.h" -OutFile dr_wav.h
audio_file.h alongside dr_wav.h. It checks input format and length, reads float samples and writes a 32-bit float WAV.audio_file.h
#ifndef AUDIO_FILE_H
#define AUDIO_FILE_H
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
/* A short-file helper for this tutorial, independent of the SDK. */
static float* read_input(size_t* count) {
drwav wav;
if (!drwav_init_file(&wav, "input.wav", NULL)) {
fprintf(stderr, "Cannot open input.wav as a WAV file.\n");
return NULL;
}
if (wav.channels != 1 || wav.sampleRate != 16000 ||
wav.translatedFormatTag != DR_WAVE_FORMAT_PCM || wav.bitsPerSample != 16 ||
wav.totalPCMFrameCount == 0 || wav.totalPCMFrameCount > 960000) {
fprintf(stderr, "Use a nonempty mono, 16 kHz, PCM16 input.wav, at most 60 seconds.\n");
drwav_uninit(&wav);
return NULL;
}
*count = (size_t)wav.totalPCMFrameCount;
float* audio = (float*)malloc(*count * sizeof(float));
if (!audio || drwav_read_pcm_frames_f32(&wav, *count, audio) != *count) {
fprintf(stderr, "Cannot read all input samples.\n");
free(audio);
audio = NULL;
}
drwav_uninit(&wav);
return audio;
}
static int write_output(const float* audio, size_t count) {
drwav wav;
drwav_data_format format = {drwav_container_riff, DR_WAVE_FORMAT_IEEE_FLOAT, 1, 16000, 32};
for (size_t i = 0; i < count; ++i) {
if (!isfinite(audio[i])) {
fprintf(stderr, "Non-finite output sample; no output written.\n");
return 0;
}
}
if (!drwav_init_file_write(&wav, "enhanced.wav", &format, NULL)) {
fprintf(stderr, "Cannot create enhanced.wav.\n");
return 0;
}
drwav_uint64 written = drwav_write_pcm_frames(&wav, count, audio);
drwav_result closed = drwav_uninit(&wav);
if (written != count || closed != DRWAV_SUCCESS) {
fprintf(stderr, "Cannot finish enhanced.wav; discard the incomplete file.\n");
return 0;
}
return 1;
}
#endif
Save the program
Save asquickstart.cpp:quickstart.cpp
#include "aic.hpp"
#include "audio_file.h"
#include <algorithm>
#include <cstring>
#include <iostream>
#include <limits>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
static void check(aic::ErrorCode error, const char* operation) {
if (error != aic::ErrorCode::Success) {
throw std::runtime_error(std::string(operation) + " failed (SDK error " +
std::to_string(static_cast<int>(error)) + ").");
}
}
int main() {
try {
const char* key = std::getenv("AIC_SDK_LICENSE");
if (!key || !*key || std::strcmp(key, "YOUR_SDK_KEY") == 0)
throw std::runtime_error("Set AIC_SDK_LICENSE to your SDK key, then retry.");
size_t count = 0;
std::unique_ptr<float, decltype(&std::free)> input(read_input(&count), &std::free);
if (!input) return 1;
auto model_result = aic::Model::create_from_file("model.aicmodel");
check(model_result.error, "Model loading");
auto model = model_result.take();
auto processor_result = aic::Processor::create(model, key);
check(processor_result.error, "Processor creation");
auto processor = processor_result.take();
const size_t block_size = model.get_optimal_block_size(16000);
check(processor.initialize(16000, block_size, false), "Initialization");
auto context_result = processor.create_context();
check(context_result.error, "Context creation");
auto context = context_result.take();
const size_t delay = context.get_audio_delay();
const size_t limit = std::numeric_limits<size_t>::max();
if (block_size == 0 || count > limit - delay || count + delay > limit - (block_size - 1))
throw std::runtime_error("Audio buffer size overflow.");
const size_t padded_count = ((count + delay + block_size - 1) / block_size) * block_size;
std::vector<float> output(padded_count, 0.0f);
std::copy(input.get(), input.get() + count, output.begin());
for (size_t start = 0; start < padded_count; start += block_size)
check(processor.process(output.data() + start, block_size), "Processing");
// Flush with silence, then omit the initial delay to align the files.
if (!write_output(output.data() + delay, count)) return 1;
std::cout << "SDK " << aic::get_sdk_version() << ", model " << model.get_id() << '\n';
std::cout << "Processed " << count << " samples at 16000 Hz; wrote enhanced.wav\n";
// Destructors release the context, processor and model on success or error.
return 0;
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
}
Build and run
Save this complete project asCMakeLists.txt:CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(aic_cpp_quickstart LANGUAGES C CXX)
include(FetchContent)
set(AIC_SDK_ALLOW_DOWNLOAD ON CACHE BOOL "Download the matching C SDK")
FetchContent_Declare(aic_sdk
GIT_REPOSITORY https://github.com/ai-coustics/aic-sdk-cpp.git
GIT_TAG 0.24.0
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(aic_sdk)
add_executable(quickstart quickstart.cpp)
target_compile_features(quickstart PRIVATE cxx_std_11)
target_link_libraries(quickstart PRIVATE aic-sdk)
aic-cpp-quickstart:cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
input.wav and model.aicmodel:./build/quickstart
.\build\Release\quickstart.exe
Check the result
A successful run exits with code zero, prints the native SDK version and resolved model ID, then reportsProcessed N samples at 16000 Hz; wrote enhanced.wav, where N is your input’s sample count (56080 for the supplied fixture). Open enhanced.wav in your audio editor: it should be mono, 16 kHz and the same duration as input.wav. The output is a 32-bit float WAV; the input is PCM16.The program pads the final block, flushes the delayed tail and removes the initial processing delay, preserving the original sample count. File writes are checked; discard any incomplete file if writing fails.Listen to both files and compare them with the same STT settings to evaluate quality.Recover from an error
| Problem | Cause and retry |
|---|---|
| Compiler, SDK header or library missing | Install the compiler and check the selected archive or CMake download. Use the same target architecture for compiler and SDK. Rerun configure and build. |
| Missing SDK key or SDK error 50 | Set AIC_SDK_LICENSE in this terminal to the complete SDK key, then run the program again. Error 50 is an invalid license format. |
| SDK error 6 or 52 | Error 6 means processing is not allowed; error 52 means the license expired. Check account entitlement, key validity and required connectivity, then restart with a new processor. |
| Input file rejected | Save a nonempty mono, 16 kHz, PCM16 WAV of at most 60 seconds as input.wav, then retry. |
| Model loading fails | Keep model.aicmodel in the current directory. Re-download the exact compatible file above; error 100 means an invalid model, 101 an unsupported model version and 103 a filesystem error. |
| SDK error 5 | The block size differs from initialization. Keep every call at the configured size and pad the final block as shown. |
| Output write fails | Check free space and write permission. Discard the incomplete enhanced.wav, fix the cause and retry. |
check turns a failed ErrorCode into an exception for this application. The SDK wrapper itself returns error codes and Result<T> values: calling .take() without checking .error or .ok() does not throw.Adapt this example
Keep one processor per stream and process blocks in order. Reset its context on a discontinuity or before unrelated audio. Downmix stereo or use a processor per channel. See audio format and streams and state.The helper reads a short recording into memory. For long files and live audio, use bounded buffers and keep file I/O, model loading and session teardown outside the audio callback. For human-listening enhancement, evaluate Rook Multi Speaker.Installation
Use a C11 compiler, CMake 3.24 or later and a supported macOS, Linux or Windows platform. Linux uses the GNU libc distribution; see the compatibility matrix. On Windows, run build commands in a Visual Studio developer terminal with the C++ build tools installed.Create an empty project directory:mkdir aic-c-quickstart
cd aic-c-quickstart
case "$(uname -s)-$(uname -m)" in
Darwin-arm64) AIC_TARGET=aarch64-apple-darwin ;;
Darwin-x86_64) AIC_TARGET=x86_64-apple-darwin ;;
Linux-aarch64) AIC_TARGET=aarch64-unknown-linux-gnu ;;
Linux-x86_64) AIC_TARGET=x86_64-unknown-linux-gnu ;;
*) echo "Select a supported SDK archive from the releases page"; exit 1 ;;
esac
curl -fL -o sdk.tar.gz "https://github.com/ai-coustics/aic-sdk-c/releases/download/0.24.0/aic-sdk-${AIC_TARGET}-0.24.0.tar.gz"
mkdir sdk
tar -xzf sdk.tar.gz -C sdk
# For an ARM64 build, replace x86_64 with aarch64.
$AicTarget = "x86_64-pc-windows-msvc"
Invoke-WebRequest "https://github.com/ai-coustics/aic-sdk-c/releases/download/0.24.0/aic-sdk-$AicTarget-0.24.0.zip" -OutFile sdk.zip
Expand-Archive sdk.zip -DestinationPath sdk
sdk/include/aic.h and sdk/lib/. Choose the archive for your compiler’s target architecture when cross-compiling. Release 0.24.0 includes all distributions.Quickstart
Prepare the key, model and input
Generate an SDK key on the developer platform. Set it in the terminal where you will run the program. Keep it out of source control and shared logs.export AIC_SDK_LICENSE="YOUR_SDK_KEY"
curl -fL -o model.aicmodel "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel"
$env:AIC_SDK_LICENSE = "YOUR_SDK_KEY"
Invoke-WebRequest "https://artifacts.ai-coustics.io/models/quail-vf-2-2-l-16khz/v7/quail_vf_2_2_l_16khz_horgwub0_v14.aicmodel" -OutFile model.aicmodel
YOUR_SDK_KEY with your key. This pins a format-7 build of quail-vf-2.2-l-16khz. Quail Voice Focus isolates the primary speaker for speech-to-text (STT) input. Downloading the model in advance does not remove SDK key authorization requirements; see authentication.Download the noisy speech fixture and save it as input.wav in this project directory. It contains 56,080 mono PCM16 samples at 16 kHz (3.505 seconds). The fixture guide includes attribution, checksums and the aligned clean reference.For your own recording, export mono, 16 kHz, signed 16-bit PCM WAV, at most 60 seconds long. Renaming a file does not convert it.Add WAV file handling
The example uses dr_wav 0.14.4 for file I/O. Download its pinned single header into the project directory:curl -fL -o dr_wav.h "https://raw.githubusercontent.com/mackron/dr_libs/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59/dr_wav.h"
Invoke-WebRequest "https://raw.githubusercontent.com/mackron/dr_libs/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59/dr_wav.h" -OutFile dr_wav.h
audio_file.h alongside dr_wav.h. It checks input format and length, reads float samples and writes a 32-bit float WAV.audio_file.h
#ifndef AUDIO_FILE_H
#define AUDIO_FILE_H
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
/* A short-file helper for this tutorial, independent of the SDK. */
static float* read_input(size_t* count) {
drwav wav;
if (!drwav_init_file(&wav, "input.wav", NULL)) {
fprintf(stderr, "Cannot open input.wav as a WAV file.\n");
return NULL;
}
if (wav.channels != 1 || wav.sampleRate != 16000 ||
wav.translatedFormatTag != DR_WAVE_FORMAT_PCM || wav.bitsPerSample != 16 ||
wav.totalPCMFrameCount == 0 || wav.totalPCMFrameCount > 960000) {
fprintf(stderr, "Use a nonempty mono, 16 kHz, PCM16 input.wav, at most 60 seconds.\n");
drwav_uninit(&wav);
return NULL;
}
*count = (size_t)wav.totalPCMFrameCount;
float* audio = (float*)malloc(*count * sizeof(float));
if (!audio || drwav_read_pcm_frames_f32(&wav, *count, audio) != *count) {
fprintf(stderr, "Cannot read all input samples.\n");
free(audio);
audio = NULL;
}
drwav_uninit(&wav);
return audio;
}
static int write_output(const float* audio, size_t count) {
drwav wav;
drwav_data_format format = {drwav_container_riff, DR_WAVE_FORMAT_IEEE_FLOAT, 1, 16000, 32};
for (size_t i = 0; i < count; ++i) {
if (!isfinite(audio[i])) {
fprintf(stderr, "Non-finite output sample; no output written.\n");
return 0;
}
}
if (!drwav_init_file_write(&wav, "enhanced.wav", &format, NULL)) {
fprintf(stderr, "Cannot create enhanced.wav.\n");
return 0;
}
drwav_uint64 written = drwav_write_pcm_frames(&wav, count, audio);
drwav_result closed = drwav_uninit(&wav);
if (written != count || closed != DRWAV_SUCCESS) {
fprintf(stderr, "Cannot finish enhanced.wav; discard the incomplete file.\n");
return 0;
}
return 1;
}
#endif
Save the program
Save asquickstart.c:quickstart.c
#include "aic.h"
#include "audio_file.h"
#include <string.h>
#define CHECK(call) do { \
enum AicErrorCode error = (call); \
if (error != AIC_ERROR_CODE_SUCCESS) { \
fprintf(stderr, "%s failed (SDK error %d).\n", #call, (int)error); \
goto cleanup; \
} \
} while (0)
int main(void) {
const char* key = getenv("AIC_SDK_LICENSE");
if (!key || !*key || strcmp(key, "YOUR_SDK_KEY") == 0) {
fprintf(stderr, "Set AIC_SDK_LICENSE to your SDK key, then retry.\n");
return 1;
}
int status = 1;
size_t count = 0, block_size = 0, delay = 0, padded_count = 0;
float* input = read_input(&count);
float* output = NULL;
struct AicModel* model = NULL;
struct AicProcessor* processor = NULL;
struct AicProcessorContext* context = NULL;
if (!input) goto cleanup;
CHECK(aic_model_create_from_file(&model, "model.aicmodel"));
CHECK(aic_model_get_optimal_block_size(model, 16000, &block_size));
CHECK(aic_processor_create(&processor, model, key, NULL));
CHECK(aic_processor_initialize(processor, 16000, block_size, false));
CHECK(aic_processor_context_create(&context, processor));
CHECK(aic_processor_context_get_audio_delay(context, &delay));
if (block_size == 0 || count > SIZE_MAX - delay ||
count + delay > SIZE_MAX - (block_size - 1)) {
fprintf(stderr, "Audio buffer size overflow.\n");
goto cleanup;
}
padded_count = ((count + delay + block_size - 1) / block_size) * block_size;
if (padded_count > SIZE_MAX / sizeof(float)) {
fprintf(stderr, "Audio buffer size overflow.\n");
goto cleanup;
}
output = (float*)calloc(padded_count, sizeof(float));
if (!output) {
fprintf(stderr, "Cannot allocate the processing buffer.\n");
goto cleanup;
}
memcpy(output, input, count * sizeof(float));
for (size_t start = 0; start < padded_count; start += block_size) {
CHECK(aic_processor_process(processor, output + start, block_size));
}
/* Flush with silence, then omit the initial delay to align the files. */
if (!write_output(output + delay, count)) goto cleanup;
printf("SDK %s, model %s\n", aic_get_sdk_version(), aic_model_get_id(model));
printf("Processed %zu samples at 16000 Hz; wrote enhanced.wav\n", count);
status = 0;
cleanup:
aic_processor_context_destroy(context);
aic_processor_destroy(processor);
aic_model_destroy(model);
free(output);
free(input);
return status;
}
Build and run
Save this complete project asCMakeLists.txt:CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(aic_c_quickstart LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
add_library(aic SHARED IMPORTED)
set(AIC_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/sdk")
if(WIN32)
set_target_properties(aic PROPERTIES
IMPORTED_LOCATION "${AIC_ROOT}/lib/aic.dll"
IMPORTED_IMPLIB "${AIC_ROOT}/lib/aic.dll.lib")
elseif(APPLE)
set_target_properties(aic PROPERTIES IMPORTED_LOCATION "${AIC_ROOT}/lib/libaic.dylib")
else()
set_target_properties(aic PROPERTIES IMPORTED_LOCATION "${AIC_ROOT}/lib/libaic.so")
endif()
set_target_properties(aic PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${AIC_ROOT}/include")
add_executable(quickstart quickstart.c)
target_link_libraries(quickstart PRIVATE aic)
if(UNIX AND NOT APPLE)
target_link_libraries(quickstart PRIVATE m)
endif()
if(WIN32)
add_custom_command(TARGET quickstart POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:aic>" "$<TARGET_FILE_DIR:quickstart>")
endif()
aic-c-quickstart:cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
input.wav and model.aicmodel:./build/quickstart
.\build\Release\quickstart.exe
Check the result
A successful run exits with code zero, prints the native SDK version and resolved model ID, then reportsProcessed N samples at 16000 Hz; wrote enhanced.wav, where N is your input’s sample count (56080 for the supplied fixture). Open enhanced.wav in your audio editor: it should be mono, 16 kHz and the same duration as input.wav. The output is a 32-bit float WAV; the input is PCM16.The program pads the final block, flushes the delayed tail and removes the initial processing delay, preserving the original sample count. File writes are checked; discard any incomplete file if writing fails.Listen to both files and compare them with the same STT settings to evaluate quality.Recover from an error
| Problem | Cause and retry |
|---|---|
| Compiler, SDK header or library missing | Install the compiler and check the selected archive or CMake download. Use the same target architecture for compiler and SDK. Rerun configure and build. |
| Missing SDK key or SDK error 50 | Set AIC_SDK_LICENSE in this terminal to the complete SDK key, then run the program again. Error 50 is an invalid license format. |
| SDK error 6 or 52 | Error 6 means processing is not allowed; error 52 means the license expired. Check account entitlement, key validity and required connectivity, then restart with a new processor. |
| Input file rejected | Save a nonempty mono, 16 kHz, PCM16 WAV of at most 60 seconds as input.wav, then retry. |
| Model loading fails | Keep model.aicmodel in the current directory. Re-download the exact compatible file above; error 100 means an invalid model, 101 an unsupported model version and 103 a filesystem error. |
| SDK error 5 | The block size differs from initialization. Keep every call at the configured size and pad the final block as shown. |
| Output write fails | Check free space and write permission. Discard the incomplete enhanced.wav, fix the cause and retry. |
sdk/lib in place for this tutorial. On Windows, it copies aic.dll beside the executable; keep that DLL with your application. See the C binding guide for deployment and static linking.Adapt this example
Keep one processor per stream and process blocks in order. Reset its context on a discontinuity or before unrelated audio. Downmix stereo or use a processor per channel. See audio format and streams and state.The helper reads a short recording into memory. For long files and live audio, use bounded buffers and keep file I/O, model loading and session teardown outside the audio callback. For human-listening enhancement, evaluate Rook Multi Speaker.Find out more
After checking your output, evaluate representative audio, then prepare your deployment. Use troubleshooting to diagnose setup and runtime failures.Audio format
Connect your input format, channels and frame sizes to the SDK.
Streams and state
Manage processor state across streams and interruptions.
Language bindings
Find binding-specific APIs, examples and lifecycle guidance.
Performance
Evaluate runtime cost and latency for your deployment.