Yet another SimpleAudioLogger

WMXZ

Well-known member
I implemented another AudioLogger
it takes i2s input (dual/quad) and passes on to usb and uSD
I tested it with ICS4343x digital microphones

it consist on an ino file and two include files
the file "record_logger.h" implements a template based "multi-channel uSD logger"
the file "mfs.h" acts as interface to a file system. here, the selected file system is latest Bill's SdFs https://github.com/greiman/SdFs
Note, as the standard "Audio.h" includes the stock SD.h library and therefore a lot of redefine errors, I chose to include individually the needed Audio objects

To learn use of templates, the AudioRecordLogger is implemented as template to avoid "defines" for array declarations.

Note further, with quad I2S the amount of memory required for overrun-free can be significant and requires 'good' uSD cards (which I do not have!)

The overrun situation needs proper design.
For this test I chose to ignore new data if buffer overrun situation occurs.

I final application would further need a header/trailer for data relevant meta data


created GitHub for this sketch
https://github.com/WMXZ-EU/AudioSimpleLogger
copy into sketch folder (not library)

Edit removed attachment as sketch is on GitHub
 
Last edited:
Hello WMXZ,

Thanks for share you work!
Have already download, save and load the new SDFs library, but after reading your comments could understand my connections are diferent from yours...
// for ICS4343x microphones
// T3.2 T3.6 Mic1 Mic2 Mic3 Mic4
// GND GND GND GND GND GND
// 3.3V 3.3V VCC VCC VCC VCC
// Pin9 Pin9 CLK CLK CLK CLK
// Pin23 Pin23 WS WS WS WS
// Pin13 Pin13 SD SD -- --
// Pin30 Pin38 -- -- SD SD
// GND GND L/R -- L/R --
// 3.3 3.3 -- L/R -- L/R

And I do have, already solder on a protoboard to despiste bad connections:
// T3.6 Mic1
// GND GND
// 3.3V VCC
// Pin11 SCK supose is the same as CLK
// Pin12 WS
// Pin13 SD
// GND L/R

and from that I know it will not work for me :) Is there a way to modify this pins in the sketch?
Thanks,
Tim
 
Tim,
the connection you have selected is not for the stock I2S object in the audio library, which works also with the SGT5000 audio board.
If you need alternative connection you need an alternativ I2S driver
send me PM if you need modified I2S driver

Edit: put some modified I2S input driver to the GitHub location. Use only with care.
Preferred solution is to use configuration that is consistent with PJRC Audio board.
 
Last edited:
Edit: put some modified I2S input driver to the GitHub location. Use only with care.
Preferred solution is to use configuration that is consistent with PJRC Audio board.

Removed modified I2S input driver from GitHub, but added a small function to main ino file that switches the pins from PJRC Audio setup to alternative RX_ONLY mode. (Relevant I2S registers are also modified)
 
Hi Walter,

I have some problems getting started with your sketch:

* I would like to use a ICS43434 breakout board (by onehorse from Tindie) with your logger sketch to record audio on an SD card with a Teensy 3.6.

* Used the following github source and installed the uSDFS library into my Teensyduino installation Arduino 1.8.5 / Teensyduino 1.40

https://github.com/WMXZ-EU/uSDFS

* used the example I2S_logger

Two problems arise now:
* lines 462 ff. in sdio.c were lacking some brackets --> fixed that, example uSDFS_test is now compiling
* ICS43432.h is not found --> I could not find a suitable library in the internet

Could you point me in the right direction, whether I am doing something wrong here or where I could find the ICS43432 library?

Thanks in advance!

All the best,

Frank
 
Hi Walter,

I have some problems getting started with your sketch:

* I would like to use a ICS43434 breakout board (by onehorse from Tindie) with your logger sketch to record audio on an SD card with a Teensy 3.6.

* Used the following github source and installed the uSDFS library into my Teensyduino installation Arduino 1.8.5 / Teensyduino 1.40

https://github.com/WMXZ-EU/uSDFS

* used the example I2S_logger

Two problems arise now:
* lines 462 ff. in sdio.c were lacking some brackets --> fixed that, example uSDFS_test is now compiling
* ICS43432.h is not found --> I could not find a suitable library in the internet

Could you point me in the right direction, whether I am doing something wrong here or where I could find the ICS43432 library?

Thanks in advance!

All the best,

Frank
Frank,
closing parenthesis are added (thanks for finding that, I copied the lines from FrankB)
The ICS43432 files are in the WMXZDevices library (also on GitHub).

If you are interested, I have a new approach for logging that used Bill Greiman's sd filesystem
It is called BasicAudioLogger now on github (it contains a couple of Audio input devices; ignore the visual studio files of this quick and dirty upload)
The interesting part may be a modification to audio library record_queue that allows queuing to be used for disk buffering

best
Walter
 
Hi Walter,

thanks a lot, that looks excellent! Will try it in the next days!

Yes, I am definitely interested in the new logging approach! During the last weeks, I realized that even with the audio library and the many recording approaches and existing code here in the forum, logging audio to an SD card is not a particularly easy task, especially if you are after a really accurate recording without glitches and similar annoying things . . . :).

The queuing approach sounds most interesting. Will come back to you when I made some experiments with that.

The project I want to use this for, is an experimental low cost sound-triggered field recorder for amphibians, to be used here in Central Europe as well as in the tropics for scientific purposes (20 Hz to 20kHz, not ultrasound this time :)).

Thanks again! Will report back here!

All the best,

Frank
 
The project I want to use this for, is an experimental low cost sound-triggered field recorder for amphibians, to be used here in Central Europe as well as in the tropics for scientific purposes (20 Hz to 20kHz, not ultrasound this time :)).

Frank,
the BasicAudioLogger is indeed a down-stripped version of a time-triggered field recorder for ecological research using I2S mems.
an extension to event-triggered logging would be interesting to me.
If you are interested to join forces you can ping me off-line.
 
Hi Walter,

thanks a lot for your logger!

Just tried the "BasicAudioLogger" and it seems to work quite well. Just some first observations from one and a half hour of experimenting:

* I changed myAPP.cpp in line 132 to the following:
AudioStereoMultiplex mux1((Fxn_t)myUpdate);
formerly was: // AudioStereoMultiplex mux1((Fxn_t)myUpdate());
--> after that it compiled nicely

* in the first trials, the logger refused to use my SD cards. Only after I erased and formatted a SanDisk Ultra 64GB with "SDFormatter", it started to record [but my SD cards are really used in many many applications, so it could be that there was something on it that the logger did not like]

* playing back the recordings is a bit demanding. I used audacity and imported as raw with settings:
- signed 16-bit PCM
- Little endian
- 2 channels stereo (I used stereo I2S setting, although I have only one mic attached --> will try later with two mics and real stereo input)
- sample rate 48000 (thats the sample rate I put into your sketch)

* the audio level from my MEMS I2S mic ICS43434 (onehorse / Pesky) was way too low and the sound in the recordings was very faint. I put a multiplier (* 20) into audio_multiplex.h lines 52&53 and lines 59&60 --> after that the audio level of the recordings was acceptable with excellent audio quality

* not a single glitch or noise or anything annoying could be heard! Never had that kind of reliability with any of the available Teensy recording sketches I tried (and I tried a lot of them . . .) --> excellent!!!

I have some questions:

1.) are the playback options in audacity the right ones? signed 16bit PCM, little endian ?
2.) is there a reason not to write a wav header to the file which includes that information (16 bit little sample rate . . .) ? That would enable to import the files more easily into an audio software
3.) I am probably using the wrong place to adjust the software gain (in audio_multiplex.h). Is there a prefered standardized way to do this?
4.) connected question: where could I start a trial to implement a trigger for starting a recording?

Will play around some more with the sketch and try to connect the second I2S mic and report my results again here.

All the best, have fun with the Teensy!

Frank
 
also managed to connect two mics to record in Stereo !

// for ICS4343x microphones
T3.6 Mic1 Mic2
GND GND GND
3.3V VCC VCC
Pin9 CLK CLK
Pin23 WS WS
Pin13 SD SD
GND L/R --
3.3V -- L/R

Works nicely!
 
Hi Walter,

I hope it is ok that I spam your thread with my observations ;-). If not, drop me note.

Here is a comparison of recordings made with ONE mic and TWO mics (MONO / STEREO)

I recorded 30 sec of music and 30 sec of silence (well, as silent as one can be without acess to a real silent audio studio) and analysed the recordings using Audacity:

https://github.com/DD4WH/quakophon/files/1766790/Basic.Audio.Logger.ICS43434.comparison.pdf

As you can see, there is low frequency noise in the recordings:

STEREO: noise peak at around 31Hz with -45dB in the silent recording, however this peak decreases to -66dB when there is input to the mic --> music recording . . .
MONO: noise peak at around 48Hz with -44dB in the silent recording, this peak is also visible with -39dB with music, however could also be part of the music . . .

When we look at frequencies above 500Hz, they have < -90dB level in "silence" and can be as loud as -22dB or higher in music, so it seems a dynamic range of 70dB can be easily achieved.

- The two mics are connected to the Teensy with breadboard clip cables of 10cm lengths
- Used Basic Audio Logger example
- used 48ksps sample rate
- used audacity to analyse the file --> Import raw with signed 16bit PCM, stereo, little endian
- normalized the file (which contains 30sec of music and 30sec of silence) with Audacity
- Analysed the parts of the audio file with music/silence with a 65536 point FFT in audacity with von Hann window and log frequency axis

So, my conclusions would be:

* about 70dB dynamic range is easily achievable for higher frequencies
* there is an issue with the low frequency range, however, the low frequency noise is dependent on the input sound level? Is there an AGC built into the I2S mic!?
* there is no real difference whether you use one or two mics for recording

All the best,

Frank
 
* the audio level from my MEMS I2S mic ICS43434 (onehorse / Pesky) was way too low and the sound in the recordings was very faint. I put a multiplier (* 20) into audio_multiplex.h lines 52&53 and lines 59&60 --> after that the audio level of the recordings was acceptable with excellent audio quality

I'm working on that
Walter
 
Frank,
I have an upgrade on GitHub, that should allow digital gain setting for 24-bit Mems microphones.

the digital gain is to be inserted at the DMA ISR level, therefore I constructed a new I2S_32 class to cover this case.

I do not know the origin of the VLF noise peaks. Do they vary with sampling frequency? if yes then they are electronic artefacts. If not they are acoustics.

Concerning sound-trigger, I would insert a processing unit into the data stream that takes all data, ignores the noise but detects the signal and passes the data then on to the queue.

I also would always use stereo mics to allow some direction finding.

What are the sound-presence criteria?
How much pre-trigger sound you want to save?
 
2.) is there a reason not to write a wav header to the file which includes that information (16 bit little sample rate . . .) ? That would enable to import the files more easily into an audio software

no particular reason. Only drawback I see, is that wav-header has info on actual size of file, which is only known at the end, consequently earlier data must be read/written again.
 
Hi Walter,

thanks a lot for this update!

I gave it a try and I was able to change gain by changing the I2S data bit shift in line 221 in myAPP.cpp

For recording near field a 12 bit shift is good, using a shift of 8 bits makes the recording too noisy and too sensitive. I was wondering whether it would be worth using the bit shift for a slowly adjusting software AGC? Just one first thought.

The VLF noise scales with sample rate and with the number of mics connected. So it is probably digital artefact/noise.

What are the sound-presence criteria?
How much pre-trigger sound you want to save?

* a sound level threshold, which is predefined when uploading the sketch --> it should check, whether the peak sound level has been higher than the threshold for longer than 10ms or so. However, when looking at the amount of VLF noise present, it could be nice to have a prefilter before the threshold detection to suppress all frequencies below - say 150Hz, but I would have to talk to my amphibian specialist to ask whether there are amphibians with such low voices (I suspect, there aren´t).

* it should be sufficient to save a few ms of pre-trigger sound, depending on the reaction time of the whole system, because the only thing this should prevent is that when a triggered recording starts, the beginning of an amphibian call is cut off.

Walter, your code is quite complex for me to understand and I have only limited knowledge of eg. interrupts/I2S handling etc. So it is quite hard for me to find out where is the most promising place to start with an extension for a triggered recording. I am highly motivated to help and expand the code. So it would be nice if you could point me in a specific direction or to a specific point in the code where I could try something :).

re: WAV header
If we have scheduled recordings or triggered recordings with predefined recording lengths (when a trigger is above the threshold, one minute is recorded, for example), we would know the length of the file in advance. So we could write that into the header, when opening the file. As I understand the code, the header is 512bytes at the moment. But a WAV header is only 44 bytes, so the rest is empty?

All the best,

Frank
 
Last edited:
Walter, your code is quite complex for me to understand and I have only limited knowledge of eg. interrupts/I2S handling etc. So it is quite hard for me to find out where is the most promising place to start with an extension for a triggered recording. I am highly motivated to help and expand the code. So it would be nice if you could point me in a specific direction or to a specific point in the code where I could try something :).
I'm already playing with that
re: WAV header
If we have scheduled recordings or triggered recordings with predefined recording lengths (when a trigger is above the threshold, one minute is recorded, for example), we would know the length of the file in advance. So we could write that into the header, when opening the file. As I understand the code, the header is 512bytes at the moment. But a WAV header is only 44 bytes, so the rest is empty?
I will think about this.
I have done that in the past, so a solution could be possible
 
So it would be nice if you could point me in a specific direction or to a specific point in the code where I could try something :).

I added a new Audio object to the GitHub that could be used to do some processing.
At the moment is simply passes on the data,
The nice thing with Paul's Audio library is that you only have to do the processing in the update method and not to worry about the overall architecture.
(It has its limitation though)

Edit: corrected some error @1840
 
As said earlier, I added a processing module to https://github.com/WMXZ-EU/BasicAudioLogger that allows data processing before saving to disk
At the moment as an example, a simple threshold detector is implemented that only passes data to be saved on disk once a threshold value is exceeded.
A single pre-trigger buffer is implemented.
 
Hi Walter,

thanks for the addition!

Took me some two hours now trying to understand what the new addition to the sketch does exactly . . .

Let me try to summarize how I understood it:

- I2S 24bit data from the mic is being acquired and pushed to
- m_process, where the audio data is only pushed further to mux, if the highpass-filtered audio exceeds the threshold --> if so, three blocks are being sent, before a new decision is being made, whether the data is louder than the threshold
- then the audio is muxed/interleaved and pushed to the queue
- if the queue has data, it is written to the SD card

However, I have not understood how the timer comes into play . . .
At the moment I can insert whatever I want into the threshold, it always records according to the setting of the timer, not according to the threshold.

From my understanding, the intended behaviour would be:
- does the timer say, it is time for recordings? if yes -->
- is the audio louder than the threshold? if yes -->
- write to SD

But I am sure I am not seeing the whole thing in the right way. I seem to be missing important parts in the sketch.
I will try again tomorrow with a fresh head . . .

Thanks Walter, this is some very good education for me (in C --> all those pointers and interrupt stuff . . . and in the inner bits of the audio lib ;-)) ! (Apart from being a very helpful contribution to the amphibian recorder project)

All the best,

Frank
 
Hi Walter,

thanks for the addition!

Took me some two hours now trying to understand what the new addition to the sketch does exactly . . .

OK,
The whole thing was growing over time.

objectives:
- provide an example for high data rate logging
- use concept behind audio library
- allow custom sample rates for standard audio interfaces
- allow timed acquisition as typically in field work where reducing power consumption is important (e.g 1 minute every 5 minutes but only at sunrise and sunset), but also continuous recordings
- only store data to disk when certain conditions are met (i.e. signals detected) (latest addition)

The whole program is not a final product, but a framework (and a hack) to be build on.
The skeleton alone could work but I see a lot of customization necessary and possible (e.g. what to put into a header etc., )
 
However, I have not understood how the timer comes into play . . .
At the moment I can insert whatever I want into the threshold, it always records according to the setting of the timer, not according to the threshold.

From my understanding, the intended behaviour would be:
- does the timer say, it is time for recordings? if yes -->
- is the audio louder than the threshold? if yes -->
- write to SD
Yes that is correct
If the threshold has no effect, then there is a bug in the program.
(I admit I programmed that without testing it with real input)

The timed acquisition is on two levels
assume you wanted to record sounds only 2hours at sunrise and 3 hours sunset, say 1 minute every 5 minutes.
the program will hibernate the teensy outside the times of interest and when not acquiring data.

I admit, the idea is simple but the implementation is somewhat complicated, and is not grown overnight. (I thank Timoteo for helping me on that aspect)

while acquiring data, the program can set to store only data of interest to uSD. At the moment a simple threshold detector is given as example and must be verified. Other processing should be possible.
 
Back
Top