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

Discussion in 'Java' started by Alex Ochoa, Jan 18, 2005.

  1. Alex Ochoa

    Alex Ochoa Guest

    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.
    Alex Ochoa, Jan 18, 2005
    #1
    1. Advertising

  2. Alex Ochoa

    Alex Ochoa Guest

    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);
    }

    }
    Alex Ochoa, Jan 18, 2005
    #2
    1. Advertising

  3. Alex Ochoa

    Yu SONG Guest

    Re: Max number of operations? (Good WAVE converter program hangswith "long" input files)

    Alex Ochoa wrote:
    > 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/
    _______________________________________________________
    Yu SONG, Jan 18, 2005
    #3
  4. Alex Ochoa

    Guest

    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.
    , Jan 18, 2005
    #4
  5. On 18 Jan 2005 04:09:42 -0800, Alex Ochoa wrote:
    > 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

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
    Gordon Beaton, Jan 18, 2005
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. red floyd
    Replies:
    5
    Views:
    1,044
    Nathan Wijnia
    Jun 21, 2007
  2. Karthik
    Replies:
    0
    Views:
    798
    Karthik
    Sep 5, 2007
  3. Summercool
    Replies:
    9
    Views:
    878
    dorayme
    Oct 23, 2007
  4. rara10
    Replies:
    0
    Views:
    942
    rara10
    Jan 30, 2009
  5. Shiva
    Replies:
    2
    Views:
    1,638
    Chris Maryan
    Feb 2, 2009
Loading...

Share This Page