1+ #include " main_utils.hpp"
2+
3+ #include < filesystem>
4+ #include < fstream>
5+ #include < iostream>
6+ #include < optional>
7+ #include < stdexcept>
8+ #include < string>
9+
10+ #include " piper.h"
11+
12+ namespace piper {
13+
14+ void printUsage (char *argv[]) {
15+ std::cerr << std::endl;
16+ std::cerr << " usage: " << argv[0 ] << " [options]" << std::endl;
17+ std::cerr << std::endl;
18+ std::cerr << " options:" << std::endl;
19+ std::cerr << " -h --help show this message and exit"
20+ << std::endl;
21+ std::cerr << " -m FILE --model FILE path to onnx model file"
22+ << std::endl;
23+ std::cerr << " -c FILE --config FILE path to model config file "
24+ " (default: model path + .json)"
25+ << std::endl;
26+ std::cerr << " -f FILE --output_file FILE path to output WAV file ('-' "
27+ " for stdout)"
28+ << std::endl;
29+ std::cerr << " -d DIR --output_dir DIR path to output directory "
30+ " (default: cwd)"
31+ << std::endl;
32+ std::cerr << " -s NUM --speaker NUM id of speaker (default: 0)"
33+ << std::endl;
34+ std::cerr << " --noise_scale NUM generator noise (default: 0.667)"
35+ << std::endl;
36+ std::cerr << " --length_scale NUM phoneme length (default: 1.0)"
37+ << std::endl;
38+ std::cerr << " --noise_w NUM phoneme width noise (default: 0.8)"
39+ << std::endl;
40+ std::cerr << " --espeak_data DIR path to espeak-ng data directory"
41+ << std::endl;
42+ std::cerr << " --json-input stdin input is lines of JSON "
43+ " instead of plain text"
44+ << std::endl;
45+ std::cerr << std::endl;
46+ }
47+
48+ void ensureArg (int argc, char *argv[], int argi) {
49+ if ((argi + 1 ) >= argc)
50+ {
51+ throw ArgError (std::string (" Missing argument for " ) + argv[argi]);
52+ }
53+ }
54+
55+ // Parse command-line arguments
56+ void parseArgsLogic (int argc, char *argv[], RunConfig &runConfig) {
57+ std::optional<std::filesystem::path> modelConfigPath;
58+
59+ for (int i = 1 ; i < argc; i++) {
60+ std::string arg = argv[i];
61+
62+ if (arg == " -m" || arg == " --model" ) {
63+ ensureArg (argc, argv, i);
64+ runConfig.modelPath = std::filesystem::path (argv[++i]);
65+ } else if (arg == " -c" || arg == " --config" ) {
66+ ensureArg (argc, argv, i);
67+ modelConfigPath = std::filesystem::path (argv[++i]);
68+ } else if (arg == " -f" || arg == " --output_file" ||
69+ arg == " --output-file" ) {
70+ ensureArg (argc, argv, i);
71+ std::string filePath = argv[++i];
72+ if (filePath == " -" ) {
73+ runConfig.outputType = OUTPUT_STDOUT ;
74+ runConfig.outputPath = std::nullopt ;
75+ } else {
76+ runConfig.outputType = OUTPUT_FILE ;
77+ runConfig.outputPath = std::filesystem::path (filePath);
78+ }
79+ } else if (arg == " -d" || arg == " --output_dir" || arg == " --output-dir" ) {
80+ ensureArg (argc, argv, i);
81+ runConfig.outputType = OUTPUT_DIRECTORY ;
82+ runConfig.outputPath = std::filesystem::path (argv[++i]);
83+ } else if (arg == " -s" || arg == " --speaker" ) {
84+ ensureArg (argc, argv, i);
85+ runConfig.speakerId = std::stol (argv[++i]);
86+ } else if (arg == " --noise_scale" || arg == " --noise-scale" ) {
87+ ensureArg (argc, argv, i);
88+ runConfig.noiseScale = std::stof (argv[++i]);
89+ } else if (arg == " --length_scale" || arg == " --length-scale" ) {
90+ ensureArg (argc, argv, i);
91+ runConfig.lengthScale = std::stof (argv[++i]);
92+ } else if (arg == " --noise_w" || arg == " --noise-w" ) {
93+ ensureArg (argc, argv, i);
94+ runConfig.noiseW = std::stof (argv[++i]);
95+ } else if (arg == " --espeak_data" || arg == " --espeak-data" ) {
96+ ensureArg (argc, argv, i);
97+ runConfig.eSpeakDataPath = std::filesystem::path (argv[++i]);
98+ } else if (arg == " --json_input" || arg == " --json-input" ) {
99+ runConfig.jsonInput = true ;
100+ } else if (arg == " --version" ) {
101+ std::cout << piper_version () << std::endl;
102+ exit (0 );
103+ } else if (arg == " -h" || arg == " --help" ) {
104+ printUsage (argv);
105+ exit (0 );
106+ }
107+ }
108+
109+ // Verify model file exists
110+ std::ifstream modelFile (runConfig.modelPath .c_str (), std::ios::binary);
111+ if (!modelFile.good ()) {
112+ throw std::runtime_error (" Model file doesn't exist" );
113+ }
114+
115+ if (!modelConfigPath) {
116+ runConfig.modelConfigPath =
117+ std::filesystem::path (runConfig.modelPath .string () + " .json" );
118+ } else {
119+ runConfig.modelConfigPath = modelConfigPath.value ();
120+ }
121+
122+ // Verify model config exists
123+ std::ifstream modelConfigFile (runConfig.modelConfigPath .c_str ());
124+ if (!modelConfigFile.good ()) {
125+ throw std::runtime_error (" Model config doesn't exist" );
126+ }
127+ }
128+
129+ void parseArgs (int argc, char *argv[], RunConfig &runConfig) {
130+ try {
131+ parseArgsLogic (argc, argv, runConfig);
132+ } catch (const ArgError &e) {
133+ std::cerr << e.what () << std::endl;
134+ printUsage (argv);
135+ exit (1 );
136+ } catch (const std::exception &e) {
137+ std::cerr << e.what () << std::endl;
138+ exit (1 );
139+ }
140+ }
141+
142+ } // namespace piper
0 commit comments