Using Java's ProcessBuilder to run SoX
I am running SoX from java using a ProcessBuilder to trim a wav file. I am sure I should be able to run SoX, cause in the other JUnit tests, I manage to successfully run the following commands:
sox/sox --version
sox/sox --i -r test/test.wav
sox/sox --i -D test/test.wav
sox/sox --i -b test/test.wav
sox/sox --i -c test/test.wav
but when I try to trim a file as in the following:
sox/sox -V3 "/Users/username/workspace/Thesis Corpus Integrator/test/test.wav" -b 16 "/Users/username/workspace/Thesis Corpus Integrator/test/newWaveFile.wav" channels 1 trim 0:00:00.000 =0:00:30.000
it throws an IOException
with the error: error=2, No such file or directory
. I tried running the command on a terminal, and it worked without a problem. If it matters, I ran it through a JUnit test from eclipse, on a macbook.
Here's the code I used to build it in ProcessBuilder:
StringBuilder command = new StringBuilder(soxCommand) // soxCommand resolves to sox/sox, and is used in all the other tests without any problems
if (WavCutter.getMetadata(srcFile.getAbsolutePath(),
MetadataField.SAMPLE_RATE) != 16000) {
command.append(" -V3");
command.append(" -G");
command.append(" \"" + srcFile.getAbsolutePath() + '\"');
command.append(" -b 16");
command.append(" \"" + destFile.getAbsolutePath() + 开发者_StackOverflow社区'\"');
command.append(" channels 1");
command.append(" gain -h");
command.append(" rate 16000");
command.append(" trim");
command.append(" " + startTime.toString());
command.append(" " + '=' + endTime.toString());
Process soxProcess = new ProcessBuilder(command.toString())
.start();
I also tried the same thing, but using an ArrayList.
Found the answer myself, with lots of help from bramp's comment. The problem is easily resolved by first using a List of Strings, and then by separating the non-dash prefixed arguments that require spaces, like sox's effects
.
So from something like:
StringBuilder s = new StringBuilder("sox/sox"); // command itself is 'sox'
// everything after this is an argument
s.add(srcFile.getPath());
s.add("-b 16");
s.add(destFile.getPath());
s.add("rate 16000");
s.add("channels 1");
you get:
ArrayList<String> s = new ArrayList<String>();
s.add("sox/sox"); // command/process
// everything after this is an argument
s.add(srcFile.getPath());
s.add("-b 16");
s.add(destFile.getPath());
s.add("rate"); // notice how I had to split up the rate argument
s.add("16000");
s.add("channels"); // same applies here
s.add("1");
I think it may have something to do with how Java sends the arguments, or how SoX receives arguments. I was able to replicate my problem in the terminal by using the following command:
sox/sox test/test.wav -b 16 test/newtest.wav "rate 16000" "channels 1"
精彩评论