Created
March 30, 2023 14:43
-
-
Save blakek/195afec017a3083196b94671521935f8 to your computer and use it in GitHub Desktop.
Music file manipulation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -eo pipefail | |
## | |
# Transpose a song from one key to another. | |
## | |
version='0.0.1' | |
# Formatting functions | |
bold() { | |
format_bold='\033[1m' | |
format_reset='\033[0m' | |
echo -e "${format_bold}$1${format_reset}" | |
} | |
error() { | |
format_red='\033[0;31m' | |
format_reset='\033[0m' | |
echo -e "${format_red}$1${format_reset}" >&2 | |
} | |
panic() { | |
error "$1" | |
exit 1 | |
} | |
# Floating point calculations | |
calculate() { | |
# `bc` cannot do fractional exponents but `awk` can | |
awk "BEGIN { print $1 }" | |
} | |
show_usage() { | |
cat <<-EOF | |
$(bold transpose) - Transpose a song from one key to another | |
$(bold USAGE) | |
$ transpose --help | |
$ transpose --version | |
$ transpose input_file output_file semitones | |
For example, to transpose a song from C to E: | |
$ transpose input_file output_file 4 | |
or, to transpose a song from E to C: | |
$ transpose input_file output_file -4 | |
$(bold OPTIONS) | |
-h, --help | |
Show this help message and exit | |
-v, --version | |
Show the version of this script and exit | |
EOF | |
} | |
transpose() { | |
# Check if usage/version was requested | |
if [[ $# -ne 3 ]]; then | |
show_usage | |
exit 0 | |
fi | |
for arg in "$@"; do | |
if [[ $arg == "--help" || $arg == "-h" ]]; then | |
show_usage | |
exit 0 | |
elif [[ $arg == "--version" || $arg == "-v" ]]; then | |
echo "$version" | |
exit 0 | |
fi | |
done | |
local input_file="$1" | |
local output_file="$2" | |
local semitones="$3" | |
# Validate arguments | |
if [[ ! -r $input_file ]]; then | |
panic "Could not read input file" | |
fi | |
if [[ $semitones -lt -12 || $semitones -gt 12 ]]; then | |
panic "Semitones must be between -12 and 12" | |
fi | |
# Find the difference between the start and end keys, picking the closest one | |
local pitch_difference | |
pitch_difference=$(calculate "2 ^ ($semitones / 12)") | |
# Show progress if pv is installed | |
if [[ $(hash pv 2>/dev/null) ]]; then | |
pv -i 0.15 "$input_file" | ffmpeg -i - -y -af "rubberband=pitch=$pitch_difference" -v quiet "$output_file" | |
else | |
ffmpeg -i "$input_file" -y -af "rubberband=pitch=$pitch_difference" -v quiet -stats "$output_file" | |
fi | |
} | |
transpose "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment