This repository was archived by the owner on Apr 5, 2026. It is now read-only.
forked from rhasspy/piper
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpiper.hpp
More file actions
111 lines (85 loc) · 2.94 KB
/
Copy pathpiper.hpp
File metadata and controls
111 lines (85 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#ifndef PIPER_H_
#define PIPER_H_
#include <filesystem>
#include <iostream>
#include <string>
#include <vector>
#include "json.hpp"
#include <espeak-ng/speak_lib.h>
#include "config.hpp"
#include "model.hpp"
#include "phonemize.hpp"
#include "synthesize.hpp"
#include "wavfile.hpp"
using json = nlohmann::json;
namespace piper {
struct Voice {
json configRoot;
PhonemizeConfig phonemizeConfig;
SynthesisConfig synthesisConfig;
ModelConfig modelConfig;
ModelSession session;
};
void initialize(std::filesystem::path cwd) {
const char *dataPath = NULL;
auto cwdDataPath = cwd.append("espeak-ng-data");
if (std::filesystem::is_directory(cwdDataPath)) {
dataPath = cwdDataPath.c_str();
}
// Set up espeak-ng for calling espeak_TextToPhonemes
int result = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,
/*buflength*/ 0,
/*path*/ dataPath,
/*options*/ 0);
if (result < 0) {
throw runtime_error("Failed to initialize eSpeak-ng");
}
}
void terminate() {
// Clean up espeak-ng
espeak_Terminate();
}
// Load Onnx model and JSON config file
void loadVoice(string modelPath, string modelConfigPath, Voice &voice,
optional<SpeakerId> &speakerId) {
ifstream modelConfigFile(modelConfigPath.c_str());
voice.configRoot = json::parse(modelConfigFile);
parsePhonemizeConfig(voice.configRoot, voice.phonemizeConfig);
parseSynthesisConfig(voice.configRoot, voice.synthesisConfig);
parseModelConfig(voice.configRoot, voice.modelConfig);
if (voice.modelConfig.numSpeakers > 1) {
// Multispeaker model
if (speakerId) {
voice.synthesisConfig.speakerId = speakerId;
} else {
// Default speaker
voice.synthesisConfig.speakerId = 0;
}
}
loadModel(modelPath, voice.session);
} /* loadVoice */
// Phonemize text and synthesize audio
void textToAudio(Voice &voice, string text, vector<int16_t> &audioBuffer,
SynthesisResult &result) {
voice.phonemizeConfig.text = text;
voice.phonemizeConfig.phonemes.reset();
phonemize(voice.phonemizeConfig);
voice.synthesisConfig.phonemeIds.clear();
phonemes2ids(voice.phonemizeConfig, voice.synthesisConfig);
synthesize(voice.synthesisConfig, voice.session, audioBuffer, result);
} /* textToAudio */
// Phonemize text and synthesize audio to WAV file
void textToWavFile(Voice &voice, string text, ostream &audioFile,
SynthesisResult &result) {
vector<int16_t> audioBuffer;
textToAudio(voice, text, audioBuffer, result);
// Write WAV
auto synthesisConfig = voice.synthesisConfig;
writeWavHeader(synthesisConfig.sampleRate, synthesisConfig.sampleWidth,
synthesisConfig.channels, (int32_t)audioBuffer.size(),
audioFile);
audioFile.write((const char *)audioBuffer.data(),
sizeof(int16_t) * audioBuffer.size());
} /* textToWavFile */
} // namespace piper
#endif // PIPER_H_