Fix Flextalk buzz: REG_DWORD speaker settings; measured pitch/speed mapping; fixed-gain normalization
This commit is contained in:
@@ -64,8 +64,8 @@ The wrapper maps voice IDs (`sam`, `mary`, `mike`, `keith-bell`, `kerry-watson`,
|
|||||||
MSTTS variants), reads `VESKSLOP_TTS_VOICE`, `VESKSLOP_TTS_SPEED` (multiplier) and
|
MSTTS variants), reads `VESKSLOP_TTS_VOICE`, `VESKSLOP_TTS_SPEED` (multiplier) and
|
||||||
`VESKSLOP_TTS_PITCH` (semitones), starts Xvfb when `DISPLAY` is unset, and writes a
|
`VESKSLOP_TTS_PITCH` (semitones), starts Xvfb when `DISPLAY` is unset, and writes a
|
||||||
48 kHz mono s16le WAV trimmed, faded and normalized to about -16 LUFS (-3 dBFS true peak).
|
48 kHz mono s16le WAV trimmed, faded and normalized to about -16 LUFS (-3 dBFS true peak).
|
||||||
Flextalk voices ignore pitch (engine limitation) and are declared with the `no-pitch`
|
Speed and pitch apply to every voice (Flextalk's numeric settings must be `REG_DWORD`,
|
||||||
flag; everything else maps as documented in `docs/TTS-DESIGN.md`.
|
which the setup script writes). Mapping details are in `docs/TTS-DESIGN.md`.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
@@ -84,8 +84,8 @@ flag; everything else maps as documented in `docs/TTS-DESIGN.md`.
|
|||||||
- `xvfb-run` is flaky on this host. `setup/run.sh` starts a persistent Xvfb
|
- `xvfb-run` is flaky on this host. `setup/run.sh` starts a persistent Xvfb
|
||||||
(`:77`) instead; Wine needs a working X display because the runtime creates
|
(`:77`) instead; Wine needs a working X display because the runtime creates
|
||||||
windows.
|
windows.
|
||||||
- Flextalk ignores pitch entirely (byte-identical output at any pitch setting); use speed.
|
- Flextalk numeric speaker settings must be `REG_DWORD` (the installer script handles
|
||||||
The host now leaves pitch/speed untouched unless passed, so voices use their own profile.
|
this); `REG_SZ` values cause a monotone buzz. Pitch and speed work on all voices.
|
||||||
- The Flextalk archive lacks `data2.cab`; `unshield -O` extracts `data1.cab`
|
- The Flextalk archive lacks `data2.cab`; `unshield -O` extracts `data1.cab`
|
||||||
but one tail file (`WatsonUNInstall.dll`) is incomplete.
|
but one tail file (`WatsonUNInstall.dll`) is incomplete.
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -33,7 +33,9 @@ From `msttsl/mstts.inf` (`[TTSReg]`):
|
|||||||
`HomographDictionary="1 ft_hgrap.dll"`, `ProperNameDictionary="3 ft_namsa.dll"`,
|
`HomographDictionary="1 ft_hgrap.dll"`, `ProperNameDictionary="3 ft_namsa.dll"`,
|
||||||
`LetterToSoundDictionary="4 ft_l2s.dll"`.
|
`LetterToSoundDictionary="4 ft_l2s.dll"`.
|
||||||
- Options: `...\FlexTalk\2.0\Options` `Gender=Male`, `SampleRate=11025`.
|
- Options: `...\FlexTalk\2.0\Options` `Gender=Male`, `SampleRate=11025`.
|
||||||
- Speakers (per-voice settings; names come from these values):
|
- Speakers (per-voice settings; names come from these values). **All numeric
|
||||||
|
values must be REG_DWORD**: with REG_SZ the engine reads garbage and
|
||||||
|
synthesizes a monotone buzz (pitch fixed at max, pitch control dead).
|
||||||
- `{11260610-C84A-11ce-AEC4-0000C0E9CB87}`: Mode Name / Speaker Name
|
- `{11260610-C84A-11ce-AEC4-0000C0E9CB87}`: Mode Name / Speaker Name
|
||||||
"Keith Bell", Pitch 27, Speaking Rate 33, Head Size 46, Expression 59,
|
"Keith Bell", Pitch 27, Speaking Rate 33, Head Size 46, Expression 59,
|
||||||
Lowering 40, Prominences 17, Age 30, Volume 100.
|
Lowering 40, Prominences 17, Age 30, Volume 100.
|
||||||
@@ -71,6 +73,16 @@ final file `WatsonUNInstall.dll` is incomplete).
|
|||||||
- 32-bit engines require a 32-bit prefix (`WINEARCH=win32`).
|
- 32-bit engines require a 32-bit prefix (`WINEARCH=win32`).
|
||||||
- `sudo` on this machine requires a password; installs are manual.
|
- `sudo` on this machine requires a password; installs are manual.
|
||||||
|
|
||||||
|
## Engine units (measured)
|
||||||
|
|
||||||
|
- speed: MSTTS range 30-450, Flextalk 50-390; the natural rate is about 150 for every
|
||||||
|
voice (duration at 100/200/300 fits a natural value near 140-150).
|
||||||
|
- pitch: engine units, roughly linear in F0 near the natural point (~1.1 Hz per unit).
|
||||||
|
Natural values: about 100 (MSTTS), 106 (Keith Bell), 186 (Kerry Watson); Flextalk max 250.
|
||||||
|
Verified with the corrected DWORD registry: Kerry 0 st = 209 Hz, -6 st = 148 Hz,
|
||||||
|
+6 st = 250 Hz (clamped at max); Keith 0 st = 119 Hz, +6 st = 170 Hz.
|
||||||
|
- The wrapper maps semitones as `natural * 2^(st/12)` and clamps to the range.
|
||||||
|
|
||||||
## Decompiled corpora (Ghidra)
|
## Decompiled corpora (Ghidra)
|
||||||
|
|
||||||
- `/mnt/ghidra/decomp/msttssyn.dll/` (786 functions, engine)
|
- `/mnt/ghidra/decomp/msttssyn.dll/` (786 functions, engine)
|
||||||
|
|||||||
+18
-1
@@ -267,7 +267,8 @@ record what the engine needs to interpret, add, or hide._
|
|||||||
|
|
||||||
### Quirks the wrapper must hide
|
### Quirks the wrapper must hide
|
||||||
|
|
||||||
- Flextalk reports default pitch/speed as maximum through `ITTSAttributes`.
|
- Flextalk numeric speaker settings must be `REG_DWORD`; `REG_SZ` values make the engine
|
||||||
|
synthesize a buzz. `setup/setup-flextalk.sh` writes them correctly.
|
||||||
- The mode list includes TruVoice names with no installed voice data; filter those out of
|
- The mode list includes TruVoice names with no installed voice data; filter those out of
|
||||||
`/voices` (or mark them `unavailable`).
|
`/voices` (or mark them `unavailable`).
|
||||||
- Wine needs a working X display; the project helper starts a persistent Xvfb.
|
- Wine needs a working X display; the project helper starts a persistent Xvfb.
|
||||||
@@ -301,6 +302,19 @@ _Added 2026-09-15._
|
|||||||
- **Display**: the daemon does not export `DISPLAY` to TTS children. The wrapper must start or
|
- **Display**: the daemon does not export `DISPLAY` to TTS children. The wrapper must start or
|
||||||
find its own Xvfb and set `DISPLAY` itself, as the project helper already does. Do not rely on
|
find its own Xvfb and set `DISPLAY` itself, as the project helper already does. Do not rely on
|
||||||
the client's display.
|
the client's display.
|
||||||
|
- **Engine selection**: the Speech settings and the TTS panel list every configured engine. The
|
||||||
|
command engine appears under `VESKSLOP_TTS_NAME` (default "custom engine") and is selectable
|
||||||
|
directly; Auto uses the command engine first. Selecting it hides the language row and shows the
|
||||||
|
`VESKSLOP_TTS_VOICES` list.
|
||||||
|
- **Start engine**: the Speech settings have a **Start engine** button (`POST /api/audio/tts/warm`,
|
||||||
|
MCP `start_tts_engine`) that runs one throwaway synthesis to warm the command engine (Xvfb, Wine,
|
||||||
|
host). Keep the wrapper able to handle a short sentence; the warm-up uses "The quick brown fox
|
||||||
|
jumps over the lazy dog." and reports the elapsed milliseconds. Two-pass `loudnorm` must not fail
|
||||||
|
on that input.
|
||||||
|
- **Lead-in silence**: Veskslop prepends a short silence at playback time (`VESKSLOP_TTS_LEAD_MS`,
|
||||||
|
default 150 ms) so Discord's voice pipeline is ready before the first syllable. It is added with
|
||||||
|
`adelay` in the player, not in the audio file. The engine needs no change and can keep its
|
||||||
|
5–10 ms edge fades.
|
||||||
- **Voice declarations**: list only usable IDs in `VESKSLOP_TTS_VOICES`. Veskslop hides the
|
- **Voice declarations**: list only usable IDs in `VESKSLOP_TTS_VOICES`. Veskslop hides the
|
||||||
espeak list while a custom command is set, so a missing declaration means an empty voice list,
|
espeak list while a custom command is set, so a missing declaration means an empty voice list,
|
||||||
not a fallback. The list accepts commas or newlines, and the optional `no-pitch` flag tells the
|
not a fallback. The list accepts commas or newlines, and the optional `no-pitch` flag tells the
|
||||||
@@ -308,5 +322,8 @@ _Added 2026-09-15._
|
|||||||
- **Flextalk pitch**: confirmed that pitch is a no-op for Keith Bell and Kerry Watson. Mark those
|
- **Flextalk pitch**: confirmed that pitch is a no-op for Keith Bell and Kerry Watson. Mark those
|
||||||
entries `no-pitch` so users are not offered a control that does nothing. Speed applies to every
|
entries `no-pitch` so users are not offered a control that does nothing. Speed applies to every
|
||||||
voice and needs no flag.
|
voice and needs no flag.
|
||||||
|
_Engine correction (2026-09-15): the no-op was caused by the speaker registry values being
|
||||||
|
`REG_SZ`; with `REG_DWORD` pitch works and the voices are declared without the flag. See the
|
||||||
|
speed/pitch section._
|
||||||
- **Licensing**: keep the engine DLLs and voice data local and out of any repository; Veskslop
|
- **Licensing**: keep the engine DLLs and voice data local and out of any repository; Veskslop
|
||||||
never bundles or redistributes them.
|
never bundles or redistributes them.
|
||||||
|
|||||||
+16
-16
@@ -62,30 +62,30 @@ REGEDIT4
|
|||||||
"SampleRate"="11025"
|
"SampleRate"="11025"
|
||||||
|
|
||||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{11260610-C84A-11ce-AEC4-0000C0E9CB87}]
|
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{11260610-C84A-11ce-AEC4-0000C0E9CB87}]
|
||||||
"Age"="30"
|
"Age"=dword:0000001e
|
||||||
"Expression"="59"
|
"Expression"=dword:0000003b
|
||||||
"Gender"=""
|
"Gender"=""
|
||||||
"Head Size"="46"
|
"Head Size"=dword:0000002e
|
||||||
"Lowering"="40"
|
"Lowering"=dword:00000028
|
||||||
"Mode Name"="Keith Bell"
|
"Mode Name"="Keith Bell"
|
||||||
"Pitch"="27"
|
"Pitch"=dword:0000001b
|
||||||
"Prominences"="17"
|
"Prominences"=dword:00000011
|
||||||
"Speaker Name"="Keith Bell"
|
"Speaker Name"="Keith Bell"
|
||||||
"Speaking Rate"="33"
|
"Speaking Rate"=dword:00000021
|
||||||
"Volume"="100"
|
"Volume"=dword:00000064
|
||||||
|
|
||||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{000031CB-3699-551F-AED0-6B4893382D57}]
|
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{000031CB-3699-551F-AED0-6B4893382D57}]
|
||||||
"Age"="30"
|
"Age"=dword:0000001e
|
||||||
"Expression"="100"
|
"Expression"=dword:00000064
|
||||||
"Gender"=""
|
"Gender"=""
|
||||||
"Head Size"="45"
|
"Head Size"=dword:0000002d
|
||||||
"Lowering"="40"
|
"Lowering"=dword:00000028
|
||||||
"Mode Name"="Kerry Watson"
|
"Mode Name"="Kerry Watson"
|
||||||
"Pitch"="65"
|
"Pitch"=dword:00000041
|
||||||
"Prominences"="17"
|
"Prominences"=dword:00000011
|
||||||
"Speaker Name"="Kerry Watson"
|
"Speaker Name"="Kerry Watson"
|
||||||
"Speaking Rate"="32"
|
"Speaking Rate"=dword:00000020
|
||||||
"Volume"="100"
|
"Volume"=dword:00000064
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "== registry"
|
echo "== registry"
|
||||||
|
|||||||
+54
-32
@@ -20,8 +20,7 @@ export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam}
|
|||||||
export WINEARCH=win32
|
export WINEARCH=win32
|
||||||
|
|
||||||
# VESKSLOP_TTS_VOICES entries: id|Name|gender|language[|flags]
|
# VESKSLOP_TTS_VOICES entries: id|Name|gender|language[|flags]
|
||||||
# `no-pitch` marks voices whose engine ignores pitch (Flextalk).
|
VOICES="sam|Sam|male|en,mary|Mary|female|en,mike|Mike|male|en,keith-bell|Keith Bell|male|en,kerry-watson|Kerry Watson|female|en,mike-telephone|Mike (for Telephone)|male|en,mary-telephone|Mary (for Telephone)|female|en,mike-hall|Mike in Hall|male|en,mike-stadium|Mike in Stadium|male|en,mike-space|Mike in Space|male|en,mary-hall|Mary in Hall|female|en,mary-stadium|Mary in Stadium|female|en,mary-space|Mary in Space|female|en"
|
||||||
VOICES="sam|Sam|male|en,mary|Mary|female|en,mike|Mike|male|en,keith-bell|Keith Bell|male|en|no-pitch,kerry-watson|Kerry Watson|female|en|no-pitch,mike-telephone|Mike (for Telephone)|male|en,mary-telephone|Mary (for Telephone)|female|en,mike-hall|Mike in Hall|male|en,mike-stadium|Mike in Stadium|male|en,mike-space|Mike in Space|male|en,mary-hall|Mary in Hall|female|en,mary-stadium|Mary in Stadium|female|en,mary-space|Mary in Space|female|en"
|
|
||||||
|
|
||||||
if [ "${1:-}" = "--voices" ]; then
|
if [ "${1:-}" = "--voices" ]; then
|
||||||
echo "$VOICES"
|
echo "$VOICES"
|
||||||
@@ -51,36 +50,38 @@ case "$VOICE" in
|
|||||||
*) ENGVOICE="Sam" ;;
|
*) ENGVOICE="Sam" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Engine units. Measured naturals: MSTTS ~150, Flextalk ~300 (words/min scale).
|
# Engine units (measured). Speed is words/min, natural rate near 150 for every
|
||||||
# Flextalk ignores ITTSAttributes pitch (verified byte-identical output).
|
# voice. Pitch units differ per voice: the engine's natural pitch corresponds to
|
||||||
|
# about 100 (MSTTS), 106 (Keith Bell) and 186 (Kerry Watson). Semitones scale
|
||||||
|
# that natural value by 2^(st/12) and clamp to the engine range.
|
||||||
case "$ENGVOICE" in
|
case "$ENGVOICE" in
|
||||||
"Keith Bell"|"Kerry Watson") NAT_SPEED=300; SMAX=390 ;;
|
"Keith Bell") SMAX=390; PMAX=250; NAT_PITCH=106 ;;
|
||||||
*) NAT_SPEED=150; SMAX=450 ;;
|
"Kerry Watson") SMAX=390; PMAX=250; NAT_PITCH=186 ;;
|
||||||
|
*) SMAX=450; PMAX=200; NAT_PITCH=100 ;;
|
||||||
esac
|
esac
|
||||||
SET_ARGS=""
|
SET_ARGS=""
|
||||||
if [ -n "$SPEED" ]; then
|
if [ -n "$SPEED" ]; then
|
||||||
S=$(awk -v m="$SPEED" -v n="$NAT_SPEED" 'BEGIN{printf "%d", n*m+0.5}')
|
S=$(awk -v m="$SPEED" 'BEGIN{printf "%d", 150*m+0.5}')
|
||||||
[ "$S" -lt 50 ] && S=50
|
[ "$S" -lt 50 ] && S=50
|
||||||
[ "$S" -gt "$SMAX" ] && S=$SMAX
|
[ "$S" -gt "$SMAX" ] && S=$SMAX
|
||||||
SET_ARGS="$SET_ARGS -s $S"
|
SET_ARGS="$SET_ARGS -s $S"
|
||||||
fi
|
fi
|
||||||
if [ -n "$PITCH" ]; then
|
if [ -n "$PITCH" ]; then
|
||||||
case "$ENGVOICE" in
|
P=$(awk -v st="$PITCH" -v nat="$NAT_PITCH" 'BEGIN{printf "%d", nat*exp(log(2)*st/12)+0.5}')
|
||||||
"Keith Bell"|"Kerry Watson") : ;;
|
[ "$P" -lt 50 ] && P=50
|
||||||
*)
|
[ "$P" -gt "$PMAX" ] && P=$PMAX
|
||||||
P=$(awk -v st="$PITCH" 'BEGIN{printf "%d", 100 + st*6.25}')
|
SET_ARGS="$SET_ARGS -p $P"
|
||||||
[ "$P" -lt 50 ] && P=50
|
|
||||||
[ "$P" -gt 200 ] && P=200
|
|
||||||
SET_ARGS="$SET_ARGS -p $P" ;;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The daemon does not export DISPLAY; keep a private Xvfb for the engine.
|
# The daemon does not export DISPLAY; keep a private Xvfb for the engine.
|
||||||
if [ -z "${DISPLAY:-}" ]; then
|
start_xvfb() {
|
||||||
if ! [ -S /tmp/.X11-unix/X77 ]; then
|
if ! [ -S /tmp/.X11-unix/X77 ]; then
|
||||||
Xvfb :77 -screen 0 1024x768x24 >/dev/null 2>&1 &
|
Xvfb :77 -screen 0 1024x768x24 >/dev/null 2>&1 &
|
||||||
sleep 1
|
sleep 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
if [ -z "${DISPLAY:-}" ]; then
|
||||||
|
start_xvfb
|
||||||
export DISPLAY=:77
|
export DISPLAY=:77
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -102,32 +103,53 @@ if [ ! -x "$HOST" ]; then HOST="$ROOT/build/sapi4host.exe"; fi
|
|||||||
if [ ! -x "$HOST" ]; then echo "engine host not built" >&2; exit 1; fi
|
if [ ! -x "$HOST" ]; then echo "engine host not built" >&2; exit 1; fi
|
||||||
if ! command -v ffmpeg >/dev/null 2>&1; then echo "ffmpeg not found" >&2; exit 1; fi
|
if ! command -v ffmpeg >/dev/null 2>&1; then echo "ffmpeg not found" >&2; exit 1; fi
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
run_engine() {
|
||||||
if ! "$HOST" -v "$ENGVOICE" -t "$(cat "$TXT")" -o "$RAW" $SET_ARGS \
|
# shellcheck disable=SC2086
|
||||||
>/dev/null 2>"$TMP/err"; then
|
"$HOST" -v "$ENGVOICE" -t "$(cat "$TXT")" -o "$RAW" $SET_ARGS \
|
||||||
head -c 400 "$TMP/err" >&2
|
>/dev/null 2>"$TMP/err"
|
||||||
exit 1
|
}
|
||||||
|
if ! run_engine; then
|
||||||
|
# A stale private Xvfb can break audio-destination creation; retry once.
|
||||||
|
if [ "${DISPLAY:-}" = ":77" ]; then
|
||||||
|
pkill -f "Xvfb :77" 2>/dev/null || true
|
||||||
|
rm -f /tmp/.X11-unix/X77
|
||||||
|
start_xvfb
|
||||||
|
if ! run_engine; then
|
||||||
|
head -c 400 "$TMP/err" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
head -c 400 "$TMP/err" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
[ -s "$RAW" ] || { echo "engine produced no audio" >&2; exit 1; }
|
[ -s "$RAW" ] || { echo "engine produced no audio" >&2; exit 1; }
|
||||||
|
|
||||||
SIL="silenceremove=start_periods=1:start_duration=0.05:start_silence=0.03:start_threshold=-50dB"
|
SIL="silenceremove=start_periods=1:start_duration=0.05:start_silence=0.03:start_threshold=-50dB"
|
||||||
PRE="highpass=f=40,$SIL,afade=t=in:st=0:d=0.008,areverse,$SIL,afade=t=in:st=0:d=0.008,areverse"
|
PRE="highpass=f=40,$SIL,afade=t=in:st=0:d=0.008,areverse,$SIL,afade=t=in:st=0:d=0.008,areverse"
|
||||||
LN="loudnorm=I=-16:TP=-3:LRA=11"
|
|
||||||
|
|
||||||
# Two-pass loudnorm: measure first, then apply with the measured values.
|
# Fixed-gain normalization: single-pass loudnorm misbehaves on short lines
|
||||||
M=$(ffmpeg -hide_banner -nostats -i "$RAW" -af "$PRE,$LN:print_format=json" \
|
# (LRA=0 causes heavy attenuation), so measure EBU R128 integrated loudness and
|
||||||
|
# true peak, then apply one gain clamped by the -3 dBFS peak target.
|
||||||
|
M=$(ffmpeg -hide_banner -nostats -i "$RAW" -af "$PRE,ebur128=peak=true" \
|
||||||
-f null - 2>&1 || true)
|
-f null - 2>&1 || true)
|
||||||
I=$(printf '%s' "$M" | sed -n 's/.*"input_i" *: *"\([^"]*\)".*/\1/p')
|
I=$(printf '%s' "$M" | sed -n 's/ *I: *\(-\{0,1\}[0-9.]*\) *LUFS.*/\1/p' | tail -1)
|
||||||
TP=$(printf '%s' "$M" | sed -n 's/.*"input_tp" *: *"\([^"]*\)".*/\1/p')
|
TP=$(printf '%s' "$M" | sed -n 's/ *Peak: *\(-\{0,1\}[0-9.]*\) *dBFS.*/\1/p' | tail -1)
|
||||||
LRA=$(printf '%s' "$M" | sed -n 's/.*"input_lra" *: *"\([^"]*\)".*/\1/p')
|
if [ -n "$I" ] && [ -n "$TP" ]; then
|
||||||
TH=$(printf '%s' "$M" | sed -n 's/.*"input_thresh" *: *"\([^"]*\)".*/\1/p')
|
GAIN=$(awk -v i="$I" -v tp="$TP" 'BEGIN{
|
||||||
OFF=$(printf '%s' "$M" | sed -n 's/.*"target_offset" *: *"\([^"]*\)".*/\1/p')
|
g = -16 - i;
|
||||||
if [ -n "$I" ] && [ -n "$TP" ] && [ -n "$LRA" ] && [ -n "$TH" ] && [ -n "$OFF" ]; then
|
lim = -3 - tp;
|
||||||
LN="$LN:measured_I=$I:measured_TP=$TP:measured_LRA=$LRA:measured_thresh=$TH:offset=$OFF:linear=true"
|
if (lim < g) g = lim;
|
||||||
|
if (g > 30) g = 30;
|
||||||
|
if (g < -20) g = -20;
|
||||||
|
printf "%.2f", g
|
||||||
|
}')
|
||||||
|
else
|
||||||
|
GAIN=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TMPOUT="$TMP/out.wav"
|
TMPOUT="$TMP/out.wav"
|
||||||
if ! ffmpeg -hide_banner -nostats -y -i "$RAW" -af "$PRE,$LN" \
|
if ! ffmpeg -hide_banner -nostats -y -i "$RAW" -af "$PRE,volume=${GAIN}dB" \
|
||||||
-ar 48000 -ac 1 -c:a pcm_s16le "$TMPOUT" >/dev/null 2>"$TMP/ff"; then
|
-ar 48000 -ac 1 -c:a pcm_s16le "$TMPOUT" >/dev/null 2>"$TMP/ff"; then
|
||||||
head -c 400 "$TMP/ff" >&2
|
head -c 400 "$TMP/ff" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user