So I am generating WAV file with Phase Cancellation. But generated WAV file plays but with no sound. Have used multiple players and devices but no sound. At first I copied the Header to the target file. Then,
Reading Data part of the WAV file and getting Audio Data Array
long arrLength = source.length() - Wav_header_size;
byte[] arr = new byte[(int) arrLength];
RandomAccessFile filein;
filein = new RandomAccessFile(source, "rw");
filein.seek(Wav_header_size);
filein.read();
filein.write(arr,0, arr.length);
filein.close();
Getting Channel arrays from the Audio Data
short[] shortAudioArray = new short[arr.length/2];
short[] channelLeft = new short[arr.length/4];
short[] channelRight = new short[arr.length/4];
ByteBuffer.wrap(arr).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shortAudioArray);
for(int i=0, j=0; i< shortAudioArray.length;i+=2, ++j){
if(channelLeft.length>j && channelLeft[j]!=0)
channelLeft[j] = shortAudioArray[i];
else
break;
if(channelRight.length>j && channelRight[j]!=0)
channelRight[j] = shortAudioArray[i+1];
else
break;
}
Processing Phase cancellation by negating one phase and then merging
for(int i =0;i< data2.length;i++) {
data2[i] = (short) -data2[i];
}
for(int i=0,j=0; j< dstAudio.length;i++,j=j+2) {
if(data1.length>i && data1[i]!=0)
dstAudio[j] = data1[i];
else
break;
if(data2.length>i && data2[i]!=0)
dstAudio[j+1] = data2[i];
else
break;
}
byte[] bytesLast = new byte[dstAudio.length * 2];
ByteBuffer.wrap(bytesLast).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(dstAudio);
This way same size Audio WAV file is getting generated but with no sound.
Can anyone please correct me if I am wrong in anyway in the whole process?
Java provides classes that handle the formatting and other structural aspects of the .wav file. I strongly suggest making use of those tools rather than attempting to write your own .wav headers and such.
You can read more about these tools at the Oracle tutorial on sound. The sixth in the series (Using Files and Format Converters) has a subsection on writing audio files.
So I have solved the issue by manipulating the byte array through inverting the bits one by one not producing or converting to anymore short arrays.
Related
I built a classic Hoffman code, with encoder and decoder. I noticed that I had a problem, I use code in "bitset", to compress the input file. But the "bitset" - does not decode all the files I send to, for example when I send a txt file, it works great, but when I send other files like BMP. It doesn't work.
Before I used bitset - the code worked - but without any compression - so I'm afraid the problem is with bitset.
The decoder I built is:
public void Decompress(String[] input_names, String[] output_names) {
HuffmanVerticle tree = new HuffmanVerticle();
tree = readTreeFile(output_names);
restoreInput(tree, output_names, input_names);
}
public static void restoreInput(HuffmanVerticle tree, String[] binary_names, String[] original_names) {
BitSet huffmanCodeBit;
try {
FileOutputStream to_original = new FileOutputStream(original_names[0]);
FileInputStream binary = new FileInputStream(binary_names[0]);
ObjectInputStream s = new ObjectInputStream(binary);
huffmanCodeBit = (BitSet) s.readObject();
System.out.println(huffmanCodeBit.toString());
int index = 0;
while(huffmanCodeBit.length() > index)
{
HuffmanVerticle tmp = tree;
while (!tmp.isNullTree())
{
boolean bit = huffmanCodeBit.get(index);
index++;
System.out.println(bit);
if (!bit)
tmp = tmp.left;
else
tmp = tmp.right;
}
to_original.write(tmp.character);
}
binary.close();
to_original.close();
} catch (Exception e) {
e.printStackTrace();
}
}
What am I missing here? Why doesn't the code work for certain files? I'm trying to run the code on some files but it doesn't work, the files that come back don't work.
The code does not work for bmp files at all, even after half an hour, for example txt files, it runs very fast.
Thank for your help.
In my application, I want to change the raw byte data to the audio. So, at first I receive the data and add it to a byte array list and than I want to change the whole array list to the audio. As the data is raw through audio jack, I would appreciate if you let me know which audio format is suitable (wav,3gp and so on)? Also, I have a problem with saving this data in a file. This is my code. in line of fileOuputStream.write( audiod.toArray()), it give an error and asked me to change the type of audiod to byte.
private static ArrayList<Byte> audiod = new ArrayList<Byte>();
audioFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myaudio.wav";
if (dg == 1) {
//audiod.append(data[i]);
for (int i = 0; data != null && i < data.length; i++) {
audiod.add(data[i]);
}
if (stt.equalsIgnoreCase(("r"))) {
dg = 0;
recordButton.setEnabled(true);
File file = new File(audioFilePath);
try {
FileOutputStream fileOuputStream = new FileOutputStream(audioFilePath);
fileOuputStream.write( audiod.toArray());
fileOuputStream.close();
System.out.println("Done");
}
catch(Exception e) {
e.printStackTrace();
}
}
}
audiod.toArray() will give you a Byte[], however you need a byte[]. In Java there are so called wrapper classes for the primitive data types. A Byte is an object that holds byte values.
Why do you use a list of Byte at all? It needs a lot more memory than a simple byte[] you seem to have anyhow (data).
The data format (wav,3gp and so on) depends on how you got your data.
I have some problems finding out, what I actually read with the AudioInputStream. The program below just prints the byte-array I get but I actually don't even know, if the bytes are actually the samples, so the byte-array is the audio wave.
File fileIn;
AudioInputStream audio_in;
byte[] audioBytes;
int numBytesRead;
int numFramesRead;
int numBytes;
int totalFramesRead;
int bytesPerFrame;
try {
audio_in = AudioSystem.getAudioInputStream(fileIn);
bytesPerFrame = audio_in.getFormat().getFrameSize();
if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) {
bytesPerFrame = 1;
}
numBytes = 1024 * bytesPerFrame;
audioBytes = new byte[numBytes];
try {
numBytesRead = 0;
numFramesRead = 0;
} catch (Exception ex) {
System.out.println("Something went completely wrong");
}
} catch (Exception e) {
System.out.println("Something went completely wrong");
}
and in some other part, I read some bytes with this:
try {
if ((numBytesRead = audio_in.read(audioBytes)) != -1) {
numFramesRead = numBytesRead / bytesPerFrame;
totalFramesRead += numFramesRead;
}
} catch (Exception e) {
System.out.println("Had problems reading new content");
}
So first of all, this code is not from me. This is my first time, reading audio-files so I got some help from the inter-webs. (Found the link:
Java - reading, manipulating and writing WAV files
stackoverflow, who would have known.
The question is, what are the bytes in audioBytes representing? Since the source is a 44kHz, stereo, there have to be 2 waves hiding in there somewhere, am I right? so how do I filter the important informations out of these bytes?
// EDIT
So what I added is this function:
public short[] Get_Sample() {
if(samplesRead == 1024) {
Read_Buffer();
samplesRead = 4;
} else {
samplesRead = samplesRead + 4;
}
short sample[] = new short[2];
sample[0] = (short)(audioBytes[samplesRead-4] + 256*audioBytes[samplesRead-3]);
sample[1] = (short)(audioBytes[samplesRead-2] + 256*audioBytes[samplesRead-1]);
return sample;
}
where Read_Buffer() reads the next 1024 (or less) Bytes and loads them into audioBytes. sample[0] is used for the left side, sample[1] for the right side. But I'm still not sure since the waves i get from this look quite "noisy". (Edit: the used WAV actually used little-endian byte order so I had to change the calculation.)
AudioInputStream read() method returns the raw audio data. You don't know what is the 'construction' of data before you read the audio format with getFormat() which returns AudioFormat. From AudioFormat you can getChannels() and getSampleSizeInBits() and more... This is because the AudioInputStream is made for known format.
If you calculate a sample value you have different possibilities with signes and
endianness of the data (in case of 16-bit sample). To make a more generic code
use your AudioFormat object returned from AudioInputStream to get more info
about the data buffer:
encoding() : PCM_SIGNED, PCM_UNSIGNED ...
bigEndian() : true or false
As you already discovered the incorrect sample building may lead to some disturbed sound. If you work with various files it may case a problems in the future. If you won't provide a support for some formats just check what says AudioFormat and throw exception (e.g. javax.sound.sampled.UnsupportedAudioFileException). It will save your time.
My basic Java problem is this: I need to read in a file by chunks, then reverse the order of the chunks, then write that out to a new file. My first (naive) attempt followed this approach:
read a chunk from the file.
reverse the bytes of the chunk
push the bytes one at a time to the front of a results list
repeat for all chunks
write result list to new file.
So this is basically a very stupid and slow way to solve the problem, but generates the correct output that I am looking for. To try to improve the situation, I change to this algorithm:
read a chunk from the file
push that chunk onto the front of a list of arrays
repeat for all chunks
foreach chunk, write to new file
And to my mind, that produces the same output. except it doesn't and I am quite confused. The first chunk in the result file matches with both methods, but the rest of the file is completely different.
Here is the meat of the Java code I am using:
FileInputStream in;
FileOutputStream out, out2;
Byte[] t = new Byte[0];
LinkedList<Byte> reversed_data = new LinkedList<Byte>();
byte[] data = new byte[bufferSize];
LinkedList<byte[]> revd2 = new LinkedList<byte[]>();
try {
in = new FileInputStream(infile);
out = new FileOutputStream(outfile1);
out2 = new FileOutputStream(outfile2);
} catch (FileNotFoundException e) {
e.printStackTrace();
return;
}
while(in.read(data) != -1)
{
revd2.addFirst(data);
byte[] revd = reverse(data);
for (byte b : revd)
{
reversed_data.addFirst(b);
}
}
for (Byte b : reversed_data)
{
out.write(b);
}
for (byte[] b : revd2)
{
out2.write(b);
}
At http://pastie.org/3113665 you can see a complete example program (a long with my debugging attempts). For simplicity I am using a bufferSize that divides evenly the size of the file so all chunks will be the same size, but this won't hold in the real world. My question is, WHY don't these two methods generate the same output? It's driving me crazy because I can't grok it.
You're constantly overwriting the data you've read previously.
while(in.read(data) != -1)
{
revd2.addFirst(data);
// ignore byte-wise stuff
}
You're adding the same object repeatedly to the list revd2, so each list node will finally contain a reference to data filled with the result of the last read. I suggest replacing that with revd2.addFirst(data.clone()).
My guess is you want to change
revd2.addFirst(data);
byte[] revd = reverse(data);
for the following so the reversed copy is added to the start of the list.
byte[] revd = reverse(data);
revd2.addFirst(revd);
I am coding in java for android. the issue is how to get mp3 file size and its audio length before hand so that I can set my Progress bar / Seek bar. to respond to seeking events.
The answer can be a simple info in a header file or a algorithm.
I am using androids mediaplayer to stream and the only issue is seeking which requires both the above mentioned things.
Any help is appreciated.
I also tried manually looking into mp3 file and get the header to decode the mp3 length, with this noob code.
total = ucon.getContentLength(); //ucon is an HTTPURLconnection
is= ucon.getInputStream();
byte[] buffer = new byte[1024];
is.read(buffer , 0, 1024);
int offset = 1024;
int loc = 2000;
//FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
while(loc == 2000 && offset< total)
{
for(int i = 0 ; i <1024 ;i++ )
{
if((int)buffer[i] == 255)
{
if((int)buffer[i+1] >= 224)
{
loc = i+1;
break;
}
}
}
is.read(buffer , 0, 1024);
offset = 1024 + offset;
}
Coudn't find the pattern which marks a mp3 header (11111111 111xxxxx). Tried on different files. Can't find anything else to do.
Update 2:
Now I know I dont have to search for mp3 headers but ID3v2 headers. But still its done when streaming the file and on Android. I really hope someone helps and there are a lot of programs doing these things I wonder why would I have to do it the hard way.
Well, I never knew about the ID3 tag system.