Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7058cc8d8d | |||
| 7919489543 | |||
| feac7f2479 |
@@ -79,8 +79,8 @@ android {
|
||||
applicationId "com.ariacockpit"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 508
|
||||
versionName "0.0.5.8"
|
||||
versionCode 509
|
||||
versionName "0.0.5.9"
|
||||
// Fallback fuer Libraries mit Product Flavors
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
}
|
||||
|
||||
@@ -32,7 +32,10 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
||||
private const val TAG = "PcmStreamPlayer"
|
||||
// Fallback wenn JS keinen Wert uebergibt.
|
||||
private const val DEFAULT_PREROLL_SECONDS = 3.5
|
||||
private const val MIN_PREROLL_SECONDS = 0.5
|
||||
// 0.0 = sofortige Wiedergabe — play() direkt beim ersten Chunk.
|
||||
// Macht Sinn fuer F5-TTS weil Render so schnell ist dass ein Puffer
|
||||
// unnoetig ist und bei kurzen Saetzen sogar stoeren kann.
|
||||
private const val MIN_PREROLL_SECONDS = 0.0
|
||||
private const val MAX_PREROLL_SECONDS = 10.0
|
||||
// Stille am Stream-Anfang, damit AudioTrack sauber anfaehrt und die
|
||||
// ersten Samples nicht abgeschnitten werden (XTTS-Warmup + play()-Latenz).
|
||||
@@ -59,9 +62,12 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
||||
// Alte Session beenden falls vorhanden
|
||||
stopInternal()
|
||||
|
||||
val prerollSec = prerollSeconds
|
||||
.coerceIn(MIN_PREROLL_SECONDS, MAX_PREROLL_SECONDS)
|
||||
.let { if (it.isFinite() && it > 0) it else DEFAULT_PREROLL_SECONDS }
|
||||
// Nur NaN/Inf → Default. 0.0 ist gueltig (= sofortige Wiedergabe).
|
||||
val prerollSec = if (prerollSeconds.isFinite() && prerollSeconds >= 0.0) {
|
||||
prerollSeconds.coerceIn(MIN_PREROLL_SECONDS, MAX_PREROLL_SECONDS)
|
||||
} else {
|
||||
DEFAULT_PREROLL_SECONDS
|
||||
}
|
||||
|
||||
val channelConfig = if (channels == 2) AudioFormat.CHANNEL_OUT_STEREO else AudioFormat.CHANNEL_OUT_MONO
|
||||
val encoding = AudioFormat.ENCODING_PCM_16BIT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "aria-cockpit",
|
||||
"version": "0.0.5.8",
|
||||
"version": "0.0.5.9",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android": "react-native run-android",
|
||||
|
||||
@@ -143,7 +143,7 @@ const MAX_RECORDING_MS = 120000;
|
||||
// Pre-Roll: Wie lange Audio im AudioTrack-Buffer liegt bevor play() startet.
|
||||
// Einstellbar via Diagnostic/Settings (Key: aria_tts_preroll_sec).
|
||||
export const TTS_PREROLL_DEFAULT_SEC = 3.5;
|
||||
export const TTS_PREROLL_MIN_SEC = 1.0;
|
||||
export const TTS_PREROLL_MIN_SEC = 0; // 0 = sofort abspielen (F5-TTS ist schnell genug)
|
||||
export const TTS_PREROLL_MAX_SEC = 6.0;
|
||||
export const TTS_PREROLL_STORAGE_KEY = 'aria_tts_preroll_sec';
|
||||
|
||||
|
||||
+34
-1
@@ -145,6 +145,15 @@
|
||||
</div>
|
||||
<textarea id="voice-preview-text" rows="4"
|
||||
style="background:#0D0D1A;border:1px solid #2A2A3E;border-radius:6px;padding:10px;color:#fff;font-size:13px;resize:vertical;"></textarea>
|
||||
|
||||
<div style="display:flex;align-items:center;gap:10px;font-size:12px;color:#8888AA;">
|
||||
<span style="min-width:120px;">Geschwindigkeit:</span>
|
||||
<button onclick="adjustPreviewSpeed(-0.1)" class="btn secondary" style="padding:4px 10px;font-size:12px;">−0.1</button>
|
||||
<span id="voice-preview-speed-value" style="min-width:52px;text-align:center;color:#fff;font-weight:600;">1.0 x</span>
|
||||
<button onclick="adjustPreviewSpeed(0.1)" class="btn secondary" style="padding:4px 10px;font-size:12px;">+0.1</button>
|
||||
<span style="color:#555570;font-size:11px;">(nur fuer dieses Modal, wird nicht gespeichert)</span>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<button id="voice-preview-play" onclick="playVoicePreview()" class="btn primary" style="padding:8px 16px;">
|
||||
▶ Abspielen
|
||||
@@ -1630,10 +1639,29 @@
|
||||
|
||||
// ── Voice Preview Modal ─────────────────────────
|
||||
const VOICE_PREVIEW_DEFAULT = 'Hallo, ich bin ARIA. Das hier ist ein kleiner Test damit du meine Stimme beurteilen kannst.';
|
||||
const PREVIEW_SPEED_DEFAULT = 1.0;
|
||||
const PREVIEW_SPEED_MIN = 0.1;
|
||||
const PREVIEW_SPEED_MAX = 5.0;
|
||||
let currentPreviewVoice = '';
|
||||
let currentPreviewSpeed = PREVIEW_SPEED_DEFAULT;
|
||||
|
||||
function _refreshPreviewSpeedLabel() {
|
||||
const el = document.getElementById('voice-preview-speed-value');
|
||||
if (el) el.textContent = currentPreviewSpeed.toFixed(1) + ' x';
|
||||
}
|
||||
|
||||
function adjustPreviewSpeed(delta) {
|
||||
const next = Math.round((currentPreviewSpeed + delta) * 10) / 10;
|
||||
if (next < PREVIEW_SPEED_MIN || next > PREVIEW_SPEED_MAX) return;
|
||||
currentPreviewSpeed = next;
|
||||
_refreshPreviewSpeedLabel();
|
||||
}
|
||||
|
||||
function openVoicePreview(name) {
|
||||
currentPreviewVoice = name;
|
||||
// Speed bei jedem Oeffnen zuruecksetzen — bewusst kein persist
|
||||
currentPreviewSpeed = PREVIEW_SPEED_DEFAULT;
|
||||
_refreshPreviewSpeedLabel();
|
||||
document.getElementById('voice-preview-name').textContent = name;
|
||||
// Text bei jedem Oeffnen zuruecksetzen
|
||||
document.getElementById('voice-preview-text').value = VOICE_PREVIEW_DEFAULT;
|
||||
@@ -1658,7 +1686,12 @@
|
||||
}
|
||||
document.getElementById('voice-preview-status').textContent = '⏳ Rendere...';
|
||||
document.getElementById('voice-preview-play').disabled = true;
|
||||
send({ action: 'preview_voice', voice: currentPreviewVoice, text });
|
||||
send({
|
||||
action: 'preview_voice',
|
||||
voice: currentPreviewVoice,
|
||||
text,
|
||||
speed: currentPreviewSpeed,
|
||||
});
|
||||
}
|
||||
|
||||
function deleteXttsVoice(name) {
|
||||
|
||||
@@ -1469,7 +1469,7 @@ wss.on("connection", (ws) => {
|
||||
} else if (msg.action === "test_tts") {
|
||||
handleTestTTS(ws, msg.text || "Test");
|
||||
} else if (msg.action === "preview_voice") {
|
||||
handleVoicePreview(ws, msg.voice || "", msg.text || "Hallo.");
|
||||
handleVoicePreview(ws, msg.voice || "", msg.text || "Hallo.", msg.speed);
|
||||
} else if (msg.action === "check_tts") {
|
||||
handleCheckTTS(ws);
|
||||
} else if (msg.action === "check_desktop") {
|
||||
@@ -1704,8 +1704,11 @@ function _handlePreviewChunk(payload) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleVoicePreview(clientWs, voice, text) {
|
||||
async function handleVoicePreview(clientWs, voice, text, speed) {
|
||||
try {
|
||||
// Speed clampen — Browser-Slider ist 0.1-5.0
|
||||
let spd = parseFloat(speed);
|
||||
if (!isFinite(spd) || spd < 0.1 || spd > 5.0) spd = 1.0;
|
||||
const requestId = crypto.randomUUID();
|
||||
_previewPending.set(requestId, { clientWs, chunks: [], sampleRate: 0, channels: 0 });
|
||||
// Timeout safety net
|
||||
@@ -1720,10 +1723,10 @@ async function handleVoicePreview(clientWs, voice, text) {
|
||||
}
|
||||
}
|
||||
}, 60000);
|
||||
log("info", "server", `Voice-Preview: voice="${voice}" text="${text.slice(0, 60)}"`);
|
||||
log("info", "server", `Voice-Preview: voice="${voice}" speed=${spd.toFixed(1)}x text="${text.slice(0, 60)}"`);
|
||||
sendToRVS_raw({
|
||||
type: "xtts_request",
|
||||
payload: { text, language: "de", requestId, voice, speed: 1.0 },
|
||||
payload: { text, language: "de", requestId, voice, speed: spd },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user