I am trying to read a wav file into an array using Android. In order to validate the results I read the same wav file using Matlab. The problem is that the values are different. Your help is highly appreciated in solving this problem.
Kindly, find below the Matlab and Android code with the associated results:
Matlab Code:
fName = 'C:\Users\me\Desktop\audioText.txt';
fid = fopen(fName,'w');
dlmwrite(fName,y_sub,'-append','delimiter','\t','newline','pc');
Matlab Results:
0.00097656
0.00045776
0.0010681
0.00073242
0.00054932
-0.00064087
0.0010376
-0.00027466
-0.00036621
-9.1553e-05
0.00015259
0.0021362
-0.00024414
-3.0518e-05
-0.00021362
Android Code:
String filePath;
private static DataOutputStream fout;
ByteArrayOutputStream out;
BufferedInputStream in;
filePath = "mnt/sdcard/audio.wav";
out = new ByteArrayOutputStream();
try {
in = new BufferedInputStream(new FileInputStream(filePath));
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
int read;
byte[] buff = new byte[2000000];
try {
while ((read = in.read(buff)) > 0)
{
out.write(buff, 0, read);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
out.flush();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
byte[] audioBytes = out.toByteArray();
}
Android Results:
82, 73, 70, 70, 92, 108, 40, 0, 87, 65, 86, 69, 102, 109
Thanks,
In Android you're reading the file header, not the actual values of the sound samples. Your values in Android are ASCII for
RIFF\l( WAVEfm
In Matlab I'm not sure what you're doing... looks like you're writing, not reading a file.
The dir command is quite helpful here. It either displays the whole content of a directory but you can also specify a glob to just return a sub-set of files, e.g. dir('*.wav'). This returns an struct-array containing file information such as name, date, bytes, isdir and so on.
To get started, try the following:
filelist = dir('*.wav');
for file = filelist
fprintf('Processing %s\n', file.name);
fid = fopen(file.name);
% Do something here with your file.
fclose(fid);
end
If a processing result has to be stored per file,
I often use the following pattern. I usually pre-allocate an array, a struct array or
a cell array of the same size as the filelist. Then I use an integer index to iterate
over the file list, which I can also use to write the output. If the information to be
stored is homogeneous (e.g. one scalar per file), use an array or a struct array.
However, if the information differs from file to file (e.g. vectors or matrices of different size) use a cell array instead.
An example using an ordinary array:
filelist = dir('*.wav');
% Pre-allocate an array to store some per-file information.
result = zeros(size(filelist));
for index = 1 : length(filelist)
fprintf('Processing %s\n', filelist(index).name);
% Read the sample rate Fs and store it.
[y, Fs] = wavread(filelist(index).name);
result(index) = Fs;
end
% result(1) .. result(N) contain the sample rates of each file.
An example using a cell array:
filelist = dir('*.wav');
% Pre-allocate a cell array to store some per-file information.
result = cell(size(filelist));
for index = 1 : length(filelist)
fprintf('Processing %s\n', filelist(index).name);
% Read the data of the WAV file and store it.
y = wavread(filelist(index).name);
result{index} = y;
end
% result{1} .. result{N} contain the data of the WAV files.
I am not sure what is the problem exactly, but I got the correct readings when I used the following code:
File filein = new File(filePath, "audio.wav");
try
{
// Open the wav file specified as the first argument
WavFile wavFile = WavFile.openWavFile(filein);
// Display information about the wav file
wavFile.display();
// Get the number of audio channels in the wav file
int numChannels = wavFile.getNumChannels();
// Create a buffer of 100 frames
double[] buffer = new double[20000 * numChannels];
int framesRead;
double min = Double.MAX_VALUE;
double max = Double.MIN_VALUE;
do
{
// Read frames into buffer
framesRead = wavFile.readFrames(buffer, 20000);
// Loop through frames and look for minimum and maximum value
for (int s=0 ; s<framesRead * numChannels ; s++)
{
if (buffer[s] > max) max = buffer[s];
if (buffer[s] < min) min = buffer[s];
}
}
while (framesRead != 0);
// Close the wavFile
wavFile.close();
// Output the minimum and maximum value
System.out.printf("Min: %f, Max: %f\n", min, max);
}
catch (Exception e)
{
System.err.println(e);
}
Related
I am able to save FMD to SQLite in Android. However when I am trying to recreate FMD it is not working properly.
Saving FMD in database.
try {
Fmd m_enrollmant_fmd = m_engine.CreateEnrollmentFmd(Fmd.Format.ANSI_378_2004, enrollThread);
if (m_success = (m_enrollmant_fmd != null)) {
byte[] fingerprintData = m_enrollmant_fmd.getData();
int fingerprintImageHeight = m_enrollmant_fmd.getHeight();
int fingerprintImageWidth = m_enrollmant_fmd.getWidth();
int fingerprintResolution = m_enrollmant_fmd.getResolution();
int fingerPosition = m_enrollmant_fmd.getViews()[0].getFingerPosition();
int cbeffId = m_enrollmant_fmd.getCbeffId();
int m_templateSize = m_enrollmant_fmd.getData().length;
m_current_fmds_count = 0; // reset count on success
// Save above values in database and this is working fine.
}
} catch (Exception e) {
m_current_fmds_count = 0;
}
Recreating FMD Code:
Fmd temp_fmd = m_engine.CreateFmd(
user.fingerPrint, // byte[]
user.width, // width
user.height, // height
user.resolution, // resolution
user.fingerPrint, //Finger position,
user.cbeffId, // Cbeff Id
Fmd.Format.ANSI_378_2004); // Format algorithm
if (temp_fmd != null) {
// m_fmd is FMD that we generate after taking fingerprint
int m_score = m_engine.Compare(m_fmd, 0, temp_fmd, 0);
if (m_score < (0x7FFFFFFF / 100000)) {
userFound = user;
break;
}
}
This gives me UareUException saying FID is invalid. However when I try to give fix values in m_engine.CreateFmd(...) except byte[] parameter, it works fine but its dissimilarity is 100%, meaning it doesn't match at all. Any help will be appreciated. I am using UareU SDK 3.1 from Crossmatch (previously known as Digital Persona).
Note that values from Database are correct there is no issue in that. Only I am unable to create correct FMD.
Try using the following to recreate the Fmds from a byte array:
Fmd print = UareUGlobal.GetImporter().ImportFmd(prints, Fmd.Format.ANSI_378_2004, Fmd.Format.ANSI_378_2004);
Where prints here is your byte array.
I have to upload big video files to a server, but it's taking too long to upload, so I decided to split/chunk the files and then send them to the server
After splitting my files, I get a response like the following:
[ /storage/emulated/0/1493357699.mp4.001, /storage/emulated/0/1493357699.mp4.002, /storage/emulated/0/1493357699.mp4.003, /storage/emulated/0/1493357699.mp4.004, /storage/emulated/0/1493357699.mp4.005, /storage/emulated/0/1493357699.mp4.006, /storage/emulated/0/1493357699.mp4.007, /storage/emulated/0/1493357699.mp4.008 ]
My thought is what is the use to upload spitting/chunk file to server?
My code for splitting files:
public static List<File> splitFile(File f) {
try {
int partCounter = 1;
List<File> result = new ArrayList<>();
int sizeOfFiles = 1024 * 1024;// 1MB
byte[] buffer = new byte[sizeOfFiles];
// create a buffer of bytes sized as the one chunk size
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
String name = f.getName();
int tmp = 0;
while ((tmp = bis.read(buffer)) > 0) {
File newFile = new File(f.getParent(), name + "." + String.format("%03d", partCounter++));
// naming files as <inputFileName>.001, <inputFileName>.002, ...
FileOutputStream out = new FileOutputStream(newFile);
out.write(buffer, 0, tmp);//tmp is chunk size. Need it for the last chunk,
// which could be less then 1 mb.
result.add(newFile);
}
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
I have implemented in one of my projects. I see two primary reasons:
To achieve multi-threaded / multiple connection for uploading chunks. You can upload multiple chunks at the same time.
Stop/Resume uploading of rest of the chunks if either of the chunk fails to upload (depending on server response)
Problem:
I want to send an image from matlab to android over bluetooth.
Matlab and android are connected to each other and I can send strings without a problem.
fprintf(tabletObj, 'sleep');
I have a really huge byteArray containing the image I want to send to android. Here you can see just the first bytes:
planString = [-119,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,72,0,0,0,72,8,6,0,0,0,85,-19,-77,71,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,-120,0,0,29,2,73,68,65,84,120,-100,-75,-100,121,-68,37, ... ]
After that, I set in matlab the OutputBufferSize to the size of the image and send it to the tablet.
s = whos('planString');
obj1.OutputBufferSize = s.bytes;
% Send it to tablet
fwrite(tabletObj, planString, 'int8');
In android you can see following incoming bytes.
Why are there just the first 6 bytes and not more?
The next incoming bytes are more then just 6 bytes, why?
I set the buffersize in android to the same size like matlab.
private void listen() {
byte[] buffer = new byte[picSize]; // buffer store for the stream
Log.i(TAG, "buffer length" + buffer.length);
while (true) {
try {
inputStream.read(buffer);
newMessageReceived(new String(buffer, "UTF-8")); // Send the obtained bytes to the UI activity
} catch (IOException e) {
break;
}
}
}
Edit #1:
I used following code to get only the "right" bytes and put that into an ArrayList with bytes. Now, it seems like that I have just the needed bytes. But it's too slow! You need to wait for more than 1 min. to get all bytes from matlab. Is there a better solution? Why are the incoming bytes split sometimes in 3, sometimes in 15, ...? (see picture below code)
ArrayList<byte[]> bytes = new ArrayList<byte[]>();
...
int nread = inputStream.read(buffer);
byte[] newOne = new byte[nread];
System.arraycopy(buffer, 0, newOne, 0, nread);
bytes.add(newOne);
private void listen() {
byte[] buffer = new byte[10000];
int nbytes = 0;
while (true) {
try {
int nread = inputStream.read(buffer, nbytes, buffer.length - nbytes);
nbytes += nread;
... // after getting all bytes
newMessageReceived(buffer, nbytes); // Send bytes to the UI activity
} catch (IOException e) {
break;
}
}
}
#greenapps thanks for the solution.
I am using the write() method in order to write in a file of the external storage. This method only accepts byte[] as an input. I have tried passing a String and I get an error message ("The method write(int) in the type FileOutputStream is not applicable for the arguments String"). If I pass an int, I don't get error but in the file nothing is written. The value I get from calling getNumSentPackets() is an int and I need to convert it to byte[]. I have been looking at other questions already answered here and I have tried the ByteBuffer option but the result I get in the file is not what I want, this means, I don't get the number of sent packets. Can anybody help me, please?
This is my code:
public void createFile(String name) {
try {
String filename = name;
File myFile = new File(Environment.getExternalStorageDirectory(), filename);
if (!myFile.exists())
myFile.createNewFile();
String title = "FLOODING RESULTS FILE\n\n";
String sent = "Number of sent packets\n";
FileOutputStream fos;
byte[] data = title.getBytes();
byte[] intSent = sent.getBytes();
int numSent = mSender.getNumSentPackets();
byte[] numSentBytes = ByteBuffer.allocate(10).putInt(numSent).array();
try{
fos = new FileOutputStream(myFile);
fos.write(data);
fos.write(intSent);
fos.write(numSentBytes);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static int getNumSentPackets() {
return nSentPackets;
}
The expected output file would be as follows:
FLOODING RESULTS FILE
Number of sent packets 200
200 is only an example, meaning with this that I would like to see there a number which would correspond to the total number of sent packets.
Thank you in advance.
As I am a lazy developer, I like to use the existing facilities in my languages of choice, for example, for java, a PrintWriter.
public void createFile(String filename) {
try {
File myFile = new File(Environment.getExternalStorageDirectory(), filename);
PrintWriter out = new PrintWriter(myFile); // this will create the file if necessary
out.println("FLOODING RESULTS FILE");
out.println();
out.print("Number of sent packets ");
out.println(mSender.getNumSentPackets());
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This is much easier to read and maintain than your current approach, and looks more idiomatic.
ByteBuffer.allocate(capacity).putInt(yourInt).array();
The text representation of "200" requires you to write 3 characters. All files are just a bunch of bytes in the end so there needs to be a mapping from character to some byte value. Assuming ASCII(*) the data to write into the file would be
// '2','0','0'
byte[] textVersion = { 50, 48, 48 }
int on the other hand is a 32bit numeric value, i.e. has 4 bytes and 200 is equivalent to
byte[] intVersion = { 0, 0, 0, 200 }
When using a ByteBuffer, you'll get this. If you write that into a file and a text viewer tries to display that it would display something like ◻◻◻Č if you're lucky. A 0 is actually a non printable control character and therefore often either skipped when printing or replaced with strange looking character like boxes. The 200 would be equivalent to Č in Windows-CP1250. It has no meaning on it's own when interpreted as UTF8 - it's the start of a 2 byte sequence and so the next 2 byte are required to determine which character to display.
You could have used
String.valueOf(200).getBytes( /* you should specify which encoding to use here */ );
which will create the "200" string first, then return you the required bytes for those 3 characters.
You should however use Java's character based IO facility: The numerous (and confusing) Reader & Writer implementations. They all(*^2) wrap an InputStream or OutputStream in the end and do the text to byte conversion for you.
PrintWriter is probably the most convenient to use but not without flaw: https://stackoverflow.com/a/15803472/995891
FileWriter should be avoided because you can't specify the encoding
The longer alternative route would be
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(file), encoding));
writer.write("Hello ");
writer.write(String.valueOf(200));
writer.newLine();
(*) most encodings are ASCII compatible for the first 127 characters which basically covers normal english text.
(*^2) nothing forces a Writer to output the characters into a stream, e.g. StringWriter. But they are used mostly that way.
I am reading values from a wav file; selecting only some of those values and writing them into another wav file (inorder to remove silence periods from the wav file). The problem is, that when I am creating this new wav file, it has background noise (which is not present in the original wav file). I am adding here the part of the code which is doing the file writing part:
private void writeToFile(String filePath) {
short nChannels = 1;
int sRate = 16000;
short bSamples = 16;
audioShorts = new short[size];
int nSamples = 0;
for(int i=0; i<size-1; i++) {
//audioShorts[i] = Short.reverseBytes((short)(zff[i]*0x8000));
if(slope[i] >= slopeThreshold) { // Voice region -- Should be written to output
audioShorts[nSamples] = Short.reverseBytes((short)(a[i]*0x8000));
audioShorts[nSamples+1] = Short.reverseBytes((short)(a[i+1]*0x8000));
nSamples += 2;
i++;
}
/*else
audioShorts[i] = 0;*/
}
finalShorts = new short[nSamples];
for(int i=0; i<nSamples; i++){
finalShorts[i] = audioShorts[i];
}
data = new byte[finalShorts.length*2];
ByteBuffer buffer = ByteBuffer.wrap(data);
ShortBuffer sbuf = buffer.asShortBuffer();
sbuf.put(finalShorts);
data = buffer.array();
Log.d("Data length------------------------------", Integer.toString(data.length));
RandomAccessFile randomAccessWriter;
try {
randomAccessWriter = new RandomAccessFile(filePath, "rw");
randomAccessWriter.setLength(0); // Set file length to 0, to prevent unexpected behaviour in case the file already existed
randomAccessWriter.writeBytes("RIFF");
randomAccessWriter.writeInt(Integer.reverseBytes(36+data.length)); // File length
randomAccessWriter.writeBytes("WAVE");
randomAccessWriter.writeBytes("fmt ");
randomAccessWriter.writeInt(Integer.reverseBytes(16)); // Sub-chunk size, 16 for PCM
randomAccessWriter.writeShort(Short.reverseBytes((short) 1)); // AudioFormat, 1 for PCM
randomAccessWriter.writeShort(Short.reverseBytes(nChannels));// Number of channels, 1 for mono, 2 for stereo
randomAccessWriter.writeInt(Integer.reverseBytes(sRate)); // Sample rate
randomAccessWriter.writeInt(Integer.reverseBytes(sRate*bSamples*nChannels/8)); // Byte rate, SampleRate*NumberOfChannels*BitsPerSample/8
randomAccessWriter.writeShort(Short.reverseBytes((short)(nChannels*bSamples/8))); // Block align, NumberOfChannels*BitsPerSample/8
randomAccessWriter.writeShort(Short.reverseBytes(bSamples)); // Bits per sample
randomAccessWriter.writeBytes("data");
randomAccessWriter.writeInt(Integer.reverseBytes(data.length)); // No. of samples
randomAccessWriter.write(data);
randomAccessWriter.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Your code snippet leaves some details out (like what slope and slopeThreshold are), so treat this answer as a suggestion only.
In general, this kind of chopping of audio data will introduce noise. It depends on where the cut happens. If the last sample before a cut is identical to the first one after it, you're safe, but otherwise you will introduce a click.
If the cuts are infrequent, you will be hearing individual clicks but if the chopping happens often enough, it might sound like continuous noise.
To do this without clicks, you would need to add a short fade out and fade in around each cut.
EDIT: try removing the "if (slope[i] >= slopeThreshold)" condition and see if the noise disappears. If so, the noise is very likely a result of what I described. Otherwise, you probably have some error with the various byte conversions.
Instead of:
data = new byte[finalShorts.length*2];
ByteBuffer buffer = ByteBuffer.wrap(data);
ShortBuffer sbuf = buffer.asShortBuffer();
sbuf.put(finalShorts);
data = buffer.array();
would not it be necessary to convert from short [] to byte [] ?
data = shortToBytes(finalShorts);
public byte [] shortToBytes(short [] input){
int short_index, byte_index;
int iterations = input.length;
byte [] buffer = new byte[input.length * 2];
short_index = byte_index = 0;
for(/*NOP*/; short_index != iterations; /*NOP*/)
{
buffer[byte_index] = (byte) (input[short_index] & 0x00FF);
buffer[byte_index + 1] = (byte) ((input[short_index] & 0xFF00) >> 8);
++short_index; byte_index += 2;
}
return buffer;
}
This work for me.