Batch measurements of .wav files with sox stats

2019-05-10 10:10发布

问题:

My question is similar to a previous question about "get-mean-amplitude-of-wav-from-sox":

Get Mean amplitude(only) of .wav from sox

I would like to be able to use the stats sox to do batch measurements of 1,000's of .wav files in a directory, and store the results in a data frame or some similar structure I can save as a csv text file.

For one sound file, the code would be:

./sox SampleSound.wav -n stat

Resulting in the following output:

Samples read:          72000000
Length (seconds):   3600.000000
Scaled by:         2147483647.0
Maximum amplitude:     0.778809
Minimum amplitude:    -1.000000
Midline amplitude:    -0.110596
Mean    norm:          0.062671
Mean    amplitude:    -0.008131
RMS     amplitude:     0.172914
Maximum delta:         1.778809
Minimum delta:         0.000000
Mean    delta:         0.014475
RMS     delta:         0.057648
Rough   frequency:         1061
Volume adjustment:        1.000

I would like to: - take batch measurements on 1,000's of sound files in a given directory, - capture the stats output in columns along with the sound file name that was measured, - and export for use as covariates in an analysis in R.

Thanks!

Matthew

回答1:

First you will need to perform a system call to sox, and capture its output. For example:

> spam = system("sox worf.wav -n stat 2>&1", intern = TRUE)
> spam
 [1] "Samples read:             34000" "Length (seconds):      3.083900"
 [3] "Scaled by:         2147483647.0" "Maximum amplitude:     0.999969"
 [5] "Minimum amplitude:    -0.938721" "Midline amplitude:     0.030624"
 [7] "Mean    norm:          0.190602" "Mean    amplitude:    -0.004302"
 [9] "RMS     amplitude:     0.244978" "Maximum delta:         1.340240"
[11] "Minimum delta:         0.000000" "Mean    delta:         0.051444"
[13] "RMS     delta:         0.099933" "Rough   frequency:          715"
[15] "Volume adjustment:        1.000"

Setting intern = TRUE returns the output of the command to a variable. Strangely, sox provides its output to stderr and not stdout, hence the need for 2>&1. The best way forward now is to wrap this in a function which also postprocesses the output of system:

get_wav_stats = function(wav_file) {
   rough_wav_stats = system(sprintf("sox %s -n stat 2>&1", wav_file), intern = TRUE)
   wav_stats = data.frame(do.call("rbind", strsplit(rough_wav_stats, split = ":")))
   names(wav_stats) = c("variable", "value")
   wav_stats = transform(wav_stats, value = as.numeric(as.character(value)))
   return(wav_stats)
}
> spam = get_wav_stats("worf.wav")
> spam
            variable         value
1       Samples read  3.400000e+04
2   Length (seconds)  3.083900e+00
3          Scaled by  2.147484e+09
4  Maximum amplitude  9.999690e-01
5  Minimum amplitude -9.387210e-01
6  Midline amplitude  3.062400e-02
7       Mean    norm  1.906020e-01
8  Mean    amplitude -4.302000e-03
9  RMS     amplitude  2.449780e-01
10     Maximum delta  1.340240e+00
11     Minimum delta  0.000000e+00
12     Mean    delta  5.144400e-02
13     RMS     delta  9.993300e-02
14 Rough   frequency  7.150000e+02
15 Volume adjustment  1.000000e+00

Next you can wrap this in an apply loop to get all the stats from a given directory:

# files_dir = list.files("path", full.names = TRUE)
# For this example I create a mock list:
files_dir = rep("worf.wav", 10)
stat_wavs = lapply(files_dir, get_wav_stats)
> str(stat_wavs)
    List of 10
     $ :'data.frame':   15 obs. of  2 variables:
      ..$ variable: Factor w/ 15 levels "Length (seconds)",..: 13 1 14 2 8 7 6 4 10 3 ...
      ..$ value   : num [1:15] 3.40e+04 3.08 2.15e+09 1.00 -9.39e-01 ...
     $ :'data.frame':   15 obs. of  2 variables:
      ..$ variable: Factor w/ 15 levels "Length (seconds)",..: 13 1 14 2 8 7 6 4 10 3 ...
      ..$ value   : num [1:15] 3.40e+04 3.08 2.15e+09 1.00 -9.39e-01 ...
<< snip >> 
     $ :'data.frame':   15 obs. of  2 variables:
      ..$ variable: Factor w/ 15 levels "Length (seconds)",..: 13 1 14 2 8 7 6 4 10 3 ...
      ..$ value   : num [1:15] 3.40e+04 3.08 2.15e+09 1.00 -9.39e-01 ...

To extract only the value column, which contains the stats you need:

stats4files = data.frame(do.call("rbind", lapply(stat_wavs, "[[", 2)))
names(stats4files) = stat_wavs[[1]][[1]]
rownames(stats4files) = files_dir # this doesn't work actually because I have repeated the same file multiple times :)

> stats4files
   Samples read Length (seconds)  Scaled by Maximum amplitude Minimum amplitude Midline amplitude
1         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
2         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
3         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
4         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
5         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
6         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
7         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
8         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
9         34000           3.0839 2147483647          0.999969         -0.938721          0.030624
10        34000           3.0839 2147483647          0.999969         -0.938721          0.030624
   Mean    norm Mean    amplitude RMS     amplitude Maximum delta Minimum delta Mean    delta
1      0.190602         -0.004302          0.244978       1.34024             0      0.051444
2      0.190602         -0.004302          0.244978       1.34024             0      0.051444
3      0.190602         -0.004302          0.244978       1.34024             0      0.051444
4      0.190602         -0.004302          0.244978       1.34024             0      0.051444
5      0.190602         -0.004302          0.244978       1.34024             0      0.051444
6      0.190602         -0.004302          0.244978       1.34024             0      0.051444
7      0.190602         -0.004302          0.244978       1.34024             0      0.051444
8      0.190602         -0.004302          0.244978       1.34024             0      0.051444
9      0.190602         -0.004302          0.244978       1.34024             0      0.051444
10     0.190602         -0.004302          0.244978       1.34024             0      0.051444
   RMS     delta Rough   frequency Volume adjustment
1       0.099933               715                 1
2       0.099933               715                 1
3       0.099933               715                 1
4       0.099933               715                 1
5       0.099933               715                 1
6       0.099933               715                 1
7       0.099933               715                 1
8       0.099933               715                 1
9       0.099933               715                 1
10      0.099933               715                 1


标签: r stat sox wav