#!/bin/bash

# print audio ascii waveform to terminal (and play)

# examples: 
# print waveform and play:    printWaveform *.flac, 
# just print waveform:        printWaveform np *.flac

# needs: ffmpeg, caca-utils, imagemagick, mpv (for playback), tput, toilet
# brontosaurusrex 2018

# to play or not to play
if [ "$1" == "np" ] || [ "$1" == "noplay" ]; then
    play="false"
    shift
else
    play="true"
fi

# tmp dir http://mywiki.wooledge.org/BashFAQ/062
tmpdir="/tmp/$RANDOM-$$"
trap '[ -n "$tmpdir" ] && rm -fr "$tmpdir"' EXIT
mkdir -m 700 "$tmpdir" || { echo '!! unable to create a tmpdir' >&2; tmpdir=; exit 1; }

# config
tmpimg="$tmpdir/wave.png"    # tmp image storage
th=$(( 24 * 1 ))             # height in terminal chars, should be even number
hires="400"                  # how many term columns (width) are considered as hires

# center text 
centertext(){
    columns=$(tput cols) 
    string="$1" 
    printf "%*s\n" $(((${#string}+columns)/2)) "$string"
}

# main
while [ $# -gt 0 ]; do

    # benchmark start
    #START=$(date +%s.%N)

    # get pixels width from terminal char width x 2 (and use something for height)
    tw="$(tput cols)"   # width in term columns
    w=$(( tw * 2 ))     # width of tmp image in pixels
    h=$(( tw * 1 ))     # height of tmp image in pixels
    
    ffmpeg -i "$1" -filter_complex \
    "aformat=channel_layouts=stereo,showwavespic=split_channels=0:scale=lin:s=${w}x${h}:colors=#000000" -y "$tmpimg" &>/dev/null && \
            
    # draw two black pixels on left/right as protection for following -trim operation
    # (https://www.imagemagick.org/discourse-server/viewtopic.php?t=16656)
    # whalf=$(( w / 2 ))
    hhalf=$(( h / 2 )) && \
    mogrify -draw "fill black color 0,${hhalf} point" "$tmpimg" && \
    wtmp=$(( w - 1 )) # for some reason we need to remove 1 pixel
    mogrify -draw "fill black color ${wtmp},${hhalf} point" "$tmpimg" && \

    # trim (behaves as audio display normalizer)
    mogrify -trim "$tmpimg" && \
    # ^ was bad idea, this would trim left and right as well, those desync. But now we have two black pixels as protection ^. (Triming however will not be identical on top and bottom.)
    
    # shave some more
    mogrify -gravity Center -shave 0x5% "$tmpimg" && \
    
    # if hires then increase the height of waveform display
    if (( tw > hires )); then
        thfinal=$(( th * 2 ))
    else 
        thfinal="$th"
    fi
    
    # print waveform, enable head for half of the waveform
    img2txt -g 2 -b 2 -y 15 -W "$tw" -H "$thfinal" -f utf8 -d none "$tmpimg" | head -$(( th / 2))
    
    # benchmark end
    #END=$(date +%s.%N) && DIFF=$(echo "$END - $START" | bc) && echo "done in $DIFF seconds"

    # echo file
    if (( tw > hires )); then
        toilet "$1" -w "$tw" # enable for very hi-res display
    else
        centertext "$1"
        #echo "$1"
    fi

    # maybe play
    "$play" && \
    mpv --no-resume-playback -af=lavfi=[loudnorm=LRA=10:I=-17] \
    --msg-level=ao/alsa=error:cplayer=error:statusline=status:display-tags=error:ffmpeg/demuxer=error \
    --no-video "$1" --term-osd-bar --term-osd-bar-chars="··█ ·"
    
    
shift
done