diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cd7664d83..cc3dc1ac8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -376,3 +376,45 @@ jobs:
tag: ${{ github.ref }} # ==> github.event.release.tag_name
file: release/*.zip
file_glob: true
+
+ build-win-cpp-example:
+ runs-on: windows-latest
+ needs: [build-cpp-shared]
+
+ env:
+ # Path to the solution file relative to the root of the project.
+ SOLUTION_FILE_PATH: example\cpp\windows\windows_example.sln
+
+ # Configuration type to build.
+ # You can convert this to a build matrix if you need coverage of multiple configuration types.
+ # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+ BUILD_CONFIGURATION: Release
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Add MSBuild to PATH
+ uses: microsoft/setup-msbuild@v1.0.2
+
+ - name: Restore NuGet packages
+ working-directory: ${{env.GITHUB_WORKSPACE}}
+ run: nuget restore ${{env.SOLUTION_FILE_PATH}}
+
+ - name: Download and extract artifact
+ uses: actions/download-artifact@v2
+ id: download
+ with:
+ name: windows-x64-cpu-cpp-shared
+ path: artifacts\
+
+ - name: Copy core.lib
+ working-directory: ${{env.GITHUB_WORKSPACE}}
+ run: |
+ mkdir example\cpp\windows\simple_tts\lib\x64
+ copy ${{steps.download.outputs.download-path}}\core.lib example\cpp\windows\simple_tts\lib\x64
+
+ - name: Build
+ working-directory: ${{env.GITHUB_WORKSPACE}}
+ # Add additional options to the MSBuild command line here (like platform or verbosity level).
+ # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
+ run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
diff --git a/.gitignore b/.gitignore
index 3a6334f00..d15e18d32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ directml*/
# Build artifacts
build/
lib/
+bin/
core/_core.cpp
# Output
@@ -32,3 +33,7 @@ CMakeCache.txt
# Voicevox release
release/
+
+# Visual Studio
+.vs/
+packages/
diff --git a/example/cpp/windows/README.md b/example/cpp/windows/README.md
new file mode 100644
index 000000000..d30a3818c
--- /dev/null
+++ b/example/cpp/windows/README.md
@@ -0,0 +1,61 @@
+# Windows C++ のサンプルプロジェクト
+
+ここには、voicevox_coreライブラリをC++から使用するサンプルプロジェクトが含まれています。
+プロジェクトを開くには、Microsoft Visual Studio Community 2022(無料)が必要です。また、「C++によるデスクトップ開発」のワークロードが必要です。
+Visual Studio Installerを使用しインストールしてください。
+
+## simple_tts
+
+単純な音声合成を行うコンシールアプリケーションです。
+
+### 環境構築・ビルド方法
+
+ビルドして実行するには、「core.dll」「core.lib」「Open JTalk辞書フォルダ」が必要です。
+以下はDebug x64でビルドする場合です。他の構成・プラットフォーム向けにビルドする場合は、適宜読み替えてください。
+
+Releasesから「windows-x64-cpu-cpp-shared.zip」をダウンロードします。
+zipファイルを展開し、展開されたフォルダに含まれているdllファイルを「core.dll」にリネームします。
+出力フォルダを作成するために、一度ビルドします。「windows_example.sln」をVisual Studioで開き、メニューの「ビルド」→「ソリューションのビルド」を押します。
+この段階では、ビルドは失敗します。「bin」フォルダと「lib」フォルダが生成されていればOKです。
+
+「core.lib」を「simple_tts\lib\x64」に配置します。
+「core.dll」を「simple_tts\bin\x64\Debug」に配置します。
+
+もう一度ビルドします。今度は成功するはずです。失敗した場合は、「core.lib」の場所を確認してください。
+
+続いて、「Open JTalk辞書フォルダ」を配置します。
+http://open-jtalk.sourceforge.net/ を開き、Dictionary for Open JTalk 欄の Binary Package (UTF-8)をクリックして「open_jtalk_dic_utf_8-1.11.tar.gz」をダウンロードします。
+
+展開してできた「open_jtalk_dic_utf_8-1.11」フォルダをフォルダごと「simple_tts\bin\x64\Debug」に配置します。
+
+最終的には以下のようなフォルダ構成になっているはずです。
+```
+simple_tts
+│ packages.config
+│ simple_tts.cpp
+│ simple_tts.h
+│ simple_tts.vcxproj
+│ simple_tts.vcxproj.filters
+│ simple_tts.vcxproj.user
+│
+├─bin
+│ └─x64
+│ └─Debug
+│ │ core.dll
+│ │ onnxruntime.dll
+│ │ onnxruntime_providers_shared.dll
+│ │ simple_tts.exe
+│ │ simple_tts.pdb
+│ │
+│ └─open_jtalk_dic_utf_8-1.11
+│
+└─lib
+ └─x64
+ │ core.lib
+ │
+ └─Debug
+```
+
+### 実行
+Visual Studioのツールバーにある「ローカル Windows デバッガー」と書いてある三角のつているボタンを押すと実行できます。出力フォルダにある「simple_tts.exe」を直接実行することもできます。
+表示されたコンソール画面に、生成したい音声の文字列を入力しエンターキーを押します。そうすると音声合成が開始し、合成された音声が再生されます。
diff --git a/example/cpp/windows/simple_tts/packages.config b/example/cpp/windows/simple_tts/packages.config
new file mode 100644
index 000000000..07a94bc06
--- /dev/null
+++ b/example/cpp/windows/simple_tts/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/example/cpp/windows/simple_tts/simple_tts.cpp b/example/cpp/windows/simple_tts/simple_tts.cpp
new file mode 100644
index 000000000..3fd6f2fc4
--- /dev/null
+++ b/example/cpp/windows/simple_tts/simple_tts.cpp
@@ -0,0 +1,141 @@
+// simple_tts.cpp : このファイルには 'main' 関数が含まれています。プログラム実行の開始と終了がそこで行われます。
+//
+
+#include "simple_tts.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "..\..\..\core\src\core.h"
+
+#define OPENJTALK_DICT_NAME L"open_jtalk_dic_utf_8-1.11"
+
+int main() {
+ std::wcout.imbue(std::locale(""));
+ std::wcin.imbue(std::locale(""));
+
+ std::wcout << L"生成する音声の文字列を入力" << std::endl;
+ std::wcout << L">";
+ std::wstring speak_words;
+ std::wcin >> speak_words;
+
+ std::wcout << L"coreの初期化中" << std::endl;
+ initialize(false);
+
+ VoicevoxResultCode result = VoicevoxResultCode::VOICEVOX_RESULT_SUCCEED;
+
+ std::wcout << L"openjtalk辞書の読み込み" << std::endl;
+ result = voicevox_load_openjtalk_dict(GetOpenJTalkDict().c_str());
+ if (result != VoicevoxResultCode::VOICEVOX_RESULT_SUCCEED) {
+ std::cout << voicevox_error_result_to_message(result) << std::endl;
+ return 0;
+ }
+
+ std::wcout << L"音声生成中" << std::endl;
+ int64_t speaker_id = 0;
+ int output_binary_size = 0;
+ uint8_t* output_wav = nullptr;
+ result = voicevox_tts(wide_to_utf8_cppapi(speak_words).c_str(), speaker_id, &output_binary_size, &output_wav);
+ if (result != VoicevoxResultCode::VOICEVOX_RESULT_SUCCEED) {
+ std::cout << voicevox_error_result_to_message(result) << std::endl;
+ return 0;
+ }
+
+ {
+ //音声ファイルの保存
+ std::ofstream out_stream(GetWaveFileName().c_str(), std::ios::binary);
+ out_stream.write(reinterpret_cast(output_wav), output_binary_size);
+ std::wcout << GetWaveFileName() << L" に保存しました。" << std::endl;
+ } //ここでファイルが閉じられる
+
+ std::wcout << L"音声再生中" << std::endl;
+ PlaySound((LPCTSTR)output_wav, nullptr, SND_MEMORY);
+
+ std::wcout << L"音声データの開放" << std::endl;
+ voicevox_wav_free(output_wav);
+
+}
+
+///
+/// OpenJTalk辞書のパスを取得します。
+///
+/// OpenJTalk辞書のパス
+std::string GetOpenJTalkDict() {
+ wchar_t buff[MAX_PATH] = {0};
+ PathCchCombine(buff, MAX_PATH, GetExeDirectory().c_str(), OPENJTALK_DICT_NAME);
+ std::string retVal = wide_to_multi_capi(buff);
+ return retVal;
+}
+
+///
+/// 音声ファイル名を取得します。
+///
+/// 音声ファイルのフルパス
+std::wstring GetWaveFileName() {
+ wchar_t buff[MAX_PATH] = {0};
+ PathCchCombine(buff, MAX_PATH, GetExeDirectory().c_str(), L"speech.wav");
+ return std::wstring(buff);
+}
+
+///
+/// 自分自身のあるパスを取得する
+///
+/// 自分のexeのフルパス
+std::wstring GetExePath() {
+ wchar_t buff[MAX_PATH] = {0};
+ GetModuleFileName(nullptr, buff, MAX_PATH);
+ return std::wstring(buff);
+}
+
+///
+/// 自分自身のあるディレクトリを取得する
+///
+/// 自分のexeのあるディレクトリ
+std::wstring GetExeDirectory() {
+ wchar_t buff[MAX_PATH] = {0};
+ wcscpy_s(buff, MAX_PATH, GetExePath().c_str());
+ //フルパスからファイル名の削除
+ PathRemoveFileSpec(buff);
+ return std::wstring(buff);
+}
+
+///
+/// ワイド文字列をShift_JISに変換します。
+///
+/// ワイド文字列
+/// Shift_JIS文字列
+///
+/// https://nekko1119.hatenablog.com/entry/2017/01/02/054629 から引用
+///
+std::string wide_to_multi_capi(std::wstring const& src) {
+ std::size_t converted{};
+ std::vector dest(src.size() * sizeof(wchar_t) + 1, '\0');
+ if (::_wcstombs_s_l(&converted, dest.data(), dest.size(), src.data(), _TRUNCATE, ::_create_locale(LC_ALL, "jpn")) !=
+ 0) {
+ throw std::system_error{errno, std::system_category()};
+ }
+ dest.resize(std::char_traits::length(dest.data()));
+ dest.shrink_to_fit();
+ return std::string(dest.begin(), dest.end());
+}
+
+///
+/// ワイド文字列をUTF8に変換します。
+///
+/// ワイド文字列
+/// UTF8文字列
+///
+/// https://nekko1119.hatenablog.com/entry/2017/01/02/054629 から引用
+///
+std::string wide_to_utf8_cppapi(std::wstring const& src) {
+ std::wstring_convert> converter;
+ return converter.to_bytes(src);
+}
diff --git a/example/cpp/windows/simple_tts/simple_tts.h b/example/cpp/windows/simple_tts/simple_tts.h
new file mode 100644
index 000000000..14e2316bb
--- /dev/null
+++ b/example/cpp/windows/simple_tts/simple_tts.h
@@ -0,0 +1,9 @@
+#pragma once
+#include
+
+std::string GetOpenJTalkDict();
+std::wstring GetWaveFileName();
+std::wstring GetExePath();
+std::wstring GetExeDirectory();
+std::string wide_to_multi_capi(std::wstring const& src);
+std::string wide_to_utf8_cppapi(std::wstring const& src);
\ No newline at end of file
diff --git a/example/cpp/windows/simple_tts/simple_tts.vcxproj b/example/cpp/windows/simple_tts/simple_tts.vcxproj
new file mode 100644
index 000000000..1a48276fa
--- /dev/null
+++ b/example/cpp/windows/simple_tts/simple_tts.vcxproj
@@ -0,0 +1,182 @@
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {7f68db71-f477-4359-947f-4e35ad8b604e}
+ simpletts
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)bin\$(Platform)\$(Configuration)\
+ $(ProjectDir)lib\$(Platform)\$(Configuration)\
+
+
+ false
+ $(ProjectDir)bin\$(Platform)\$(Configuration)\
+ $(ProjectDir)lib\$(Platform)\$(Configuration)\
+
+
+ true
+ $(ProjectDir)bin\$(Platform)\$(Configuration)\
+ $(ProjectDir)lib\$(Platform)\$(Configuration)\
+
+
+ false
+ $(ProjectDir)bin\$(Platform)\$(Configuration)\
+ $(ProjectDir)lib\$(Platform)\$(Configuration)\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ..\..\..\core\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ Shlwapi.lib;Pathcch.lib;Winmm.lib;core.lib;%(AdditionalDependencies)
+ $(ProjectDir)lib\$(Platform)\
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ..\..\..\core\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ true
+ true
+ Shlwapi.lib;Pathcch.lib;Winmm.lib;core.lib;%(AdditionalDependencies)
+ $(ProjectDir)lib\$(Platform)\
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ..\..\..\core\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ Shlwapi.lib;Pathcch.lib;Winmm.lib;core.lib;%(AdditionalDependencies)
+ $(ProjectDir)lib\$(Platform)\
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ..\..\..\core\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ true
+ true
+ Shlwapi.lib;Pathcch.lib;Winmm.lib;core.lib;%(AdditionalDependencies)
+ $(ProjectDir)lib\$(Platform)\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。
+
+
+
+
+
\ No newline at end of file
diff --git a/example/cpp/windows/simple_tts/simple_tts.vcxproj.filters b/example/cpp/windows/simple_tts/simple_tts.vcxproj.filters
new file mode 100644
index 000000000..a96485cbb
--- /dev/null
+++ b/example/cpp/windows/simple_tts/simple_tts.vcxproj.filters
@@ -0,0 +1,32 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ ソース ファイル
+
+
+
+
+ ヘッダー ファイル
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/cpp/windows/simple_tts/simple_tts.vcxproj.user b/example/cpp/windows/simple_tts/simple_tts.vcxproj.user
new file mode 100644
index 000000000..88a550947
--- /dev/null
+++ b/example/cpp/windows/simple_tts/simple_tts.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/example/cpp/windows/windows_example.sln b/example/cpp/windows/windows_example.sln
new file mode 100644
index 000000000..995b2479b
--- /dev/null
+++ b/example/cpp/windows/windows_example.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32228.430
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_tts", "simple_tts\simple_tts.vcxproj", "{7F68DB71-F477-4359-947F-4E35AD8B604E}"
+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
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Debug|x64.ActiveCfg = Debug|x64
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Debug|x64.Build.0 = Debug|x64
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Debug|x86.ActiveCfg = Debug|Win32
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Debug|x86.Build.0 = Debug|Win32
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Release|x64.ActiveCfg = Release|x64
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Release|x64.Build.0 = Release|x64
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Release|x86.ActiveCfg = Release|Win32
+ {7F68DB71-F477-4359-947F-4E35AD8B604E}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {001C3FD2-0646-4227-97B4-86453599A519}
+ EndGlobalSection
+EndGlobal