I am working on sound processing with the use of Java now. Within my project, I have to deal with the stream. So I have a lot of staffs to do with DataLine and OutputStream or InputStream.
But to me, they are too similar:(
Is there someone who can help me with this question? Thanks in advance!
Here are some code I used :
TargetDataLine line;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int frameSizeInBytes = format.getFrameSize();
int bufferLengthInFrames = line.getBufferSize() / 8;
int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
byte[] data = new byte[bufferLengthInBytes];
int numBytesRead;
try {
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format, line.getBufferSize());
} catch (LineUnavailableException ex) {
shutDown("Unable to open the line: " + ex);
return;
} catch (SecurityException ex) {
shutDown(ex.toString());
return;
} catch (Exception ex) {
shutDown(ex.toString());
return;
}
line.start();
while (thread != null) {
if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
break;
}
out.write(data, 0, numBytesRead);
}
I have read the documentation of the class TargetDataLine, it is said :"'read(byte[] b, int off, int len)' Reads audio data from the data line's input buffer."
But where do we define it?
Also the line of type TargetDataLine has not been attached to any mixer, so how can we know for which mixer it is for???
A DataLine is an interface related to handling sampled sound (a.k.a PCM data) in Java. I don't really know a lot of that.
An OutputStream is an interface that represents anything that can get bytes written to it. A simple sample of an OutputStream is a FileOutputStream: all bytes written to that stream will be written to the file it was opened for.
An InputStream is the other end: it's an interface that represents anything from which bytes can be read. A simple sample of an InputStream is a FileInputStream: it can be used to read the data from a file.
So if you were to read audio data from the hard disk, you'd eventually use a FileInputStream to read the data. If you manipulate it and later want to write the resulting data back to the hard disk, you'd use a FileOutputStream to do the actual writing.
An InputStream represents a stream of bytes, where we can read bytes one be one (or in blocks) until it is empty. An OutputStream is the other direction - we write bytes one be one (or in blocks) until we have nothing more to write.
Streams are used to send or receive unstructured byte data.
DataLine handles audio data, in other words, bytes with a special meaning. And it offers some special methods to control the line (start/stop), get the actual format of the audio data and some other characteristics.
Related
In my project I have implemented an audio record option. For reading real-time voice I used TargetDataLine.I want to record audio with high volume. How can I do that?
TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
File file = new File("RecordedVoice.raw");
if(file.exists())
file.delete();
file.createNewFile();
fos = new FileOutputStream(file);
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Line not supported: " + format.toString());
System.exit(0);
} else {
try {
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
out = new ByteArrayOutputStream();
int numBytesRead;
byte[] data = new byte[line.getBufferSize()/5];
line.start();
while (!isCancelled()) {
numBytesRead = line.read(data, 0, data.length);
out.write(data, 0, numBytesRead);
fos.write(data, 0, data.length);
}
out.close();
} catch (Exception excp) {
System.out.println("Error! Could not open Audio System line!");
excp.printStackTrace();
}
}
In the while loop, these steps:
convert the bytes to PCM values (depends on format, e.g., 16 bit is two bytes, 24 bit is three bytes, also pay attention whether it is big-endian or little-endian as this gives you the order of the bytes
multiply the PCM values by a volume factor (e.g., 1.1 to raise the volume a bit). You might want to also include a Math.min() to prevent the values from exceeding the range of the bits used to encode the values.
convert the PCM values back to bytes, according to your audio format specs
There may be a way to do this instead via Controls. The plan I wrote about is basically how to do it manually, as written about in the linked tutorial in the last section "Manipulating the Audio Data Directly". Benefits: this is all within Java, instead of being dependent upon the given PC and OS (audio Controls are not guaranteed to exist). Also you have frame-level granularity. I think the Controls in the article tend to only enact changes at buffer boundaries.
I want to convert a byte array into an AudioInputStream. The byte array was filled from a *.wav file before. I have the following code:
public static AudioInputStream writeBytesBackToStream(byte[] bytes) {
ByteArrayInputStream baiut = new ByteArrayInputStream(bytes);
AudioInputStream stream = null;
try {
stream = AudioSystem.getAudioInputStream(baiut);
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(stream.equals(null) || stream == null) {
System.out.println("WARNING: Stream read by byte array is null!");
}
return stream;
}
Now I only want to convert this byte array into an AudioInputStream, but an UnsupportedAudioFileException is thrown:
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream
Has anyone got an idea?
Another way to do this, if the data is actually PCM, is to set the AudioFormat parameters manually. Here is an example to create an A minor.
byte[] b = new byte[64000];
//lets make a 440hz tone for 1s at 32kbps, and 523.25hz.
for(int i = 0; i<b.length/2; i++){
b[i*2+1] = (byte)(127*Math.sin(4*Math.PI*440.0/b.length*i));
b[i*2] = (byte)(127*Math.sin(4*Math.PI*523.25/b.length*i));
}
AudioInputStream stream = new AudioInputStream(
new ByteArrayInputStream(b),
new AudioFormat(16000, 8, 2, true, false),
64000
);
Also be careful if you're making bytes into sounds and you have earphones in.
If you properly read the WAV file, the byte array will just contain raw PCM data. Consequently the AudioSystem can not identify the format of the stream and throws the exception.
This can not work by design. You need to provide a complete audio format image in your stream to have AudioSystem recognize what format the stream is, not just raw data.
I´m having a problem, in my server, after I send a file with X bytes, I send a string saying this file is over and another file is coming, like
FILE: a SIZE: Y\r\n
send Y bytes
FILE a FINISHED\r\n
FILE b SIZE: Z\r\n
send Z byes
FILE b FINISHED\r\n
FILES FINISHED\r\n
In my client it does not recive properly.
I use readline() to get the command lines after reading Y or Z bytes from the socket.
With one file it works fine, with multiple files it rarely works (yeah, I dont know how it worked once or twice)
Here are some code I use to transfer binary
public static void readInputStreamToFile(InputStream is, FileOutputStream fout,
long size, int bufferSize) throws Exception
{
byte[] buffer = new byte[bufferSize];
long curRead = 0;
long totalRead = 0;
long sizeToRead = size;
while(totalRead < sizeToRead)
{
if(totalRead + buffer.length <= sizeToRead)
{
curRead = is.read(buffer);
}
else
{
curRead = is.read(buffer, 0, (int)(sizeToRead - totalRead));
}
totalRead = totalRead + curRead;
fout.write(buffer, 0, (int) curRead);
}
}
public static void writeFileInputStreamToOutputStream(FileInputStream in, OutputStream out, int bufferSize) throws Exception
{
byte[] buffer = new byte[bufferSize];
int count = 0;
while((count = in.read(buffer)) != -1)
{
out.write(buffer, 0, count);
}
}
just for note I could solve replacing readline to this code:
ByteArrayOutputStream ba = new ByteArrayOutputStream();
int ch;
while(true)
{
ch = is.read();
if(ch == -1)
throw new IOException("Conecção finalizada");
if(ch == 13)
{
ch = is.read();
if(ch == 10)
return new String(ba.toByteArray(), "ISO-8859-1");
else
ba.write(13);
}
ba.write(ch);
}
PS: "is" is my input stream from socket: socket.getInputStream();
still I dont know if its the best implementation to do, im tryinf to figure out
There's no readLine() calls in the code here, but to answer your question; Yes, calling BufferedReader.readLine() might very well leave stuff around in its internal buffer. It's buffering the input.
If you wrap one of your InputStream in a BufferedReader, you can't really get much sane behavior if you read from the BufferedReader and then later on read from the InputStream.
You could read bytes from your InputStream and parse out a text line from that by looking for a pair of \r\n bytes. When you got a line saying "FILE: a SIZE: Y\r\n" , you go on as usual, except the buffer you used to parse lines might contain the first few bytes of your file, so write those bytes out first.
Or you use the idea of FTP and use one TCP stream for commands and one TCP stream for the actual transfer, reading from the command stream with a BufferedReader.readLine(), and reading the data as you already do with an InputStream.
Yes, the main point of a BufferedReader is to buffer the data. It is reading input from its underlying Reader in bigger chunks to avoid having multiple small reads.
That it has a readLine() method is just a nice bonus which is made easily possible by the buffering.
You may want to use a DataInputStream (on top of a BufferedInputStream) and it's readLine() method, if you really have to mix text and binary data over the same connection - read the data from the same DataInputStream. (But take care about the encoding here.)
Call flush() on the OutputStream after you've written data that you want to be certain has been sent. So essentially at the end of each file call flush().
I guess you must flush your output stream in order to make sure any buffered bytes are properly sent down the stream. Closing the stream will equally have this process run.
The Javadocs for flush say:
Flushes this output stream and forces
any buffered output bytes to be
written out. The general contract of
flush is that calling it is an
indication that, if any bytes
previously written have been buffered
by the implementation of the output
stream, such bytes should immediately
be written to their intended
destination.
Someone explain to me what InputStream and OutputStream are?
I am confused about the use cases for both InputStream and OutputStream.
If you could also include a snippet of code to go along with your explanation, that would be great. Thanks!
The goal of InputStream and OutputStream is to abstract different ways to input and output: whether the stream is a file, a web page, or the screen shouldn't matter. All that matters is that you receive information from the stream (or send information into that stream.)
InputStream is used for many things that you read from.
OutputStream is used for many things that you write to.
Here's some sample code. It assumes the InputStream instr and OutputStream osstr have already been created:
int i;
while ((i = instr.read()) != -1) {
osstr.write(i);
}
instr.close();
osstr.close();
InputStream is used for reading, OutputStream for writing. They are connected as decorators to one another such that you can read/write all different types of data from all different types of sources.
For example, you can write primitive data to a file:
File file = new File("C:/text.bin");
file.createNewFile();
DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
stream.writeBoolean(true);
stream.writeInt(1234);
stream.close();
To read the written contents:
File file = new File("C:/text.bin");
DataInputStream stream = new DataInputStream(new FileInputStream(file));
boolean isTrue = stream.readBoolean();
int value = stream.readInt();
stream.close();
System.out.printlin(isTrue + " " + value);
You can use other types of streams to enhance the reading/writing. For example, you can introduce a buffer for efficiency:
DataInputStream stream = new DataInputStream(
new BufferedInputStream(new FileInputStream(file)));
You can write other data such as objects:
MyClass myObject = new MyClass(); // MyClass have to implement Serializable
ObjectOutputStream stream = new ObjectOutputStream(
new FileOutputStream("C:/text.obj"));
stream.writeObject(myObject);
stream.close();
You can read from other different input sources:
byte[] test = new byte[] {0, 0, 1, 0, 0, 0, 1, 1, 8, 9};
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(test));
int value0 = stream.readInt();
int value1 = stream.readInt();
byte value2 = stream.readByte();
byte value3 = stream.readByte();
stream.close();
System.out.println(value0 + " " + value1 + " " + value2 + " " + value3);
For most input streams there is an output stream, also. You can define your own streams to reading/writing special things and there are complex streams for reading complex things (for example there are Streams for reading/writing ZIP format).
From the Java Tutorial:
A stream is a sequence of data.
A program uses an input stream to read data from a source, one item at a time:
A program uses an output stream to write data to a destination, one item at time:
The data source and data destination pictured above can be anything that holds, generates, or consumes data. Obviously this includes disk files, but a source or destination can also be another program, a peripheral device, a network socket, or an array.
Sample code from oracle tutorial:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("xanadu.txt");
out = new FileOutputStream("outagain.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
This program uses byte streams to copy xanadu.txt file to outagain.txt , by writing one byte at a time
Have a look at this SE question to know more details about advanced Character streams, which are wrappers on top of Byte Streams :
byte stream and character stream
you read from an InputStream and write to an OutputStream.
for example, say you want to copy a file. You would create a FileInputStream to read from the source file and a FileOutputStream to write to the new file.
If your data is a character stream, you could use a FileReader instead of an InputStream and a FileWriter instead of an OutputStream if you prefer.
InputStream input = ... // many different types
OutputStream output = ... // many different types
byte[] buffer = new byte[1024];
int n = 0;
while ((n = input.read(buffer)) != -1)
output.write(buffer, 0, n);
input.close();
output.close();
OutputStream is an abstract class that represents writing output. There are many different OutputStream classes, and they write out to certain things (like the screen, or Files, or byte arrays, or network connections, or etc). InputStream classes access the same things, but they read data in from them.
Here is a good basic example of using FileOutputStream and FileInputStream to write data to a file, then read it back in.
A stream is a continuous flow of liquid, air, or gas.
Java stream is a flow of data from a source into a destination. The source or destination can be a disk, memory, socket, or other programs. The data can be bytes, characters, or objects. The same applies for C# or C++ streams. A good metaphor for Java streams is water flowing from a tap into a bathtub and later into a drainage.
The data represents the static part of the stream; the read and write methods the dynamic part of the stream.
InputStream represents a flow of data from the source, the OutputStream represents a flow of data into the destination.
Finally, InputStream and OutputStream are abstractions over low-level access to data, such as C file pointers.
Stream: In laymen terms stream is data , most generic stream is binary representation of data.
Input Stream : If you are reading data from a file or any other source , stream used is input stream. In a simpler terms input stream acts as a channel to read data.
Output Stream : If you want to read and process data from a source (file etc) you first need to save the data , the mean to store data is output stream .
An output stream is generally related to some data destination like a file or a network etc.In java output stream is a destination where data is eventually written and it ends
import java.io.printstream;
class PPrint {
static PPrintStream oout = new PPrintStream();
}
class PPrintStream {
void print(String str) {
System.out.println(str)
}
}
class outputstreamDemo {
public static void main(String args[]) {
System.out.println("hello world");
System.out.prinln("this is output stream demo");
}
}
For one kind of InputStream, you can think of it as a "representation" of a data source, like a file.
For example:
FileInputStream fileInputStream = new FileInputStream("/path/to/file/abc.txt");
fileInputStream represents the data in this path, which you can use read method to read bytes from the file.
For the other kind of InputStream, they take in another inputStream and do further processing, like decompression.
For example:
GZIPInputStream gzipInputStream = new GZIPInputStream(fileInputStream);
gzipInputStream will treat the fileInputStream as a compressed data source. When you use the read(buffer, 0, buffer.length) method, it will decompress part of the gzip file into the buffer you provide.
The reason why we use InputStream because as the data in the source becomes larger and larger, say we have 500GB data in the source file, we don't want to hold everything in the memory (expensive machine; not friendly for GC allocation), and we want to get some result faster (reading the whole file may take a long time).
The same thing for OutputStream. We can start moving some result to the destination without waiting for the whole thing to finish, plus less memory consumption.
If you want more explanations and examples, you have check these summaries: InputStream, OutputStream, How To Use InputStream, How To Use OutputStream
In continue to the great other answers, in my simple words:
Stream - like mentioned #Sher Mohammad is data.
Input stream - for example is to get input – data – from the file. The case is when I have a file (the user upload a file – input) – and I want to read what we have there.
Output Stream – is the vice versa. For example – you are generating an excel file, and output it to some place.
The “how to write” to the file, is defined at the sender (the excel workbook class) not at the file output stream.
See here example in this context.
try (OutputStream fileOut = new FileOutputStream("xssf-align.xlsx")) {
wb.write(fileOut);
}
wb.close();
I need to pass audio data into a 3rd party system as a "16bit integer array" (from the limited documentation I have).
This is what I've tried so far (the system reads it in from the resulting bytes.dat file).
AudioInputStream inputStream = AudioSystem.getAudioInputStream(new File("c:\\all.wav"));
int numBytes = inputStream.available();
byte[] buffer = new byte[numBytes];
inputStream.read(buffer, 0, numBytes);
BufferedWriter fileOut = new BufferedWriter(new FileWriter(new File("c:\\temp\\bytes.dat")));
ByteBuffer bb = ByteBuffer.wrap(buffer);
while (bb.remaining() > 1) {
short current = bb.getShort();
fileOut.write(String.valueOf(current));
fileOut.newLine();
}
This doesn't seem to work - the 3rd party system doesn't recognise it and I also can't import the file into Audacity as raw audio.
Is there anything obvious I'm doing wrong, or is there a better way to do it?
Extra info: the wave file is 16bit, 44100Hz, mono.
I've just managed to sort this out.
I had to add this line after creating the ByteBuffer.
bb.order(ByteOrder.LITTLE_ENDIAN);
Edit 2:
I rarely use AudioInputStream but the way you write out the raw data seems to be rather complicated. A file is just a bunch of subsequent bytes so you could write your audio byte array with one single FileOutputStream.write() call. The system might use big endian format whereas the WAV file is stored in little endian (?). Then your audio might play but extremely silently for example.
Edit 3
Removed the code sample.
Is there a reason you are writing the audio bytes as strings into the file with newlines?
I would think the system expects the audio data in binary format, not in string format.
AudioFileFormat audioFileFormat;
try {
File file = new File("path/to/wav/file");
audioFileFormat = AudioSystem.getAudioFileFormat(file);
int intervalMSec = 10; // 20 or 30
byte[] buffer = new byte[160]; // 320 or 480.
AudioInputStream audioInputStream = new AudioInputStream(new FileInputStream(file),
audioFileFormat.getFormat(), (long) audioFileFormat.getFrameLength());
int off = 0;
while (audioInputStream.available() > 0) {
audioInputStream.read(buffer, off, 160);
off += 160;
intervalMSec += 10;
ByteBuffer wrap = ByteBuffer.wrap(buffer);
int[] array = wrap.asIntBuffer().array();
}
audioInputStream.close();
} catch (UnsupportedAudioFileException | IOException e) {
e.printStackTrace();
}