|
@@ -0,0 +1,154 @@
|
|
|
+#!/bin/bash
|
|
|
+
|
|
|
+# Best settings like in mixcloud.com
|
|
|
+SETT_PART_COUNT=5
|
|
|
+SETT_PART_DURATION=5
|
|
|
+SETT_CROSSFADE=1
|
|
|
+SETT_FORMAT="mp3"
|
|
|
+
|
|
|
+# Get system utilites with full path
|
|
|
+UTIL_FFMPEG=`whereis ffmpeg | awk {'print $2'}`
|
|
|
+UTIL_CUT=`whereis cut | awk {'print $2'}`
|
|
|
+UTIL_ECHO=`whereis echo | awk {'print $2'}`
|
|
|
+UTIL_EXPR=`whereis expr | awk {'print $2'}`
|
|
|
+UTIL_RM=`whereis rm | awk {'print $2'}`
|
|
|
+UTIL_MV=`whereis mv | awk {'print $2'}`
|
|
|
+
|
|
|
+# Get current process ID
|
|
|
+UNIQ_STR="$$"
|
|
|
+
|
|
|
+# Input and output files
|
|
|
+INPUT_FILE="$1"
|
|
|
+OUTPUT_FILE="$2"
|
|
|
+
|
|
|
+# Temp dir, RAM disk is the best place
|
|
|
+TEMP_DIR="$3"
|
|
|
+
|
|
|
+# Set default temp dir if not set
|
|
|
+if [ "$TEMP_DIR" != "" ]; then
|
|
|
+ TEMP_DIR=${3%/}
|
|
|
+
|
|
|
+else
|
|
|
+ TEMP_DIR="/tmp"
|
|
|
+fi
|
|
|
+
|
|
|
+# Check if temp dir is exists
|
|
|
+if [ ! -d "$TEMP_DIR" ]; then
|
|
|
+ $UTIL_ECHO " ✗ Temporary directory ($TEMP_DIR) is not available"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Checks, if all system utilites are present
|
|
|
+if [ "$UTIL_FFMPEG" = "" ] || [ "$UTIL_CUT" = "" ] || [ "$UTIL_ECHO" = "" ] || [ "$UTIL_EXPR" = "" ] || [ "$UTIL_RM" = "" ] || [ "$UTIL_MV" = "" ]; then
|
|
|
+ $UTIL_ECHO " ✗ Some utility, what needed for work is not present in system"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Check if input file is set
|
|
|
+if [ "$INPUT_FILE" = "" ]; then
|
|
|
+ $UTIL_ECHO " ✗ Please set source file name"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Check if output file is set
|
|
|
+if [ "$OUTPUT_FILE" = "" ]; then
|
|
|
+ $UTIL_ECHO " ✗ Please set output file name"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Check if input file is exist
|
|
|
+if [ ! -f "$INPUT_FILE" ]; then
|
|
|
+ $UTIL_ECHO " ✗ Source file is not exist"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Perfomance check
|
|
|
+PROC_START=`date +%s`
|
|
|
+
|
|
|
+# Extract file length
|
|
|
+INPUT_LEN_STR=`$UTIL_FFMPEG -i $INPUT_FILE 2>&1 | awk '/Duration/ { print substr($2,0,length($2)-1) }' | $UTIL_CUT -d. -f1`
|
|
|
+if [ "$INPUT_LEN_STR" = "" ]; then
|
|
|
+ $UTIL_ECHO " ✗ Can't get file duration"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Convert length to integer
|
|
|
+INPUT_LEN_HOURS=`$UTIL_ECHO $INPUT_LEN_STR | $UTIL_CUT -d: -f1`
|
|
|
+INPUT_LEN_MINUTES=`$UTIL_ECHO $INPUT_LEN_STR | $UTIL_CUT -d: -f2`
|
|
|
+INPUT_LEN_SECONDS=`$UTIL_ECHO $INPUT_LEN_STR | $UTIL_CUT -d: -f3`
|
|
|
+INPUT_LEN_HOURS=`$UTIL_EXPR $INPUT_LEN_HOURS + 0`
|
|
|
+INPUT_LEN_MINUTES=`$UTIL_EXPR $INPUT_LEN_MINUTES + 0`
|
|
|
+INPUT_LEN_SECONDS=`$UTIL_EXPR $INPUT_LEN_SECONDS + 0`
|
|
|
+
|
|
|
+# Convert length to seconds
|
|
|
+INPUT_LENGTH=$((INPUT_LEN_HOURS * 60 * 60))
|
|
|
+INPUT_LENGTH=$((INPUT_LENGTH + INPUT_LEN_MINUTES * 60))
|
|
|
+INPUT_LENGTH=$((INPUT_LENGTH + INPUT_LEN_SECONDS))
|
|
|
+
|
|
|
+# Some temp vars
|
|
|
+TMP_STEP=$((INPUT_LENGTH / SETT_PART_COUNT))
|
|
|
+
|
|
|
+# Check for minimum length
|
|
|
+INPUT_LEN_MINIMUM=$((SETT_PART_COUNT * SETT_PART_DURATION + SETT_CROSSFADE * SETT_PART_DURATION))
|
|
|
+if (( INPUT_LENGTH < INPUT_LEN_MINIMUM )); then
|
|
|
+ $UTIL_ECHO " ✗ File length is too small"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# Some temp vars
|
|
|
+TMP_LEN=$((SETT_PART_DURATION + SETT_CROSSFADE))
|
|
|
+TMP_CMD_FILES=""
|
|
|
+TMP_CMD_FILTERS=""
|
|
|
+TMP_CMD_CROSSFADE=""
|
|
|
+TMP_CMD_LAST=""
|
|
|
+
|
|
|
+# Split file to parts and generate filters
|
|
|
+for ((i = 1; i <= SETT_PART_COUNT; i++)); do
|
|
|
+ TMP_S=$((i * TMP_STEP - TMP_STEP))
|
|
|
+ TMP_E=$((i * TMP_STEP - TMP_STEP))
|
|
|
+ TMP_E=$((TMP_E + SETT_PART_DURATION + SETT_CROSSFADE))
|
|
|
+ TMP_CMD="$UTIL_FFMPEG -i $INPUT_FILE -ss $TMP_S -to $TMP_E -c copy -y $TEMP_DIR/$UNIQ_STR_$i.$SETT_FORMAT"
|
|
|
+ TMP_OUTPUT=`$TMP_CMD 2>&1`
|
|
|
+ k=$((i - 1))
|
|
|
+ TMP_CMD_FILES="$TMP_CMD_FILES -i $TEMP_DIR/$UNIQ_STR_$i.$SETT_FORMAT"
|
|
|
+ TMP_CMD_FILTERS="$TMP_CMD_FILTERS[$k]atrim=0:$TMP_LEN[a$i];"
|
|
|
+ if (( i >= 2 )); then
|
|
|
+ if (( i == 2 )); then
|
|
|
+ TMP_CMD_CROSSFADE="$TMP_CMD_CROSSFADE[a$k][a$i]acrossfade=d=$SETT_CROSSFADE[r$k];"
|
|
|
+ TMP_CMD_LAST="r$k"
|
|
|
+ else
|
|
|
+ r=$((k - 1))
|
|
|
+ if (( i >= SETT_PART_COUNT )); then
|
|
|
+ TMP_CMD_CROSSFADE="$TMP_CMD_CROSSFADE[r$r][a$i]acrossfade=d=$SETT_CROSSFADE[r$k]"
|
|
|
+ else
|
|
|
+ TMP_CMD_CROSSFADE="$TMP_CMD_CROSSFADE[r$r][a$i]acrossfade=d=$SETT_CROSSFADE[r$k];"
|
|
|
+ fi
|
|
|
+ TMP_CMD_LAST="r$k"
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+done
|
|
|
+$UTIL_ECHO " ✓ Particles created ($SETT_PART_COUNT)"
|
|
|
+
|
|
|
+# Connect all parts with crosfade effect
|
|
|
+TMP_OUTPUT=`$UTIL_FFMPEG $TMP_CMD_FILES -filter_complex "$TMP_CMD_FILTERS$TMP_CMD_CROSSFADE" -map [$TMP_CMD_LAST] -y $OUTPUT_FILE 2>&1`
|
|
|
+$UTIL_ECHO " ✓ Particles connected together"
|
|
|
+
|
|
|
+# Make fade-in at start and fade-out at the end
|
|
|
+TMP_OUTPUT=`$UTIL_FFMPEG -i $OUTPUT_FILE -af 'afade=t=in:ss=0:d=0.8,afade=t=out:st=25:d=0.8' -y tmp.$OUTPUT_FILE 2>&1`
|
|
|
+$UTIL_RM $OUTPUT_FILE
|
|
|
+$UTIL_MV tmp.$OUTPUT_FILE $OUTPUT_FILE
|
|
|
+$UTIL_ECHO " ✓ FadeIn/FadeOut created"
|
|
|
+
|
|
|
+# Delete temp parts
|
|
|
+for ((i = 1; i <= SETT_PART_COUNT; i++)); do
|
|
|
+ $UTIL_RM $TEMP_DIR/$UNIQ_STR_$i.$SETT_FORMAT
|
|
|
+done
|
|
|
+
|
|
|
+# Perfomance check
|
|
|
+PROC_END=`date +%s`
|
|
|
+PROC_ALL=$((PROC_END - PROC_START))
|
|
|
+$UTIL_ECHO " ✓ Particle files deleted"
|
|
|
+
|
|
|
+# Done
|
|
|
+$UTIL_ECHO " ✓ Done in $PROC_ALL second(s)"
|
|
|
+exit 0
|