mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 21:27:02 +01:00
i3 config was filed under periodic_background, which it never was. It is now linux_configuration/i3/ (config + installer) and linux_configuration/i3blocks/ (the status scripts), both at depth 2. misc/testsAndMisc-bash/ was a directory named after the repo it already lived in, so its contents moved up to misc/. Its stray .gitignore came along, keeping the media rules working from the new location; its .vscode/tasks.json did not, because it invoked Bash/transcribe.sh, a path this repo dropped long ago. Most of this commit is the references the previous flatten missed. Its regex skipped anything with a variable prefix, which left 16 files -- including check_and_enable_services.sh and install_core_system.sh, the orchestrators -- still naming $CONFIG_DIR/scripts/periodic_background/... It had also rewritten three i3 paths into scripts/i3blocks/, a directory that has never existed; the i3blocks suites caught that by failing. 13 more symlinks broke on the i3 move. Repointed, and cpu_monitor/volume/ disk were run again to confirm the bar still reports. Depth 139 -> 104. Roughly 47 of the remainder sit in digital_wellbeing and hosts, still deferred. The rest encode real structure -- a C project, Python package directories, artgate's routes/styles, systemd unit dirs -- so flattening them further would destroy information rather than taxonomy. Verified: 1798 tests at 100%, both i3blocks suites pass, the shell coverage gate is clean, and the relocated media rules still ignore what they should while test_fw.srt stays tracked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
231 lines
5.7 KiB
Bash
Executable File
231 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
# shellcheck source=lib/clean_audio_filters.sh
|
|
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/clean_audio_filters.sh"
|
|
|
|
# clean_audio.sh — Fully automatic audio cleaner for speech (ASR-friendly)
|
|
#
|
|
# - Default preset is tuned for ASR (faster-whisper):
|
|
# mono, 16 kHz, high-pass filter, denoise (RNNoise arnndn by default if model found/provided; else afftdn),
|
|
# peak limiting to -0.5 dBFS. No aggressive gating/compression by default.
|
|
# - Optional "podcast" preset adds gentle dynamics and loudness leveling.
|
|
# - Accepts single files or directories (recursively).
|
|
# - Optional parallel processing.
|
|
#
|
|
# Dependencies: ffmpeg (arnndn filter recommended for best results)
|
|
# Optional: an RNNoise model file for arnndn (auto-discovered if present; otherwise falls back to afftdn)
|
|
#
|
|
# Usage examples:
|
|
# Bash/clean_audio.sh input.wav # -> input_clean.wav (same folder)
|
|
# Bash/clean_audio.sh input.wav -O out_dir # -> out_dir/input_clean.wav
|
|
# Bash/clean_audio.sh input_dir -O cleaned/ -j 4 # -> processes all audio files in dir
|
|
# Bash/clean_audio.sh input.wav -m models/rn.nn # -> use RNNoise model
|
|
# Bash/clean_audio.sh input.wav --preset podcast # -> add dynamics leveler
|
|
#
|
|
|
|
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
|
|
|
|
|
|
|
|
# Defaults
|
|
OUT_DIR=""
|
|
OUT_EXT="wav"
|
|
RN_MODEL=""
|
|
NO_ML=false
|
|
REQUIRE_ML=true # default: require RNNoise; install/guide if missing; fail fast if unavailable
|
|
PRESET="asr"
|
|
JOBS=1
|
|
FORCE=false
|
|
QUIET=false
|
|
LOWPASS=""
|
|
SUFFIX="_clean"
|
|
HIGHPASS="80"
|
|
AFFTDN_NF="-25" # noise floor in dB for afftdn
|
|
AFFTDN_MD="8" # mode for afftdn (higher can be more aggressive); requires builds that support 'md'
|
|
NO_ADVANCED=false # when true, avoid advanced options that some ffmpeg builds lack
|
|
|
|
# Parse args
|
|
if [[ $# -lt 1 ]]; then
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
|
|
INPUT_PATH="$1"
|
|
shift || true
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-O | --out-dir)
|
|
OUT_DIR="$2"
|
|
shift 2
|
|
;;
|
|
-e | --ext)
|
|
OUT_EXT="$2"
|
|
shift 2
|
|
;;
|
|
-m | --model)
|
|
RN_MODEL="$2"
|
|
shift 2
|
|
;;
|
|
--no-ml)
|
|
NO_ML=true
|
|
shift
|
|
;;
|
|
--preset)
|
|
PRESET="$2"
|
|
shift 2
|
|
;;
|
|
-j | --jobs)
|
|
JOBS="$2"
|
|
shift 2
|
|
;;
|
|
-f | --force)
|
|
FORCE=true
|
|
shift
|
|
;;
|
|
-q | --quiet)
|
|
QUIET=true
|
|
shift
|
|
;;
|
|
--lowpass)
|
|
LOWPASS="$2"
|
|
shift 2
|
|
;;
|
|
--suffix)
|
|
SUFFIX="$2"
|
|
shift 2
|
|
;;
|
|
--no-advanced | --compat)
|
|
NO_ADVANCED=true
|
|
shift
|
|
;;
|
|
--allow-fallback)
|
|
REQUIRE_ML=false
|
|
shift
|
|
;;
|
|
-h | --help)
|
|
print_usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
require_cmd ffmpeg
|
|
|
|
# Resolve FFmpeg binary (env override -> local build -> system)
|
|
FFMPEG_BIN=${FFMPEG_BIN:-}
|
|
if [[ -z ${FFMPEG_BIN} ]]; then
|
|
if [[ -x "$SCRIPT_DIR/ffmpeg-build/FFmpeg/ffmpeg" ]]; then
|
|
FFMPEG_BIN="$SCRIPT_DIR/ffmpeg-build/FFmpeg/ffmpeg"
|
|
else
|
|
FFMPEG_BIN="ffmpeg"
|
|
fi
|
|
fi
|
|
|
|
if ! command -v "$FFMPEG_BIN" > /dev/null 2>&1 && [[ ! -x $FFMPEG_BIN ]]; then
|
|
echo "Error: FFmpeg binary not found: $FFMPEG_BIN" >&2
|
|
exit 1
|
|
fi
|
|
if ! $QUIET; then
|
|
echo "Using FFmpeg binary: $FFMPEG_BIN" >&2
|
|
fi
|
|
|
|
FFMPEG_LOG=(-hide_banner)
|
|
if $QUIET; then
|
|
FFMPEG_LOG+=(-loglevel error)
|
|
else
|
|
FFMPEG_LOG+=(-loglevel info)
|
|
fi
|
|
|
|
FFMPEG_OVERWRITE=(-n)
|
|
if $FORCE; then
|
|
FFMPEG_OVERWRITE=(-y)
|
|
fi
|
|
|
|
arnndn_available=false
|
|
if "$FFMPEG_BIN" -hide_banner -h filter=arnndn > /dev/null 2>&1; then
|
|
arnndn_available=true
|
|
else
|
|
if "$FFMPEG_BIN" -hide_banner -filters 2> /dev/null | grep -Eq '(^|[[:space:]])arnndn([[:space:]]|$)'; then
|
|
arnndn_available=true
|
|
fi
|
|
fi
|
|
if ! $QUIET; then
|
|
echo "arnndn_available=$arnndn_available" >&2
|
|
fi
|
|
|
|
# Check if afftdn supports 'md' option
|
|
afftdn_supports_md=false
|
|
if "$FFMPEG_BIN" -hide_banner -h filter=afftdn 2> /dev/null | grep -q " md="; then
|
|
afftdn_supports_md=true
|
|
fi
|
|
|
|
|
|
use_arnndn=false
|
|
if [[ $NO_ML == false ]]; then
|
|
if [[ $arnndn_available == false ]]; then
|
|
if $REQUIRE_ML; then
|
|
echo "Error: FFmpeg 'arnndn' filter not available. Please install/upgrade FFmpeg with librnnoise (see Bash/install_ffmpeg_with_arnndn.sh)." >&2
|
|
exit 9
|
|
fi
|
|
else
|
|
# arnndn available; require an external model
|
|
if [[ -n $RN_MODEL && -f $RN_MODEL ]]; then
|
|
:
|
|
else
|
|
if model_path=$(find_default_rn_model); then
|
|
RN_MODEL="$model_path"
|
|
else
|
|
if [[ -x "$SCRIPT_DIR/get_rnnoise_model.sh" ]]; then
|
|
RN_TARGET_DIR="$SCRIPT_DIR/models" RN_TARGET_NAME="rnnoise_model.rnnn" "$SCRIPT_DIR/get_rnnoise_model.sh" --yes || true
|
|
if model_path=$(find_default_rn_model); then
|
|
RN_MODEL="$model_path"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
if [[ -z $RN_MODEL ]]; then
|
|
echo "Error: RNNoise model required but not found. Automatic download failed." >&2
|
|
echo "Hint: Set RN_URL to a reachable model URL and run Bash/get_rnnoise_model.sh, or supply -m /path/to/model.nn." >&2
|
|
exit 10
|
|
fi
|
|
use_arnndn=true
|
|
echo "Using RNNoise external model: $RN_MODEL" >&2
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Concurrency helpers (bash >= 5 supports wait -n; fallback to sequential if not)
|
|
supports_wait_n=false
|
|
if [[ -n ${BASH_VERSINFO:-} && ${BASH_VERSINFO[0]} -ge 5 ]]; then
|
|
supports_wait_n=true
|
|
fi
|
|
|
|
|
|
main() {
|
|
# Sanity checks and notices
|
|
if [[ -n $RN_MODEL && $use_arnndn == false && $NO_ML == false ]]; then
|
|
echo "Note: arnndn filter not available in your ffmpeg or model missing — using afftdn." >&2
|
|
fi
|
|
|
|
if [[ -f $INPUT_PATH ]]; then
|
|
process_one "$INPUT_PATH"
|
|
elif [[ -d $INPUT_PATH ]]; then
|
|
run_dir "$INPUT_PATH"
|
|
else
|
|
echo "Error: Input path not found: $INPUT_PATH" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
main "$@"
|