Jump to position in audio file using Java Sound API - java

I'm using a AudioInputStream to feed bytes to a SourceDataLine to play a PCM file. I want to give the user the ability to move a slider to jump to some point in the file.
Issues I'm having:
markSupported() returns false on my AudioInputStream. So I
cannot use my initial approach to call reset() then skip() (which
I already thought was kind of ugly...)
I would really prefer not to tear down the InputStream and create a new one just to jump to a position prior to my current mark.
SourceLineData.getLongFramePosition() does not seem to be very reliable... I know it has a buffer, but even if account for the bytes left in the buffer, i do not understand the behavior
I have considered using a Memory-Mapped File to feed bytes to the line that way I can jump wherever I want, but I don't want to add complexity to the function if I don't have to. Is there a good way to do this that I'm missing? also can anyone explain what the frame number returned by getLongFramePosition() actually means? is it number of frames passed through speakers (does not appear to be)?

Did the BigClip work for you?
If not, here's something that could work. Warning, it is a little convoluted.
http://hexara.com/VSL/VSL2.htm
With this Applet, you can load a wav -- I've loaded wavs longer than 5 minutes and it has worked fine, but audio data does take up a lot of RAM.
Once the WAV is loaded, you can mouse to any point and playback via holding the mouse down and dragging. Obviously, that's not exactly what YOU want to do, since you want to play back from a point, and not worry about dragging or dragging speed. But the path I take to get the data in a playable state should still work for you.
If you have a working AudioInputStream and AudioFileFormat, you can set up an internal array and read the data directly into it. The audio file format gives you the encoding and the length in frames which you can use to calculate your array dimension.
Then, make a TargetDataLine that gets its audio data from the array you made. A TDL has to have a variable that marks where the next read will start. You can use your JSlider to change the contents of that variable to point to whatever frame you want.
If you don't have a working AudioInputStream, there are ways to get one...but it is more convoluted, involving ByteArrayOutput & Input Stream objects. Probably no need to go there. (I use them to read client data in the above Applet.)
As to your question about the current Frame location, the key problem is that the JVM processes audio data in chunks, and it tends to run ahead of what is heard in bursts. I banged my head against this problem for a long while, then came up with this:
http://www.java-gaming.org/index.php/topic,24605.0.html

The cleanest way I could come up with was to use a FileChannel to read the bytes into the SourceDataLine this way based on the user moving a slider I could determine the byte position in the file (making sure to adjust or round it to line up with a frame) and then set that position in the FileChannel and then continue playback. I flushed the line when this happened to keep from playing remaining bytes.

Related

Java using mp3, ogg and wav files with javax.sound.sampled.Clip (or getting the bitrate of the sound file)

My goal is to play multiple mp3, ogg, or wav music files at the same time in order to create adaptative music in a video game.
Instead of using the Clip class from the java sound API, I managed to create a class named Track which, thanks to mp3spi, and vorbisspi, can read mp3, ogg, and wav files by writing the audio data in a SourceDataLine.
I found this solution thanks to this post:
https://stackoverflow.com/a/17737483/13326269
Everything works fine with a thread into the stream function so I can create many Track objects to play multiple sounds at the same time. But I want to create a function like void setMicrosecondPosition(long microseconds); from the Clip class.
I tried many things and I found a way to do it :
in = getAudioInputStream(new File(file).getAbsoluteFile());
int seconds = 410;
int bitrate = 320; //in kbit/s
in.skip(seconds*bitrate*1000/8); // divided by 8 because the skip method use bytes.
But I need the bitrate of the file. So, how can I get the bitrate of any sound file? Or better, how can I use mp3 and ogg files with the javax.sound.sampled.Clip class.
I believe if you really do have working AudioInputStreams, the skip function references a number of bytes which should be a fixed amount per frame, determined by the audio format. For example stereo, 16-bit would be 4 bytes per frame, regardless. So you should be able to use the frame rate (e.g., 44100 frames/sec) to skip to the desired start point.
Another dodge would be to read but ignore the bytes incoming from the AudioInputStream in a method similar to the stream method in your link solution's example. You this can pretty quickly get you to the desired point, since you won't be blocked by the sdl write(). But if that works, the skip method should also work and would be preferable.

Reading (Potentially Large) Text Files without Reading to Memory in Java?

I'm working on a program to read in various text files and display them without having to read the entire file to memory.
A brief description of what I want the program to do:
Assume a file of say, 3000 lines.
Display 50 lines at a time
Allow user to scroll down to read further lines, however these lines are loaded in real-time from reader. lines further up that are now not displayed are not stored in memory.
Allow user to scroll up to read previous lines, however these lines are also loaded in real-time or at least in a similar manner as reading forward.
What I want is to tailor the program to be memory-efficient and handle large files without fizzling out. I was looking at BufferedReaders but there doesn't seem to be a dependable way of backwards traversal. I was originally looking at how mark() and reset() functioned but I couldn't find a class that could set multiple marks.
I'm wondering if anybody could help me out and give me a few pointers towards some useful classes I could use. I was starting to poke around NIO classes like ByteBuffers and CharBuffers but I'm rather lost as to how I could implement them towards what I want to accomplish.
Thanks!
Back in the olden days of computing (1980's), this is exactly how we had to process large files for display.
Basically, you need an input method that can read specified lines from a file. Something like
List<String> block = readFile(file, 51, 100);
which would read the 51st through 100th lines of the file.
I see two ways you could accomplish this.
Read from the beginning of the file each time, skipping the first nth records and retrieving 50 (or some other number) strings.
Read the file once, and break it up into x files of length 50 (or some other number). Read your temporary files to get blocks of strings.
Either way, you would keep 3 blocks in memory; the current block, the previous block and the next block.
As you move forward through the strings, the current block becomes the previous block, the next block becomes the current block, and you read a new next block.
As you move backward through the strings, the current block becomes the next block, the previous block becomes the current block, and you read a new previous block.
Random access to a file is available in Java. So you can surf through the bytes of a file pretty easily, and have a region of file mapped to memory at a time.
You can have a Deque<E> implementation for readable region. Then you can add/remove data chunks or "lines" from both ends, to represent a visual data scroll.
If the "lines" are defined the characters that fit the width of the visual display (such as a console window), then you might just keep loading next x bytes/characters, and removing previous x bytes/characters.
Otherwise, you may need to scan ahead, and build some metadata about the file, noting down the positions of lines, or other interesting structures within the file. Then you can use this metadata to quickly navigate the file.

Java File Marker API

I have a need for my application to be able to read large (very large, 100GB+) text files and process the content in these files potentially at different times. For instance, it might run for an hour and finish processing a few GBs, and then I shut it down and come back to it a few days later to resume processsing the same file.
To do this I will need to read the files into memory-friendly chunks; each chunk/page/block/etc will be read in, one at a time, processed, before then next chunk is read into memory.
I need the program to be able to mark where it is inside the input file, so if it shuts down, or if I need to "replay" the last chunk being processed, I can jump right to the point in the file where I am and continue processing. Specifically, I need to be able to do the following things:
When the processing begings, scan a file for a "MARKER" (some marker that indicates where we left off processing the last time)
If the MARKER exists, jump to it and begin processing from that point
Else, if the MARKER doesn't exist, then place a MARKER after the first chunk (for now, let's say that a "chunk" is just a line-of-text, as BufferedReader#readLine() would read in) and begin processing the first chunk/line
For each chunk/line processed, move the MARKER after the next chunk (thus, advancing the MARKER further down the file)
If we reach a point where there are no more chunks/lines after the current MARKER, we've finished processing the file
I tried coding this up myself and notice that BufferedReader has some interesting methods on it that sounds like they're suited for this very purpose: mark(), reset(), etc. But the Javadocs on them are kind of vague and I'm not sure that these "File Marker" methods will accomplish all the things I need to be able to do. I'm also completely open to a 3rd party JAR/lib that has this capability built into it, but Google didn't turn anything up.
Any ideas here?
Forget about markers. You cannot "insert" text without rewritting the whole file.
Use a RandomAccessFile and store the current position you are reading. When you need to open again the file, just use seek to find the position.
A Reader's "mark" is not persistent; it solely forms part of the state of the Reader itself.
I suggest that you not store the state information in the text file itself; instead, have a file alongside which stores the byte offset of the most recently processed chunk. That'll eliminate the obvious problems involving overwriting data in the original text file.
The marker of the buffered reader is not persisted after different runs of your application. I would neither change the content of that huge file to mark a position, since this can lead to significant IO and/or filesystem fragmentation, depending on your OS.
I would use a properties file to store the configuration of the program externally. Have a look at the documentation, the API is straight forward:
http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html

Creating a rolling window on a byte stream in java

I have a byte stream that comes into my app (its actually reading from a file, but this could change).
The data is of the form <tag><value>. Im looking for a specific tag, and wish to discard all others.
My thinking was to have a 'window' of length (taglength + valuelength), and push data into it, with old data dropping off the end. Then as soon as the first (taglength) bytes match the tag im interested in I can just get the whole window and process it.
I dont think there's anything in the SDK that matches my needs, but would love to be proven wrong. Any ideas?
EDIT: To clarify,the data isnt xml - ive just used angled brackets to show the delimitation. The data is actually a binary stream.
Using a byte stream to parse an XML file is calling for trouble.
I would strongly suggest to use a streaming XML parser (e.g. a SAXParser) that does not buffer the whole document in memory (or create a complete DOM representation). The SAX parser that is built into the JDK is quite efficient in terms of memory usage.
The closest thing in the JDK is to use ByteBuffer.compact() which allows you to shuffle along data in a buffer. One way to avoid too many calls to compact is to make the buffer fairly large and call it only when you are running out of space.
I would only use a ByteBuffer if your data format is simple, i.e. not full XML standard.
Use a ring buffer, i.e., a circular fixed-length buffer (array). You keep two pointers, one pointing to the start of the data (i.e., the oldest bytes in the ring), and another pointing to the end of the data (to the newest bytes).
You scan the ring from the start pointer to the end pointer. At certain times, such as when you've exhausted the contents of the ring, you read in fresh data into the ring, overwriting the old data, and then adjust the pointers appropriately. Since it's a ring, when you increment a pointer past the end of the array, you wrap around back to the beginning of the array.
UPDATE
An example of using a ring buffer in Java is at: http://david.tribble.com/src/java/tribble/util/FifoQueue.java

Shift the file while writing?

Is it possible to shift the contents of a file while writing to it using FileWriter?
I need to write data constants to the head of the file and if I do that it overwrites the file.
What technique should I use to do this or should I make make copies of the file (with the new data on top) on every file write?
If you want to overwrite certain bytes of the file and not others, you can use seek and write to do so. If you want to change the content of every byte in the file (by, for example, adding a single byte to the beginning of the file) then you need to write a new file and potentially rename it after you've done writing it.
Think of the answer to the question "what will be the contents of the byte at offset x after I'm done?". If, for a large percent of the possible values of x the answer is "not what it used to be" then you need a new file.
Rather than contending ourselves with the question "what will be the contents of the byte at offset x after I'm done?", lets change the mindset and ask why can't the file system or perhaps the hard disk firmware do : a) provide another mode of accessing the file [let's say, inline] b) increase the length of the file by the number of bytes added at the front or in the middle or even at the end c) move each byte that starts from the crossection by the newcontent.length positions
It would be easier and faster to handle these operations at the disk firmware or file system implementation level rather than leaving that job to the application developer. I hope file system writers or hard disk vendors would offer such feature soon.
Regards,
Samba

Categories