termux-tts 1.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. termux_tts-1.1.3/LICENSE +17 -0
  2. termux_tts-1.1.3/PKG-INFO +80 -0
  3. termux_tts-1.1.3/README.md +31 -0
  4. termux_tts-1.1.3/README.pypi.md +47 -0
  5. termux_tts-1.1.3/pyproject.toml +43 -0
  6. termux_tts-1.1.3/setup.cfg +4 -0
  7. termux_tts-1.1.3/setup.py +38 -0
  8. termux_tts-1.1.3/termux_tts/__init__.py +47 -0
  9. termux_tts-1.1.3/termux_tts/adapter.py +99 -0
  10. termux_tts-1.1.3/termux_tts/audio.py +75 -0
  11. termux_tts-1.1.3/termux_tts/cli.py +82 -0
  12. termux_tts-1.1.3/termux_tts/control/__init__.py +4 -0
  13. termux_tts-1.1.3/termux_tts/control/component.py +242 -0
  14. termux_tts-1.1.3/termux_tts/control/errors.py +52 -0
  15. termux_tts-1.1.3/termux_tts/control/instances.py +137 -0
  16. termux_tts-1.1.3/termux_tts/control/models.py +151 -0
  17. termux_tts-1.1.3/termux_tts/control/status.py +13 -0
  18. termux_tts-1.1.3/termux_tts/engine.py +157 -0
  19. termux_tts-1.1.3/termux_tts/engine_dsp.py +332 -0
  20. termux_tts-1.1.3/termux_tts/engine_native.py +104 -0
  21. termux_tts-1.1.3/termux_tts/engine_onnx.py +199 -0
  22. termux_tts-1.1.3/termux_tts/exceptions.py +28 -0
  23. termux_tts-1.1.3/termux_tts/g2p_korean.py +242 -0
  24. termux_tts-1.1.3/termux_tts/tokenizer.py +184 -0
  25. termux_tts-1.1.3/termux_tts/vulkan_probe.py +25 -0
  26. termux_tts-1.1.3/termux_tts.egg-info/PKG-INFO +80 -0
  27. termux_tts-1.1.3/termux_tts.egg-info/SOURCES.txt +35 -0
  28. termux_tts-1.1.3/termux_tts.egg-info/dependency_links.txt +1 -0
  29. termux_tts-1.1.3/termux_tts.egg-info/entry_points.txt +5 -0
  30. termux_tts-1.1.3/termux_tts.egg-info/requires.txt +11 -0
  31. termux_tts-1.1.3/termux_tts.egg-info/top_level.txt +1 -0
  32. termux_tts-1.1.3/tests/test_expressive_presets.py +29 -0
  33. termux_tts-1.1.3/tests/test_g2p_korean.py +73 -0
  34. termux_tts-1.1.3/tests/test_granular_tts.py +141 -0
  35. termux_tts-1.1.3/tests/test_native_engine.py +38 -0
  36. termux_tts-1.1.3/tests/test_onnx_engine.py +48 -0
  37. termux_tts-1.1.3/tests/test_vulkan_routing.py +52 -0
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 UnoKim & AMEVA Open-Source Foundation
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,80 @@
1
+ Metadata-Version: 2.4
2
+ Name: termux-tts
3
+ Version: 1.1.3
4
+ Summary: On-device Text-to-Speech framework utilizing device resources (DSP Formant Vocoder, ONNX Neural Runtime & Android Native Voice Bridge)
5
+ Home-page: https://github.com/uno-km/termux-tts
6
+ Author: AMEVA Foundation
7
+ Author-email: AOSF / uno-km <zhfldk014745@naver.com>
8
+ License: Apache-2.0
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: numpy>=1.20.0
22
+ Provides-Extra: onnx
23
+ Requires-Dist: onnxruntime>=1.15.0; extra == "onnx"
24
+ Provides-Extra: neural
25
+ Requires-Dist: onnxruntime>=1.15.0; extra == "neural"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: paramiko>=3.0; extra == "dev"
29
+ Dynamic: author
30
+ Dynamic: home-page
31
+ Dynamic: license-file
32
+ Dynamic: requires-python
33
+
34
+ # Termux-TTS (Python)
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/termux-tts.svg?style=flat-square&color=0369a1)](https://pypi.org/project/termux-tts/)
37
+ [![Python](https://img.shields.io/pypi/pyversions/termux-tts.svg?style=flat-square)](https://pypi.org/project/termux-tts/)
38
+ [![License](https://img.shields.io/badge/License-Apache_2.0-004499.svg?style=flat-square)](https://github.com/uno-km/termux-tts)
39
+
40
+ > **High-Performance Multi-Backend Speech Synthesis Framework for Android Termux & Edge Linux**
41
+ > Supports Zero-Dependency Parametric DSP Formant Vocoder, Deep Learning ONNX Neural Runtime, and Android Native System Voice Bridge.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install termux-tts
47
+ ```
48
+
49
+ ## Quickstart
50
+
51
+ ```python
52
+ import termux_tts as tts
53
+
54
+ # 1. Zero-Dependency DSP Formant Mode (Default)
55
+ with tts.load(engine="dsp", language="ko") as engine:
56
+ res = engine.synthesize("안녕하세요, 텀묵스 음성 합성입니다.", output="dsp.wav")
57
+ print(f"Synthesized in {res.elapsed_ms:.1f}ms (RTF: {res.rtf:.4f}x)")
58
+
59
+ # 2. Deep Learning ONNX Mode
60
+ with tts.load(engine="onnx", model="vits_ko.onnx", language="ko") as engine:
61
+ res = engine.synthesize("신경망 고품질 음성 합성입니다.", output="onnx.wav")
62
+
63
+ # 3. Android System Native Speak Mode
64
+ with tts.load(engine="native", language="ko") as engine:
65
+ engine.speak("스피커로 즉시 발화합니다.")
66
+ ```
67
+
68
+ ## Features
69
+ - **Zero-Dependency DSP Engine**: Instant CPU execution with 0MB download overhead (Rosenberg Glottal Pulse + 5-Band Biquad Filters).
70
+ - **Authentic ONNX Neural Runtime**: Deep learning acoustic model execution for VITS, Piper, and FastSpeech ONNX models.
71
+ - **Android Native Bridge**: Direct speaker speech playback via Termux IPC.
72
+ - **Cross-Platform CLI & Node.js Binding**: First-class support for Python, npm, and shell scripts.
73
+
74
+ ## Documentation
75
+ - [Official Documentation & API Reference](https://uno-km.vercel.app/lib/tts/)
76
+ - [GitHub Repository](https://github.com/uno-km/termux-tts)
77
+
78
+ ## License
79
+ Apache-2.0 License. Copyright (c) 2026 Eunho Kim (@uno-km).
80
+
@@ -0,0 +1,31 @@
1
+ # termux-tts
2
+
3
+ [![License](https://img.shields.io/badge/License-Apache_2.0-004499.svg?style=flat-square)](https://github.com/uno-km/uno-km)
4
+
5
+ > ****
6
+ > **
7
+
8
+ ---
9
+
10
+ ## 📌 Architecture & Overview
11
+
12
+
13
+
14
+
15
+
16
+ ---
17
+
18
+ ## 🚀 Installation & Quickstart
19
+
20
+
21
+ ---
22
+
23
+ ## 📖 Official Documentation & Benchmarks
24
+ - [Official Architecture & API Reference](https://uno-km.vercel.app/lib/tts/)
25
+ - [Ecosystem Metrics & Registry Stats](https://uno-km.vercel.app/foundation/metrics)
26
+ - [AMEVA Open-Source Foundation Portal](https://uno-km.vercel.app/foundation/index.html)
27
+
28
+ ---
29
+
30
+ ## 📄 License
31
+ Licensed under the Apache-2.0 License. Copyright (c) 2026 Eunho Kim ([@uno-km](https://github.com/uno-km)).
@@ -0,0 +1,47 @@
1
+ # Termux-TTS (Python)
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/termux-tts.svg?style=flat-square&color=0369a1)](https://pypi.org/project/termux-tts/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/termux-tts.svg?style=flat-square)](https://pypi.org/project/termux-tts/)
5
+ [![License](https://img.shields.io/badge/License-Apache_2.0-004499.svg?style=flat-square)](https://github.com/uno-km/termux-tts)
6
+
7
+ > **High-Performance Multi-Backend Speech Synthesis Framework for Android Termux & Edge Linux**
8
+ > Supports Zero-Dependency Parametric DSP Formant Vocoder, Deep Learning ONNX Neural Runtime, and Android Native System Voice Bridge.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pip install termux-tts
14
+ ```
15
+
16
+ ## Quickstart
17
+
18
+ ```python
19
+ import termux_tts as tts
20
+
21
+ # 1. Zero-Dependency DSP Formant Mode (Default)
22
+ with tts.load(engine="dsp", language="ko") as engine:
23
+ res = engine.synthesize("안녕하세요, 텀묵스 음성 합성입니다.", output="dsp.wav")
24
+ print(f"Synthesized in {res.elapsed_ms:.1f}ms (RTF: {res.rtf:.4f}x)")
25
+
26
+ # 2. Deep Learning ONNX Mode
27
+ with tts.load(engine="onnx", model="vits_ko.onnx", language="ko") as engine:
28
+ res = engine.synthesize("신경망 고품질 음성 합성입니다.", output="onnx.wav")
29
+
30
+ # 3. Android System Native Speak Mode
31
+ with tts.load(engine="native", language="ko") as engine:
32
+ engine.speak("스피커로 즉시 발화합니다.")
33
+ ```
34
+
35
+ ## Features
36
+ - **Zero-Dependency DSP Engine**: Instant CPU execution with 0MB download overhead (Rosenberg Glottal Pulse + 5-Band Biquad Filters).
37
+ - **Authentic ONNX Neural Runtime**: Deep learning acoustic model execution for VITS, Piper, and FastSpeech ONNX models.
38
+ - **Android Native Bridge**: Direct speaker speech playback via Termux IPC.
39
+ - **Cross-Platform CLI & Node.js Binding**: First-class support for Python, npm, and shell scripts.
40
+
41
+ ## Documentation
42
+ - [Official Documentation & API Reference](https://uno-km.vercel.app/lib/tts/)
43
+ - [GitHub Repository](https://github.com/uno-km/termux-tts)
44
+
45
+ ## License
46
+ Apache-2.0 License. Copyright (c) 2026 Eunho Kim (@uno-km).
47
+
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "termux-tts"
7
+ version = "1.1.3"
8
+ description = "On-device Text-to-Speech framework utilizing device resources (DSP Formant Vocoder, ONNX Neural Runtime & Android Native Voice Bridge)"
9
+ readme = "README.pypi.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "Apache-2.0" }
12
+ authors = [
13
+ { name = "AOSF / uno-km", email = "zhfldk014745@naver.com" }
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 5 - Production/Stable",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: Apache Software License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
25
+ ]
26
+ dependencies = [
27
+ "numpy>=1.20.0",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ onnx = ["onnxruntime>=1.15.0"]
32
+ neural = ["onnxruntime>=1.15.0"]
33
+ dev = ["pytest>=7.0", "paramiko>=3.0"]
34
+
35
+ [project.scripts]
36
+ termux-tts = "termux_tts.cli:main"
37
+
38
+ [project.entry-points."ameva.components"]
39
+ termux-tts = "termux_tts.adapter:create_adapter"
40
+
41
+ [tool.setuptools.packages.find]
42
+ where = ["."]
43
+ include = ["termux_tts*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,38 @@
1
+ import os
2
+ from setuptools import setup, find_packages
3
+
4
+ setup(
5
+ name="termux-tts",
6
+ version="1.1.3",
7
+ description="Ultra-Fast On-Device Dual-Engine Text-to-Speech Framework (Parametric Formant Acoustic Synthesizer & Android Native Voice Bridge)",
8
+ long_description=open("README.pypi.md", encoding="utf-8").read() if os.path.exists("README.pypi.md") else open("README.md", encoding="utf-8").read(),
9
+ long_description_content_type="text/markdown",
10
+ author="AMEVA Foundation",
11
+ license="Apache-2.0",
12
+ url="https://github.com/uno-km/termux-tts",
13
+ packages=find_packages(include=["termux_tts", "termux_tts.*"]),
14
+ python_requires=">=3.8",
15
+ install_requires=[
16
+ "numpy>=1.20.0",
17
+ "ameva-vulkan-runtime>=1.0.0",
18
+ ],
19
+ extras_require={
20
+ "onnx": ["onnxruntime>=1.15.0"],
21
+ "neural": ["onnxruntime>=1.15.0"],
22
+ "dev": ["pytest>=7.0.0", "pytest-asyncio"],
23
+ },
24
+ entry_points={
25
+ "console_scripts": [
26
+ "termux-tts=termux_tts.cli:main",
27
+ ],
28
+ },
29
+ classifiers=[
30
+ "Development Status :: 5 - Production/Stable",
31
+ "Intended Audience :: Developers",
32
+ "License :: OSI Approved :: Apache Software License",
33
+ "Operating System :: Android",
34
+ "Operating System :: POSIX :: Linux",
35
+ "Programming Language :: Python :: 3",
36
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
37
+ ],
38
+ )
@@ -0,0 +1,47 @@
1
+ """
2
+ termux-tts: Production-Grade Dual-Engine TTS Framework for Android Termux.
3
+ - Option A: Deep Learning VITS ONNX Neural Vocoder (Vulkan GPU Accelerated)
4
+ - Option B: Android System Native Voice Engine Bridge (Samsung / Google Voice)
5
+ """
6
+
7
+ from .engine import TTSEngine, load, doctor
8
+ from .engine_native import NativeAndroidEngine, NativeResult
9
+ from .engine_dsp import ParametricDSPEngine, DSPResult, QUALITY_PRESETS, DSPSynthesizer
10
+ from .engine_onnx import ONNXNeuralEngine, ONNXResult
11
+ from .tokenizer import PhoneticTokenizer, EXPRESSIVE_TAGS
12
+ from .g2p_korean import KoreanG2PEngine, korean_text_to_phonemes
13
+ from .audio import AudioBuffer
14
+ from .exceptions import (
15
+ TTSError,
16
+ TTSModelLoadError,
17
+ TTSInferenceError,
18
+ VulkanInitializationError,
19
+ TTSAudioEncodingError,
20
+ TTSLanguageNotSupportedError
21
+ )
22
+
23
+ __version__ = "1.1.2"
24
+ __all__ = [
25
+ "TTSEngine",
26
+ "load",
27
+ "doctor",
28
+ "ParametricDSPEngine",
29
+ "DSPSynthesizer",
30
+ "DSPResult",
31
+ "NativeAndroidEngine",
32
+ "NativeResult",
33
+ "ONNXNeuralEngine",
34
+ "ONNXResult",
35
+ "QUALITY_PRESETS",
36
+ "PhoneticTokenizer",
37
+ "KoreanG2PEngine",
38
+ "korean_text_to_phonemes",
39
+ "EXPRESSIVE_TAGS",
40
+ "AudioBuffer",
41
+ "TTSError",
42
+ "TTSModelLoadError",
43
+ "TTSInferenceError",
44
+ "VulkanInitializationError",
45
+ "TTSAudioEncodingError",
46
+ "TTSLanguageNotSupportedError"
47
+ ]
@@ -0,0 +1,99 @@
1
+ """
2
+ termux_tts.adapter
3
+ ===================
4
+ AMEVA Component Protocol v1 — Orchestrator Adapter (v0.8.1 호환)
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from typing import Any, AsyncIterator
9
+
10
+ from ameva_component.adapter_base import BaseOrchestratorAdapter
11
+ from termux_tts.control.component import TTSControl
12
+
13
+
14
+ class TTSOrchestratorAdapter(BaseOrchestratorAdapter):
15
+ """TTS (Text-to-Speech) Orchestrator Adapter.
16
+
17
+ 합성은 파일 기반으로 수행됩니다.
18
+ infer()는 text를 받아 audio 파일 경로를 반환합니다.
19
+ 요청 모델과 실행 모델이 다르면 fallback_used=True를 명시합니다.
20
+ """
21
+
22
+ COMPONENT_ID = "termux-tts"
23
+
24
+ def __init__(self, control: TTSControl | None = None) -> None:
25
+ self._control = control or TTSControl()
26
+
27
+ async def infer(self, request: dict[str, Any]) -> AsyncIterator[dict[str, Any]]:
28
+ """TTS synthesis: text → audio file path.
29
+
30
+ request 키:
31
+ text (str): 합성할 텍스트 (필수)
32
+ voice_id (str): 목소리 ID (선택)
33
+ model_id (str): 모델 ID (선택)
34
+ output_path (str): 출력 파일 경로 (선택, 없으면 임시 파일)
35
+
36
+ 반환 프레임:
37
+ {"type": "audio", "audio_path": str, "final": bool, "fallback_used": bool}
38
+ {"type": "error", "code": str, "message": str}
39
+ """
40
+ text = request.get("text", "").strip()
41
+ if not text:
42
+ yield {
43
+ "type": "error",
44
+ "ok": False,
45
+ "error": {
46
+ "code": "TEXT_EMPTY",
47
+ "message": "text is required and must not be empty",
48
+ "operation": "infer",
49
+ "component_id": self.COMPONENT_ID,
50
+ "retryable": False,
51
+ },
52
+ }
53
+ return
54
+
55
+ if hasattr(self._control, "synthesize"):
56
+ try:
57
+ result = await self._control.synthesize(request)
58
+ audio_path = result.get("audio_path", "")
59
+ if not audio_path:
60
+ yield {
61
+ "type": "error",
62
+ "ok": False,
63
+ "error": {
64
+ "code": "SYNTHESIS_FAILED",
65
+ "message": "synthesize() returned no audio_path",
66
+ "operation": "infer",
67
+ "component_id": self.COMPONENT_ID,
68
+ "retryable": True,
69
+ },
70
+ }
71
+ return
72
+ yield {
73
+ "type": "audio",
74
+ "audio_path": audio_path,
75
+ "final": True,
76
+ "fallback_used": result.get("fallback_used", False),
77
+ "requested_voice": result.get("requested_voice"),
78
+ "executed_voice": result.get("executed_voice"),
79
+ "ok": True,
80
+ }
81
+ except Exception as exc:
82
+ yield {
83
+ "type": "error",
84
+ "ok": False,
85
+ "error": {
86
+ "code": "SYNTHESIS_FAILED",
87
+ "message": str(exc),
88
+ "operation": "infer",
89
+ "component_id": self.COMPONENT_ID,
90
+ "retryable": True,
91
+ },
92
+ }
93
+ else:
94
+ yield self._not_supported("infer.synthesize")
95
+
96
+
97
+ def create_adapter() -> TTSOrchestratorAdapter:
98
+ """Entry Point Factory."""
99
+ return TTSOrchestratorAdapter()
@@ -0,0 +1,75 @@
1
+ """
2
+ Zero-Dependency Audio Buffer and RIFF WAV Stream Encoder.
3
+ Handles 16-bit Linear PCM formatting with soft-clipping protection.
4
+ """
5
+
6
+ import io
7
+ import wave
8
+ import numpy as np
9
+ from typing import Union
10
+ from .exceptions import TTSAudioEncodingError
11
+
12
+ class AudioBuffer:
13
+ """Manages raw floating-point audio samples and converts to 16-bit PCM WAV."""
14
+
15
+ def __init__(self, samples: Union[np.ndarray, list], sample_rate: int = 22050):
16
+ if isinstance(samples, list):
17
+ self.samples = np.array(samples, dtype=np.float32)
18
+ elif isinstance(samples, np.ndarray):
19
+ self.samples = samples.astype(np.float32).flatten()
20
+ else:
21
+ raise TTSAudioEncodingError("Samples must be a list or numpy ndarray.")
22
+
23
+ self.sample_rate = sample_rate
24
+ self._normalize_and_clip()
25
+
26
+ def _normalize_and_clip(self) -> None:
27
+ """Apply peak normalization and soft clipping to prevent distortion."""
28
+ if len(self.samples) == 0:
29
+ return
30
+
31
+ peak = np.max(np.abs(self.samples))
32
+ if peak > 1.0:
33
+ self.samples = self.samples / peak
34
+ elif peak < 0.0001:
35
+ pass # Keep quiet signals as is
36
+ else:
37
+ # Gentle scale to target -1dB
38
+ self.samples = self.samples * 0.95
39
+
40
+ @property
41
+ def duration_seconds(self) -> float:
42
+ """Duration of the audio in seconds."""
43
+ if self.sample_rate <= 0:
44
+ return 0.0
45
+ return len(self.samples) / float(self.sample_rate)
46
+
47
+ def to_pcm16_bytes(self) -> bytes:
48
+ """Convert float32 [-1.0, 1.0] samples into 16-bit signed integer bytes."""
49
+ clipped = np.clip(self.samples, -1.0, 1.0)
50
+ pcm16 = (clipped * 32767.0).astype(np.int16)
51
+ return pcm16.tobytes()
52
+
53
+ def to_wav_bytes(self) -> bytes:
54
+ """Encode raw samples into standard RIFF WAV format."""
55
+ try:
56
+ pcm_bytes = self.to_pcm16_bytes()
57
+ buf = io.BytesIO()
58
+ with wave.open(buf, "wb") as wav_file:
59
+ wav_file.setnchannels(1) # Mono
60
+ wav_file.setsampwidth(2) # 16-bit (2 bytes)
61
+ wav_file.setframerate(self.sample_rate)
62
+ wav_file.writeframes(pcm_bytes)
63
+ return buf.getvalue()
64
+ except Exception as e:
65
+ raise TTSAudioEncodingError(f"Failed to encode WAV buffer: {e}") from e
66
+
67
+ def save(self, filepath: str) -> str:
68
+ """Save the audio buffer to a WAV file on disk."""
69
+ wav_data = self.to_wav_bytes()
70
+ try:
71
+ with open(filepath, "wb") as f:
72
+ f.write(wav_data)
73
+ return filepath
74
+ except Exception as e:
75
+ raise TTSAudioEncodingError(f"Failed to save WAV to '{filepath}': {e}") from e
@@ -0,0 +1,82 @@
1
+ """
2
+ Command-Line Interface for termux-tts:
3
+ - termux-tts synth : Option A Deep Learning Neural Synthesis to File
4
+ - termux-tts speak : Option B Android System Native Immediate Voice Output
5
+ - termux-tts doctor: 12-Stage Vulkan GPU Hardware Diagnostics
6
+ """
7
+
8
+ import argparse
9
+ from .engine import load, doctor
10
+
11
+ def main():
12
+ parser = argparse.ArgumentParser(
13
+ prog="termux-tts",
14
+ description="Termux Neural & Native Text-to-Speech Engine"
15
+ )
16
+ subparsers = parser.add_subparsers(dest="command", help="Sub-commands")
17
+
18
+ # 1. Synth (Option A: DSP Formant or ONNX Neural Vocoder to File)
19
+ synth_parser = subparsers.add_parser("synth", help="Synthesize text to audio WAV file (DSP / ONNX)")
20
+ synth_parser.add_argument("-t", "--text", required=True, help="Input text to synthesize")
21
+ synth_parser.add_argument("-o", "--output", default="output.wav", help="Output WAV filepath")
22
+ synth_parser.add_argument("-l", "--lang", default="ko", help="Language code (ko, en)")
23
+ synth_parser.add_argument("-e", "--engine", default="auto", choices=["auto", "dsp", "onnx"], help="Synthesis engine (dsp=zero-dependency, onnx=deep learning)")
24
+ synth_parser.add_argument("-m", "--model", default=None, help="Path to .onnx model file (required for onnx engine)")
25
+ synth_parser.add_argument("-p", "--preset", default="balanced", choices=["fast", "balanced", "expressive", "ultra"])
26
+ synth_parser.add_argument("-d", "--device", default="auto", choices=["auto", "gpu", "vulkan", "cpu"])
27
+ synth_parser.add_argument("-s", "--speed", type=float, default=1.0, help="Speech speed multiplier (0.5 to 2.0)")
28
+
29
+ # 2. Speak (Option B: Native Samsung/Google System Voice)
30
+ speak_parser = subparsers.add_parser("speak", help="Speak text directly through device speaker (Option B: Native)")
31
+ speak_parser.add_argument("-t", "--text", required=True, help="Input text to speak")
32
+ speak_parser.add_argument("-l", "--lang", default="ko", help="Language code (ko, en)")
33
+ speak_parser.add_argument("-s", "--stream", default="MUSIC", help="Audio stream (MUSIC, NOTIFICATION, ALARM)")
34
+
35
+ # 3. Doctor (Diagnostics)
36
+ subparsers.add_parser("doctor", help="Run 12-stage Vulkan GPU hardware diagnostics")
37
+
38
+ # ── AMEVA Component Protocol v1 ─────────────────────────────────────────
39
+ _protocol_available = False
40
+ try:
41
+ from ameva_component.cli_support import build_protocol_subcommands
42
+ build_protocol_subcommands(subparsers)
43
+ _protocol_available = True
44
+ except ImportError:
45
+ pass
46
+ # ────────────────────────────────────────────────────────────────────────
47
+
48
+ args = parser.parse_args()
49
+
50
+ if args.command == "synth":
51
+ with load(model=args.model, language=args.lang, preset=args.preset, device=args.device, engine=args.engine) as engine:
52
+ res = engine.synthesize(args.text, output=args.output, speed=args.speed)
53
+ print(f"[SUCCESS] Synthesized via {res.backend} ({res.model_name}) -> {args.output}")
54
+ print(f" Duration: {res.duration_sec:.2f}s | Elapsed: {res.elapsed_ms:.1f}ms | RTF: {res.rtf:.4f}x")
55
+
56
+ elif args.command == "speak":
57
+ with load(language=args.lang) as engine:
58
+ res = engine.speak(args.text, stream=args.stream)
59
+ print(f"[SUCCESS] Spoken via {res.engine_name} on stream {args.stream} ({res.elapsed_ms:.1f}ms)")
60
+
61
+ elif args.command == "doctor":
62
+ diag = doctor()
63
+ print("=" * 60)
64
+ print(" TERMUX-TTS 12-STAGE VULKAN HARDWARE DIAGNOSTICS")
65
+ print("=" * 60)
66
+ for k, v in diag.items():
67
+ print(f" - {k:30s}: {v}")
68
+ print("=" * 60)
69
+
70
+ elif args.command in ("component", "model", "instance") and _protocol_available:
71
+ from ameva_component.cli_support import dispatch_protocol
72
+ from termux_tts.control import TTSControl
73
+ dispatch_protocol(args, TTSControl())
74
+ elif args.command in ("component", "model", "instance"):
75
+ print("[ERROR] ameva-component-sdk not installed.", file=sys.stderr)
76
+ sys.exit(1)
77
+ else:
78
+ parser.print_help()
79
+
80
+ if __name__ == "__main__":
81
+ main()
82
+
@@ -0,0 +1,4 @@
1
+ """termux_tts.control — AMEVA Component Protocol v1."""
2
+ from .component import TTSControl
3
+ from .status import TTSStatusWriter
4
+ __all__ = ["TTSControl", "TTSStatusWriter"]