/** * Inflect-Nano-v2 TTS CLI * * Usage: tts_cli --text "Hello world" --output output.wav [--speed 1.0] * * Build: cmake .. && make tts_cli */ #include #include #include #include #include #include #include "inflect_tts.hpp" static const char* kUsage = R"(Usage: tts_cli --text [OPTIONS] Options: --text Text to synthesize (required) --output Output WAV file (default: output.wav) --encoder Encoder AXMODEL path (default: ../models/inflect_encoder.axmodel) --decoder Decoder AXMODEL path (default: ../models/inflect_decoder.axmodel) --speed Playback speed 0.5-2.0 (default: 1.0) --variation Voice variation 0.0-1.0 (default: 0.667) -h, --help Show this help )"; int main(int argc, char* argv[]) { std::string text; std::string output = "output.wav"; std::string encoder_path = "../models/inflect_encoder.axmodel"; std::string decoder_path = "../models/inflect_decoder.axmodel"; float speed = 1.0f; float variation = 0.667f; for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if ((arg == "--text" || arg == "-t") && i + 1 < argc) text = argv[++i]; else if (arg == "--output" && i + 1 < argc) output = argv[++i]; else if (arg == "--encoder" && i + 1 < argc) encoder_path = argv[++i]; else if (arg == "--decoder" && i + 1 < argc) decoder_path = argv[++i]; else if (arg == "--speed" && i + 1 < argc) speed = std::stof(argv[++i]); else if (arg == "--variation" && i + 1 < argc) variation = std::stof(argv[++i]); else if (arg == "--help" || arg == "-h") { std::cout << kUsage; return 0; } } if (text.empty()) { std::cerr << "Error: --text is required\n" << kUsage; return 1; } std::cout << "🎤 Text: " << text << "\n"; std::cout << "📁 Output: " << output << "\n"; try { TTSEngine engine(encoder_path, decoder_path); auto t0 = std::chrono::steady_clock::now(); auto waveform = engine.synthesize(text, speed, variation); auto t1 = std::chrono::steady_clock::now(); double elapsed = std::chrono::duration(t1 - t0).count(); double duration = waveform.size() / 24000.0; std::cout << "⏱ " << elapsed << "s wall, " << duration << "s audio, RTF=" << (duration > 0 ? elapsed / duration : 0) << "x\n"; // Write raw float32 PCM (add WAV header with libsndfile in production) std::ofstream out(output, std::ios::binary); if (!out) { std::cerr << "Error: cannot open " << output << "\n"; return 1; } out.write(reinterpret_cast(waveform.data()), waveform.size() * sizeof(float)); std::cout << "✅ Done → " << output << "\n"; } catch (const std::exception& e) { std::cerr << "❌ Error: " << e.what() << "\n"; return 1; } return 0; }