Skip to content

Instantly share code, notes, and snippets.

@coderofsalvation
Created February 26, 2012 11:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save coderofsalvation/1916306 to your computer and use it in GitHub Desktop.
Save coderofsalvation/1916306 to your computer and use it in GitHub Desktop.
samplescan.sh - converts directories with audiosamples into symbolically linked trees sorted on harmonic key/scale
#!/bin/bash
#
# Samplescan - scans directories with wav-files on harmonic content
#
# (By determining the keys, and a symbolically linked directory structure)
#
# pre-requisites: vamp-plugin-sdk package (http://www.vamp-plugins.org)
#
###########################################################################
#
# Copyright (C) 2012 Coder of Salvation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# <indir> <outdir> [prefix] [sleep] # this will scan the given directory for keys
keys(){
if [ ${#1} == 0 ]; then echo "$CMDS" | echo "Usage: "; _usage; fi
if [ ${#2} == 0 ]; then echo "$CMDS" | echo "Usage: "; _usage; fi
local dirinput="$1"
local diroutput="$2"
local prefix="$3"
local sleep="$4"
local recurse="$5"
local i=0
if [ ! -d "$diroutput" ]; then
mkdir "$diroutput"
create_outputdir "$diroutput"
fi
if [ "$recurse" != 1 ]; then
echo "[x] caching already scanned files using mlocate (please wait)"
updatedb -o $diroutput/.mlocate -U $diroutput
fi
for file in "$dirinput/*"; do
if [ -d "$file" ]; then
if [ "$file" != "$diroutput" ]; then keys "$file" "$diroutput" "$prefix" "$sleep" "1"; fi
else
key "$file" "$diroutput" "$prefix" "$sleep";
fi
# if [ ${#sleep} != 0 ]; then nice -n19 sleep $sleep; fi
# ((i=i+1))
# if [ $i == 5 ]; then exit; fi
done
}
# <file> <outdir> [prefix] [sleep] # this will scan the given file for keys
key(){
local tmp=/tmp/samplescan.tmp
local input=$(echo "$1"| sed "s/\.\///g")
local inputbase=$(basename "$input")
local inputismp3=$(echo "$inputbase" | grep -i "mp3")
local outputdir="$2"
local prefix="$3"
local sleep="$4"
printf "\r[x] checking $input"
local scanned=$(locate -d "$outputdir/.mlocate" "$inputbase" | grep "$outputdir" )
if [ ${#scanned} != 0 ]; then return; fi
if [ ${#inputismp3} != 0 ]; then
sox -V1 "$input" /tmp/samplescan.wav
local output=$(vamp-simple-host qm-vamp-plugins.so:qm-keydetector "/tmp/samplescan.wav" -o "$tmp" 1> /dev/null 2>&1 )
else
local output=$(vamp-simple-host qm-vamp-plugins.so:qm-keydetector "$input" -o "$tmp" 1> /dev/null 2>&1 )
fi
if [ -f "$tmp" ]; then
cat "$tmp" | while read key; do
local key=$( key_to_string "$key" )
local out="$outputdir/$key/$inputbase"
if [ ! -f "$out" ] ; then
if [ ! -e "$out" ]; then ln -s "$prefix$input" "$out"; fi
fi
printf "\n[x] '$key' -> $out\n"
done
rm "$tmp";
fi
}
create_outputdir(){
local i=1
local dir="$1"
while [ "$i" != 25 ]; do
local dirname=$(key_to_string "$i")
mkdir "$dir/$dirname" 1> /dev/null 2>&1
((i=i+1))
done
}
key_to_string(){
# The estimated key for each key change, returned as a single-valued feature
# at the point where the key change is detected, with value counted from 1 to 24
# where 1-12 are the major keys and 13-24 are the minor keys, such that C major is
# 1, C# major is 2, and so on up to B major which is 12; then C minor is 13, Db
# minor is 14, and so on up to B minor which is 24.
local key=$(echo "$1" | sed "s/ //g;s/.*://g")
if [ "$key" == "1" ] ; then key="C" ; fi
if [ "$key" == "2" ] ; then key="Cmaj" ; fi
if [ "$key" == "3" ] ; then key="D" ; fi
if [ "$key" == "4" ] ; then key="Dmaj" ; fi
if [ "$key" == "5" ] ; then key="E" ; fi
if [ "$key" == "6" ] ; then key="F" ; fi
if [ "$key" == "7" ] ; then key="Fmaj" ; fi
if [ "$key" == "8" ] ; then key="G" ; fi
if [ "$key" == "9" ] ; then key="Gmaj" ; fi
if [ "$key" == "10" ] ; then key="A" ; fi
if [ "$key" == "11" ] ; then key="Amaj" ; fi
if [ "$key" == "12" ] ; then key="B" ; fi
if [ "$key" == "13" ] ; then key="C" ; fi
if [ "$key" == "14" ] ; then key="Cmin" ; fi
if [ "$key" == "15" ] ; then key="D" ; fi
if [ "$key" == "16" ] ; then key="Dmin" ; fi
if [ "$key" == "17" ] ; then key="E" ; fi
if [ "$key" == "18" ] ; then key="F" ; fi
if [ "$key" == "19" ] ; then key="Fmin" ; fi
if [ "$key" == "20" ] ; then key="G" ; fi
if [ "$key" == "21" ] ; then key="Gmin" ; fi
if [ "$key" == "22" ] ; then key="A" ; fi
if [ "$key" == "23" ] ; then key="Amin" ; fi
if [ "$key" == "24" ] ; then key="B" ; fi
echo "$key"
}
_usage(){
grep "^[^_].\+(){$" $0 | while read line; do
local cmd=$(echo "$line" | sed "s/(){//g")
local info=$(grep -C0 -A0 -B1 "$cmd(){" $0 | sed "N;s/\n.*//g" )
printf " $0 %-5s %-40s\n" "$cmd" "$info" | grep "#"
done;
printf "\n example: samplescan keys . sorted-by-key \"../../\"\n\n"
exit
}
# run arguments as commands if any, or show Usage
"$@"
if [ ${#1} == 0 ]; then echo "$CMDS" | echo "Usage: "; _usage; fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment