> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ai-coustics.com/llms.txt
> Use this file to discover all available pages before exploring further.

# C++

> Build a C++ WAV-processing program with checked results and scoped native lifetimes.

**ai-coustics** provides a C++11 wrapper around the native C SDK. This page pins the wrapper and native library to 0.25.0. Use the [C++ API reference](/reference/sdk/api/cpp/index) for types, methods, ownership and errors. The [released header](https://github.com/ai-coustics/aic-sdk-cpp/blob/0.25.0/include/aic.hpp) provides the wrapper declarations and inline implementation.

## Installation

Use a C++11 compiler, Git and CMake 3.24 or later on a [supported platform](/reference/sdk/compatibility-matrix). On Windows, use a Visual Studio developer terminal with the C++ build tools installed. Create an empty project directory:

```bash theme={null}
mkdir aic-cpp-quickstart
cd aic-cpp-quickstart
```

The CMake project below pins the C++ wrapper to 0.25.0. On the first configure, it downloads the matching native C SDK and checks its checksum. The example links the native SDK statically; network access is needed during configuration.

## Quickstart

### Prepare the key, model and input

Generate an SDK key on the [developer platform](https://developers.ai-coustics.com). Set it in the terminal where you will run the program. Keep it out of source control and shared logs.

<CodeGroup>
  ```bash macOS / Linux theme={null}
  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"
  ```

  ```powershell Windows PowerShell theme={null}
  $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
  ```
</CodeGroup>

Replace `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](/models/get-started/authenticate-apps).

Download the [noisy speech fixture](/assets/audio/noisy-speech.wav) 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](/guides/test-audio) 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](https://github.com/mackron/dr_libs/tree/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59) for file I/O. Download its pinned single header into the project directory:

<CodeGroup>
  ```bash macOS / Linux theme={null}
  curl -fL -o dr_wav.h "https://raw.githubusercontent.com/mackron/dr_libs/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59/dr_wav.h"
  ```

  ```powershell Windows PowerShell theme={null}
  Invoke-WebRequest "https://raw.githubusercontent.com/mackron/dr_libs/86cc48cbfd981fa00ea94905ac9d6df4b18d4e59/dr_wav.h" -OutFile dr_wav.h
  ```
</CodeGroup>

Save this helper as `audio_file.h` alongside `dr_wav.h`. It checks input format and length, reads float samples and writes a 32-bit float WAV.

```c audio_file.h theme={null}
#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 as `quickstart.cpp`:

```cpp quickstart.cpp theme={null}
#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 as `CMakeLists.txt`:

```cmake CMakeLists.txt theme={null}
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.25.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)
```

Configure and build from `aic-cpp-quickstart`:

```bash theme={null}
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
```

Run from the project directory so the program can find `input.wav` and `model.aicmodel`:

<CodeGroup>
  ```bash macOS / Linux theme={null}
  ./build/quickstart
  ```

  ```powershell Windows PowerShell theme={null}
  .\build\Release\quickstart.exe
  ```
</CodeGroup>

### Check the result

A successful run exits with code zero, prints the native SDK version and resolved model ID, then reports `Processed 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](/reference/concepts/latency), 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](/models/get-started/authenticate-apps), 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. |

The helper `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](/reference/concepts/audio-format) and [streams and state](/reference/concepts/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](/models/perceptual-speech-enhancement/rook-multi-speaker).

## Integration behavior

| Concern | C++ wrapper 0.25.0 behavior |
| - | - |
| **Error handling** | Constructors exposed as factory methods return `Result<T>`. Check `.ok()` or `.error` before `.take()`. Initialization and processing return `ErrorCode`; they do not throw on an SDK failure. |
| **Audio buffer** | `processor.process(audio, count)` modifies the writable mono float32 buffer in place. Keep the buffer valid throughout the call. |
| **State** | Retain one processor per stream. Use `context.reset()` on a discontinuity or before unrelated audio; check its return code. Reset retains the audio configuration. |
| **Context** | `processor.create_context()` returns a checked `Result<ProcessorContext>`. The context exposes parameter control and delay in samples at the initialized rate. |
| **Ownership** | Models, processors and contexts own their handles and release them in destructors. Use moves for ownership transfer; the handles are not copyable. |
| **Model lifetime** | Processors retain an internal reference to the model data. The memory-mapped model file must remain unchanged while any dependent object exists. |
| **Concurrency** | Sequence processing calls on one instance. Use independent processors for simultaneous streams and consult the header for each context method's thread-safety contract. |
| **Session termination** | Destruction ends the session automatically. `terminate_session()` requests termination earlier; check its return code. The processor cannot continue processing after termination is handled. |

The tutorial converts failed SDK results into exceptions. Use explicit error branches if your application disables exceptions.

## Build and deploy

The CMake target `aic-sdk` carries its native dependency and required system libraries. `AIC_SDK_ALLOW_DOWNLOAD=ON` enables the configure-time download. To use a preinstalled distribution, supply `AIC_SDK_ROOT` with `include/` and `lib/` directories; see the [released CMake configuration](https://github.com/ai-coustics/aic-sdk-cpp/blob/0.25.0/CMakeLists.txt).

Static linking is the default. `AIC_SDK_USE_STATIC=OFF` selects a shared library and makes its runtime deployment your responsibility. On Windows, match the target architecture and MSVC runtime flavor. Keep model download, object construction and teardown outside the audio callback.

The [released examples](https://github.com/ai-coustics/aic-sdk-cpp/tree/0.25.0/example) cover enhancement, voice activity detection (VAD) and analysis as separate objects with different model types. See [streams and state](/reference/concepts/streams-and-state) before combining them. An enhancement processor can also report speech through [`create_energy_vad_context()`](/reference/sdk/api/cpp/processing#aic-Processor-create_energy_vad_context), without a second model.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.