Created
March 18, 2020 22:17
-
-
Save muzzol/5f5d27c155d6113069445c7d3b6910f2 to your computer and use it in GitHub Desktop.
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
#!/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