xiph/flac

Distored flac output with MCU port

Closed this issue · 9 comments

I try to port flac-1.4.2 encoder for MCU so I turn off all the peformance features.
Then I try simulate the port with Qt app (does not need to be Qt because that is the dev enviroment I have)

input: 123.raw (16 bit pcm 16khz) from adacity
The playback of the output out.flac seems distorted

Then I try turn on and off FLAC__INTEGER_ONLY_LIBRARY, the output are different between integer and float and both have the distored effect.

Is my port bad or something else?

See flac4.zip

ktmf01 commented

I think you made a mistake in how samples are to be lined up for FLAC__stream_encoder_process_interleaved. The following line doesn't make any sense to me

pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);

What are you trying to do with that?

hi @ktmf01 , that is simply converting 16 bits signed interleaved PCM stream into 32 bits signed interleaved data.
You can find similar code elsewhere:

ktmf01 commented

What happens if you change

const FLAC__int8 *buffer = (const FLAC__int8 *)data.constData();

to

const FLAC__uint8 *buffer = (const FLAC__uint8 *)data.constData();

@ktmf01 : thank you so much. Solved. That work!
The ouput are the same with and without FLAC__INTEGER_ONLY_LIBRARY.

ktmf01 commented

@robc2023 Just out of curiousity, what MCU are you targetting?

I saw you're using blocksize 64. This will severely harm compression. It might not be a big problem for your certain application of course, but if you would like a little more compression, I would suggest disabling LPC to free up memory so a larger blocksize can be chosen. You can disable LPC by choosing compression levels 0, 1 or 2, or explicitly setting it to 0 with FLAC__stream_encoder_set_max_lpc_order, which must be used after setting a compression level, if you're setting any. You can also disable LPC by setting FLAC__INTEGER_ONLY_LIBRARY, because there is currently no integer only LPC implementation in libFLAC.

Here is my target Renesas RA6M1. It has a shiny less than 250kb and my budget is for the compression is around 40kb. It has 2xI2S microphones with 18 bits PCM with 16kHz target., the data is streamed to an SD-card which is way too slow. So I turn to FLAC, and with my qt-app testing it shows 0.2 compress ration which is perfect. However when I get to use the actual hardware it running into various memory issue as you described.

I will try to disable LPC as you mention, and will let you know the outcome. Thank you.

I learnt these today when running FLAC in the RA6M1, and it hitting many memorry limit issues so I have to reduce the block size to 16, and the compress ratio is about 0.8 -terrible. It is not memory friendly to my little MCU.

I found FLAC__bitreader_init(), and FLAC__bitwriter_init() allocate 8k blocks (FLAC__BITREADER_DEFAULT_CAPACITY, FLAC__BITWRITER_DEFAULT_CAPACITY). I made this to be smaller but I don't know the consequence of this . Have you any advice?

I also see the FLAC reallocates many memory block - this is definite not embedded friendly, my memory manager is not doing well and cause memory fragmentation. Any advice on reduce memory usage is wellcome.

Furthermore is there a way to stop it from growing memory (bitwriter_grow_()) or bound to an upper limit?

ktmf01 commented

That is not a lot of memory indeed, so you'll have to make some choices. I think the easiest one is not using the verify option, that probably uses quite a bit of memory, as there will be no calls to bitreader_init anymore. The consequence of lowering the default capacity is that the bitwriter needs to be grown more often.

Considering an upper limit, it should be about equal to the input size. So, if you have a blocksize of 64 and 16 bps, 2 channels, the maximum expected framesize would be 256 byte, so the upper limit would that too.

So, I'd suggest disabling the verify feature, disabling the use of LPC, increasing the blocksize to at least 64 but preferably larger (better compression -> lower memory usage), and lowering the FLAC__BITWRITER_DEFAULT_CAPACITY to 2k.

What would be the value for FLAC__stream_encoder_set_max_lpc_order? I assume 0

Your suggest reduce the memory usage to about 17Kb If I change FLAC__BITWRITER_DEFAULT_CAPACITY to 1K, it is further reduced the total memory usage to 9Kb. And the compress ratio for the sampe data is still around 0.21. Awesome!

ktmf01 commented

Yes, that would be zero. However, compiling with FLAC__INTEGER_ONLY_LIBRARY also disables LPC and might help bringing binary size down, if that is a problem. That is because FLAC__INTEGER_ONLY_LIBRARY completely removes the LPC code instead of only not using it.

Nice to see that it helps a lot. Maybe you can increase blocksize a bit further, that might help with SD write speeds (as you're writing larger 'packets'). You might need to increase the default capacity a bit if you increase the blocksize though.