Hi, I am using android to capture audio from phone's microphone via android's AudioRecord class. This gives me raw pcm data in an byte[] array. I then convert the byte[] array to int[] array. I am then using this code to encode the pcm data to flac but I get noise only.
FLACEncoderflacEncoder=newFLACEncoder();StreamConfigurationstreamConfiguration=newStreamConfiguration();streamConfiguration.setBitsPerSample(16);streamConfiguration.setChannelCount(1);streamConfiguration.setSampleRate(32000);//streamConfiguration.setMinBlockSize(5292);//streamConfiguration.setMaxBlockSize(10584);//1)SetStreamConfigurationtoappropriatevalues.Afterastreamisopened,thismustnot//bealtereduntilthestreamisclosed.
flacEncoder.setStreamConfiguration(streamConfiguration);FLACFileOutputStreamflacOutputStream=newFLACFileOutputStream(newFile(recordingdirplusname));//2)SetFLACOutputStream,objecttowriteresultsto.
flacEncoder.setOutputStream(flacOutputStream);//3)OpenFLACStreamflacEncoder.openFLACStream();//4)SetEncodingConfiguration(ifdefaultsareinsufficient).
//EncodingConfigurationencodingConfiguration=newEncodingConfiguration();//flacEncoder.setEncodingConfiguration(encodingConfiguration);int[]intbuffer=convertToIntArray(buffer); // buffer is the raw pcm data byte[] bufferflacEncoder.addSamples(intbuffer,(intbuffer.length/2));intencoded=flacEncoder.encodeSamples((intbuffer.length/2),false);
and this is the method I use to convert byte[] to int[]:
I can't be certain without more information on your source format and how you're reading them from the AudioRecord instance, but It looks like your problem will be with the source format conversion to int. If you're reading 16-bit PCM from the AudioRecord object, make sure you're reading those into a short[] and not a byte[] https://developer.android.com/reference/android/media/AudioRecord.html#read(short[],%20int,%20int)
If you use a byte[] for 16-bit(which is deprecated but should work), it will split the samples across two bytes and those must be combined into a single value when converting to int. You can either do that conversion, or read directly into a 16-bit short from AudioRecord.
If this doesn't solve the problem, I'd be happy to look at it deeper if you provide the code for reading your samples, and any information you have on what format is used on the source side.
Good luck
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have another question, how can I resume recording at the end of a previously saved flac file. When I try to add encoded data at the end of previously saved flac file, the recording resumes but there is an audible gap in between when the last recording was stopped and then resumed. What is the correct way to do this in javaFlacEncoder? Thanks
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Unfortunately, there's not a built-in way to properly append new data directly to a previously saved file using this encoder. Information about the encoded data(md5-hash, length, number of frames, etc) is kept while encoding, and this information is written out to the header space of the FLAC stream when the stream is closed. Currently, there is no method of restoring the encoder state necessary to write a proper header to the existing stream if appending new data.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, FlacEncoder worked before but now it is not working properly. Some media players are unable to play the recording and the others that play do not display duration and provide seek options. Java code and the recording is attached. Can you tell me where is the problem?
I'm not actually certain at the moment what might be the problem. It sounds like the FLAC stream is not being finalized by the line, "flacEncoder.encodeSamples(flacEncoder.samplesAvailableToEncode(), true)"
When the flac stream is finalized, various details needed for seeking(including length of stream and min/max encoded frame size) are written to the front of the stream if possible(this step will be ignored if the stream isn't seekable, but yours should be since you're writing to a file).
First thing I'd check is that the return value from the above line is equal to the value given to encodeSamples, "flacEncoder.samplesAvailableToEncode()". Based on your code it should be equal, but being less than the number of samples requested to encode would indicate the stream is not being finalized. I've loaded the flac file you posted into a hex editor and it looks like the header is indeed not being updated; checking the return value would give more information on what the encoder is actually attempting to do. In any case, the file should remain playable even if the stream isn't finalized. There's one value in the written header(min frame size), that I noticed may not be set to the correct default. I'll double check the FLACEncoder source code tomorrow when I get a chance; in the meantime, feel free to post back if you check that return value or otherwise make progress.
Also, while I don't see it as part of this problem, you should probably be adding samples using the returned value numRead from AudioRecord.read() in place of (int buffer.length), as there may be some cases where AudioRecord doesn't return a full block(this shouldn't prevent the file from playing or seeking, but could introduce random noise into the stream).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I just checked the value returned by '"flacEncoder.samplesAvailableToEncode()" and "flacEncoder.encodeSamples(flacEncoder.samplesAvailableToEncode(), true);" are the same. I check again the value of '"flacEncoder.samplesAvailableToEncode()" and it is equal to 0.
I am using (int buffer.length) to give sample count parameter and not numRead.
I have attached a recording that was recorded a while back from the same source code. I haven't changed anything in the source code that I know of. This recording is playing normally in all media players.
Interesting. The header for the #277 file is properly finalized, while the header for #388 is not. Does your code only occasionaly fail to produce a proper file now, or always fail? For example, did the run that verified the two values were equal also produce a good file, or a bad file? My point is I'm curious if something is only occasionally interrupting that code before it reaches the point of finalizing the header.
I did check the library source though, and there is indeed a bug that might cause some players to fail to play the file outright if the header isn't finalized(it must've caused problems for others, I'm glad you've posted here). I'll post an update to fix this as soon as I'm able. The update won't fully fix your problem though, as something is still preventing the stream headers from being finalized in the first place. The bug-fix should allow files to remain playable, but they won't be seekable or have a known length.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have fixed my problem. I had imported javaFlacEncoder source code and not the jar file. So, I deleted the source code and imported the jar file as a library. Before this, my code was failing everytime on all occassions but now it is encoding properly and producing good files that are seekable and have a known length.
I will be waiting for the update though.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
java.lang.NullPointerException: Attempt to read from field 'int javaFlacEncoder.BlockEncodeRequest.count' on a null object reference
at javaFlacEncoder.FLACEncoder.samplesAvailableToEncode(FLACEncoder.java:681)
This happens sometimes and not all the times. What can I do to properly finalize?
Last edit: Muhammad Moemin Ali 2017-09-22
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I haven't seen that before but it sounds like an internal bug in the flac library. I'll check it out. In the meantime, can you tell me the conditions of the failure(which javaFlacEncoder version, encode settings used, is this still 16-bit mono as above?)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Version is 0.3.1 , 16-bit mono. I reproduced these errors on the following sampling rates:
48 kHz, 44.1 kHz, 32 kHz, 22.05 kHz, 16 kHz. 11.025 kHz. Haven't seen it on 8 kHz till now.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've been looking at that section of code and I think I found the bug. There's an unchecked access on a potentially null object in the method samplesAvailableToEncode(). If it happens that the number of samples added up to the point you call samplesAvailableToEncode() is a perfect multiple of the block-size used by the encoder, it should trigger the exception(or if no samples were ever added). I'll create a test case and verify this later tonight. Hopefully I will get the update posted tomorrow to fix it.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, I am using android to capture audio from phone's microphone via android's AudioRecord class. This gives me raw pcm data in an byte[] array. I then convert the byte[] array to int[] array. I am then using this code to encode the pcm data to flac but I get noise only.
and this is the method I use to convert byte[] to int[]:
What am I doing wrong here? Why do I only get noise and no sound in the FLAC file that is produced? Please help me on this. Thanks.
Last edit: Muhammad Moemin Ali 2017-08-02
Greetings!
I can't be certain without more information on your source format and how you're reading them from the AudioRecord instance, but It looks like your problem will be with the source format conversion to int. If you're reading 16-bit PCM from the AudioRecord object, make sure you're reading those into a short[] and not a byte[] https://developer.android.com/reference/android/media/AudioRecord.html#read(short[],%20int,%20int)
If you use a byte[] for 16-bit(which is deprecated but should work), it will split the samples across two bytes and those must be combined into a single value when converting to int. You can either do that conversion, or read directly into a 16-bit short from AudioRecord.
If this doesn't solve the problem, I'd be happy to look at it deeper if you provide the code for reading your samples, and any information you have on what format is used on the source side.
Good luck
Hi, I did what you said and now I am able to successfully record in flac format. Thanks very much for the help!
Last edit: Muhammad Moemin Ali 2017-08-02
I have another question, how can I resume recording at the end of a previously saved flac file. When I try to add encoded data at the end of previously saved flac file, the recording resumes but there is an audible gap in between when the last recording was stopped and then resumed. What is the correct way to do this in javaFlacEncoder? Thanks
Unfortunately, there's not a built-in way to properly append new data directly to a previously saved file using this encoder. Information about the encoded data(md5-hash, length, number of frames, etc) is kept while encoding, and this information is written out to the header space of the FLAC stream when the stream is closed. Currently, there is no method of restoring the encoder state necessary to write a proper header to the existing stream if appending new data.
Hi, FlacEncoder worked before but now it is not working properly. Some media players are unable to play the recording and the others that play do not display duration and provide seek options. Java code and the recording is attached. Can you tell me where is the problem?
I'm not actually certain at the moment what might be the problem. It sounds like the FLAC stream is not being finalized by the line, "flacEncoder.encodeSamples(flacEncoder.samplesAvailableToEncode(), true)"
When the flac stream is finalized, various details needed for seeking(including length of stream and min/max encoded frame size) are written to the front of the stream if possible(this step will be ignored if the stream isn't seekable, but yours should be since you're writing to a file).
First thing I'd check is that the return value from the above line is equal to the value given to encodeSamples, "flacEncoder.samplesAvailableToEncode()". Based on your code it should be equal, but being less than the number of samples requested to encode would indicate the stream is not being finalized. I've loaded the flac file you posted into a hex editor and it looks like the header is indeed not being updated; checking the return value would give more information on what the encoder is actually attempting to do. In any case, the file should remain playable even if the stream isn't finalized. There's one value in the written header(min frame size), that I noticed may not be set to the correct default. I'll double check the FLACEncoder source code tomorrow when I get a chance; in the meantime, feel free to post back if you check that return value or otherwise make progress.
Also, while I don't see it as part of this problem, you should probably be adding samples using the returned value numRead from AudioRecord.read() in place of (int buffer.length), as there may be some cases where AudioRecord doesn't return a full block(this shouldn't prevent the file from playing or seeking, but could introduce random noise into the stream).
I just checked the value returned by '"flacEncoder.samplesAvailableToEncode()" and "flacEncoder.encodeSamples(flacEncoder.samplesAvailableToEncode(), true);" are the same. I check again the value of '"flacEncoder.samplesAvailableToEncode()" and it is equal to 0.
I am using (int buffer.length) to give sample count parameter and not numRead.
I have attached a recording that was recorded a while back from the same source code. I haven't changed anything in the source code that I know of. This recording is playing normally in all media players.
Interesting. The header for the #277 file is properly finalized, while the header for #388 is not. Does your code only occasionaly fail to produce a proper file now, or always fail? For example, did the run that verified the two values were equal also produce a good file, or a bad file? My point is I'm curious if something is only occasionally interrupting that code before it reaches the point of finalizing the header.
I did check the library source though, and there is indeed a bug that might cause some players to fail to play the file outright if the header isn't finalized(it must've caused problems for others, I'm glad you've posted here). I'll post an update to fix this as soon as I'm able. The update won't fully fix your problem though, as something is still preventing the stream headers from being finalized in the first place. The bug-fix should allow files to remain playable, but they won't be seekable or have a known length.
I have fixed my problem. I had imported javaFlacEncoder source code and not the jar file. So, I deleted the source code and imported the jar file as a library. Before this, my code was failing everytime on all occassions but now it is encoding properly and producing good files that are seekable and have a known length.
I will be waiting for the update though.
Hi, sometimes while closing the stream and finalizing using
This Fatal Exception is thrown
This happens sometimes and not all the times. What can I do to properly finalize?
Last edit: Muhammad Moemin Ali 2017-09-22
I haven't seen that before but it sounds like an internal bug in the flac library. I'll check it out. In the meantime, can you tell me the conditions of the failure(which javaFlacEncoder version, encode settings used, is this still 16-bit mono as above?)
Version is 0.3.1 , 16-bit mono. I reproduced these errors on the following sampling rates:
48 kHz, 44.1 kHz, 32 kHz, 22.05 kHz, 16 kHz. 11.025 kHz. Haven't seen it on 8 kHz till now.
I've been looking at that section of code and I think I found the bug. There's an unchecked access on a potentially null object in the method samplesAvailableToEncode(). If it happens that the number of samples added up to the point you call samplesAvailableToEncode() is a perfect multiple of the block-size used by the encoder, it should trigger the exception(or if no samples were ever added). I'll create a test case and verify this later tonight. Hopefully I will get the update posted tomorrow to fix it.
I just posted an update that should fix these two bugs.
I confirm that the update fixed the bugs.