<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Audio Processing on kenji.blog</title><link>http://kenji.blog/en/categories/audio-processing/</link><description>Recent content in Audio Processing on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 04:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/en/categories/audio-processing/index.xml" rel="self" type="application/rss+xml"/><item><title>How to Integrate Speech Recognition AI (Whisper) into a C++ Project</title><link>http://kenji.blog/en/p/whisper-cpp-integration-guide/</link><pubDate>Fri, 11 Sep 2026 04:00:00 +0900</pubDate><guid>http://kenji.blog/en/p/whisper-cpp-integration-guide/</guid><description>&lt;img src="http://kenji.blog/p/whisper-cpp-integration-guide/img/eyecatch.jpg" alt="Featured image of post How to Integrate Speech Recognition AI (Whisper) into a C++ Project" />&lt;h2 id="1-introduction-why-c-for-speech-recognition">1. Introduction: Why C++ for Speech Recognition?
&lt;/h2>&lt;p>Since OpenAI open-sourced its highly accurate speech recognition model, &amp;ldquo;Whisper,&amp;rdquo; it has been utilized in various applications. While it is commonly used in Python environments (based on PyTorch), relying on a Python interpreter becomes a major performance bottleneck when integrating it into &lt;strong>edge devices (smartphones, IoT devices, embedded systems)&lt;/strong> or &lt;strong>native C++ applications that require strict real-time performance&lt;/strong> (game engines, DAW software, robotics, etc.).&lt;/p>
&lt;p>This is where &lt;strong>&lt;a class="link" href="https://github.com/ggerganov/whisper.cpp" target="_blank" rel="noopener"
>whisper.cpp&lt;/a>&lt;/strong>, developed by Georgi Gerganov, comes to the rescue. Based on &lt;code>ggml&lt;/code>, a tensor computation library for machine learning, this library minimizes dependencies and implements Whisper&amp;rsquo;s inference entirely in C/C++.&lt;/p>
&lt;p>In this article, we will thoroughly explain how to integrate top-tier speech recognition capabilities into your custom C++ project using &lt;code>whisper.cpp&lt;/code>. We will cover everything from the basics of audio signal processing, detailed API usage, memory management, and multi-threading optimization, to implementation patterns for real-time processing.&lt;/p>
&lt;hr>
&lt;h2 id="2-audio-signal-processing-and-whispers-input-requirements">2. Audio Signal Processing and Whisper&amp;rsquo;s Input Requirements
&lt;/h2>&lt;p>To make an AI understand speech, we must convert the analog signal (&amp;ldquo;sound&amp;rdquo;) into digital data and format it into a tensor that the AI model can process. The audio format required by Whisper is very strict.&lt;/p>
&lt;h3 id="21-audio-format-required-by-whisper">2.1 Audio Format Required by Whisper
&lt;/h3>&lt;p>The Whisper model accepts audio data with the following specifications:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Sample Rate&lt;/strong>: 16,000 Hz (16 kHz)&lt;/li>
&lt;li>&lt;strong>Channels&lt;/strong>: 1 (Mono)&lt;/li>
&lt;li>&lt;strong>Data Type&lt;/strong>: 32-bit floating point (&lt;code>float&lt;/code> in C/C++)&lt;/li>
&lt;li>&lt;strong>Normalization&lt;/strong>: Values scaled to the range of $[-1.0, 1.0]$&lt;/li>
&lt;/ul>
&lt;p>For example, if you input an audio file with CD quality (44.1kHz, Stereo, 16-bit PCM), you must perform downsampling, channel mixdown, and format conversion beforehand.&lt;/p>
&lt;p>The formula for calculating the data transfer rate is as follows:&lt;/p>
$$ \text{Data Rate (bytes/sec)} = \text{Sample Rate} \times \text{Channels} \times \frac{\text{Bit Depth}}{8} $$
&lt;p>For Whisper&amp;rsquo;s requirements (16kHz, 1ch, 32-bit Float), the data size per second is:&lt;/p>
$$ 16000 \times 1 \times \frac{32}{8} = 64,000 \text{ bytes/sec (64 KB/s)} $$
&lt;p>Since this is extremely lightweight, even edge devices with limited memory bandwidth can easily buffer it.&lt;/p>
&lt;h3 id="22-the-mathematics-of-mel-spectrogram-conversion">2.2 The Mathematics of Mel-Spectrogram Conversion
&lt;/h3>&lt;p>Internally, Whisper does not process 1D audio waveform data (Raw Waveform) directly. The audio is converted into a &lt;strong>Mel-Spectrogram&lt;/strong>, a frequency representation close to human auditory characteristics, before being fed into the Transformer model. While &lt;code>whisper.cpp&lt;/code> includes this conversion process within its C++ implementation, understanding how it works is useful for noise mitigation and optimizing preprocessing.&lt;/p>
&lt;p>The mathematical formula to convert a regular frequency $f$ (Hz) into the Mel scale $m$ is approximated as follows:&lt;/p>
$$ m = 2595 \log_{10} \left( 1 + \frac{f}{700} \right) $$
&lt;p>Conversely, the inverse conversion from the Mel scale back to frequency is:&lt;/p>
$$ f = 700 \left( 10^{\frac{m}{2595}} - 1 \right) $$
&lt;p>Furthermore, the audio waveform is transformed into the time-frequency domain using the &lt;strong>Short-Time Fourier Transform (STFT)&lt;/strong>. The discrete form of STFT using a window function $w(n)$ is expressed as:&lt;/p>
$$ X(m, k) = \sum_{n=0}^{N-1} x(n + mH) w(n) e^{-j \frac{2\pi}{N} k n} $$
&lt;p>
&lt;em>(Here, $N$ is the FFT window size, $H$ is the hop size, and $w(n)$ is a window function like the Hann window)&lt;/em>&lt;/p>
&lt;p>The Whisper model typically uses a window size $N = 400$ (25ms), a hop size $H = 160$ (10ms), and an 80-dimensional Mel filter bank. This feature extraction is executed automatically (and rapidly using SIMD instructions) when calling &lt;code>whisper_full()&lt;/code> within &lt;code>whisper.cpp&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="3-architecture-and-pipeline-design">3. Architecture and Pipeline Design
&lt;/h2>&lt;p>Let&amp;rsquo;s design the audio processing pipeline in a C++ application. The flow starts from a file or microphone input, goes through preprocessing, inference via &lt;code>whisper.cpp&lt;/code>, and finally reaches the text output.&lt;/p>
&lt;div class="mermaid">graph TD
A["Audio Source (Microphone/File)"] -->|Raw Bytes, e.g. 48kHz Stereo| B["Audio Decoder &amp; Resampler (FFmpeg/miniaudio)"]
B -->|16kHz Mono 32-bit Float| C["Ring Buffer / Memory Array"]
C -->|Feed PCM Data| D["whisper.cpp Core (ggml)"]
D --> E["Mel Spectrogram Extraction"]
E --> F["Transformer Encoder-Decoder"]
F --> G["Text Tokens Generation"]
G --> H["Text Output (UTF-8 String)"]&lt;/div>
&lt;p>The application is responsible for the &lt;strong>section from A to C (audio decoding and resampling)&lt;/strong> in the diagram above. Since &lt;code>whisper.cpp&lt;/code> itself does not include an audio file decoder, the best practice is to combine it with libraries like FFmpeg or &lt;code>miniaudio&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="4-building-and-integrating-whispercpp">4. Building and Integrating whisper.cpp
&lt;/h2>&lt;p>Here are the steps to integrate &lt;code>whisper.cpp&lt;/code> into your project. Using CMake is the most versatile approach.&lt;/p>
&lt;h3 id="cmakeliststxt-configuration">CMakeLists.txt Configuration
&lt;/h3>&lt;p>You can include &lt;code>whisper.cpp&lt;/code> into your project as source code or add it as a submodule and link it.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.14&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">WhisperApp&lt;/span> &lt;span class="s">C&lt;/span> &lt;span class="s">CXX&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">17&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD_REQUIRED&lt;/span> &lt;span class="s">ON&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Enable CPU instruction extensions (AVX, F16C, etc.)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># For MacOS, the NEON/Accelerate framework is automatically enabled
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">WHISPER_SUPPORT_SDL2&lt;/span> &lt;span class="s">OFF&lt;/span> &lt;span class="s">CACHE&lt;/span> &lt;span class="s">BOOL&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span> &lt;span class="s">FORCE&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">whisper.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">whisper_app&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">whisper_app&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">whisper&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>With this configuration, the highly optimized &lt;code>ggml&lt;/code> backend of &lt;code>whisper.cpp&lt;/code> is built and statically linked to your application.&lt;/p>
&lt;hr>
&lt;h2 id="5-c-api-details-and-implementation-steps">5. C++ API Details and Implementation Steps
&lt;/h2>&lt;p>Now, let&amp;rsquo;s explain how to use the API by looking at actual C++ code.&lt;/p>
&lt;h3 id="51-context-initialization-and-model-loading">5.1 Context Initialization and Model Loading
&lt;/h3>&lt;p>In &lt;code>whisper.cpp&lt;/code>, all states and memory allocations are managed by the &lt;code>whisper_context&lt;/code> struct.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;#34;whisper.h&amp;#34;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Initialize parameters
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">struct&lt;/span> &lt;span class="nc">whisper_context_params&lt;/span> &lt;span class="n">cparams&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_context_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cparams&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">use_gpu&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Use GPU acceleration (CuBLAS/Metal) if available
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. Load the model (ggml format binary model)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">model_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;models/ggml-base.bin&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">struct&lt;/span> &lt;span class="nc">whisper_context&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_init_from_file_with_params&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">cparams&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Error: Failed to load the model - &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">model_path&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Model loaded successfully.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Set parameters for full inference (using Greedy Sampling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">struct&lt;/span> &lt;span class="nc">whisper_full_params&lt;/span> &lt;span class="n">wparams&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_full_default_params&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WHISPER_SAMPLING_GREEDY&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Set the number of threads (matching the physical CPU cores is optimal)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">wparams&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_threads&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Language setting (&amp;#34;auto&amp;#34; for auto-detection, &amp;#34;ja&amp;#34; for Japanese)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">wparams&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">language&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;ja&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Suppress standard output for intermediate results (to control it within the app)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">wparams&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">print_progress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">wparams&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">print_realtime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Translation feature (set to true to directly translate Japanese audio to English text)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">wparams&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">translate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Virtual audio data (in reality, PCM data obtained from a file or microphone)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 3 seconds (16000 Hz * 3 sec = 48000 samples)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">pcmf32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">48000&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.0f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. Run inference
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">whisper_full&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">wparams&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pcmf32&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">pcmf32&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Error: Failed to execute whisper_full.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">whisper_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. Retrieve and display the results
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_segments&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_full_n_segments&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">n_segments&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_full_get_segment_text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Retrieve timestamps (Unit: 10ms)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int64_t&lt;/span> &lt;span class="n">t0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_full_get_segment_t0&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="kt">int64_t&lt;/span> &lt;span class="n">t1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">whisper_full_get_segment_t1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">t0&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mf">10.0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; ms -&amp;gt; &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">t1&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mf">10.0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; ms]: &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">text&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 6. Free memory
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">whisper_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This code block serves as the most fundamental template for using Whisper in C++.&lt;/p>
&lt;hr>
&lt;h2 id="6-advanced-implementation-of-real-time-speech-recognition">6. Advanced Implementation of Real-Time Speech Recognition
&lt;/h2>&lt;p>Processing pre-recorded files is easy, but to improve the application&amp;rsquo;s UX, &amp;ldquo;real-time speech recognition (streaming recognition)&amp;rdquo; from a microphone input is necessary.&lt;/p>
&lt;p>To implement this, a multi-threaded architecture and managing the audio stream using a Ring Buffer are essential.&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "Audio Thread (High Priority)"
A["Audio Capture API (CoreAudio/WASAPI/ALSA)"] -->|Callback| B["Resampler (to 16kHz)"]
B --> C["Ring Buffer"]
end
subgraph "Main / Worker Thread"
C -->|Pop 30ms-1000ms chunk| D["Voice Activity Detection (VAD)"]
D -->|If speech detected| E["Accumulate PCM Buffer"]
E -->|Trigger Inference| F["whisper_full()"]
F --> G["Update UI/Text"]
end&lt;/div>
&lt;h3 id="61-the-importance-of-voice-activity-detection-vad">6.1 The Importance of Voice Activity Detection (VAD)
&lt;/h3>&lt;p>In real-time processing, it is a waste of computational resources to constantly run inference on silent parts. By inserting a VAD algorithm (like simple energy-based thresholding or WebRTC VAD) in the preceding stage, you can implement control logic such as: &lt;strong>&amp;ldquo;Start buffering only when speech begins, and kick off &lt;code>whisper_full&lt;/code> when speech ends (after a certain period of silence).&amp;rdquo;&lt;/strong>&lt;/p>
&lt;h3 id="62-sliding-window-approach">6.2 Sliding Window Approach
&lt;/h3>&lt;p>When speech continues for a long time, we use a &amp;ldquo;sliding window&amp;rdquo; approach where chunks are cut out every few seconds for inference. However, if you simply chop the audio abruptly, words may be cut off in the middle, significantly degrading recognition accuracy.&lt;/p>
&lt;p>As a countermeasure, we use a technique where we &lt;strong>&amp;ldquo;always run inference including the context of the past N seconds&amp;rdquo;&lt;/strong> (overlapping). &lt;code>whisper.cpp&lt;/code> also has a feature called &lt;code>wparams.prompt_tokens&lt;/code> that carries over past text tokens as a prompt, enabling highly accurate streaming recognition that maintains context.&lt;/p>
&lt;hr>
&lt;h2 id="7-memory-management-and-optimization-for-edge-devices">7. Memory Management and Optimization for Edge Devices
&lt;/h2>&lt;p>Let&amp;rsquo;s delve deeper into performance and memory efficiency, which are the greatest advantages of &lt;code>whisper.cpp&lt;/code>.&lt;/p>
&lt;h3 id="71-the-power-of-the-ggml-tensor-library">7.1 The Power of the ggml Tensor Library
&lt;/h3>&lt;p>&lt;code>ggml&lt;/code>, the backend of &lt;code>whisper.cpp&lt;/code>, is a C-language tensor library with no dependencies. Its biggest feature is its support for &lt;strong>dynamic quantization of weight data&lt;/strong>.&lt;/p>
&lt;p>For example, let&amp;rsquo;s calculate the memory size of the Whisper &lt;code>Small&lt;/code> model (about 244 million parameters).
For standard precision (16-bit Float = 2 bytes):&lt;/p>
$$ \text{Memory (FP16)} \approx 244,000,000 \times 2 \text{ bytes} \approx 488 \text{ MB} $$
&lt;p>If we convert this to 4-bit quantization (Q4_0 format), it averages about 0.5 bytes per parameter (approximately 0.56 bytes including overhead like scaling factors).&lt;/p>
$$ \text{Memory (Q4\_0)} \approx 244,000,000 \times 0.56 \text{ bytes} \approx 137 \text{ MB} $$
&lt;p>In environments with strict RAM constraints like iOS devices or Raspberry Pi, reducing this memory footprint directly translates to the overall stability of the application.&lt;/p>
&lt;h3 id="72-utilizing-hardware-acceleration">7.2 Utilizing Hardware Acceleration
&lt;/h3>&lt;p>While it is sufficiently fast on a CPU alone due to AVX2 or NEON instructions, &lt;code>whisper.cpp&lt;/code> also supports hardware acceleration from various GPUs and NPUs as backends.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Apple Silicon (Mac/iOS)&lt;/strong>: Metal API support via &lt;code>ggml-metal&lt;/code>. Ultra-fast inference using the GPU.&lt;/li>
&lt;li>&lt;strong>NVIDIA GPU (Windows/Linux)&lt;/strong>: &lt;code>cuBLAS&lt;/code> support. Specify &lt;code>-DWHISPER_CUBLAS=ON&lt;/code> during CMake build.&lt;/li>
&lt;li>&lt;strong>Intel (Windows/Linux)&lt;/strong>: &lt;code>OpenVINO&lt;/code> backend support. Can utilize the NPU on the latest Intel Core processors.&lt;/li>
&lt;/ul>
&lt;p>When using these accelerators in a C++ project, there is almost no need to modify the source code. As long as &lt;code>cparams.use_gpu = true;&lt;/code> is set during context initialization, the workload is automatically offloaded to the hardware depending on the built backend.&lt;/p>
&lt;h3 id="73-tuning-caches-and-the-number-of-threads">7.3 Tuning Caches and the Number of Threads
&lt;/h3>&lt;p>The setting of &lt;code>wparams.n_threads&lt;/code> is extremely important. Blindly increasing the number of threads will not improve performance due to the memory bandwidth bottleneck (Memory Bound).&lt;/p>
&lt;p>As a rule of thumb, it is ideal to determine the number of threads using the following formula:&lt;/p>
$$ N_{\text{threads}} = \min(\text{Physical CPU Cores}, 4 \sim 8) $$
&lt;p>Including logical cores like Hyper-Threading often causes cache contention and conversely slows down the inference speed, so setting it to the &lt;strong>number of physical cores&lt;/strong> is a golden rule. If you use &lt;code>std::thread::hardware_concurrency()&lt;/code> in C++11, it returns the number of logical cores, so it is recommended to hardcode it depending on the environment or get the physical core count via OS-level APIs.&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusion">8. Conclusion
&lt;/h2>&lt;p>In this article, we thoroughly explained how to leverage &lt;code>whisper.cpp&lt;/code> to integrate top-tier speech recognition AI into a C++ project, covering everything from theory to practice and optimization.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Strict adherence to input requirements&lt;/strong>: Ensure 16kHz, 1ch, 32-bit Float.&lt;/li>
&lt;li>&lt;strong>Intuitive API usage&lt;/strong>: A simple design where inference is completed just with &lt;code>whisper_init_from_file_with_params&lt;/code> and &lt;code>whisper_full&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Real-time implementation&lt;/strong>: Multi-thread control using VAD and sliding windows.&lt;/li>
&lt;li>&lt;strong>Overwhelming optimization&lt;/strong>: The benefits of 4-bit quantization via &lt;code>ggml&lt;/code> and hardware backends like Metal/cuBLAS.&lt;/li>
&lt;/ul>
&lt;p>Break free from dependencies on massive Python environments or cloud APIs, and please make use of &lt;code>whisper.cpp&lt;/code> to develop audio processing applications that run fast and securely in native environments. Local-only AI will become an extremely crucial core technology in future software development from the perspectives of privacy protection and latency.&lt;/p></description></item></channel></rss>