9

for a single .mp3, I can convert it to wav using

sox ./input/filename.mp3 ./output/filename.wav

I tried:

#!/bin/bash
for i in  $(ls *mp3)
do
    sox -t wav $i waves/$(basename $i)
done

But it throws the following error:

sox FAIL formats: can't open input file `filename.mp3': WAVE: RIFF header not found

How would I run this sox conversion over all mp3 files in the input folder and save the generated wav's to the output folder?

PS : I don't know why it shows the file enclosed between a back quote ( ` ) and an apostrophe '

`filename.mp3'

I played all the mp3's and they work perfectly file.

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
kRazzy R
  • 259
  • 1
  • 2
  • 13
  • 1
    Regarding the back quote (`\``) and apostrophe (`'`), see [this](https://unix.stackexchange.com/q/85303/80216 "Where does this convention for quotation marks (``…'') come from?"), [this](https://unix.stackexchange.com/q/155674/80216 "Why some strings are quoted with double back ticks and double single quotes in man pages?"), [this](https://unix.stackexchange.com/q/73989/80216 "Why do Unix man pages use double back ticks in place of double quotes?"), [this](https://unix.stackexchange.com/q/204868/80216 "Man page quotation characters"),  … (Cont’d) – G-Man Says 'Reinstate Monica' Feb 21 '18 at 03:23
  • 1
    (Cont’d) … [this](https://unix.stackexchange.com/q/269462/80216 "Manual pages uses the quotation: \`' (quoting string inside grave accent and apostrophe)"), and [this](https://unix.stackexchange.com/q/87644/80216 "Where do back tick and single quote come from when denoting commands, e.g., `prog'?"). What none of those threads mentions is that some error messages also use that convention. – G-Man Says 'Reinstate Monica' Feb 21 '18 at 03:23

3 Answers3

11

It sounds like you're running into a problem with spaces in the filename. If you have a file named "My Greatest Hits.mp3", your command will try to convert the three different files named "My", "Greatest", and "Hits.mp3". Instead of using the "$()" syntax, just use "*.mp3" in the for line, and make sure to quote the file names in the sox command.

In addition, the basename command doesn't remove the file extension, just any folder names. So this command will create a bunch of WAV files with a ".mp3" extension. Adding "-s .mp3" to the command tells basename to strip the extension, and then put ".wav" on the end adds the correct extension.

Put it all together, and you have this:

for i in *.mp3
do
    sox "$i" "waves/$(basename -s .mp3 "$i").wav"
done
HiddenWindshield
  • 597
  • 4
  • 11
  • 1
    You should quote the `$i` *inside* the `\`…\``, too.  And, just for clarity, you might want to change `\`…\`` to ``$(…)`` — see [this](//unix.stackexchange.com/q/5778), [this](//unix.stackexchange.com/q/147838), and [this](//unix.stackexchange.com/q/104119). – G-Man Says 'Reinstate Monica' Feb 20 '18 at 23:33
  • 1
    If you'll notice, I **did** put $i inside the backticks. But I get what you mean by using $() instead. I'll edit my answer. – HiddenWindshield Feb 21 '18 at 00:51
  • 1
    Yes, I know that you *put* the `$i` inside the `\`…\`` (and thanks for changing that to `$(…)`, by the way).  What I said was that you should ***quote*** the `$i` inside the command substitution, like this: `"waves/$(basename -s .mp3 "$i").wav"`.  Try your version with `i="foo bar.mp3"`. – G-Man Says 'Reinstate Monica' Feb 21 '18 at 02:30
  • 1
    Ok, I understand what you're saying now. And you're right. I'll edit again. – HiddenWindshield Feb 21 '18 at 02:55
  • 1
    I would up vote you, except I already did.    :-)    ⁠ – G-Man Says 'Reinstate Monica' Feb 21 '18 at 03:03
  • just the way you are saving to waves folder, in case I want sox to read from an input directory from a particular folder , how would I do that ex ./input/media? – kRazzy R Feb 21 '18 at 03:36
  • You can put a path in the first line. For instance: "for i in ./input/media/*.mp3". – HiddenWindshield Mar 02 '18 at 20:30
  • Hello. What If I want to convert all files to wav? should I simply replace *.mp3 with `*.*` ? and what about the `.mp3` line inside line 3`sox ". . . .... "? Thank you. – kRazzy R Jun 11 '18 at 13:33
2

First, don't use ls like that, it doesn't actually do anything, since it's the shell that actually generates the filenames in the glob *mp3 anyway. Plus it breaks if any of your files have whitespace in their names.

As for the error, I think sox here tries to interpret the MP3 file as a wav, since you gave the -t wav flag. I think you could do without it, as you did in the single-file case. You just need to change the extension on the output file name too. basename can remove the suffix too, if you tell it what to remove.

#!/bin/bash
for i in *.mp3
do
    sox "$i" "waves/$(basename "$i" .mp3).wav"
done

(The backtick-apostrophe is an ancient custom of `quoting' the file name. I the backtick is supposed to look like the left-side quotation mark, the one that looks like a rotated comma (see examples on Wikipedia). But technically, it's wrong, and it looks awful in most current fonts.)

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
  • thanks for the answer. in case I want it to take an input directory from a particular folder , how would I do that ex `./input/media` – kRazzy R Feb 20 '18 at 23:42
  • 1
    @kRazzyR, just put the directory in the pattern: `for i in /some/path/*.mp3 ...` and fix the destination directory as required. `basename` removes the directory from the file name anyway, so that part's not a problem. – ilkkachu Feb 21 '18 at 08:51
0

Clearly, sox is saying it can't process the mp3 format file. I would be very interested in getting the output on your system for:

sox ./input/filename.mp3 ./output/filename.wav

Because it seems your sox cannot process mp3 in general. Yes, sox can be recompiled to handle mp3, but your error message indicates it is reading the file, but it's expecting a wav: WAVE: RIFF header not found.

The other comments about issues with spaces still apply in general, but the file filename.mp3 doesn't have spaces; it's an mp3.

PePa
  • 81
  • 1
  • 2