> ## 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.

# Migrate to Mono Processing

> Update SDK integrations from the multi-channel buffer APIs to the mono processing and buffering API.

**Before:** you passed a multi-channel buffer. The SDK mixed it down to mono internally, enhanced it, and mixed the result back into your channels. That mixback was hard to predict per channel, so the output level and spatial presentation could surprise you.

**Now:** every audio API takes one mono buffer. Channel handling is yours, so the result is whatever you decide it is.

<Warning>
  The same release also moves voice activity detection into a dedicated `Vad` object and removes energy-based VAD. If you read a VAD signal from a processor, see [Migrate to the dedicated VAD](/reference/deprecated/energy-vad-to-dedicated-vad).
</Warning>

## What changed

<Tabs>
  <Tab title="Python">
    | Before                                                                          | Now                                                             |
    | ------------------------------------------------------------------------------- | --------------------------------------------------------------- |
    | `ProcessorConfig(sample_rate, num_channels, num_frames, allow_variable_frames)` | `ProcessorConfig(sample_rate, block_size, variable_block_size)` |
    | `ProcessorConfig.optimal(model, num_channels=2)`                                | `ProcessorConfig.optimal(model)`                                |
    | `model.get_optimal_num_frames(sample_rate)`                                     | `model.get_optimal_block_size(sample_rate)`                     |
    | `processor.process(audio)` with a 2D `(channels, frames)` array                 | `processor.process(audio)` with a 1D mono array                 |
    | `collector.buffer(audio)` with a 2D array                                       | `collector.buffer(audio)` with a 1D mono array                  |
  </Tab>

  <Tab title="C">
    | Before                                                                                              | Now                                                                                 |
    | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
    | `aic_processor_initialize(processor, sample_rate, num_channels, num_frames, allow_variable_frames)` | `aic_processor_initialize(processor, sample_rate, block_size, variable_block_size)` |
    | `aic_model_get_optimal_num_frames`                                                                  | `aic_model_get_optimal_block_size`                                                  |
    | `aic_processor_process_planar` / `_interleaved` / `_sequential`                                     | `aic_processor_process(processor, audio_ptr, audio_len)`                            |
    | `aic_collector_buffer_planar` / `_interleaved` / `_sequential`                                      | `aic_collector_buffer(collector, audio_ptr, audio_len)`                             |
  </Tab>
</Tabs>

Your old `num_frames` value is your new `block_size`, because it already meant samples per channel. Error codes were renamed too, see the [changelog](/changelog).

<Warning>
  Do not pass the total length of a multi-channel buffer. A stereo block of 480 frames holds 960 samples, but the mono block size is still 480. A mismatch returns `AIC_ERROR_CODE_AUDIO_CONFIG_MISMATCH`.
</Warning>

## If you still want multi-channel output

Two steps: downmix to mono, then distribute the enhanced mono back across your channels.

### 1. Downmix to mono

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    # audio is (frames, channels), as returned by soundfile.read
    mono = np.ascontiguousarray(audio.mean(axis=1), dtype=np.float32)

    enhanced = processor.process(mono)
    ```

    Cast back to `float32`, because `mean()` widens to `float64`. `process()` also needs a contiguous array.
  </Tab>

  <Tab title="C">
    ```c theme={null}
    // interleaved stereo in, mono out
    for (size_t i = 0; i < block_size; ++i) {
        mono[i] = 0.5f * (interleaved[i * 2] + interleaved[i * 2 + 1]);
    }

    aic_processor_process(processor, mono, block_size);
    ```

    Allocate `mono` once outside the processing loop, because allocation is not real-time safe.
  </Tab>
</Tabs>

### 2. Copy the enhanced mono into each channel

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    # Back to (frames, channels), same enhanced signal in every channel
    out = np.repeat(enhanced[:, None], num_channels, axis=1)
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    // aic_processor_process enhanced mono in place
    for (size_t i = 0; i < block_size; ++i) {
        for (uint16_t ch = 0; ch < num_channels; ++ch) {
            interleaved[i * num_channels + ch] = mono[i];
        }
    }
    ```
  </Tab>
</Tabs>

<Warning>
  This does not reproduce the old mixback. Every channel now carries the identical enhanced signal, so any stereo image in the input is gone and the perceived level may differ. Check loudness and enhancement level against representative audio.
</Warning>

See [Audio Format](/reference/concepts/audio-format) for downmix caveats when channel gain or phase matters.

## If your channels are independent streams

Do not downmix. Two sides of a call, or two speakers on separate mics, are separate streams. Create one processor per stream, each with its own state:

```python theme={null}
left_processor = aic.Processor(model, license_key, config)
right_processor = aic.Processor(model, license_key, config)

enhanced_left = left_processor.process(left)
enhanced_right = right_processor.process(right)
```

The processors can share one model. The old 16-channel limit is gone, since concurrency is now bounded only by how many instances you create. The same applies to the analyzer: one collector and analyzer pair per stream.

## Related migrations

<CardGroup cols={2}>
  <Card title="Migrate to the dedicated VAD" href="/reference/deprecated/energy-vad-to-dedicated-vad">
    Move voice activity detection onto a dedicated VAD model.
  </Card>

  <Card title="Python SDK 2.5 to 3.0" href="/reference/deprecated/python-2-5-to-3-0">
    Every Python-specific rename in this release.
  </Card>
</CardGroup>
