How do I convert heapbytebuffer to "File"? - java

I have a heapbytebuffer in a variable "myByteBuffer" that represents an audio wav that I want to playback. I see that AudioInputStream is a way to play files using AudioSystem.getAudioInputStream(soundFile). Since it accepts a "File", how can I convert the heapbytebuffer I have to a "File"?

Don't use the File overload unless you have (or want to save) a physical file. Just take your data and wrap it in an InputStream:
AudioSystem.getAudioInputStream(new ByteArrayInputStream(myByteBuffer.array()))
This assumes you're using the full buffer. If not, you can slice out the part you're using as necessary. See here for details.

Related

When calling javax.imageio.ImageIO.read, can I specify the format?

In Java, I want to use the class javax.imageio.ImageIO to read a image from an InputStream. This class has a static method, read(InputStream input), which can do this.
However, this method does not allow me to specify the format (such as png, jpeg, bmp ...). According to the documentation of this class, it seems that this method will detect the format automatically from the InputStream. But to me, this seems unsafe. What if a byte sequence can be interpreted as two different image formats? After all, a byte sequence is meaningless unless a format is specified. Besides, it seems that custom image formats and their readers can be registered to the ImageIO class, which makes this problem more severe.
So, is there a way to read an image from an InputStream with a format specified?
No, none of the static ImageIO.read(...) methods allows specifying the format to be read.
For these methods, the registered reader plugins briefly inspects the stream/file contents and decides whether or not it is able to decode it. The first reader plugin that can decode is chosen, and an actual reader instance is created to perform the decoding.
For most file formats, this method is a common and completely safe way to determine the file format, and is based on the "magic identifier" or file signature. There are file formats that does not have such signatures that are hard to detect, like WBMP, PICT or old TGA files. But the formats you mention, like BMP, JPEG and PNG are all easily and correctly detected using this mechanism.
If however, you know that your inputs are always the same format or explicitly only want to support a single format, that is possible with a little extra code. This is probably also a tiny bit faster than detecting the file format by inspection, although I doubt it matters much.
If the only format you want is JPEG, use ImageIO.getImageReadersByFormatName("JPEG") (getImageReadersBySuffix("jpg") or getImageReadersByMIMEType("image/jpeg") will also do) to get a reader and then pass the input directly to this reader. The code would look something like this:
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
ImageReader reader = readers.next(); // There should always be a JPEG reader installed, for other formats you might want to check
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) {
reader.setInput(stream);
BufferedImage image = reader.read(0);
}
finally {
reader.dispose();
}
Yes you can speficy the format. You do that with the file name.
BufferedImage img = ImageIO.read(new File("abc.jpg"));
For more information, like accepted file formats, take a look here.
https://docs.oracle.com/javase/tutorial/2d/images/loadimage.html
This topic didn't let me sleep last night. Take a look at this solution:
The computer must know, how to handle a file and for that, it takes a look into the file. Just open an image with the normal editor and you see what I mean.
You can write a method for specification by yourself. This method needs to read a file (or a part of it), and then check for the format.

Java Sound API: Recording and monitoring same input source

I'm trying to record from the microphone to a wav file as per this example. At the same time, I need to be able to test for input level/volume and send an alert if it's too low. I've tried what's described in this link and seems to work ok.
The issue comes when trying to record and read bytes at the same time using one TargetDataLine (bytes read for monitoring are being skipped for recording and vice-versa.
Another thing is that these are long processes (hours probably) so memory usage should be considered.
How should I proceed here? Any way to clone TargetDataLine? Can I buffer a number of bytes while writing them with AudioSystem.write()? Is there any other way to write to a .wav file without filling the system memory?
Thanks!
If you are using a TargetDataLine for capturing audio similar to the example given in the Java Tutorials, then you have access to a byte array called "data". You can loop through this array to test the volume level before outputting it.
To do the volume testing, you will have to convert the bytes to some sort of sensible PCM data. For example, if the format is 16-bit stereo little-endian, you might take two bytes and assemble to either a signed short or a signed, normalized float, and then test.
I apologize for not looking more closely at your examples before posting my "solution".
I'm going to suggest that you extend InputStream, making a customized version that also performs the volume test. Override the 'read' method so that it obtains the byte that it returns from the code you have that tests the volume. You'll have to modify the volume-testing code to work on a per-byte basis and to pass through the required byte.
You should then be able to use this extended InputStream as an argument when you create the AudioInputStream for the output-to-wav stage.
I've used this approach to save audio successfully via two data sources: once from an array that is populated beforehand, once from a streaming audio mix passing through a "mixer" I wrote to combine audio data sources. The latter would be more like what you need to do. I haven't done it from a microphone source, though. But the same approach should work, as far as I can tell.

File type detection in Java without I/O

There is a built-in method in the Java JDK that detects file types:
Files.probeContentType(Paths.get("/temp/word.doc"));
The javadoc says that a FileTypeDetector may examine the filename, or it may examine a few bytes in the file, which means that it would have to actually try to pull the file from a URL.
This is unacceptable in our app; the content of the file is available only through an InputStream.
I tried to step through the code to see what the JDK is actually doing, but it seems that it goes to FileTypeDetectors.defaultFileTypeDetector.probeContentType(path) which goes to sun.nio.fs.AbstractFileTypeDetector, and I couldn't step into that code because there's no source attachment.
How do I use JDK file type detection and force it to use file content that I supply, rather than having it go out and perform I/O on its own?
The docs for Files.probeContentType() explain how to plug in your own FileTypeDetector implementation, but if you follow the docs you'll find that there is no reliable way to ensure that your implementation is the one that is selected (the idea is that different implementations serve as fallbacks for each other, not alternatives). There is certainly no documented way to prevent the built-in implementation from ever reading the target file.
You can surely find a map of common filename extensions to content types in various places around the web and probably on your own system; mime.types is a common name for such files. If you want to rely only on such a mapping file then you probably need to use your own custom facility, not the Java standard library's.
The JDK's Files.probeContentType() simply loads a FileTypeDetector available in your JDK installation and asks it to detect the MIME type. If none exists then it does nothing.
Apache has a library called Tika which does exactly what you want. It determines the MIME type of the given content. It can also be plugged into your JDK to make your Files.probeContentType() function using Tika. Check this tutorial for quick code - http://wilddiary.com/detect-file-type-from-content/
If you are worried about reading the contents of an InputStream you can wrap it in a PushBackInputStream to "unread" those bytes so the next detector implementation can read it.
Usually binary file's magic numbers are 4 bytes so having a new PushBackInputStream(in, 4) should be sufficient.
PushBackInputStream pushbackStream = new PushBackInputStream(in, 4);
byte[] magicNumber = new byte[4];
//for this example we will assume it reads whole array
//for production you will need to check all 4 bytes read etc
pushbackStream.read(magicNumber);
//now figure out content type basic on magic number
ContentType type = ...
//now pushback those 4 bytes so you can read the whole stream
pushbackStream.unread(magicNumber);
//now your downstream process can read the pushbackStream as a
//normal InputStream and gets those magic number bytes back
...

Reading .wav signal in matlab and java

When I loaded .wav signal in matlab,the values ​​of samples are like this 0.001853466033936, 0.003706693649292 etc.
When I loaded same signal in Java with:
byte[] buffer = new byte[blockSize];
FileInputStream s = new FileInputStream(file);
s.read(buffer, 0, blockSize);
i have values like this: 73, 70...
I tried to convert to double and I never got the same result like in matlab.
I need this for Android!
Can someone help me? THANKS!
Your java code is reading the file from the beginning. Look at the WAVE file format, the data is stored after the header.
You will need to write a wav file reader (or find an android compatible one) to parse the header, read the NumChannels, BitsPerSample etc, find the start of the data and read.
This is what MATLAB's wavread does (presumably this is what you are using?). You can see how it parses wav files, type edit wavread.
Have a look at this simple Java WAV File IO class. It may do all you need or at least get you started.

Read specific bytes from RandomAccessFile using FileChannel : Java

I have a RandomAccessFile and its FileChannel. What I'm trying to do is read a specific section of the bytes from said file; however, while looking over the FileChannel read methods, I didn't see overloads that would help with what I'm trying to do, only methods which would read the entire content, or read content to a specific position in the buffer that the read method takes in. Is there a method that I'm missing that will help me accomplish my goal of reading a specific chunk of bytes, or will I need to read in the entire channel into the buffer and then parse out the section somehow?
You can go to a specific position in the file using FileChannel#position(long) and then read a buffer in the desired size.

Categories

Resources