0

I have this script that I use to convert all the wav-files in the directory to 16 bit with 44100 hz. However, it also converts files that already have these properties. How can I filter the files so that only the ones that need conversion are converted?

I am working on Win 10 with ubuntu.

#!/bin/sh
for i in *.WAV;
do
  name=`echo "$i" | cut -d'.' -f1`
  echo "$name"
  ffmpeg -i -f "$i" -acodec pcm_s16le -ar 44100 "${name}.wav";
done

Edit: Would it also be possible to have this loop over the files in subdirectories as well?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
Max J.
  • 153
  • 12
  • With `bash` (`sh` is usally not `bash`): `shopt -s globstar; for i in **/*.wav; do echo "$i"; done` – Cyrus Feb 01 '21 at 20:29
  • I'm new to writing shell scripts. I am running my script using sh myscript.sh. So maybe I'm using sh and not bash? Would that work there also? – Max J. Feb 01 '21 at 20:31
  • Your code works with `bash`, too. – Cyrus Feb 01 '21 at 20:32

1 Answers1

1

Use an if statement:

#!/bin/bash

mkdir output
shopt -s nocaseglob
for i in *.wav;
do
  if [ "$(ffprobe -v error -show_entries stream=sample_fmt -of csv=p=0 "$i")" != "s16" ] || [ "$(ffprobe -v error -show_entries stream=sample_rate -of csv=p=0 "$i")" != "44100" ]
    then
      echo "$i"
      ffmpeg -y -i "$i" -c:a pcm_s16le -ar 44100 "output/${i%.*}.wav";
  fi
done
  • ffprobe is used to get the sample format and sample rate. If it doesn't equal s16,44100 then it will re-encode.
  • Outputs are placed in a directory named output because ffmpeg can't edit files in-place (the input and output can't be the same file).
  • No need for echo and cut when you can use parameter expansion.
  • Would it also be possible to have this loop over the files in subdirectories as well? Use find, but that's worth asking as a new question because it is separate from the main question.
llogan
  • 121,796
  • 28
  • 232
  • 243
  • This seems to filter correctly some files that are not 16bit. However, I get the error "file or directory does not exist" and the output folder is empty. – Max J. Feb 01 '21 at 20:37
  • @MaxJ. I copied your original command and it has a typo I didn't notice. Fixed. See updated answer. – llogan Feb 01 '21 at 20:39
  • thank you for your help. The output folder now contains only one file when there are multiple files that should be converted. Also, are you sure that I can't overwrite the existing files? My code above seemed to just do that. – Max J. Feb 01 '21 at 20:41
  • @MaxJ. Yes, I am absolutely sure you shouldn't use the same name for input and output with ffmpeg. It "works" for you because your input is `file.WAV` and your output is `file.wav`, but it is safer and cleaner to output the new files to a new directory. You can then deal with the originals however you prefer. My answer worked for me. Show the output of `ffprobe -v error -show_entries stream=sample_fmt,sample_rate -of csv=p=0 input.WAV` for a file that does not work with. – llogan Feb 01 '21 at 20:51
  • For example, this "s32,44100" has not been converted. – Max J. Feb 01 '21 at 20:55
  • @MaxJ. Worked for me for a `s32,44100` input. Does the input file have the extension `.WAV` (notice the caps)? Try updated answer. Maybe it will be less fragile. – llogan Feb 01 '21 at 20:58
  • Unfortunately, it is still not working for me. All but one of my sample files have remained untouched and the output folder is empty (after the original of the only find has been replaced by the converted file by me) – Max J. Feb 01 '21 at 21:00
  • @MaxJ. Show output of `ffmpeg -i input-that-does-not-convert-although-it-should.WAV` – llogan Feb 01 '21 at 21:01
  • Input #0, wav, from 'RimshotVerb_01_SP.wav': Metadata: encoded_by : Digital Performer originator_reference: US 0026BB520A6018082727409432 date : 2014-12-2 creation_time : 18:08:2 time_reference : 26 umid : 0x060A2B3401010105010109201300000093899A584EA64F0383F6C56717F6CB68 coding_history : =PCM,F=44100,W=24,M=stereo,T=Digital Performer 7.24 comment : Duration: 00:00:02.03, bitrate: 2158 kb/s Stream #0:0: Audio: pcm_s24le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s32 (24 bit), 2116 kb/s – Max J. Feb 01 '21 at 21:04
  • @MaxJ. That is named `.wav`, not `.WAV`. The script, as in your original, is for `.WAV`. It's why I asked if the input is `.WAV` instead of `.wav`. Do you need to convert **both** `.WAV` and `.wav`? – llogan Feb 01 '21 at 21:06
  • Oh, I am sorry! I was not aware of that. Now I understand the comment you made earlier. Yes, I would need the script to identify all wave files, both wav and WAV – Max J. Feb 01 '21 at 21:07
  • 1
    @MaxJ. [Many](https://stackoverflow.com/questions/37448166/bash-script-looping-through-multiple-file-extensions-in-folder-ignoring-file-e) [ways](https://stackoverflow.com/questions/34382072/for-loop-in-bash-go-though-files-with-two-specific-extensions) to [deal](https://stackoverflow.com/questions/6223817/matching-files-with-various-extensions-using-for-loop) with that, but I just added `shopt -s nocaseglob` to ignore case. – llogan Feb 01 '21 at 21:18
  • I appreciate your help, thank you. It seems to work now! – Max J. Feb 01 '21 at 21:24