Audio Recording / Logging to SD card --> microSoundRecorder

I just found this thread while looking for how to write WAV rather than just RAW to an SD card. What a great project! (And thanks for using the Tympan BTW.)

And, Walter, thanks for packaging up your code on GitHub so that I can learn from it.

Chip
 
We now use a total of 12 microSoundRecorders for recording nocturnal Crex crex (corn crake). Thank you again, Walter, for providing us with this Teensy 3.6 recording tool with your software!

Our hardware setup now consists of a plastic lunch box with:

* two LiIon batteries of type 18650 with 3.7 Volts and 3.4Ah each
* two battery protection chips (AliExpress)
* integrated µ-USB charge module (AliExpress)
* Teensy 3.6 using the integrated SD card slot
* one ICS43434 I2S microphone on a separate tiny PCB (if you do not dare to solder this mic, the ready-to-use PCB can be purchased from onehorse / Pesky products on tindie)

microSoundRecorder DD4WH 2019_06_25.jpgmicroSoundRecorder2 DD4WH 2019_06_25.jpg

A zip plastic bag makes the whole thing waterproof. The thin plastic does not alter the sound characteristics or the sound level significantly in our experience.

We use a PCB originally designed for the PassiveRecorder, an ultrasound recording device for bats. We just leave the ultrasound specific parts (preamp) and the display/joystick etc. unmounted.

https://framagit.org/PiBatRecorderPojects/TeensyRecorders

Our hardware setup for the Audio Recorder is the same as shown in the Wiki, but we use an additional RC (470 Ohms, 470µF) combination to filter the power supply of the ICS43434 microphone.

You can imagine that the amount of wav file audio recordings very quickly grows into tens or hundreds of Gigabytes. So it will very quickly be impossible to listen to all the recordings. So we need artificial intelligence!

I added some open source tools which can automatically classify audio recordings to species using different artifical intelligence algorithms in the microSoundRecorder WIKI.

https://github.com/WMXZ-EU/microSoundRecorder/wiki/(Bio)Acoustic-resources

Have fun with the microSoundRecorder! All the best,

Frank DD4WH
 
Walter and/or Frank,

I've recently updated my Arduino IDE / Teensyduino. Unfortunately, the SD writing via the greiman library doesn't work anymore.

As you know, your fast SD writing is enabled by using the Greiman SD library in place of the default Sd library. The problem is that there is a conflict over the function sdhc_isr(), which is present in both libraries. The greiman library has always defined this function sdhc_isr(), so I don't know why the compiler is only now having a problem with there being multiple definitions. Why has it worked before but has stopped working now?!? Grr.

In compiling your own microSoundRecorder, here is the error shown in the Arduino IDE (I have verbose output enabled)...

Code:
C:\Users\wea\AppData\Local\Temp\arduino_build_187894\libraries\SD\utility\NXP_SDHC.cpp.o: In function `sdhc_isr':

C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\SD\utility/NXP_SDHC.cpp:911: multiple definition of `sdhc_isr'

C:\Users\wea\AppData\Local\Temp\arduino_build_187894\libraries\SdFs\SdCard\SdioTeensy.cpp.o:C:\Users\wea\Documents\Arduino\libraries\SdFs\src\SdCard/SdioTeensy.cpp:210: first defined here

I'm having a hard time figuring out how to get around this error. Do you have any suggestions so that I can resume using high speed SD routines for writing audio to SD?

(Yes, I realize that I could just delete the reference from the default SD library, but I'm trying to figure out how to solve this problem more generally for my Tympan library [which uses the Greiman library, too] without asking users to make edits to the underlying Arduino/Teensyduino installation.)

Is there anything to the Greiman library that I can do? Or is there a change that I/we can do a pull-request for in the Teensy build of the default SD library?

Chip
Arduino IDE 1.8.9
Teensyduino 1.46
 
does it compile if you declare in sdio_Teensy.cpp sdhc_isr as static ?
Code:
static void sdhc_isr()
{...
}

Noted that this does not compile, as sdhc_isr is in kinetis.h declared as extern without the static attribute
So I ended up to modify Greiman's code by simply adding a 'm' as in

Code:
static void msdhc_isr()
{...
}
[/QUOTE]

and also changed the attach interrupt line
 
and also changed the attach interrupt line

When I renamed the Greiman sdhc_isr() to another name (like was suggested above), nothing worked...presumably because the sdhc_isr was a special name that was being attached to an interrupt somewhere. I could never find where this isr was attached to the interrupt.

Where do I find the attach interrupt line so that I can change it? This would be great!

Chip
 
Good afternoon everyone. Hope to be in the right forum.
My hardware setup is a teensy 3.6 board with the Cirrus Logic codec CS42448. The project consists of a 4 channel audio recorder to detect the direction of sound sources in city environment. In terms of software, I started by using the Recorder code provided in the Teensyduino examples. Everything worked fine except for glitches on audio and loss of sample blocks from time to time when writing to the SD card (a problem widely discussed in the forum). So after searching the forum, I found that WMXZ developed a recorder, microSoundRecorder, with modifications from the PJRC Audio Library. I tested this code and the problem of glitches and loss of audio blocks was solved (congratulations to WMXZ for the excellent work done). However, recording audio samples is only done if I first run the Recorder code provided in the Teensyduino examples. It looks like it's a TDM initialization problem. Analyzed on the oscilloscope, pin 23 has the right clock frequency. But pin 13 does not show data.

In fact, I've tried everything and couldn't solve the situation. I'm a little desperate. I wonder how I can solve this situation.

All the best
 
@jpaudio
I'm on travel right now, but can look into the problem beginning next Tuesday.
mean while could you please be a little bit more specific?
maybe you could post the config.h file and give any indication of modifications you have done.
best
Walter
 
When I renamed the Greiman sdhc_isr() to another name (like was suggested above), nothing worked...presumably because the sdhc_isr was a special name that was being attached to an interrupt somewhere. I could never find where this isr was attached to the interrupt.

Where do I find the attach interrupt line so that I can change it? This would be great!

Chip

Sorry Chip, did you find meanwhile the attachInterrupt line?
 
Hi WMXZ, thank you for your quick response.

Here it is the config.h
/Users/joelpaulo/Documents/Projects/Teensy/microSoundRecorder-master/microSoundRecorder_buttons/config.h

I'm using ar = 20 (uint32_t ar; // acquisition rate, i.e. every ar seconds (if < on then continuous acquisition)) in order to have continuous recording.

Hope it helps to understand my problem.

Thanks in advance
 
I believe some problem occurred with the config.h upload
Let's try again

/* Sound Recorder for Teensy 3.6
* Copyright (c) 2018, Walter Zimmer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

/*********************** Begin possible User Modifications ********************************/
// possible modifications are marked with //<<<======>>>
//
//----------------------------------------------------------------------------------------
#define DO_DEBUG 1 // print debug info over usb-serial line //<<<======>>>

#define F_SAMP 48000 // desired sampling frequency //<<<======>>>
/*
* NOTE: changing frequency impacts the macros
* AudioProcessorUsage and AudioProcessorUsageMax
* defined in stock AudioStream.h
*/

////////////////////////////////////////////////////////////
// ------------------------- Acquisition interface control ----------------------------
// possible ACQ interfaces
#define _ADC_0 0 // single ended ADC0
#define _ADC_D 1 // differential ADC0
#define _ADC_S 2 // stereo ADC0 and ADC1
#define _I2S 3 // I2S (16 bit stereo audio)
#define _I2S_32 4 // I2S (32 bit stereo audio), eg. two ICS43434 mics
#define _I2S_QUAD 5 // I2S (16 bit quad audio)
#define _I2S_32_MONO 6 // I2S (32 bit mono audio), eg. one ICS43434 mic
#define _I2S_TYMPAN 7 // I2S (16 bit tympan stereo audio audio) for use the tympan board
#define _I2S_TDM 8 // I2S (8 channel TDM) // only first 5 channels are used (modify myAcq.h if less or more channels)

#define ACQ _I2S_TDM // selected acquisition interface //<<<======>>>

// For ADC SE pins can be changed
#if ACQ == _ADC_0
#define ADC_PIN A2 // can be changed //<<<======>>>
#define DIFF 0
#elif ACQ == _ADC_D
#define ADC_PIN A10 //fixed analog pin
#define DIFF 1
#elif ACQ == _ADC_S
#define ADC_PIN1 A2 // can be changed //<<<======>>>
#define ADC_PIN2 A3 // can be changed //<<<======>>>
#define DIFF 0
#elif (ACQ == _I2S_32) || (ACQ == _I2S_32_MONO) || (ACQ == _I2S_TDM)
#define NSHIFT 15 // number of bits to shift data to the right before extracting 16 bits //<<<======>>>
#endif

#define MDEL -1 // maximal delay in buffer counts (128/fs each; for fs= 48 kHz: 128/48 = 2.5 ms each) //<<<======>>>
// MDEL == -1 connects ACQ interface directly to mux and queue

#define GEN_WAV_FILE // generate wave files, if undefined generate raw data (with 512 byte header) //<<<======>>>

/****************************************************************************************/
// some structures to be used for controlling acquisition
// -----------------------scheduled acquisition------------------------------------------
typedef struct
{ uint32_t on; // acquisition on time in seconds
uint32_t ad; // acquisition file size in seconds
uint32_t ar; // acquisition rate, i.e. every ar seconds (if < on then continuous acquisition)
uint32_t T1,T2; // first acquisition window (from T1 to T2) in Hours of day
uint32_t T3,T4; // second acquisition window (from T1 to T2) in Hours of day
uint32_t rec; // time when recording started
char name[8]; // prefix for recorder file names
} ACQ_Parameters_s;

// T1 to T3 are increasing hours, T4 can be before or after midnight
// choose for continuous recording {0,12,12,24}
// if "ar" > "on" the do dutycycle, i.e.sleep between on and ar seconds
//
// Example
// ACQ_Parameters_s acqParameters = {120, 60, 180, 0, 12, 12, 24, 0, "WMXZ"};
// acquire 2 files each 60 s long (totaling 120 s)
// sleep for 60 s (to reach 180 s acquisition interval)
// acquire whole day (from midnight to noon and noot to midnight)
//

ACQ_Parameters_s acqParameters = { 40, 20, 20, 0, 12, 12, 24, 0, "TDM"}; //<<<======>>>

// the following global variable may be set from anywhere
// if one wanted to close file immediately
// mustClose = -1: disable this feature, close on time limit but finish to fill diskBuffer
// mustcClose = 0: flush data and close exactly on time limit
// mustClose = 1: flush data and close immediately (not for user, this will be done by program)

int16_t mustClose = -1;// initial value (can be -1: ignore event trigger or 0: implement event trigger) //<<<======>>>

//---------------------------------- snippet extraction module ---------------------------------------------
typedef struct
{ int32_t iproc; // type of detection processor (0: high-pass-threshold; 1: Taeger-Kaiser-Operator)
int32_t thresh; // power SNR for snippet detection (-1: disable snippet extraction)
int32_t win0; // noise estimation window (in units of audio blocks)
int32_t win1; // detection watchdog window (in units of audio blocks typically 10x win0)
int32_t extr; // min extraction window
int32_t inhib; // guard window (inhibit follow-on secondary detections)
int32_t nrep; // noise only interval (nrep =0 indicates no noise archiving)
int32_t ndel; // pre trigger delay (in units of audio blocks)
} SNIP_Parameters_s;

SNIP_Parameters_s snipParameters = { 0, -1, 1000, 10000, 3750, 375, 0, MDEL}; //<<<======>>>

//-------------------------- hibernate control---------------------------------------------------------------
// The following two lines control the maximal hibernate (sleep) duration
// this may be useful when using a powerbank, or other cases where frequent booting is desired
// is used in audio_hibernate.h
//#define SLEEP_SHORT // comment when sleep duration is not limited //<<<======>>>
#define ShortSleepDuration 60 // value in seconds //<<<======>>>

//------------------------- Additional sensors ---------------------------------------------------------------
#define USE_ENVIRONMENTAL_SENSORS 0 // to use environmental sensors set to 1 otherwise set to 0 //<<<======>>>

//------------------------- special Hardware configuration ----------------------------------------------------
#if ACQ == _I2S_TYMPAN
#undef USE_ENVIRONMENTAL_SENSORS
#define USE_ENVIRONMENTAL_SENSORS 0 // for tympan switch off environmental sensors
#define TYMPAN_REVISION TYMPAN_REV_C //TYMPAN_REV_C or TYMPAN_REV_D //<<<======>>>
#define TYMPAN_INPUT_DEVICE TYMPAN_INPUT_ON_BOARD_MIC // use the on-board microphones //<<<======>>>
//TYMPAN_INPUT_JACK_AS_MIC // use the microphone jack - defaults to mic bias 2.5V
//TYMPAN_INPUT_JACK_AS_LINEIN // use the microphone jack - defaults to mic bias OFF
#define input_gain_dB 10.5f //<<<======>>>
#endif

//
/*********************** End possible User Modifications ********************************/
 
Hi WMXZ

Did you figure out what could be the problem?
I implemented CS42448 Audio, 6 Inputs, 8 Outputs from OSH Park by PaulStoffregen

Another question is how can I play sound files from SD card using you code.

Thanks in advance
 
Hi WMXZ

Did you figure out what could be the problem?
I implemented CS42448 Audio, 6 Inputs, 8 Outputs from OSH Park by PaulStoffregen

Another question is how can I play sound files from SD card using you code.

Thanks in advance

There is a misunderstanding, the "microSoundRecorder" does not allow playback. it only records to uSD.
 
Hi WMXZ

Yes, I know that the main purpose of the "microSoundRecorder" is to record audio only. However, for my work in the field, it was interesting to be able to listening to, at least, the last sound recorded from the SD card. Is it very complicated to do? I believe I can not use the Audio library from PJRC, right? Any suggestions?

Nevertheless, the crucial issue I have to solve (and I didn't yet) is how can I run this code without first run the Recorder code of PJRC (which uses the Audio library from PJRC).

Many thanks
 
Hi,
So the quick version of my question is: how hard would it be to modify the code to use the I2s MEMS microphones (SPH0645LM4H) from Adafruit (https://www.adafruit.com/product/3421)? Or do I buy new mics and replace them?

Now the long version. I am setting up a sound recorder to record wolf vocalizations in the field using 4 I2S microphones with the Teensy 3.6. I had four of the above microphones from a previous project using an Arduino board and wrongly assumed that I2S MEMS microphones are interchangeable (same communication protocol). I got everything all soldered up and now discover that the SPH0645LM4H microphones have some difference in I2S communication so they do not work with microsoundrecorder code. I do get some audio but it is terrible and blocky. See spectrogram image from Audacity.
Whistle_test.jpg
My investigations took me as far as figuring out that there is a communication difference. I found this discussion on it (https://forum.pjrc.com/threads/42562-MEMS-i2c-microphone-SPH0645LM4H-with-teensy-audio-library). So do I de-solder the SPH0645LM4H microphones and buy new ones or can the code be easily changed and get good recordings?
On another note does anyone have quad channel recording working with audio triggered recording? I see it is not built into the code on GitHub so I was hoping someone already has it functioning that would be willing to share code or at least point me to the things I need to do in the code to get it working. I already changed the code based on suggestion on reply #91 and was able to get I2S_QUAD to compile at least. Thanks for any assistance anyone can give.
SCOTT
 
@jpaudio,
As I do not have a CS42448 Audio board, I will try to look into the code only, and you have to do the testing for me.
From your description, it means that there is some initialization missing.

The other point
When you say you wanted to playback the files, you mean via the CS42448 codec, right? or do you man via PC( i,e. downloading the files)?

@redscott
Again, I do not have SPH0645LM4H, but try to understand the protocol from datasheet.
 
Last edited:
Hi WMXZ

Yes, obviously I'll test your suggestions.

Yes, it seems to be an initialization missing.
- Considering the Recorder code provided in the Teensyduino examples: I verified that the pin 13 is activated with the properly signal (see photo- pin 13 data (ch1) and pin 23 clock (ch2)) before the code enter in Setup(). So, the initialisation seems to be made scopeSignals.jpgwhen this code line is instantiated
"AudioControlCS42448 cs42448; //xy=573.6666564941406,228.99999237060547"

Notice that these code lines are inside the Setup()
cs42448.enable();
delay(500);

- Considering now the "microSoundRecorder" code: I verified that the pin 13 is activated with the properly signal, also, before the code enter in Setup(), if I run the Recorder code provided in the Teensyduino examples before (without turnoff power supply). Therefore, seems to be activated inside this code section
/*-------------------------- (multi channel TDM) -----------------------------*/


and yes, I want to playback the files via the CS42448 codec

Many thanks
 
Hi WMXZ

Thank you for your help. I've just tested your modified code and it works perfectly well. The initialisation of CS42448 codec is made.

I'm gonna try to implement the routine to playback sound files. Have you some hints to do that?

Many thanks
 
Hi WMXZ

Thank you for your help. I've just tested your modified code and it works perfectly well. The initialisation of CS42448 codec is made.

I'm gonna try to implement the routine to playback sound files. Have you some hints to do that?

Many thanks

I have not looked into playing back on CS42448, but will do soon.
 
Hi WMXZ,
So I studied the datasheets for the 43434 and SPH0645LM4H microphones and discovered what I believe to be the differences causing the issues but I am not sure where to adjust the code. I may need to adjust the SCK frequency (or period) depending on what it is set at. It would appear the SPH0645LM4H runs at an optimal of 3.072 MHz (about 325.5 ns period). SCK high time and SCK low time are also different 85.45 ns on the SPH0645LM4H (vs. 50 ns on the 43434). The WS setup time on the SPH0645LM4H is 85.45 ns (vs 0 on the 43434). Finally the WS hold is 85.45 ns on the SPH0645LM4H (vs. 20 ns on the 43434). I am at a loss of how to adjust these in the code even after extensive searching. I assume it is in the audio library somewhere and I found these lines in the input_i2s.cpp or similar files that seem to be referring to specific aspects of I2S communication.
I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX
Any help you could give in locating the exact code to be adjusted would be appreciated.
SCOTT
 
@WMXZ

Quick question for you, Sir. Do you know what it would take to convert this over from a Teensy 3.6 setup to be compatible with a Teensy 4.0? If its somewhat simple I'm happy to do the legwork; if you would be so kind as to point me in the right direction.
 
@WMXZ

Quick question for you, Sir. Do you know what it would take to convert this over from a Teensy 3.6 setup to be compatible with a Teensy 4.0? If its somewhat simple I'm happy to do the legwork; if you would be so kind as to point me in the right direction.

testing it for all inputs (ADC, I2S, TDM etc) testing will most likely be lengthy, but if you have a particular input in mind, may it is possible.
 
Back
Top