Skip to content

Instantly share code, notes, and snippets.

@muzzol
Created March 18, 2020 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muzzol/5f5d27c155d6113069445c7d3b6910f2 to your computer and use it in GitHub Desktop.
Save muzzol/5f5d27c155d6113069445c7d3b6910f2 to your computer and use it in GitHub Desktop.
#!/bin/bash
# copy one track between ardour projects including layers
# àngel "mussol" bosch - muzzol@gmail.com
VER="0.2"
TOOLS="xmlstarlet sed" # external binaries needed
PREFIX_SOURCE="Imported-" # prefix used to avoid name collision
PREFIX_BCK=`date +%F_%H-%M-%S` # prefix used for project name backup
SOURCE_PROJECT="$1"
DEST_PROJECT="$2"
TRACK_NAME="$3"
SLEEP_SECONDS="0.1" # pause after each operation (mostly for debugging). can be 0 or fractions (0.2)
basic_check(){
if [ "$DEST_PROJECT" == "" ]; then
echo "Copies one ardour track from one project to another INCLUDING layers."
echo "Tested with Ardour 5 and Mixbus 5."
echo "Use it at your own risk! always do backups before trying anything."
echo ""
echo "Usage: $0 <source project file> <destination project file> <track name>"
exit 1
fi
if [ ! -e "$SOURCE_PROJECT" ]; then
echo "ERROR: can't find [$SOURCE_PROJECT] file"
exit 1
fi
if [ ! -e "$DEST_PROJECT" ]; then
echo "ERROR: can't find [$DEST_PROJECT] file"
exit 1
fi
# simple binary checker
for t in $TOOLS ; do
type $t > /dev/null
if [ "$?" != "0" ]; then
echo "ERROR: missing tool $t"
echo "Please, install it and execute again."
exit 1
fi
done
}
list_tracks(){
SOURCE_CONTENT="$1"
LIST_TRACKS=`echo "$SOURCE_CONTENT" | xmlstarlet sel -t -v "/Session/Routes/Route/@name"`
echo "Tracks in [$SOURCE_PROJECT]: "
echo ""
echo "$LIST_TRACKS"
exit 1
}
newids(){
# simple function that returns xml with ids changed
DEST_ID_CONTENT="$1" # this is the last used id
CONTENT="$2" # xml we want to parse
NEW_CONTENT=""
IFS=$'\n'
for l in $CONTENT ; do
WITH_ID=`echo "$l" | grep "[[:space:]]id=\"[[:digit:]]*\""`
if [ "$WITH_ID" == "" ]; then
NEW="$l"
else
O_ID=`echo "$l" | sed "s/.*[[:space:]]id=\"//" | cut -d'"' -f1`
N_ID=$((DEST_ID_CONTENT + O_ID))
NEW=`echo "$l" | sed "s/[[:space:]]id=\"$O_ID\"/ id=\"$N_ID\"/"`
fi
NEW_CONTENT="$NEW_CONTENT
$NEW"
# echo "DEBUG: [$l] O_ID [$O_ID]" && echo "DEBUG: [$NEW] N_ID [$N_ID]" && read a
done
echo "$NEW_CONTENT"
}
convert_track(){
SOURCE_CONTENT="$1"
DEST_CONTENT="$2"
# working directories
DIR_SOURCE="$( cd "$( dirname "${SOURCE_PROJECT}" )" >/dev/null 2>&1 && pwd )"
DIR_DEST="$( cd "$( dirname "${DEST_PROJECT}" )" >/dev/null 2>&1 && pwd )"
SOURCE_SESSION_NAME=`echo "$SOURCE_CONTENT" | xmlstarlet sel -t -v "/Session/@name"`
SOURCE_SRATE=`echo "$SOURCE_CONTENT" | xmlstarlet sel -t -v "/Session/@sample-rate"`
DEST_SESSION_NAME=`echo "$DEST_CONTENT" | xmlstarlet sel -t -v "/Session/@name"`
DEST_SRATE=`echo "$DEST_CONTENT" | xmlstarlet sel -t -v "/Session/@sample-rate"`
# we don't support mixed sample rates
if [ "$SOURCE_SRATE" != "$DEST_SRATE" ]; then
echo "ERROR: different sample rates not supported."
echo "$SOURCE_SRATE : $SOURCE_PROJECT"
echo "$DEST_SRATE : $DEST_PROJECT"
exit 1
fi
DEST_ID_CONTENT=`echo "$DEST_CONTENT" | xmlstarlet sel -t -v "/Session/@id-counter"`
# track and route are synonyms in ardour
TRACK_INFO=`echo "$SOURCE_CONTENT" | xmlstarlet sel -t -c "/Session/Routes/Route[@name=\"$TRACK_NAME\"]"`
TRACK_ID=`echo "$TRACK_INFO" | xmlstarlet sel -t -v "//Route/@id"`
PLAYLIST_NAME=`echo "$TRACK_INFO" | xmlstarlet sel -t -v "//Route/Diskstream/@playlist"`
if [ "$PLAYLIST_NAME" == "" ]; then
echo "ERROR: can't find playlist for track [$TRACK_NAME]"
echo "Are you sure this track contains a playlist?"
echo ""
echo "Check your track name:"
list_tracks "$SOURCE_CONTENT"
exit 1
fi
PLAYLIST_INFO=`echo "$SOURCE_CONTENT" | xmlstarlet sel -t -c "/Session/Playlists/Playlist[@name=\"$PLAYLIST_NAME\"]"`
REGIONS=`echo "$PLAYLIST_INFO" | xmlstarlet sel -t -v "//Region/@name"`
if [ "$REGIONS" == "" ]; then
echo "ERROR: can't find any regions for track [$TRACK_NAME]"
echo "Are you sure this track contains regions?"
echo ""
echo "Check your track name:"
list_tracks "$SOURCE_CONTENT"
exit 1
fi
TRACK_NAME_NEW="${PREFIX_SOURCE}${TRACK_NAME}"
PLAYLIST_NAME_NEW="${PREFIX_SOURCE}${PLAYLIST_NAME}"
TRACK_INFO_NEW=`newids "$DEST_ID_CONTENT" "$TRACK_INFO" | sed "s/name=\"$TRACK_NAME\"/name=\"$TRACK_NAME_NEW\"/" | sed "s,name=\"$TRACK_NAME/,name=\"$TRACK_NAME_NEW/,g" | sed "s/playlist=\"${PLAYLIST_NAME}\"/playlist=\"${PLAYLIST_NAME_NEW}\"/"`
# simple check to see if we already modified destination project
echo "$DEST_CONTENT" | xmlstarlet sel -t -c "/Session/Routes/Route[@name=\"$TRACK_NAME_NEW\"]" > /dev/null
if [ "$?" == "0" ]; then
echo "ERROR: destination project already contains a track/region named [$TRACK_NAME_NEW]"
echo "be carefull running this script several times and check"
echo "PREFIX_SOURCE variable [$PREFIX_SOURCE] at the beggining of this script"
exit 1
fi
echo "preparing track/route [$TRACK_NAME]"
DEST_CONTENT_NEW=`echo "$DEST_CONTENT" | xmlstarlet ed -P -s "/Session/Routes" -t text -n "" -v "$TRACK_INFO_NEW " | xmlstarlet unesc`
sleep "$SLEEP_SECONDS"
echo "preparing playlist [$PLAYLIST_NAME]"
PLAYLIST_ORIG_TRACK_ID=`echo "$PLAYLIST_INFO" | xmlstarlet sel -t -v "//Playlist/@orig-track-id"`
PLAYLIST_ORIG_TRACK_ID_NEW=$((PLAYLIST_ORIG_TRACK_ID + DEST_ID_CONTENT))
PLAYLIST_ORIG_ELEMENT=`echo "$PLAYLIST_INFO" | grep '<Playlist id="'`
PLAYLIST_ORIG_ELEMENT_NEW=`newids "$DEST_ID_CONTENT" "${PLAYLIST_ORIG_ELEMENT} </Playlist>" | sed "s/orig-track-id=\"$PLAYLIST_ORIG_TRACK_ID\"/orig-track-id=\"$PLAYLIST_ORIG_TRACK_ID_NEW\"/" | sed "s/name=\"$PLAYLIST_NAME\"/name=\"$PLAYLIST_NAME_NEW\"/"`
DEST_CONTENT_NEW=`echo "$DEST_CONTENT_NEW" | xmlstarlet ed -P -s "/Session/Playlists" -t text -n "" -v "$PLAYLIST_ORIG_ELEMENT_NEW " | xmlstarlet unesc`
sleep "$SLEEP_SECONDS"
IFS=$'\n'
# we can have lot of regions for a single track
for r in $REGIONS ; do
echo " preparing region [$r]"
R_INFO=`echo "$PLAYLIST_INFO" | xmlstarlet sel -t -c "//Region[@name=\"$r\"]"`
R_NAME_NEW="${PREFIX_SOURCE}${r}"
R_SOURCE_ID=`echo "$PLAYLIST_INFO" | xmlstarlet sel -t -v "//Region[@name=\"$r\"]/@source-0"`
R_SOURCE_ID_NEW=$((R_SOURCE_ID + DEST_ID_CONTENT))
R_MASTER_SOURCE_ID=`echo "$PLAYLIST_INFO" | xmlstarlet sel -t -v "//Region[@name=\"$r\"]/@master-source-0"`
R_MASTER_SOURCE_ID_NEW=$((R_MASTER_SOURCE_ID + DEST_ID_CONTENT))
R_INFO_NEW=`newids "$DEST_ID_CONTENT" "$R_INFO" | sed "s/source-0=\"${R_SOURCE_ID}\"/source-0=\"${R_SOURCE_ID_NEW}\"/" | sed "s/master-source-0=\"${R_MASTER_SOURCE_ID}\"/master-source-0=\"${R_MASTER_SOURCE_ID_NEW}\"/" | sed "s/name=\"${r}\"/name=\"${R_NAME_NEW}\"/"`
DEST_CONTENT_NEW=`echo "$DEST_CONTENT_NEW" | xmlstarlet ed -P -s "/Session/Playlists/Playlist[@name=\"${PLAYLIST_NAME_NEW}\"]" -t text -n "" -v "$R_INFO_NEW " | xmlstarlet unesc`
sleep "$SLEEP_SECONDS"
S_INFO=`echo "$SOURCE_CONTENT" | xmlstarlet sel -t -c "/Session/Sources/Source[@id=\"$R_MASTER_SOURCE_ID\"]"`
S_WAV=`echo "$S_INFO" | xmlstarlet sel -t -v "/Source/@name"`
S_WAV_FULL="${DIR_SOURCE}/interchange/${SOURCE_SESSION_NAME}/audiofiles/${S_WAV}"
D_WAV="${PREFIX_SOURCE}${S_WAV}"
D_WAV_FULL="${DIR_DEST}/interchange/${DEST_SESSION_NAME}/audiofiles/${D_WAV}"
if [ -e "$D_WAV_FULL" ]; then
echo " INFO: destination file [$D_WAV_FULL] already exists (probably copied from previous region)"
else
echo " copying audio file [$S_WAV]"
echo -n " "
cp -v "$S_WAV_FULL" "$D_WAV_FULL"
fi
sleep "$SLEEP_SECONDS"
echo " preparing source [$S_WAV]"
S_INFO_NEW=`newids "$DEST_ID_CONTENT" "$S_INFO" | sed "s/name=\"$S_WAV\"/name=\"$D_WAV\"/"`
DEST_CONTENT_NEW=`echo "$DEST_CONTENT_NEW" | xmlstarlet ed -P -s "/Session/Sources" -t text -n "" -v "$S_INFO_NEW " | xmlstarlet unesc`
sleep "$SLEEP_SECONDS"
done
LAST_ID=`echo "$DEST_CONTENT_NEW" | xmlstarlet sel -t -v "//@id" | grep -o '[[:digit:]]*' | sort -n | tail -n1`
ID_COUNTER_NEW=$(($LAST_ID + 100)) # we add 100 to last used id just because
DEST_CONTENT_NEW=`echo "$DEST_CONTENT_NEW" | xmlstarlet edit -u "/Session/@id-counter" -v "$ID_COUNTER_NEW"`
BACKUP_PROJECT="${DIR_DEST}/${PREFIX_BCK}-`basename ${DEST_PROJECT}`"
echo "creating project backup [$BACKUP_PROJECT]"
cp -v "$DEST_PROJECT" "$BACKUP_PROJECT"
sleep "$SLEEP_SECONDS"
echo "modifying project"
# beautifying
echo "$DEST_CONTENT_NEW" | xmlstarlet fo > "$DEST_PROJECT"
}
###################################################################
basic_check
# we dump all project into a variable
SOURCE_CONTENT=`cat "$SOURCE_PROJECT"`
DEST_CONTENT=`cat "$DEST_PROJECT"`
if [ "$TRACK_NAME" == "" ]; then
list_tracks "$SOURCE_CONTENT"
fi
convert_track "$SOURCE_CONTENT" "$DEST_CONTENT"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment