0

so I am very new to coding and recently wrote a little program that involved R and sox. It looked like this

file <- "test.mp3"

testSox = paste("sox ",file," -n spectrogram -o ",file,".png stats",sep='')
sox = system(testSox, intern = TRUE)
print(sox)

Now, instead of assigning the one file manually within the code, I would just like to have this code read through all the mp3s in a folder automatically. Is this possible? Any help would be greatly appreciated. Thanks!

EDIT: Actually, I should add that I tried list.files, but when it comes to running the system() command, I get

"Error in system(command, as.integer(flag), f, stdout, stderr) : character string expected as first argument"

Here's the list.files code I tried:

> temp = list.files(path = ".", pattern=".mp3")
> 
> file <- temp
> 
> firstSox = paste("sox ",file," -n spectrogram -o ",file,".png stats",sep='')
> sox = system(firstSox, intern = TRUE)
Error in system(command, as.integer(flag), f, stdout, stderr) : 
  character string expected as first argument
> print(sox)

I'm guessing this is not the correct route to go? Because I basically need to replace 'file' in the firstSox line with each mp3 that's in the temp array. So instead of running:

file <- "test.mp3"

...I would just like to have it re-assign each time for every file in the folder..., so it runs through as test.mp3, then 1.mp3, then 2.mp3, then 3.mp, etc.

I've scoured the net, and just feel like I've hit a brick wall. As stated in the comments, I've read up on loops, but for some reason I can't wrap my head around how to incorporate it into what I have written. I feel like I just need someone to show me at least the way, or maybe even write me an example so I can wrap my head around it. Would greatly appreciate help and any tips on what I'm doing wrong and could correct. Thanks.

  • This could be interesting for you to read https://stackoverflow.com/questions/9564489/opening-all-files-in-a-folder-and-applying-a-function – talat May 19 '14 at 19:48
  • Thanks, beginneR, I will check this page out ASAP. – TwinSpiritRadio May 19 '14 at 19:58
  • Have you ever encountered the programming concept of a "loop"? Because that might be useful here. – joran May 19 '14 at 20:02
  • Yes, but I have not incorporated it into any code of my own as of yet. Like I said, I'm brand new :-). I've read up on loops but I feel like an idiot because I don't know how to incorporate it into my code. This is actually just a portion of the code I wrote, and it all works for one file. I just need to wrap my head around how to get it to work with an entire folder of files except one. – TwinSpiritRadio May 19 '14 at 20:04

2 Answers2

0

Your firstSox variable will be a vector of commands to run (paste will generate a vector, one string for each element of file). So now you just need to run each command through system

One way to do this and capture the output is to use the lapply or sapply function:

sox <- lapply( firstSox, function(x) system(x, intern=TRUE) )

In this code lapply will run the function for each element of firstSox one at a time, the function just takes the current element (in x) and passes that to system. Then lapply gathers all the outputs together and combines them into a list that it puts into sox.

If the results of each run give the same shape of results (single number or vector of same length) then you can use sapply instead and it will simplify the return into a vector or matrix.

Greg Snow
  • 48,497
  • 6
  • 83
  • 110
  • Thanks, Greg, this works great for running the code up top, though I have a lot more code running on the file, so the for loop that Rohit supplied fits my overall situation more. Thanks for the tip, though! – TwinSpiritRadio May 20 '14 at 14:50
  • @TwinSpiritRadio, you can write a function to do all the work you want, then pass that function to `sapply`. In general if you only care about side effects then a `for` loop is fine, but when you want to store the output from each iteration then in the long run `lapply` and `sapply` will generally be better. – Greg Snow May 20 '14 at 15:09
  • Thanks, Greg. I'm going to apply it to my code in the way you just described and see what works best. Really appreciate the tips! – TwinSpiritRadio May 21 '14 at 14:54
0

Try the below code. I am using dir() instead of list.files, just because I find it easier. Remember there are many ways to do the same thing in R.

files <- dir(path = ".",pattern = ".mp3") #Get all the mp3 files

for(f in files) {     #Loop over the mp3 files one at a time

    firstSox = paste("sox ",f," -n spectrogram -o ",f,".png stats",sep='')
    sox = system(firstSox, intern = TRUE)
    print(sox)

}
Rohit Das
  • 1,962
  • 3
  • 14
  • 23
  • Rohit, this worked beautifully! I added the rest of my code in, and it all works, except one thing. I have stop() notices in the original code because I didn't want certain mp3s going through the entire program. Is there another command other than stop() that could just make the loop stop if it comes to a certain if statement then restart the loop with the next mp3? – TwinSpiritRadio May 19 '14 at 22:36
  • You are welcome. I am sure you must have figured it our by now, but look into `next` http://cran.r-project.org/doc/manuals/r-release/R-lang.html#Looping. I was tempted to provide an answer using one of the apply functions but considering that you are just getting started, a for loop is easier to visualize. But Definitely look into the solution provided by Greg Snow as that will allow you to write much more efficient code. – Rohit Das May 29 '14 at 21:32