Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/test-build-wheel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ jobs:
matrix:
# See https://github.com/actions/runner-images
include:
- os: ubuntu-22.04
python-version: "3.7"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.8"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.9"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.10"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.11"
- os: ubuntu-22.04
- os: ubuntu-latest
python-version: "3.12"
- os: ubuntu-latest
python-version: "3.13"

- os: macos-13
python-version: "3.8"
Expand Down Expand Up @@ -103,7 +103,7 @@ jobs:
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
cmake --version

export SHERPA_ONNX_MAKE_ARGS="VERBOSE=1 -j"
export SHERPA_ONNX_MAKE_ARGS="VERBOSE=1 -j2"

python3 setup.py bdist_wheel
ls -lh dist
Expand Down
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
### Supported functions

|Speech recognition| Speech synthesis | Source separation |
|Speech recognition| [Speech synthesis][tts-url] | [Source separation][ss-url] |
|------------------|------------------|-------------------|
| ✔️ | ✔️ | ✔️ |

|Speaker identification| Speaker diarization | Speaker verification |
|Speaker identification| [Speaker diarization][sd-url] | Speaker verification |
|----------------------|-------------------- |------------------------|
| ✔️ | ✔️ | ✔️ |

| Spoken Language identification | Audio tagging | Voice activity detection |
| [Spoken Language identification][slid-url] | [Audio tagging][at-url] | [Voice activity detection][vad-url] |
|--------------------------------|---------------|--------------------------|
| ✔️ | ✔️ | ✔️ |

| Keyword spotting | Add punctuation | Speech enhancement |
| [Keyword spotting][kws-url] | [Add punctuation][punct-url] | [Speech enhancement][se-url] |
|------------------|-----------------|--------------------|
| ✔️ | ✔️ | ✔️ |

Expand Down Expand Up @@ -501,3 +501,12 @@ It uses sherpa-onnx for speech-to-text and text-to-speech.
[spleeter]: https://github.com/deezer/spleeter
[UVR]: https://github.com/Anjok07/ultimatevocalremovergui
[gtcrn]: https://github.com/Xiaobin-Rong/gtcrn
[tts-url]: https://k2-fsa.github.io/sherpa/onnx/tts/all-in-one.html
[ss-url]: https://k2-fsa.github.io/sherpa/onnx/source-separation/index.html
[sd-url]: https://k2-fsa.github.io/sherpa/onnx/speaker-diarization/index.html
[slid-url]: https://k2-fsa.github.io/sherpa/onnx/spoken-language-identification/index.html
[at-url]: https://k2-fsa.github.io/sherpa/onnx/audio-tagging/index.html
[vad-url]: https://k2-fsa.github.io/sherpa/onnx/vad/index.html
[kws-url]: https://k2-fsa.github.io/sherpa/onnx/kws/index.html
[punct-url]: https://k2-fsa.github.io/sherpa/onnx/punctuation/index.html
[se-url]: https://k2-fsa.github.io/sherpa/onnx/speech-enhancment/index.html
1 change: 1 addition & 0 deletions flutter/sherpa_onnx/lib/src/sherpa_onnx_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ final class SherpaOnnxOfflineTtsKokoroModelConfig extends Struct {
external double lengthScale;
external Pointer<Utf8> dictDir;
external Pointer<Utf8> lexicon;
external Pointer<Utf8> lang;
}

final class SherpaOnnxOfflineTtsModelConfig extends Struct {
Expand Down
8 changes: 7 additions & 1 deletion flutter/sherpa_onnx/lib/src/tts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class OfflineTtsKokoroModelConfig {
this.lengthScale = 1.0,
this.dictDir = '',
this.lexicon = '',
this.lang = '',
});

factory OfflineTtsKokoroModelConfig.fromJson(Map<String, dynamic> json) {
Expand All @@ -128,12 +129,13 @@ class OfflineTtsKokoroModelConfig {
lengthScale: (json['lengthScale'] as num?)?.toDouble() ?? 1.0,
dictDir: json['dictDir'] as String? ?? '',
lexicon: json['lexicon'] as String? ?? '',
lang: json['lang'] as String? ?? '',
);
}

@override
String toString() {
return 'OfflineTtsKokoroModelConfig(model: $model, voices: $voices, tokens: $tokens, dataDir: $dataDir, lengthScale: $lengthScale, dictDir: $dictDir, lexicon: $lexicon)';
return 'OfflineTtsKokoroModelConfig(model: $model, voices: $voices, tokens: $tokens, dataDir: $dataDir, lengthScale: $lengthScale, dictDir: $dictDir, lexicon: $lexicon, lang: $lang)';
}

Map<String, dynamic> toJson() => {
Expand All @@ -144,6 +146,7 @@ class OfflineTtsKokoroModelConfig {
'lengthScale': lengthScale,
'dictDir': dictDir,
'lexicon': lexicon,
'lang': lang,
};

final String model;
Expand All @@ -153,6 +156,7 @@ class OfflineTtsKokoroModelConfig {
final double lengthScale;
final String dictDir;
final String lexicon;
final String lang;
}

class OfflineTtsModelConfig {
Expand Down Expand Up @@ -286,6 +290,7 @@ class OfflineTts {
c.ref.model.kokoro.lengthScale = config.model.kokoro.lengthScale;
c.ref.model.kokoro.dictDir = config.model.kokoro.dictDir.toNativeUtf8();
c.ref.model.kokoro.lexicon = config.model.kokoro.lexicon.toNativeUtf8();
c.ref.model.kokoro.lang = config.model.kokoro.lang.toNativeUtf8();

c.ref.model.numThreads = config.model.numThreads;
c.ref.model.debug = config.model.debug ? 1 : 0;
Expand All @@ -302,6 +307,7 @@ class OfflineTts {
calloc.free(c.ref.ruleFsts);
calloc.free(c.ref.model.provider);

calloc.free(c.ref.model.kokoro.lang);
calloc.free(c.ref.model.kokoro.lexicon);
calloc.free(c.ref.model.kokoro.dictDir);
calloc.free(c.ref.model.kokoro.dataDir);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static SherpaOnnxOfflineTtsKokoroModelConfig GetOfflineTtsKokoroModelConfig(
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(length_scale, lengthScale);
SHERPA_ONNX_ASSIGN_ATTR_STR(dict_dir, dictDir);
SHERPA_ONNX_ASSIGN_ATTR_STR(lexicon, lexicon);
SHERPA_ONNX_ASSIGN_ATTR_STR(lang, lang);

return c;
}
Expand Down Expand Up @@ -177,6 +178,7 @@ static Napi::External<SherpaOnnxOfflineTts> CreateOfflineTtsWrapper(
SHERPA_ONNX_DELETE_C_STR(c.model.kokoro.data_dir);
SHERPA_ONNX_DELETE_C_STR(c.model.kokoro.dict_dir);
SHERPA_ONNX_DELETE_C_STR(c.model.kokoro.lexicon);
SHERPA_ONNX_DELETE_C_STR(c.model.kokoro.lang);

SHERPA_ONNX_DELETE_C_STR(c.model.provider);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class OfflineTtsKokoroModelConfig {
public lengthScale: number = 1.0;
public dictDir: string = '';
public lexicon: string = '';
public lang: string = '';
}

export class OfflineTtsModelConfig {
Expand Down
4 changes: 4 additions & 0 deletions scripts/dotnet/OfflineTtsKokoroModelConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public OfflineTtsKokoroModelConfig()

DictDir = "";
Lexicon = "";
Lang = "";
}
[MarshalAs(UnmanagedType.LPStr)]
public string Model;
Expand All @@ -38,5 +39,8 @@ public OfflineTtsKokoroModelConfig()

[MarshalAs(UnmanagedType.LPStr)]
public string Lexicon;

[MarshalAs(UnmanagedType.LPStr)]
public string Lang;
}
}
4 changes: 4 additions & 0 deletions scripts/go/sherpa_onnx.go
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ type OfflineTtsKokoroModelConfig struct {
DataDir string // Path to espeak-ng-data directory
DictDir string // Path to dict directory
Lexicon string // Path to lexicon files
Lang string // Example: es for Spanish, fr-fr for French. Can be empty
LengthScale float32 // Please use 1.0 in general. Smaller -> Faster speech speed. Larger -> Slower speech speed
}

Expand Down Expand Up @@ -1006,6 +1007,9 @@ func NewOfflineTts(config *OfflineTtsConfig) *OfflineTts {
c.model.kokoro.lexicon = C.CString(config.Model.Kokoro.Lexicon)
defer C.free(unsafe.Pointer(c.model.kokoro.lexicon))

c.model.kokoro.lang = C.CString(config.Model.Kokoro.Lang)
defer C.free(unsafe.Pointer(c.model.kokoro.lang))

c.model.kokoro.length_scale = C.float(config.Model.Kokoro.LengthScale)

c.model.num_threads = C.int(config.Model.NumThreads)
Expand Down
1 change: 1 addition & 0 deletions sherpa-onnx/c-api/c-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,7 @@ static sherpa_onnx::OfflineTtsConfig GetOfflineTtsConfig(
SHERPA_ONNX_OR(config->model.kokoro.dict_dir, "");
tts_config.model.kokoro.lexicon =
SHERPA_ONNX_OR(config->model.kokoro.lexicon, "");
tts_config.model.kokoro.lang = SHERPA_ONNX_OR(config->model.kokoro.lang, "");

tts_config.model.num_threads = SHERPA_ONNX_OR(config->model.num_threads, 1);
tts_config.model.debug = config->model.debug;
Expand Down
1 change: 1 addition & 0 deletions sherpa-onnx/c-api/c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ SHERPA_ONNX_API typedef struct SherpaOnnxOfflineTtsKokoroModelConfig {
float length_scale; // < 1, faster in speech speed; > 1, slower in speed
const char *dict_dir;
const char *lexicon;
const char *lang;
} SherpaOnnxOfflineTtsKokoroModelConfig;

SHERPA_ONNX_API typedef struct SherpaOnnxOfflineTtsModelConfig {
Expand Down
1 change: 1 addition & 0 deletions sherpa-onnx/c-api/cxx-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ OfflineTts OfflineTts::Create(const OfflineTtsConfig &config) {
c.model.kokoro.length_scale = config.model.kokoro.length_scale;
c.model.kokoro.dict_dir = config.model.kokoro.dict_dir.c_str();
c.model.kokoro.lexicon = config.model.kokoro.lexicon.c_str();
c.model.kokoro.lang = config.model.kokoro.lang.c_str();

c.model.num_threads = config.model.num_threads;
c.model.debug = config.model.debug;
Expand Down
1 change: 1 addition & 0 deletions sherpa-onnx/c-api/cxx-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ struct OfflineTtsKokoroModelConfig {
std::string data_dir;
std::string dict_dir;
std::string lexicon;
std::string lang;

float length_scale = 1.0; // < 1, faster in speed; > 1, slower in speed
};
Expand Down
62 changes: 55 additions & 7 deletions sherpa-onnx/csrc/kokoro-multi-lang-lexicon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class KokoroMultiLangLexicon::Impl {
InitEspeak(data_dir); // See ./piper-phonemize-lexicon.cc
}

std::vector<TokenIDs> ConvertTextToTokenIds(const std::string &_text) const {
std::vector<TokenIDs> ConvertTextToTokenIds(const std::string &_text,
const std::string &voice) const {
std::string text = ToLowerCase(_text);
if (debug_) {
SHERPA_ONNX_LOGE("After converting to lowercase:\n%s", text.c_str());
Expand Down Expand Up @@ -124,7 +125,7 @@ class KokoroMultiLangLexicon::Impl {
SHERPA_ONNX_LOGE("Non-Chinese: %s", ms.c_str());
}

ids_vec = ConvertEnglishToTokenIDs(ms, meta_data_.voice);
ids_vec = ConvertNonChineseToTokenIDs(ms, voice);
}

for (const auto &ids : ids_vec) {
Expand Down Expand Up @@ -255,8 +256,30 @@ class KokoroMultiLangLexicon::Impl {
return ans;
}

std::vector<std::vector<int32_t>> ConvertEnglishToTokenIDs(
std::vector<std::vector<int32_t>> ConvertTextToTokenIDsWithEspeak(
const std::string &text, const std::string &voice) const {
auto temp = ConvertTextToTokenIdsKokoro(
phoneme2id_, meta_data_.max_token_len, text, voice);
std::vector<std::vector<int32_t>> ans;
ans.reserve(temp.size());

for (const auto &i : temp) {
ans.emplace_back(i.tokens.begin(), i.tokens.end());
}

return ans;
}

std::vector<std::vector<int32_t>> ConvertNonChineseToTokenIDs(
const std::string &text, const std::string &voice) const {
if (!voice.empty()) {
return ConvertTextToTokenIDsWithEspeak(text, voice);
}

// If voice is empty, we split the text into words and use the lexicon
// to lookup the pronunciation of each word, fallback to espeak if
// a word is not in the lexicon.

std::vector<std::string> words = SplitUtf8(text);
if (debug_) {
std::ostringstream os;
Expand Down Expand Up @@ -317,7 +340,7 @@ class KokoroMultiLangLexicon::Impl {

piper::eSpeakPhonemeConfig config;

config.voice = voice;
config.voice = meta_data_.voice;

std::vector<std::vector<piper::Phoneme>> phonemes;

Expand Down Expand Up @@ -391,9 +414,28 @@ class KokoroMultiLangLexicon::Impl {

void InitTokens(std::istream &is) {
token2id_ = ReadTokens(is); // defined in ./symbol-table.cc

std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
std::u32string s;
for (const auto &p : token2id_) {
s = conv.from_bytes(p.first);

if (s.size() != 1) {
SHERPA_ONNX_LOGE("Error for token %s with id %d", p.first.c_str(),
p.second);
SHERPA_ONNX_EXIT(-1);
}

char32_t c = s[0];
phoneme2id_.insert({c, p.second});
}
}

void InitLexicon(const std::string &lexicon) {
if (lexicon.empty()) {
return;
}

std::vector<std::string> files;
SplitStringToVector(lexicon, ",", false, &files);
for (const auto &f : files) {
Expand All @@ -404,6 +446,10 @@ class KokoroMultiLangLexicon::Impl {

template <typename Manager>
void InitLexicon(Manager *mgr, const std::string &lexicon) {
if (lexicon.empty()) {
return;
}

std::vector<std::string> files;
SplitStringToVector(lexicon, ",", false, &files);
for (const auto &f : files) {
Expand Down Expand Up @@ -445,7 +491,7 @@ class KokoroMultiLangLexicon::Impl {

std::vector<int32_t> ids = ConvertTokensToIds(token2id_, token_list);

if (ids.empty()) {
if (ids.empty() && word != "呣") {
SHERPA_ONNX_LOGE(
"Invalid pronunciation for word '%s' at line %d:%s. Ignore it",
word.c_str(), line_num, line.c_str());
Expand All @@ -465,6 +511,8 @@ class KokoroMultiLangLexicon::Impl {
// tokens.txt is saved in token2id_
std::unordered_map<std::string, int32_t> token2id_;

std::unordered_map<char32_t, int32_t> phoneme2id_;

std::unique_ptr<cppjieba::Jieba> jieba_;
bool debug_ = false;
};
Expand All @@ -487,8 +535,8 @@ KokoroMultiLangLexicon::KokoroMultiLangLexicon(
meta_data, debug)) {}

std::vector<TokenIDs> KokoroMultiLangLexicon::ConvertTextToTokenIds(
const std::string &text, const std::string & /*unused_voice = ""*/) const {
return impl_->ConvertTextToTokenIds(text);
const std::string &text, const std::string &voice /*= ""*/) const {
return impl_->ConvertTextToTokenIds(text, voice);
}

#if __ANDROID_API__ >= 9
Expand Down
6 changes: 3 additions & 3 deletions sherpa-onnx/csrc/offline-speech-denoiser-model-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ struct OfflineSpeechDenoiserModelConfig {

OfflineSpeechDenoiserModelConfig() = default;

OfflineSpeechDenoiserModelConfig(OfflineSpeechDenoiserGtcrnModelConfig gtcrn,
int32_t num_threads, bool debug,
const std::string &provider)
OfflineSpeechDenoiserModelConfig(
const OfflineSpeechDenoiserGtcrnModelConfig &gtcrn, int32_t num_threads,
bool debug, const std::string &provider)
: gtcrn(gtcrn),
num_threads(num_threads),
debug(debug),
Expand Down
7 changes: 7 additions & 0 deletions sherpa-onnx/csrc/offline-tts-frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define SHERPA_ONNX_CSRC_OFFLINE_TTS_FRONTEND_H_
#include <cstdint>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -57,6 +58,12 @@ class OfflineTtsFrontend {
// implementation is in ./piper-phonemize-lexicon.cc
void InitEspeak(const std::string &data_dir);

// implementation in ./piper-phonemize-lexicon.cc
std::vector<TokenIDs> ConvertTextToTokenIdsKokoro(
const std::unordered_map<char32_t, int32_t> &token2id,
int32_t max_token_len, const std::string &text,
const std::string &voice = "");

} // namespace sherpa_onnx

#endif // SHERPA_ONNX_CSRC_OFFLINE_TTS_FRONTEND_H_
Loading
Loading