opencardev / snd-i2s_rpi

Linux kernel driver/DKMS for the Adafruit I2S MEMS Microphone
42 stars 27 forks source link

Volume #4

Open StuartIanNaylor opened 3 years ago

StuartIanNaylor commented 3 years ago

Is the volume low because the default data is 32bit whilst the mics are likely creating a 24bit data stream?

static const struct snd_soc_pcm_stream dai_params = {
      .formats = SNDRV_PCM_FMTBIT_S24_LE,
      .rate_min = 8000,
      .rate_max = 48000,
      .channels_min = 2,
      .channels_max = 2,
};

Haven't a clue how you define the format but generally with I2S its 24bit (the mics probably are) but looking at the Pi examples it would seem we have 32bit which is really only a computer mechanism for headroom and register ease. I pasted the above as a pure guess but somewhere you should be able to define parameters then the source will always be 24 bit and when you resample the level will be equivalent to the original 24bit source as those extra 8 bits of 32bit will just drop the volume without scaling. They will be the MSBs as well so likely to have much effect on volume as there is no difference with raw 24bit & 32bit data but how its assigned greatly affects volume which prob corresponds to the softvol with 30db gain as that is a lot of gain but does the job.

Nitnelav commented 3 years ago

Hi, the volume is low because the mems has a 18bit precision (see the SPH0645LM4H-B datasheet) : "The Data Format is I2S, 24 bit, 2’s compliment, MSB first. The Data Precision is 18 bits, unused bits are zeros." BTW, the adafruit arduino code (after capture) effectively converts the data to 18bits before scaling to 32bits integers.

To answer your first question, in ALSA, the format is defined in weird places. In this case, the compatible formats are defined in the devicetree (you can google that, ... it's complicated). After that the format you actually use is defined by the user when setting up the device for capture (via libasound or via arecord). But you can make ALSA convert everything for you if you use "plughw" instead of "hw" ...

Consider this a list of keywords to search if you want to know more :)

StuartIanNaylor commented 3 years ago

That is great I just saw the mention of why is the volume low and as said had a hunch it would be bit precision. Haven't used the SPH0645LM4H-B and 18bit is a surprise but thought it would be 24/32 not 18/24 mismatch.

I have used INMP441 with your driver and the softvol several months ago and I can not remember but pretty sure they where 24 bit. I will have to check again.

My dev & C is woeful and the above was about best I could do in reply to why the volume was low.

https://invensense.tdk.com/wp-content/uploads/2015/02/Low-Noise-Directional-Studio-Microphone-Reference-Design1.pdf

Maybe the above might interest you and rather than L/R we could have F/R and the eventual mono directional mems? Wishful thinking from me but with alsaeq the coding is miminal but as I say beyond me :)

Thanks

StuartIanNaylor commented 3 years ago

PS I did have a look at SPH0645LM4H-B and yeah surprisingly 18 bit but another thing I noticed is they will push to 64kHz SR which means 5.4mm samples and higher order endfires or higher the notch null will become. That is one advantage they do have over the INMP441 as think they are limited to 48Khz

StuartIanNaylor commented 3 years ago

Its not just precision its just the bare minimum to get I2S working is there but there is formatting and clocking information missing.

The Data Format is I2S, 24-bit, 2’s compliment, MSB first

I can tell from wav input that the click and squiggle as you start recording is due to wrong formatting.

On a ESP32 using the same mics INMP441 which are also I2S, 24-bit, 2’s compliment, MSB first. I have been using https://github.com/atomic14/ICS-43434-breakout-board/blob/main/sketch/sketch.ino Where I have to change .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S), to I2S_COMM_FORMAT_STAND_MSB

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html

I2S_COMM_FORMAT_STAND_I2S = 0X01
I2S communication I2S Philips standard, data launch at second BCK

I2S_COMM_FORMAT_STAND_MSB = 0X03
I2S communication MSB alignment standard, data launch at first BCK

Because there is no declaration I guess the I2S Philips standard is the default as you do get that starting input squiggle if incorrectly set.

My C is non existent but if you ignore all the soundcard controls and just focus on the clocking and format parts this repo should help much. https://github.com/pguyot/wm8960

Liam Girdwood who provided the Linux source https://github.com/torvalds/linux/blob/d2912cb15bdda8ba4a5dd73396ad62641af2f520/sound/soc/codecs/wm8960.c is prob a busy guy but he is extremely kind and helpful.

The docs are not too bad https://01.org/linuxgraphics/gfx-docs/drm/sound/soc/clocking.html

But yeah its got nothing to do with precision of the mems its just that the driver provides no format or clocking info and the raw info just ends up in the 32bit words of the 64bit I2S packet.

Can we leave this open as I am not worthy to make changes I might have a hack if I have the time as looking I think I can sort a few things out by just using https://github.com/pguyot/wm8960 as a reference as know it does work.

https://drive.google.com/open?id=1FQkvVXz-4xSGMut8JCYTe96_uW_Absuy is 16bit 44100hz Stereo raw on the ESP32 with I2S_COMM_FORMAT_STAND_MSB the code actually converts to 16bit but as you will see because of the clocking and format it is scaled correctly.

I will come back to this and give it a go but if this issue is open maybe someone who is a little more C orientated will give it a go.

thisiscam commented 1 year ago

Is there any update on this? It would be nice if I can get regular volume out of this driver