Fangjun Kuang преди 2 години
родител
ревизия
80888d81c5

+ 138 - 0
.github/workflows/mfc.yaml

@@ -0,0 +1,138 @@
+name: mfc
+
+on:
+  push:
+    branches:
+      - master
+    tags:
+      - '*'
+    paths:
+      - '.github/workflows/mfc.yaml'
+      - 'CMakeLists.txt'
+      - 'cmake/**'
+      - 'mfc-examples/**'
+      - 'sherpa-ncnn/csrc/*'
+      - 'sherpa-ncnn/c-api/*'
+  pull_request:
+    branches:
+      - master
+    paths:
+      - '.github/workflows/mfc.yaml'
+      - 'CMakeLists.txt'
+      - 'cmake/**'
+      - 'mfc-examples/**'
+      - 'sherpa-ncnn/csrc/*'
+      - 'sherpa-ncnn/c-api/*'
+  release:
+    types:
+      - published
+
+  workflow_dispatch:
+    inputs:
+      release:
+        description: "Whether to release"
+        type: boolean
+
+env:
+  RELEASE:
+    |- # Release if there is a release tag name or a release flag in workflow_dispatch
+    ${{ github.event.release.tag_name != '' || github.event.inputs.release == 'true' }}
+
+concurrency:
+  group: mfc-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  mfc:
+    name: MFC for ${{ matrix.arch }}
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [windows-latest]
+        arch: [x64, Win32]
+
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: Display MSBuild info
+        shell: cmd
+        run: |
+          set path="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin"
+          msbuild -help
+
+      - name: Configure CMake
+        shell: bash
+        run: |
+          mkdir build
+          cd build
+          cmake -A ${{ matrix.arch }} -D CMAKE_BUILD_TYPE=Release -D BUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=./install ..
+
+      - name: Build sherpa-ncnn for windows ${{ matrix.arch }}
+        shell: bash
+        run: |
+          cd build
+          cmake --build . --config Release -- -m:2
+          cmake --build . --config Release --target install -- -m:2
+
+          ls -lh install/*
+
+          ls -lh install/lib
+          ls -lh install/bin
+
+      - name: Build MFC
+        if: matrix.arch == 'x64'
+        shell: cmd
+        run: |
+          set path="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin"
+
+          cd mfc-examples
+
+          msbuild .\mfc-examples.sln /property:Configuration=Release /property:Platform=x64
+
+      - name: Build MFC
+        if: matrix.arch == 'Win32'
+        shell: cmd
+        run: |
+          set path="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin"
+
+          cd mfc-examples
+
+          msbuild .\mfc-examples.sln /property:Configuration=Release /property:Platform=x86
+
+      - name: Copy files
+        shell: bash
+        run: |
+          SHERPA_NCNN_VERSION=v$(grep "SHERPA_NCNN_VERSION" ./CMakeLists.txt  | cut -d " " -f 2  | cut -d '"' -f 2)
+          arch=${{ matrix.arch }}
+          d=$PWD
+
+          ls -lh mfc-examples
+          ls -lh mfc-examples/*
+
+          if [[ $arch == 'x64' ]]; then
+            cd mfc-examples/$arch/Release
+            cp RealtimeSpeechRecognition.exe $d/sherpa-ncnn-x64-${SHERPA_NCNN_VERSION}.exe
+          else
+            cd mfc-examples/Release
+            cp RealtimeSpeechRecognition.exe $d/sherpa-ncnn-x86-${SHERPA_NCNN_VERSION}.exe
+          fi
+
+          ls -lh
+          ls -lh $d/
+
+      - name: Upload artifact
+        uses: actions/upload-artifact@v2
+        with:
+          name: sherpa-ncnn-${{ matrix.arch }}
+          path: ./sherpa-ncnn*.exe
+
+      - name: Release pre-compiled binaries for Windows ${{ matrix.arch }}
+        if: env.RELEASE == 'true'
+        uses: svenstaro/upload-release-action@v2
+        with:
+          file_glob: true
+          overwrite: true
+          file: ./sherpa-ncnn*.exe

+ 14 - 1
CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
 project(sherpa-ncnn)
 
-set(SHERPA_NCNN_VERSION "2.0.4")
+set(SHERPA_NCNN_VERSION "2.0.5")
 
 # Disable warning about
 #
@@ -53,6 +53,19 @@ endif()
 if(BUILD_SHARED_LIBS AND MSVC)
   set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
 endif()
+
+if(NOT BUILD_SHARED_LIBS AND MSVC)
+  # see https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html
+  # https://stackoverflow.com/questions/14172856/compile-with-mt-instead-of-md-using-cmake
+  if(MSVC)
+      add_compile_options(
+          $<$<CONFIG:>:/MT> #---------|
+          $<$<CONFIG:Debug>:/MTd> #---|-- Statically link the runtime libraries
+          $<$<CONFIG:Release>:/MT> #--|
+      )
+  endif()
+endif()
+
 message(STATUS "CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}")
 message(STATUS "BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}")
 message(STATUS "SHERPA_NCNN_ENABLE_PYTHON ${SHERPA_NCNN_ENABLE_PYTHON}")

+ 17 - 0
cmake/portaudio.cmake

@@ -52,6 +52,23 @@ function(download_portaudio)
   endif()
 
   add_subdirectory(${portaudio_SOURCE_DIR} ${portaudio_BINARY_DIR} EXCLUDE_FROM_ALL)
+
+  if(BUILD_SHARED_LIBS)
+    set_target_properties(portaudio PROPERTIES OUTPUT_NAME "sherpa-ncnn-portaudio")
+
+    if(SHERPA_NCNN_ENABLE_PYTHON AND WIN32)
+      install(TARGETS portaudio DESTINATION ..)
+    else()
+      install(TARGETS portaudio DESTINATION lib)
+    endif()
+  else()
+    set_target_properties(portaudio_static PROPERTIES OUTPUT_NAME "sherpa-ncnn-portaudio_static")
+    if(SHERPA_NCNN_ENABLE_PYTHON AND WIN32)
+      install(TARGETS portaudio_static DESTINATION ..)
+    else()
+      install(TARGETS portaudio_static DESTINATION lib)
+    endif()
+  endif()
 endfunction()
 
 download_portaudio()

+ 399 - 0
mfc-examples/.gitignore

@@ -0,0 +1,399 @@
+# See https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml

+ 92 - 0
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognition.cpp

@@ -0,0 +1,92 @@
+
+// RealtimeSpeechRecognition.cpp : Defines the class behaviors for the application.
+//
+
+#include "pch.h"
+#include "framework.h"
+#include "RealtimeSpeechRecognition.h"
+#include "RealtimeSpeechRecognitionDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// CRealtimeSpeechRecognitionApp
+
+BEGIN_MESSAGE_MAP(CRealtimeSpeechRecognitionApp, CWinApp)
+	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+
+// CRealtimeSpeechRecognitionApp construction
+
+CRealtimeSpeechRecognitionApp::CRealtimeSpeechRecognitionApp()
+{
+	// TODO: add construction code here,
+	// Place all significant initialization in InitInstance
+}
+
+
+// The one and only CRealtimeSpeechRecognitionApp object
+
+CRealtimeSpeechRecognitionApp theApp;
+
+
+// CRealtimeSpeechRecognitionApp initialization
+
+BOOL CRealtimeSpeechRecognitionApp::InitInstance()
+{
+	CWinApp::InitInstance();
+
+
+	// Create the shell manager, in case the dialog contains
+	// any shell tree view or shell list view controls.
+	CShellManager *pShellManager = new CShellManager;
+
+	// Activate "Windows Native" visual manager for enabling themes in MFC controls
+	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
+
+	// Standard initialization
+	// If you are not using these features and wish to reduce the size
+	// of your final executable, you should remove from the following
+	// the specific initialization routines you do not need
+	// Change the registry key under which our settings are stored
+	// TODO: You should modify this string to be something appropriate
+	// such as the name of your company or organization
+	SetRegistryKey(_T("Local AppWizard-Generated Applications"));
+
+	CRealtimeSpeechRecognitionDlg dlg;
+	m_pMainWnd = &dlg;
+	INT_PTR nResponse = dlg.DoModal();
+	if (nResponse == IDOK)
+	{
+		// TODO: Place code here to handle when the dialog is
+		//  dismissed with OK
+	}
+	else if (nResponse == IDCANCEL)
+	{
+		// TODO: Place code here to handle when the dialog is
+		//  dismissed with Cancel
+	}
+	else if (nResponse == -1)
+	{
+		TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
+		TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
+	}
+
+	// Delete the shell manager created above.
+	if (pShellManager != nullptr)
+	{
+		delete pShellManager;
+	}
+
+#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
+	ControlBarCleanUp();
+#endif
+
+	// Since the dialog has been closed, return FALSE so that we exit the
+	//  application, rather than start the application's message pump.
+	return FALSE;
+}
+

+ 32 - 0
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognition.h

@@ -0,0 +1,32 @@
+
+// RealtimeSpeechRecognition.h : main header file for the PROJECT_NAME application
+//
+
+#pragma once
+
+#ifndef __AFXWIN_H__
+	#error "include 'pch.h' before including this file for PCH"
+#endif
+
+#include "resource.h"		// main symbols
+
+
+// CRealtimeSpeechRecognitionApp:
+// See RealtimeSpeechRecognition.cpp for the implementation of this class
+//
+
+class CRealtimeSpeechRecognitionApp : public CWinApp
+{
+public:
+	CRealtimeSpeechRecognitionApp();
+
+// Overrides
+public:
+	virtual BOOL InitInstance();
+
+// Implementation
+
+	DECLARE_MESSAGE_MAP()
+};
+
+extern CRealtimeSpeechRecognitionApp theApp;

BIN
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognition.rc


+ 219 - 0
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognition.vcxproj

@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>17.0</VCProjectVersion>
+    <ProjectGuid>{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}</ProjectGuid>
+    <Keyword>MFCProj</Keyword>
+    <RootNamespace>RealtimeSpeechRecognition</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <UseOfMfc>Static</UseOfMfc>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="sherpa-ncnn-deps.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="sherpa-ncnn-deps.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="sherpa-ncnn-deps.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="sherpa-ncnn-deps.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Midl>
+      <MkTypLibCompatible>false</MkTypLibCompatible>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </Midl>
+    <ResourceCompile>
+      <Culture>0x0409</Culture>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="framework.h" />
+    <ClInclude Include="pch.h" />
+    <ClInclude Include="RealtimeSpeechRecognition.h" />
+    <ClInclude Include="RealtimeSpeechRecognitionDlg.h" />
+    <ClInclude Include="Resource.h" />
+    <ClInclude Include="targetver.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="pch.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="RealtimeSpeechRecognition.cpp" />
+    <ClCompile Include="RealtimeSpeechRecognitionDlg.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="RealtimeSpeechRecognition.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\RealtimeSpeechRecognition.rc2" />
+  </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\RealtimeSpeechRecognition.ico" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 63 - 0
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognition.vcxproj.filters

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="RealtimeSpeechRecognition.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="RealtimeSpeechRecognitionDlg.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="framework.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="targetver.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Resource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pch.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="RealtimeSpeechRecognition.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="RealtimeSpeechRecognitionDlg.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="pch.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="RealtimeSpeechRecognition.rc">
+      <Filter>Resource Files</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\RealtimeSpeechRecognition.rc2">
+      <Filter>Resource Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\RealtimeSpeechRecognition.ico">
+      <Filter>Resource Files</Filter>
+    </Image>
+  </ItemGroup>
+</Project>

+ 488 - 0
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognitionDlg.cpp

@@ -0,0 +1,488 @@
+
+// RealtimeSpeechRecognitionDlg.cpp : implementation file
+//
+// clang-format off
+#include "pch.h"
+#include "framework.h"
+#include "afxdialogex.h"
+// clang-format on
+#include "RealtimeSpeechRecognitionDlg.h"
+
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "RealtimeSpeechRecognition.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+Microphone::Microphone() {
+  PaError err = Pa_Initialize();
+  if (err != paNoError) {
+    fprintf(stderr, "portaudio error: %s\n", Pa_GetErrorText(err));
+    exit(-2);
+  }
+}
+
+Microphone::~Microphone() {
+  PaError err = Pa_Terminate();
+  if (err != paNoError) {
+    fprintf(stderr, "portaudio error: %s\n", Pa_GetErrorText(err));
+    exit(-2);
+  }
+}
+
+// CRealtimeSpeechRecognitionDlg dialog
+
+CRealtimeSpeechRecognitionDlg::CRealtimeSpeechRecognitionDlg(
+    CWnd *pParent /*=nullptr*/)
+    : CDialogEx(IDD_REALTIMESPEECHRECOGNITION_DIALOG, pParent) {
+  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+CRealtimeSpeechRecognitionDlg::~CRealtimeSpeechRecognitionDlg() {
+  if (recognizer_) {
+    DestroyRecognizer(recognizer_);
+    recognizer_ = nullptr;
+  }
+}
+
+void CRealtimeSpeechRecognitionDlg::DoDataExchange(CDataExchange *pDX) {
+  CDialogEx::DoDataExchange(pDX);
+  DDX_Control(pDX, IDOK, my_btn_);
+  DDX_Control(pDX, IDC_EDIT1, my_text_);
+}
+
+BEGIN_MESSAGE_MAP(CRealtimeSpeechRecognitionDlg, CDialogEx)
+ON_WM_PAINT()
+ON_WM_QUERYDRAGICON()
+ON_BN_CLICKED(IDOK, &CRealtimeSpeechRecognitionDlg::OnBnClickedOk)
+END_MESSAGE_MAP()
+
+// CRealtimeSpeechRecognitionDlg message handlers
+
+BOOL CRealtimeSpeechRecognitionDlg::OnInitDialog() {
+  CDialogEx::OnInitDialog();
+
+  // Set the icon for this dialog.  The framework does this automatically
+  //  when the application's main window is not a dialog
+  SetIcon(m_hIcon, TRUE);   // Set big icon
+  SetIcon(m_hIcon, FALSE);  // Set small icon
+
+  // TODO: Add extra initialization here
+  InitMicrophone();
+
+  return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+// If you add a minimize button to your dialog, you will need the code below
+//  to draw the icon.  For MFC applications using the document/view model,
+//  this is automatically done for you by the framework.
+
+void CRealtimeSpeechRecognitionDlg::OnPaint() {
+  if (IsIconic()) {
+    CPaintDC dc(this);  // device context for painting
+
+    SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()),
+                0);
+
+    // Center icon in client rectangle
+    int cxIcon = GetSystemMetrics(SM_CXICON);
+    int cyIcon = GetSystemMetrics(SM_CYICON);
+    CRect rect;
+    GetClientRect(&rect);
+    int x = (rect.Width() - cxIcon + 1) / 2;
+    int y = (rect.Height() - cyIcon + 1) / 2;
+
+    // Draw the icon
+    dc.DrawIcon(x, y, m_hIcon);
+  } else {
+    CDialogEx::OnPaint();
+  }
+}
+
+// The system calls this function to obtain the cursor to display while the user
+// drags
+//  the minimized window.
+HCURSOR CRealtimeSpeechRecognitionDlg::OnQueryDragIcon() {
+  return static_cast<HCURSOR>(m_hIcon);
+}
+
+// see
+// https://stackoverflow.com/questions/7153935/how-to-convert-utf-8-stdstring-to-utf-16-stdwstring
+static std::wstring Utf8ToUtf16(const std::string &utf8) {
+  std::vector<unsigned long> unicode;
+  size_t i = 0;
+  while (i < utf8.size()) {
+    unsigned long uni;
+    size_t todo;
+    bool error = false;
+    unsigned char ch = utf8[i++];
+    if (ch <= 0x7F) {
+      uni = ch;
+      todo = 0;
+    } else if (ch <= 0xBF) {
+      throw std::logic_error("not a UTF-8 string");
+    } else if (ch <= 0xDF) {
+      uni = ch & 0x1F;
+      todo = 1;
+    } else if (ch <= 0xEF) {
+      uni = ch & 0x0F;
+      todo = 2;
+    } else if (ch <= 0xF7) {
+      uni = ch & 0x07;
+      todo = 3;
+    } else {
+      throw std::logic_error("not a UTF-8 string");
+    }
+    for (size_t j = 0; j < todo; ++j) {
+      if (i == utf8.size()) throw std::logic_error("not a UTF-8 string");
+      unsigned char ch = utf8[i++];
+      if (ch < 0x80 || ch > 0xBF) throw std::logic_error("not a UTF-8 string");
+      uni <<= 6;
+      uni += ch & 0x3F;
+    }
+    if (uni >= 0xD800 && uni <= 0xDFFF)
+      throw std::logic_error("not a UTF-8 string");
+    if (uni > 0x10FFFF) throw std::logic_error("not a UTF-8 string");
+    unicode.push_back(uni);
+  }
+  std::wstring utf16;
+  for (size_t i = 0; i < unicode.size(); ++i) {
+    unsigned long uni = unicode[i];
+    if (uni <= 0xFFFF) {
+      utf16 += (wchar_t)uni;
+    } else {
+      uni -= 0x10000;
+      utf16 += (wchar_t)((uni >> 10) + 0xD800);
+      utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00);
+    }
+  }
+  return utf16;
+}
+
+void CRealtimeSpeechRecognitionDlg::AppendTextToEditCtrl(const std::string &s) {
+  // get the initial text length
+  int nLength = my_text_.GetWindowTextLength();
+  // put the selection at the end of text
+  my_text_.SetSel(nLength, nLength);
+  // replace the selection
+
+  std::wstring wstr = Utf8ToUtf16(s);
+
+  // my_text_.ReplaceSel(wstr.c_str());
+  my_text_.ReplaceSel(wstr.c_str());
+}
+
+void CRealtimeSpeechRecognitionDlg::AppendLineToMultilineEditCtrl(
+    const std::string &s) {
+  AppendTextToEditCtrl("\r\n" + s);
+}
+
+void CRealtimeSpeechRecognitionDlg::InitMicrophone() {
+  int default_device = Pa_GetDefaultInputDevice();
+  int device_count = Pa_GetDeviceCount();
+  if (default_device == paNoDevice) {
+    // CString str;
+    // str.Format(_T("No default input device found!"));
+    // AfxMessageBox(str, MB_OK | MB_ICONSTOP);
+    // exit(-1);
+    AppendLineToMultilineEditCtrl("No default input device found!");
+    my_btn_.EnableWindow(FALSE);
+    return;
+  }
+  AppendLineToMultilineEditCtrl(std::string("Selected device ") +
+                                Pa_GetDeviceInfo(default_device)->name);
+}
+
+static int32_t RecordCallback(const void *input_buffer,
+                              void * /*output_buffer*/,
+                              unsigned long frames_per_buffer,  // NOLINT
+                              const PaStreamCallbackTimeInfo * /*time_info*/,
+                              PaStreamCallbackFlags /*status_flags*/,
+                              void *user_data) {
+  auto dlg = reinterpret_cast<CRealtimeSpeechRecognitionDlg *>(user_data);
+
+  auto stream = dlg->stream_;
+  if (stream) {
+    AcceptWaveform(stream, 16000, reinterpret_cast<const float *>(input_buffer),
+                   frames_per_buffer);
+  }
+
+  return dlg->started_ ? paContinue : paComplete;
+}
+
+void CRealtimeSpeechRecognitionDlg::OnBnClickedOk() {
+  if (!recognizer_) {
+    AppendLineToMultilineEditCtrl("Creating recognizer...");
+    InitRecognizer();
+    if (!recognizer_) {
+      // failed to create the recognizer
+      return;
+    }
+    AppendLineToMultilineEditCtrl("Recognizer created!");
+  }
+
+  if (!started_) {
+    started_ = true;
+
+    if (stream_) {
+      DestroyStream(stream_);
+      stream_ = nullptr;
+    }
+
+    stream_ = CreateStream(recognizer_);
+
+    PaStreamParameters param;
+    param.device = Pa_GetDefaultInputDevice();
+    const PaDeviceInfo *info = Pa_GetDeviceInfo(param.device);
+    param.channelCount = 1;
+    param.sampleFormat = paFloat32;
+    param.suggestedLatency = info->defaultLowInputLatency;
+    param.hostApiSpecificStreamInfo = nullptr;
+    float sample_rate = 16000;
+    pa_stream_ = nullptr;
+    PaError err =
+        Pa_OpenStream(&pa_stream_, &param, nullptr, /* &outputParameters, */
+                      sample_rate,
+                      0,          // frames per buffer
+                      paClipOff,  // we won't output out of range samples
+                                  // so don't bother clipping them
+                      RecordCallback, this);
+    if (err != paNoError) {
+      AppendLineToMultilineEditCtrl(std::string("PortAudio error: ") +
+                                    Pa_GetErrorText(err));
+      my_btn_.EnableWindow(FALSE);
+      return;
+    }
+
+    err = Pa_StartStream(pa_stream_);
+    if (err != paNoError) {
+      AppendLineToMultilineEditCtrl(std::string("PortAudio error: ") +
+                                    Pa_GetErrorText(err));
+      my_btn_.EnableWindow(FALSE);
+      return;
+    }
+    AppendLineToMultilineEditCtrl("Started! Please speak");
+    my_btn_.SetWindowText(_T("Stop"));
+
+    thread_ = new RecognizerThread(this);
+    thread_->CreateThread(CREATE_SUSPENDED);
+    thread_->m_bAutoDelete = false;  // Let me delete it.
+    thread_->ResumeThread();
+  } else {
+    started_ = false;
+    Pa_Sleep(200);  // sleep for 200ms
+    if (pa_stream_) {
+      PaError err = Pa_CloseStream(pa_stream_);
+      if (err != paNoError) {
+        AppendLineToMultilineEditCtrl(std::string("PortAudio error: ") +
+                                      Pa_GetErrorText(err));
+        my_btn_.EnableWindow(FALSE);
+        return;
+      }
+    }
+    pa_stream_ = nullptr;
+
+    WaitForSingleObject(thread_->m_hThread, INFINITE);
+    delete thread_;
+    thread_ = nullptr;
+
+    // AfxMessageBox("stopped", MB_OK);
+    my_btn_.SetWindowText(_T("Start"));
+    AppendLineToMultilineEditCtrl("Stopped");
+  }
+}
+
+bool CRealtimeSpeechRecognitionDlg::Exists(const std::string &filename) {
+  std::ifstream is(filename);
+  return is.good();
+}
+
+void CRealtimeSpeechRecognitionDlg::InitRecognizer() {
+  std::string encoder_param = "./encoder_jit_trace-pnnx.ncnn.param";
+  std::string encoder_bin = "./encoder_jit_trace-pnnx.ncnn.bin";
+  std::string decoder_param = "./decoder_jit_trace-pnnx.ncnn.param";
+  std::string decoder_bin = "./decoder_jit_trace-pnnx.ncnn.bin";
+  std::string joiner_param = "./joiner_jit_trace-pnnx.ncnn.param";
+  std::string joiner_bin = "./joiner_jit_trace-pnnx.ncnn.bin";
+  std::string tokens = "./tokens.txt";
+
+  bool is_ok = true;
+  if (!Exists(encoder_param)) {
+    std::string msg = encoder_param + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!Exists(encoder_bin)) {
+    std::string msg = encoder_bin + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!Exists(decoder_param)) {
+    std::string msg = decoder_param + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!Exists(decoder_bin)) {
+    std::string msg = decoder_bin + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!Exists(joiner_param)) {
+    std::string msg = joiner_param + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!Exists(joiner_bin)) {
+    std::string msg = joiner_bin + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!Exists(tokens)) {
+    std::string msg = tokens + " does not exist!";
+    AppendLineToMultilineEditCtrl(msg);
+    is_ok = false;
+  }
+
+  if (!is_ok) {
+    my_btn_.EnableWindow(FALSE);
+    std::string msg =
+        "\r\nPlease go to\r\n"
+        "https://k2-fsa.github.io/sherpa/ncnn/pretrained_models/index.html"
+        "\r\n";
+    msg += "to download a pre-trained model.\r\n\r\n";
+    msg +=
+        "We use the following model as an example to show you how "
+        "to do "
+        "that.\r\n";
+    msg +=
+        "https://k2-fsa.github.io/sherpa/ncnn/pretrained_models/"
+        "zipformer-transucer-models.html#csukuangfj-sherpa-ncnn-"
+        "streaming-zipformer-bilingual-zh-en-2023-02-13-bilingual-"
+        "chinese-english";
+    msg += "\r\n\r\n";
+    msg +=
+        "wget "
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/encoder_jit_trace-pnnx.ncnn.param\r\n";
+    msg +=
+        "wget "
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/encoder_jit_trace-pnnx.ncnn.bin\r\n";
+    msg +=
+        "wget "
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/decoder_jit_trace-pnnx.ncnn.param\r\n";
+    msg +=
+        "wget "
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/decoder_jit_trace-pnnx.ncnn.bin\r\n";
+    msg +=
+        "wget "
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/joiner_jit_trace-pnnx.ncnn.param\r\n";
+    msg +=
+        "wget "
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/joiner_jit_trace-pnnx.ncnn.bin\r\n";
+    msg +=
+        "https://huggingface.co/csukuangfj/"
+        "sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-"
+        "13/resolve/main/tokens.txt\r\n";
+
+    msg += "\r\n\r\nThat's it!\r\n";
+
+    AppendLineToMultilineEditCtrl(msg);
+    return;
+  }
+
+  SherpaNcnnRecognizerConfig config;
+  config.model_config.num_threads = 1;
+
+  config.decoder_config.decoding_method = "greedy_search";
+  config.decoder_config.num_active_paths = 4;
+
+  config.feat_config.sampling_rate = 16000;
+  config.feat_config.feature_dim = 80;
+
+  config.enable_endpoint = 1;
+  config.rule1_min_trailing_silence = 1.2f;
+  config.rule2_min_trailing_silence = 0.8f;
+  config.rule3_min_utterance_length = 300.0f;
+
+  config.model_config.tokens = tokens.c_str();
+  config.model_config.encoder_param = encoder_param.c_str();
+  config.model_config.encoder_bin = encoder_bin.c_str();
+  config.model_config.decoder_param = decoder_param.c_str();
+  config.model_config.decoder_bin = decoder_bin.c_str();
+  config.model_config.joiner_param = joiner_param.c_str();
+  config.model_config.joiner_bin = joiner_bin.c_str();
+
+  recognizer_ = CreateRecognizer(&config);
+}
+static std::string Cat(const std::vector<std::string> &results,
+                       const std::string &s) {
+  std::ostringstream os;
+  std::string sep;
+
+  int i = 0;
+  for (i = 0; i != results.size(); ++i) {
+    os << sep << i << ": " << results[i];
+    sep = "\r\n";
+  }
+
+  if (!s.empty()) {
+    os << sep << i << ": " << s;
+  }
+  return os.str();
+}
+int CRealtimeSpeechRecognitionDlg::RunThread() {
+  std::vector<std::string> results;
+
+  std::string last_text;
+  while (started_) {
+    while (IsReady(recognizer_, stream_)) {
+      Decode(recognizer_, stream_);
+    }
+
+    auto r = GetResult(recognizer_, stream_);
+    std::string text = r->text;
+    DestroyResult(r);
+    if (!text.empty() && last_text != text) {
+      // CString str;
+      // str.Format(_T("%s"), Cat(results, text).c_str());
+      auto str = Utf8ToUtf16(Cat(results, text).c_str());
+      my_text_.SetWindowText(str.c_str());
+      my_text_.SetFocus();
+      my_text_.SetSel(-1);
+      last_text = text;
+    }
+    int is_endpoint = IsEndpoint(recognizer_, stream_);
+    if (is_endpoint) {
+      Reset(recognizer_, stream_);
+      if (!text.empty()) {
+        results.push_back(std::move(text));
+      }
+    }
+
+    Pa_Sleep(100);  // sleep for 100ms
+  }
+
+  return 0;
+}

+ 83 - 0
mfc-examples/RealtimeSpeechRecognition/RealtimeSpeechRecognitionDlg.h

@@ -0,0 +1,83 @@
+
+// RealtimeSpeechRecognitionDlg.h : header file
+//
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "portaudio.h"
+#include "sherpa-ncnn/c-api/c-api.h"
+
+class Microphone {
+ public:
+  Microphone();
+  ~Microphone();
+};
+
+class RecognizerThread;
+
+// CRealtimeSpeechRecognitionDlg dialog
+class CRealtimeSpeechRecognitionDlg : public CDialogEx {
+  // Construction
+ public:
+  CRealtimeSpeechRecognitionDlg(
+      CWnd *pParent = nullptr);  // standard constructor
+  ~CRealtimeSpeechRecognitionDlg();
+
+// Dialog Data
+#ifdef AFX_DESIGN_TIME
+  enum { IDD = IDD_REALTIMESPEECHRECOGNITION_DIALOG };
+#endif
+
+ protected:
+  virtual void DoDataExchange(CDataExchange *pDX);  // DDX/DDV support
+
+  // Implementation
+ protected:
+  HICON m_hIcon;
+
+  // Generated message map functions
+  virtual BOOL OnInitDialog();
+  afx_msg void OnPaint();
+  afx_msg HCURSOR OnQueryDragIcon();
+  DECLARE_MESSAGE_MAP()
+ public:
+  afx_msg void OnBnClickedOk();
+  int RunThread();
+
+ private:
+  Microphone mic_;
+
+  SherpaNcnnRecognizer *recognizer_ = nullptr;
+
+  PaStream *pa_stream_ = nullptr;
+  RecognizerThread *thread_ = nullptr;
+
+ public:
+  bool started_ = false;
+  SherpaNcnnStream *stream_ = nullptr;
+
+ public:
+  CButton my_btn_;
+  CEdit my_text_;
+
+ private:
+  void AppendTextToEditCtrl(const std::string &s);
+  void AppendLineToMultilineEditCtrl(const std::string &s);
+  void InitMicrophone();
+
+  bool Exists(const std::string &filename);
+  void InitRecognizer();
+};
+
+class RecognizerThread : public CWinThread {
+ public:
+  RecognizerThread(CRealtimeSpeechRecognitionDlg *dlg) : dlg_(dlg) {}
+  virtual BOOL InitInstance() { return TRUE; }
+  virtual int Run() { return dlg_->RunThread(); }
+
+ private:
+  CRealtimeSpeechRecognitionDlg *dlg_;
+};

+ 18 - 0
mfc-examples/RealtimeSpeechRecognition/Resource.h

@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by RealtimeSpeechRecognition.rc
+//
+#define IDD_REALTIMESPEECHRECOGNITION_DIALOG 102
+#define IDR_MAINFRAME                   128
+#define IDC_EDIT1                       1000
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        130
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif

+ 39 - 0
mfc-examples/RealtimeSpeechRecognition/framework.h

@@ -0,0 +1,39 @@
+#pragma once
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers
+#endif
+
+#include "targetver.h"
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit
+
+// turns off MFC's hiding of some common and often safely ignored warning messages
+#define _AFX_ALL_WARNINGS
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+
+
+
+
+
+#ifndef _AFX_NO_OLE_SUPPORT
+#include <afxdtctl.h>           // MFC support for Internet Explorer 4 Common Controls
+#endif
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>             // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <afxcontrolbars.h>     // MFC support for ribbons and control bars
+
+
+
+
+
+
+
+
+
+
+

+ 5 - 0
mfc-examples/RealtimeSpeechRecognition/pch.cpp

@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

+ 13 - 0
mfc-examples/RealtimeSpeechRecognition/pch.h

@@ -0,0 +1,13 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#include "framework.h"
+
+#endif //PCH_H

BIN
mfc-examples/RealtimeSpeechRecognition/res/RealtimeSpeechRecognition.ico


BIN
mfc-examples/RealtimeSpeechRecognition/res/RealtimeSpeechRecognition.rc2


+ 30 - 0
mfc-examples/RealtimeSpeechRecognition/sherpa-ncnn-deps.props

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?> 
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+	<SherpaNcnnBuildDirectory>..\..\build</SherpaNcnnBuildDirectory>
+	<SherpaNcnnInstallDirectory>..\..\build\install</SherpaNcnnInstallDirectory>
+	<SherpaNcnnLibraries>
+	  sherpa-ncnn-portaudio_static.lib;
+	  sherpa-ncnn-c-api.lib;;
+	  sherpa-ncnn-core.lib;
+	  kaldi-native-fbank-core.lib;
+	  ncnn.lib
+	</SherpaNcnnLibraries>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+	  <AdditionalIncludeDirectories>
+	    $(SherpaNcnnBuildDirectory)\_deps\portaudio-src\include;
+		$(SherpaNcnnInstallDirectory)\include;
+		%(AdditionalIncludeDirectories)
+	  </AdditionalIncludeDirectories>
+	</ClCompile>
+	 <Link>
+	   <AdditionalLibraryDirectories>$(SherpaNcnnInstallDirectory)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+	   <AdditionalDependencies>$(SherpaNcnnLibraries);</AdditionalDependencies>
+	 </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup />
+</Project>

+ 8 - 0
mfc-examples/RealtimeSpeechRecognition/targetver.h

@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>

+ 31 - 0
mfc-examples/mfc-examples.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.6.33829.357
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RealtimeSpeechRecognition", "RealtimeSpeechRecognition\RealtimeSpeechRecognition.vcxproj", "{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Debug|x64.ActiveCfg = Debug|x64
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Debug|x64.Build.0 = Debug|x64
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Debug|x86.ActiveCfg = Debug|Win32
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Debug|x86.Build.0 = Debug|Win32
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Release|x64.ActiveCfg = Release|x64
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Release|x64.Build.0 = Release|x64
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Release|x86.ActiveCfg = Release|Win32
+		{F837BDD7-E9A7-40F4-8B7F-CBEB2987D7E6}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1857C170-CAF2-45AD-9E22-9BECD869D857}
+	EndGlobalSection
+EndGlobal