Max number of operations? (Good WAVE converter program hangs with "long" input files)

A

Alex Ochoa

Hi, I wrote a Java program that takes a stereo .wav file and turns it
into a mono .wav file by appropriately deleting the information on one
channel (it ask you which one you want to keep). I don't think the
details of the sound editing matter. I'm not interested in simply
converting the .wav files from stereo to mono (I have retail programs
that do that already), but I want to solve my problem just to be a
better programmer.

The point is that I load an input stream and operate on it (loading
other streams in between to change the format of the info I'm reading)
and then write to the original file. I ran the program on a 52-byte
..wav file and IT WORKED, but on the other files (around 30 KB each) the
program hangs. Moreover, I compiled it placing
System.out.println("everything is fine here") and variations to see how
far down the code the program would stop, and I saw that with long
enough files (30 KB) the program would stop after exactly 513
iterations of a while loop in it. I only had one 1 KB file I could
work with and for this one it would finish all the necesary while
iterations (because they were less than 513), but the program would
later hang when trying to write the final stream to the .wav file.

I can put the code here if you want, it's not too long, but probably
long enough for a forum. What I was wondering is if anybody knows a
priori how to fix this (in case it is a known and general issue with
programs that do a lot of operations) or is this a problem specific to
my code, which might look good but actually isn't.
Your help will be greatly appreciated.
 
A

Alex Ochoa

Here's the code of my program:

import java.awt.*;
import java.io.*;
import javax.sound.sampled.*;
import javax.swing.*;

public class StereoToMono extends Object{

public StereoToMono (File wavFile, boolean isLeft){

try{
AudioInputStream stereoStream =
AudioSystem.getAudioInputStream (wavFile);
AudioFormat oldFmt = stereoStream.getFormat();
AudioFormat newFmt = new AudioFormat(oldFmt.getEncoding(),
oldFmt.getSampleRate(), oldFmt.getSampleSizeInBits(), 1,
oldFmt.getFrameSize(), oldFmt.getFrameRate(), oldFmt.isBigEndian());

if (oldFmt.getChannels() != 2) System.out.println ("Source
file is not in stereo");
else{
// create a new PipedOutputStream with the bytes I
want, then feed to PipedInputStream, then make that into an
AudioInputStream with
// the first constructor here
http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/sampled/AudioInputStream.html
// Finally, use AudioSystem to turn this
AudioInputStream into the file.
PipedInputStream monoStream = new PipedInputStream();
PipedOutputStream streamOut = new
PipedOutputStream(monoStream);

int frameSize = oldFmt.getFrameSize();
byte[] frameStereo = new byte[frameSize];
int reading = stereoStream.read(frameStereo);

if (isLeft == true){
while (reading != -1){
for (int j = 0; j <= frameSize/2-1; j++)
streamOut.write(frameStereo[j]);
reading = stereoStream.read(frameStereo);
}
}
else{
while (reading != -1){
for (int j = frameSize/2; j <= frameSize-1;
j++) streamOut.write(frameStereo[j]);
reading = stereoStream.read(frameStereo);
}
}

AudioInputStream audioMonoStream = new
AudioInputStream(monoStream, newFmt, stereoStream.getFrameLength());

try{
AudioSystem.write(audioMonoStream,
AudioFileFormat.Type.WAVE, wavFile);
System.out.println("Stereo to mono conversion is
complete");
}
catch (IOException e){
System.out.println ("Destination file not
opened:\n" + e.toString());
}
monoStream.close();
}
stereoStream.close();

}
catch (IOException e){
System.out.println ("Source file not opened:\n" +
e.toString());
}
catch (UnsupportedAudioFileException e){
System.out.println ("Source file is not a valid audio
file:\n" + e.toString());
}
}

public static void main (String[] args){
boolean isLeftChosen;
JFileChooser chooser = new JFileChooser();
if (chooser.showOpenDialog(null) ==
JFileChooser.APPROVE_OPTION){
int leftChosen = (JOptionPane.showConfirmDialog(chooser,
"Do you want to keep the left channel?\n(Choosing No will keep the
right channel)"));
if (leftChosen == JOptionPane.CANCEL_OPTION);
else{
if (leftChosen == JOptionPane.YES_OPTION) isLeftChosen
= true;
else isLeftChosen = false;
StereoToMono converter = new StereoToMono
(chooser.getSelectedFile(), isLeftChosen);
}
}
System.exit(0);
}

}
 
Y

Yu SONG

Alex said:
Hi, I wrote a Java program that takes a stereo .wav file and turns it
into a mono .wav file by appropriately deleting the information on one
channel (it ask you which one you want to keep). I don't think the
details of the sound editing matter. I'm not interested in simply
converting the .wav files from stereo to mono (I have retail programs
that do that already), but I want to solve my problem just to be a
better programmer.


I have not debugged your program, but I think something wrong with your
loop conditions.

I would suggest you to have a look at "tritonus" (especially
org.tritonus.share.sampled). My implementation can read/write "n" MB
audio file without any problem you mentioned.


--
Song

/* E-mail.c */
#define User "Yu.Song"
#define At '@'
#define Warwick "warwick.ac.uk"
int main() {
printf("Yu Song's E-mail: %s%c%s", User, At, Warwick);
return 0;}

Further Info. : http://www.dcs.warwick.ac.uk/~esubbn/
_______________________________________________________
 
P

pfalstad

you're writing to a PipedOutputStream, but you don't have anybody
reading from it until you're completely done. PipedOutputStream isn't
designed for this; it has a fairly small buffer size. It's intended to
be written in one thread and read in the other.

I think ByteArrayOutputStream can be used to write an arbitrarily large
amount of data. But do you really want to store the whole file in
memory? .wav files get really huge.

If I were doing this, I would create a new file immediately, read from
the old file and write to the new one, and then when I'm done, I would
rename the new file to the old one, overwriting it. That also solves
the problem of what happens if something bad happens when you're
writing the new file.. You don't want to destroy the old one until
you're done.
 
G

Gordon Beaton

The point is that I load an input stream and operate on it (loading
other streams in between to change the format of the info I'm reading)
and then write to the original file. I ran the program on a 52-byte
.wav file and IT WORKED, but on the other files (around 30 KB each) the
program hangs. Moreover, I compiled it placing
System.out.println("everything is fine here") and variations to see how
far down the code the program would stop, and I saw that with long
enough files (30 KB) the program would stop after exactly 513
iterations of a while loop in it. I only had one 1 KB file I could
work with and for this one it would finish all the necesary while
iterations (because they were less than 513), but the program would
later hang when trying to write the final stream to the .wav file.

There is no limit on the number of operations.

Your problem is that you are using a PipedStream to buffer all of the
intermediate data from the "read" part of your code, before you invoke
the "write" part.

PipedStreams are intended to be read and written (more or less) at the
same time, and the buffer space is therefore limited.

You have (at least) three options:

1. Start a separate thread for one of the two (read or write) parts,
and let the two operations proceed at the same time.

2. Replace the Piped streams. Write the intermediate data to a
suitably large byte array (possibly using a ByteArrayOutputStream).
Then create a ByteArrayInputStream using the same byte array, and
pass that instead of the PipedInputStream to the AudioInputStream.

3. Write a subclass of FilterInputStream and pass that to the
AudioInputStream. Your class can read and filter the data as it is
requested by the AudioInputStream, so you don't need to buffer any
significant amount of data and you don't need to use separate
threads for reading and writing.

/gordon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top