mia-narrative 1.0.0
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.
- package/README.md +149 -0
- package/bin/mia-narrative.ts +86 -0
- package/dist/bin/mia-narrative.d.ts +3 -0
- package/dist/bin/mia-narrative.d.ts.map +1 -0
- package/dist/bin/mia-narrative.js +34 -0
- package/dist/bin/mia-narrative.js.map +1 -0
- package/dist/src/audio/processor.d.ts +6 -0
- package/dist/src/audio/processor.d.ts.map +1 -0
- package/dist/src/audio/processor.js +72 -0
- package/dist/src/audio/processor.js.map +1 -0
- package/dist/src/commands/generate.d.ts +19 -0
- package/dist/src/commands/generate.d.ts.map +1 -0
- package/dist/src/commands/generate.js +104 -0
- package/dist/src/commands/generate.js.map +1 -0
- package/dist/src/commands/voices.d.ts +8 -0
- package/dist/src/commands/voices.d.ts.map +1 -0
- package/dist/src/commands/voices.js +60 -0
- package/dist/src/commands/voices.js.map +1 -0
- package/dist/src/config/defaults.d.ts +54 -0
- package/dist/src/config/defaults.d.ts.map +1 -0
- package/dist/src/config/defaults.js +30 -0
- package/dist/src/config/defaults.js.map +1 -0
- package/dist/src/config/voices.d.ts +15 -0
- package/dist/src/config/voices.d.ts.map +1 -0
- package/dist/src/config/voices.js +79 -0
- package/dist/src/config/voices.js.map +1 -0
- package/dist/src/engines/ElevenLabsEngine.d.ts +10 -0
- package/dist/src/engines/ElevenLabsEngine.d.ts.map +1 -0
- package/dist/src/engines/ElevenLabsEngine.js +78 -0
- package/dist/src/engines/ElevenLabsEngine.js.map +1 -0
- package/dist/src/engines/SystemTtsEngine.d.ts +9 -0
- package/dist/src/engines/SystemTtsEngine.d.ts.map +1 -0
- package/dist/src/engines/SystemTtsEngine.js +56 -0
- package/dist/src/engines/SystemTtsEngine.js.map +1 -0
- package/dist/src/engines/base.d.ts +23 -0
- package/dist/src/engines/base.d.ts.map +1 -0
- package/dist/src/engines/base.js +3 -0
- package/dist/src/engines/base.js.map +1 -0
- package/dist/src/engines/factory.d.ts +6 -0
- package/dist/src/engines/factory.d.ts.map +1 -0
- package/dist/src/engines/factory.js +20 -0
- package/dist/src/engines/factory.js.map +1 -0
- package/dist/src/engines/piper.d.ts +12 -0
- package/dist/src/engines/piper.d.ts.map +1 -0
- package/dist/src/engines/piper.js +118 -0
- package/dist/src/engines/piper.js.map +1 -0
- package/dist/src/utils/file-reader.d.ts +5 -0
- package/dist/src/utils/file-reader.d.ts.map +1 -0
- package/dist/src/utils/file-reader.js +26 -0
- package/dist/src/utils/file-reader.js.map +1 -0
- package/dist/src/utils/logger.d.ts +10 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +27 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/package.json +35 -0
- package/src/audio/processor.ts +94 -0
- package/src/commands/generate.ts +144 -0
- package/src/commands/voices.ts +68 -0
- package/src/config/defaults.ts +41 -0
- package/src/config/voices.ts +89 -0
- package/src/engines/ElevenLabsEngine.ts +81 -0
- package/src/engines/SystemTtsEngine.ts +61 -0
- package/src/engines/base.ts +26 -0
- package/src/engines/factory.ts +28 -0
- package/src/engines/piper.ts +134 -0
- package/src/types/say.d.ts +26 -0
- package/src/utils/file-reader.ts +25 -0
- package/src/utils/logger.ts +33 -0
- package/tsconfig.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# 🎙️ mia-narrative CLI
|
|
2
|
+
|
|
3
|
+
A powerful, multi-engine text-to-speech command-line tool for narrative audio generation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multiple TTS Engines**:
|
|
8
|
+
- `system`: Uses the operating system's built-in TTS. No setup required.
|
|
9
|
+
- `elevenlabs`: High-quality, low-latency speech from ElevenLabs. Requires an API key.
|
|
10
|
+
- `piper`: High-quality, local, and private TTS via Piper. Requires Piper to be installed.
|
|
11
|
+
- **Audio Effects**: Customize your audio with effects like speed, pitch, volume, and more.
|
|
12
|
+
- **Simple Interface**: Easy-to-use commands for generating audio and listing voices.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Prerequisites
|
|
17
|
+
|
|
18
|
+
1. **Node.js**: v18 or higher.
|
|
19
|
+
2. **FFmpeg**: For audio processing.
|
|
20
|
+
3. **(Optional) Piper TTS**: If you plan to use the `piper` engine. Install from [https://github.com/rhasspy/piper](https://github.com/rhasspy/piper).
|
|
21
|
+
|
|
22
|
+
### Setup
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cd /workspace/MiaNar/cli
|
|
26
|
+
npm install
|
|
27
|
+
npm run build
|
|
28
|
+
npm link # Makes 'mia-narrative' globally available
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
### System Engine
|
|
34
|
+
|
|
35
|
+
No configuration is required. This is the default engine.
|
|
36
|
+
|
|
37
|
+
### ElevenLabs Engine
|
|
38
|
+
|
|
39
|
+
Set your ElevenLabs API key as an environment variable:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
export ELEVENLABS_API_KEY="your_api_key_here"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Piper Engine
|
|
46
|
+
|
|
47
|
+
Set the path to your Piper model(s) directory:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
export MIA_NARRATIVE_PIPER_MODEL_PATH="/path/to/your/piper/models"
|
|
51
|
+
```
|
|
52
|
+
You also need to specify the piper executable path if it's not in your PATH:
|
|
53
|
+
```bash
|
|
54
|
+
export MIA_NARRATIVE_PIPER_PATH="/path/to/your/piper/executable"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
### Generate Audio
|
|
60
|
+
|
|
61
|
+
**Using the default `system` engine:**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
mia-narrative generate --text "Hello from my computer" --output hello.mp3
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Using the `elevenlabs` engine:**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
mia-narrative generate --engine elevenlabs --text "Hello from the cloud" --voiceId "Rachel" --output cloud.mp3
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Using the `piper` engine with a file:**
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
mia-narrative generate --engine piper --file story.txt --voiceId "en_US-lessac-medium" --output story.mp3
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**With audio parameters:**
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mia-narrative generate \
|
|
83
|
+
--file chapter.txt \
|
|
84
|
+
--engine piper \
|
|
85
|
+
--voiceId "en_US-lessac-medium" \
|
|
86
|
+
--speed 0.9 \
|
|
87
|
+
--pitch 1.1 \
|
|
88
|
+
--output chapter.mp3
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### List Voices
|
|
92
|
+
|
|
93
|
+
List voices for a specific engine.
|
|
94
|
+
|
|
95
|
+
**List system voices:**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
mia-narrative voices --engine system
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**List ElevenLabs voices (in JSON format):**
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
mia-narrative voices --engine elevenlabs --format json
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**List Piper voices:**
|
|
108
|
+
```bash
|
|
109
|
+
mia-narrative voices --engine piper
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Audio Parameters
|
|
113
|
+
|
|
114
|
+
| Parameter | Range | Default | Effect |
|
|
115
|
+
|---------------|-----------|---------|------------------|
|
|
116
|
+
| speed | 0.5-2.0 | 1.0 | Speech rate |
|
|
117
|
+
| pitch | 0.5-2.0 | 1.0 | Tonal height |
|
|
118
|
+
| volume | 0.0-1.0 | 0.8 | Loudness |
|
|
119
|
+
| emphasis | 0.0-1.0 | 0.5 | Dramatic intensity |
|
|
120
|
+
| reverb | 0.0-1.0 | 0.2 | Spatial acoustics|
|
|
121
|
+
| echo | 0.1-2.0 | 0.1 | Delay effect |
|
|
122
|
+
| compression | 0.0-1.0 | 0.3 | Dynamic range |
|
|
123
|
+
| pause | 0.1-2.0s | 0.5 | Break timing |
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
## Environment Variables
|
|
127
|
+
|
|
128
|
+
- `ELEVENLABS_API_KEY`: Your API key for the ElevenLabs engine.
|
|
129
|
+
- `MIA_NARRATIVE_PIPER_PATH`: Custom path to the Piper binary (e.g., `/usr/local/bin/piper`).
|
|
130
|
+
- `MIA_NARRATIVE_PIPER_MODEL_PATH`: Path to the directory containing Piper voice models.
|
|
131
|
+
- `DEBUG`: Set to `1` for verbose debug output.
|
|
132
|
+
|
|
133
|
+
## Troubleshooting
|
|
134
|
+
|
|
135
|
+
### FFmpeg not found
|
|
136
|
+
|
|
137
|
+
Install FFmpeg using your system's package manager (e.g., `brew install ffmpeg`, `sudo apt-get install ffmpeg`).
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
Build the project:
|
|
142
|
+
```bash
|
|
143
|
+
npm run build
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Run in development mode:
|
|
147
|
+
```bash
|
|
148
|
+
npm run dev -- voices --engine system
|
|
149
|
+
```
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { generateCommand } from '../src/commands/generate.js';
|
|
5
|
+
import { voicesCommand } from '../src/commands/voices.js';
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('mia-narrative')
|
|
11
|
+
.description('Text-to-speech CLI for narrative audio generation')
|
|
12
|
+
.version('1.0.0');
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command('generate')
|
|
16
|
+
.description('Generate audio from text')
|
|
17
|
+
.option('--text <text>', 'Text to convert to speech')
|
|
18
|
+
.option('--file <path>', 'Read text from file')
|
|
19
|
+
.option(
|
|
20
|
+
'--engine <name>',
|
|
21
|
+
'TTS engine to use (system, elevenlabs, piper)',
|
|
22
|
+
'system'
|
|
23
|
+
)
|
|
24
|
+
.option('--voiceId <id>', 'Voice ID to use')
|
|
25
|
+
.option(
|
|
26
|
+
'--output <path>',
|
|
27
|
+
'Output MP3 file path (default: output.mp3)'
|
|
28
|
+
)
|
|
29
|
+
.option(
|
|
30
|
+
'--speed <number>',
|
|
31
|
+
'Speech rate (default: 1.0)',
|
|
32
|
+
parseFloat
|
|
33
|
+
)
|
|
34
|
+
.option(
|
|
35
|
+
'--pitch <number>',
|
|
36
|
+
'Pitch (default: 1.0)',
|
|
37
|
+
parseFloat
|
|
38
|
+
)
|
|
39
|
+
.option(
|
|
40
|
+
'--volume <number>',
|
|
41
|
+
'Volume (default: 0.8)',
|
|
42
|
+
parseFloat
|
|
43
|
+
)
|
|
44
|
+
.option(
|
|
45
|
+
'--emphasis <number>',
|
|
46
|
+
'Emphasis (default: 0.5)',
|
|
47
|
+
parseFloat
|
|
48
|
+
)
|
|
49
|
+
.option(
|
|
50
|
+
'--reverb <number>',
|
|
51
|
+
'Reverb (default: 0.2)',
|
|
52
|
+
parseFloat
|
|
53
|
+
)
|
|
54
|
+
.option(
|
|
55
|
+
'--echo <number>',
|
|
56
|
+
'Echo (default: 0.1)',
|
|
57
|
+
parseFloat
|
|
58
|
+
)
|
|
59
|
+
.option(
|
|
60
|
+
'--compression <number>',
|
|
61
|
+
'Compression (default: 0.3)',
|
|
62
|
+
parseFloat
|
|
63
|
+
)
|
|
64
|
+
.option(
|
|
65
|
+
'--pause <number>',
|
|
66
|
+
'Pause length (default: 0.5)',
|
|
67
|
+
parseFloat
|
|
68
|
+
)
|
|
69
|
+
.action(generateCommand);
|
|
70
|
+
|
|
71
|
+
program
|
|
72
|
+
.command('voices')
|
|
73
|
+
.description('List available voices for a specific engine')
|
|
74
|
+
.option(
|
|
75
|
+
'--engine <name>',
|
|
76
|
+
'TTS engine to list voices for (system, elevenlabs, piper)',
|
|
77
|
+
'system'
|
|
78
|
+
)
|
|
79
|
+
.option(
|
|
80
|
+
'--format <format>',
|
|
81
|
+
'Output format (json, table, list)',
|
|
82
|
+
'table'
|
|
83
|
+
)
|
|
84
|
+
.action(voicesCommand);
|
|
85
|
+
|
|
86
|
+
program.parse();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mia-narrative.d.ts","sourceRoot":"","sources":["../../bin/mia-narrative.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { generateCommand } from '../src/commands/generate.js';
|
|
4
|
+
import { voicesCommand } from '../src/commands/voices.js';
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name('mia-narrative')
|
|
8
|
+
.description('Text-to-speech CLI for narrative audio generation')
|
|
9
|
+
.version('1.0.0');
|
|
10
|
+
program
|
|
11
|
+
.command('generate')
|
|
12
|
+
.description('Generate audio from text')
|
|
13
|
+
.option('--text <text>', 'Text to convert to speech')
|
|
14
|
+
.option('--file <path>', 'Read text from file')
|
|
15
|
+
.option('--engine <name>', 'TTS engine to use (system, elevenlabs, piper)', 'system')
|
|
16
|
+
.option('--voiceId <id>', 'Voice ID to use')
|
|
17
|
+
.option('--output <path>', 'Output MP3 file path (default: output.mp3)')
|
|
18
|
+
.option('--speed <number>', 'Speech rate (default: 1.0)', parseFloat)
|
|
19
|
+
.option('--pitch <number>', 'Pitch (default: 1.0)', parseFloat)
|
|
20
|
+
.option('--volume <number>', 'Volume (default: 0.8)', parseFloat)
|
|
21
|
+
.option('--emphasis <number>', 'Emphasis (default: 0.5)', parseFloat)
|
|
22
|
+
.option('--reverb <number>', 'Reverb (default: 0.2)', parseFloat)
|
|
23
|
+
.option('--echo <number>', 'Echo (default: 0.1)', parseFloat)
|
|
24
|
+
.option('--compression <number>', 'Compression (default: 0.3)', parseFloat)
|
|
25
|
+
.option('--pause <number>', 'Pause length (default: 0.5)', parseFloat)
|
|
26
|
+
.action(generateCommand);
|
|
27
|
+
program
|
|
28
|
+
.command('voices')
|
|
29
|
+
.description('List available voices for a specific engine')
|
|
30
|
+
.option('--engine <name>', 'TTS engine to list voices for (system, elevenlabs, piper)', 'system')
|
|
31
|
+
.option('--format <format>', 'Output format (json, table, list)', 'table')
|
|
32
|
+
.action(voicesCommand);
|
|
33
|
+
program.parse();
|
|
34
|
+
//# sourceMappingURL=mia-narrative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mia-narrative.js","sourceRoot":"","sources":["../../bin/mia-narrative.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,mDAAmD,CAAC;KAChE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,eAAe,EAAE,2BAA2B,CAAC;KACpD,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;KAC9C,MAAM,CACL,iBAAiB,EACjB,+CAA+C,EAC/C,QAAQ,CACT;KACA,MAAM,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;KAC3C,MAAM,CACL,iBAAiB,EACjB,4CAA4C,CAC7C;KACA,MAAM,CACL,kBAAkB,EAClB,4BAA4B,EAC5B,UAAU,CACX;KACA,MAAM,CACL,kBAAkB,EAClB,sBAAsB,EACtB,UAAU,CACX;KACA,MAAM,CACL,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,CACX;KACA,MAAM,CACL,qBAAqB,EACrB,yBAAyB,EACzB,UAAU,CACX;KACA,MAAM,CACL,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,CACX;KACA,MAAM,CACL,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,CACX;KACA,MAAM,CACL,wBAAwB,EACxB,4BAA4B,EAC5B,UAAU,CACX;KACA,MAAM,CACL,kBAAkB,EAClB,6BAA6B,EAC7B,UAAU,CACX;KACA,MAAM,CAAC,eAAe,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CACL,iBAAiB,EACjB,2DAA2D,EAC3D,QAAQ,CACT;KACA,MAAM,CACL,mBAAmB,EACnB,mCAAmC,EACnC,OAAO,CACR;KACA,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AudioParameters } from '../config/defaults.js';
|
|
2
|
+
export declare class AudioProcessor {
|
|
3
|
+
static buildFFmpegFilter(params: AudioParameters): string;
|
|
4
|
+
static processAudio(inputPath: string, outputPath: string, params: AudioParameters): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../../../src/audio/processor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,qBAAa,cAAc;IACzB,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM;WAuC5C,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC;CA6CjB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
export class AudioProcessor {
|
|
4
|
+
static buildFFmpegFilter(params) {
|
|
5
|
+
const filters = [];
|
|
6
|
+
if (params.speed !== 1.0) {
|
|
7
|
+
filters.push(`atempo=${Math.max(0.5, Math.min(2.0, params.speed))}`);
|
|
8
|
+
}
|
|
9
|
+
if (params.volume !== 0.8) {
|
|
10
|
+
filters.push(`volume=${Math.max(0.0, Math.min(1.0, params.volume))}`);
|
|
11
|
+
}
|
|
12
|
+
if (params.pitch !== 1.0) {
|
|
13
|
+
const sampleRateMultiplier = Math.max(0.5, Math.min(2.0, params.pitch));
|
|
14
|
+
filters.push(`asetrate=44100*${sampleRateMultiplier}`);
|
|
15
|
+
}
|
|
16
|
+
if (params.reverb > 0.0) {
|
|
17
|
+
const reverb = Math.min(1.0, params.reverb);
|
|
18
|
+
filters.push(`aecho=0.8:${0.88 * reverb}:${6 + reverb * 100}:${0.3 + reverb * 0.4}`);
|
|
19
|
+
}
|
|
20
|
+
if (params.echo !== 0.1) {
|
|
21
|
+
const echoDelay = Math.max(0.1, Math.min(2.0, params.echo)) * 100;
|
|
22
|
+
filters.push(`aecho=0.8:0.88:${echoDelay}:0.4`);
|
|
23
|
+
}
|
|
24
|
+
if (params.compression > 0.0) {
|
|
25
|
+
const ratio = 2 + params.compression * 8; // 2:1 to 10:1
|
|
26
|
+
const threshold = Math.max(0.001, Math.min(1, 0.3 + params.compression * 0.5));
|
|
27
|
+
filters.push(`acompressor=ratio=${ratio}:threshold=${threshold}:makeup=${params.compression * 5}`);
|
|
28
|
+
}
|
|
29
|
+
return filters.length > 0 ? filters.join(',') : '';
|
|
30
|
+
}
|
|
31
|
+
static async processAudio(inputPath, outputPath, params) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const filterComplex = this.buildFFmpegFilter(params);
|
|
34
|
+
const args = [
|
|
35
|
+
'-i',
|
|
36
|
+
inputPath,
|
|
37
|
+
'-codec:a',
|
|
38
|
+
'libmp3lame',
|
|
39
|
+
'-b:a',
|
|
40
|
+
'192k',
|
|
41
|
+
'-ar',
|
|
42
|
+
'44100',
|
|
43
|
+
'-ac',
|
|
44
|
+
'2',
|
|
45
|
+
];
|
|
46
|
+
if (filterComplex) {
|
|
47
|
+
Logger.debug(`Applying FFMpeg filters: ${filterComplex}`);
|
|
48
|
+
args.push('-af', filterComplex);
|
|
49
|
+
}
|
|
50
|
+
args.push(outputPath);
|
|
51
|
+
const ffmpeg = spawn('ffmpeg', args);
|
|
52
|
+
ffmpeg.on('close', (code) => {
|
|
53
|
+
if (code === 0) {
|
|
54
|
+
Logger.debug('FFmpeg processing completed');
|
|
55
|
+
resolve();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
Logger.error(`FFmpeg exited with code ${code}`);
|
|
59
|
+
reject(new Error(`FFmpeg failed with exit code ${code}`));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
ffmpeg.stderr.on('data', (data) => {
|
|
63
|
+
Logger.debug(`ffmpeg: ${data}`);
|
|
64
|
+
});
|
|
65
|
+
ffmpeg.on('error', (err) => {
|
|
66
|
+
Logger.error(`Failed to start FFmpeg: ${err.message}`);
|
|
67
|
+
reject(err);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.js","sourceRoot":"","sources":["../../../src/audio/processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EngineType } from '../engines/factory.js';
|
|
2
|
+
interface GenerateOptions {
|
|
3
|
+
text?: string;
|
|
4
|
+
file?: string;
|
|
5
|
+
engine?: EngineType;
|
|
6
|
+
voiceId?: string;
|
|
7
|
+
output?: string;
|
|
8
|
+
speed?: number;
|
|
9
|
+
pitch?: number;
|
|
10
|
+
volume?: number;
|
|
11
|
+
emphasis?: number;
|
|
12
|
+
reverb?: number;
|
|
13
|
+
echo?: number;
|
|
14
|
+
compression?: number;
|
|
15
|
+
pause?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function generateCommand(options: GenerateOptions): Promise<void>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/generate.ts"],"names":[],"mappings":"AAYA,OAAO,EAAiB,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGlE,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqBD,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6F7E"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { writeFileSync, unlinkSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { DEFAULT_AUDIO_PARAMS, AUDIO_PARAM_RANGES, ExitCode, } from '../config/defaults.js';
|
|
6
|
+
import { FileReader } from '../utils/file-reader.js';
|
|
7
|
+
import { Logger } from '../utils/logger.js';
|
|
8
|
+
import { EngineFactory } from '../engines/factory.js';
|
|
9
|
+
import { AudioProcessor } from '../audio/processor.js';
|
|
10
|
+
function validateParams(params) {
|
|
11
|
+
// Filter out undefined values to preserve defaults
|
|
12
|
+
const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== undefined));
|
|
13
|
+
const validated = { ...DEFAULT_AUDIO_PARAMS, ...definedParams };
|
|
14
|
+
Object.entries(AUDIO_PARAM_RANGES).forEach(([key, range]) => {
|
|
15
|
+
const param = key;
|
|
16
|
+
const value = validated[param];
|
|
17
|
+
if (typeof value === 'number') {
|
|
18
|
+
validated[param] = Math.max(range.min, Math.min(range.max, value));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return validated;
|
|
22
|
+
}
|
|
23
|
+
export async function generateCommand(options) {
|
|
24
|
+
const spinner = ora();
|
|
25
|
+
try {
|
|
26
|
+
if (!options.text && !options.file) {
|
|
27
|
+
Logger.error('Please provide either --text or --file');
|
|
28
|
+
process.exit(ExitCode.INVALID_PARAMS);
|
|
29
|
+
}
|
|
30
|
+
if (options.text && options.file) {
|
|
31
|
+
Logger.error('Please provide either --text or --file, not both');
|
|
32
|
+
process.exit(ExitCode.INVALID_PARAMS);
|
|
33
|
+
}
|
|
34
|
+
let text;
|
|
35
|
+
if (options.file) {
|
|
36
|
+
spinner.start('Reading file...');
|
|
37
|
+
text = FileReader.readTextFile(options.file);
|
|
38
|
+
spinner.succeed('File read successfully');
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
text = options.text;
|
|
42
|
+
}
|
|
43
|
+
const engineType = options.engine || 'system';
|
|
44
|
+
spinner.start(`Initializing ${engineType} TTS engine...`);
|
|
45
|
+
const engine = await EngineFactory.create(engineType, {
|
|
46
|
+
piperPath: process.env.MIA_NARRATIVE_PIPER_PATH,
|
|
47
|
+
modelPath: process.env.MIA_NARRATIVE_PIPER_MODEL,
|
|
48
|
+
});
|
|
49
|
+
spinner.succeed('TTS engine ready');
|
|
50
|
+
if (!(await engine.isAvailable())) {
|
|
51
|
+
Logger.error(`${engine.getName()} engine not available. Please check your configuration.`);
|
|
52
|
+
process.exit(ExitCode.TTS_ENGINE_ERROR);
|
|
53
|
+
}
|
|
54
|
+
const voices = await engine.getVoices();
|
|
55
|
+
const voiceId = options.voiceId || voices[0]?.id;
|
|
56
|
+
if (!voiceId) {
|
|
57
|
+
Logger.error(`No voices available for the ${engineType} engine.`);
|
|
58
|
+
process.exit(ExitCode.INVALID_PARAMS);
|
|
59
|
+
}
|
|
60
|
+
Logger.info(`Using voice: ${voiceId}`);
|
|
61
|
+
const audioParams = validateParams({
|
|
62
|
+
speed: options.speed,
|
|
63
|
+
pitch: options.pitch,
|
|
64
|
+
volume: options.volume,
|
|
65
|
+
emphasis: options.emphasis,
|
|
66
|
+
reverb: options.reverb,
|
|
67
|
+
echo: options.echo,
|
|
68
|
+
compression: options.compression,
|
|
69
|
+
pauseLength: options.pause,
|
|
70
|
+
});
|
|
71
|
+
spinner.start('Generating audio...');
|
|
72
|
+
const rawAudioBuffer = await engine.generateAudio({
|
|
73
|
+
text,
|
|
74
|
+
voiceId,
|
|
75
|
+
parameters: audioParams,
|
|
76
|
+
});
|
|
77
|
+
spinner.succeed('Audio generated');
|
|
78
|
+
spinner.start('Applying audio effects...');
|
|
79
|
+
const tempAudioPath = join(tmpdir(), `temp-audio-${Date.now()}.wav`);
|
|
80
|
+
writeFileSync(tempAudioPath, rawAudioBuffer);
|
|
81
|
+
const outputPath = options.output || 'output.mp3';
|
|
82
|
+
await AudioProcessor.processAudio(tempAudioPath, outputPath, audioParams);
|
|
83
|
+
spinner.succeed('Audio effects applied');
|
|
84
|
+
try {
|
|
85
|
+
unlinkSync(tempAudioPath);
|
|
86
|
+
Logger.debug(`Cleaned up temporary file: ${tempAudioPath}`);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
// ignore
|
|
90
|
+
}
|
|
91
|
+
Logger.success(`Audio generated: ${outputPath}`);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
spinner.fail();
|
|
95
|
+
if (error instanceof Error) {
|
|
96
|
+
Logger.error(error.message);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
Logger.error('Unknown error occurred');
|
|
100
|
+
}
|
|
101
|
+
process.exit(ExitCode.GENERAL_ERROR);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EngineType } from '../engines/factory.js';
|
|
2
|
+
interface VoicesListOptions {
|
|
3
|
+
engine?: EngineType;
|
|
4
|
+
format?: 'json' | 'table' | 'list';
|
|
5
|
+
}
|
|
6
|
+
export declare function voicesCommand(options: VoicesListOptions): Promise<void>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=voices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voices.d.ts","sourceRoot":"","sources":["../../../src/commands/voices.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIlE,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;CACpC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyD7E"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger.js';
|
|
2
|
+
import { EngineFactory } from '../engines/factory.js';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { ExitCode } from '../config/defaults.js';
|
|
5
|
+
export async function voicesCommand(options) {
|
|
6
|
+
const spinner = ora();
|
|
7
|
+
try {
|
|
8
|
+
const engineType = options.engine || 'system';
|
|
9
|
+
spinner.start(`Initializing ${engineType} TTS engine...`);
|
|
10
|
+
const engine = await EngineFactory.create(engineType, {
|
|
11
|
+
piperPath: process.env.MIA_NARRATIVE_PIPER_PATH,
|
|
12
|
+
modelPath: process.env.MIA_NARRATIVE_PIPER_MODEL,
|
|
13
|
+
});
|
|
14
|
+
spinner.succeed('TTS engine ready');
|
|
15
|
+
spinner.start('Fetching voices...');
|
|
16
|
+
const voices = await engine.getVoices();
|
|
17
|
+
spinner.succeed('Voices fetched');
|
|
18
|
+
if (voices.length === 0) {
|
|
19
|
+
Logger.warn(`No voices found for the ${engineType} engine.`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const format = options.format || 'table';
|
|
23
|
+
if (format === 'json') {
|
|
24
|
+
Logger.log(JSON.stringify(voices, null, 2));
|
|
25
|
+
}
|
|
26
|
+
else if (format === 'list') {
|
|
27
|
+
voices.forEach((voice) => {
|
|
28
|
+
Logger.log(voice.id);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Table format
|
|
33
|
+
Logger.log('');
|
|
34
|
+
Logger.log(`Available Voices for ${engineType}:`);
|
|
35
|
+
Logger.log('─'.repeat(80));
|
|
36
|
+
const idHeader = 'ID'.padEnd(30);
|
|
37
|
+
const nameHeader = 'Name';
|
|
38
|
+
Logger.log(` ${idHeader}${nameHeader}`);
|
|
39
|
+
Logger.log('─'.repeat(80));
|
|
40
|
+
voices.forEach((voice) => {
|
|
41
|
+
const idStr = (voice.id || 'unknown').padEnd(30);
|
|
42
|
+
const nameStr = voice.name || 'Unknown';
|
|
43
|
+
Logger.log(` ${idStr}${nameStr}`);
|
|
44
|
+
});
|
|
45
|
+
Logger.log('─'.repeat(80));
|
|
46
|
+
Logger.log('');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
spinner.fail();
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
Logger.error(error.message);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
Logger.error('Unknown error occurred');
|
|
56
|
+
}
|
|
57
|
+
process.exit(ExitCode.GENERAL_ERROR);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=voices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voices.js","sourceRoot":"","sources":["../../../src/commands/voices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface AudioParameters {
|
|
2
|
+
speed: number;
|
|
3
|
+
pitch: number;
|
|
4
|
+
volume: number;
|
|
5
|
+
emphasis: number;
|
|
6
|
+
reverb: number;
|
|
7
|
+
echo: number;
|
|
8
|
+
compression: number;
|
|
9
|
+
pauseLength: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const DEFAULT_AUDIO_PARAMS: AudioParameters;
|
|
12
|
+
export declare const AUDIO_PARAM_RANGES: {
|
|
13
|
+
speed: {
|
|
14
|
+
min: number;
|
|
15
|
+
max: number;
|
|
16
|
+
};
|
|
17
|
+
pitch: {
|
|
18
|
+
min: number;
|
|
19
|
+
max: number;
|
|
20
|
+
};
|
|
21
|
+
volume: {
|
|
22
|
+
min: number;
|
|
23
|
+
max: number;
|
|
24
|
+
};
|
|
25
|
+
emphasis: {
|
|
26
|
+
min: number;
|
|
27
|
+
max: number;
|
|
28
|
+
};
|
|
29
|
+
reverb: {
|
|
30
|
+
min: number;
|
|
31
|
+
max: number;
|
|
32
|
+
};
|
|
33
|
+
echo: {
|
|
34
|
+
min: number;
|
|
35
|
+
max: number;
|
|
36
|
+
};
|
|
37
|
+
compression: {
|
|
38
|
+
min: number;
|
|
39
|
+
max: number;
|
|
40
|
+
};
|
|
41
|
+
pauseLength: {
|
|
42
|
+
min: number;
|
|
43
|
+
max: number;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export declare enum ExitCode {
|
|
47
|
+
SUCCESS = 0,
|
|
48
|
+
GENERAL_ERROR = 1,
|
|
49
|
+
INVALID_PARAMS = 2,
|
|
50
|
+
CONFIG_ERROR = 3,
|
|
51
|
+
TTS_ENGINE_ERROR = 4,
|
|
52
|
+
OUTPUT_ERROR = 5
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,oBAAoB,EAAE,eASlC,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAS9B,CAAC;AAEF,oBAAY,QAAQ;IAClB,OAAO,IAAI;IACX,aAAa,IAAI;IACjB,cAAc,IAAI;IAClB,YAAY,IAAI;IAChB,gBAAgB,IAAI;IACpB,YAAY,IAAI;CACjB"}
|