/* ESP32_SD_FT.ino reads 0.1sec from sd file, sound.wav, at specified time offset and calculates full Fourier Transform at 1/4 step interval i.e. caculates FT as if there were 4 times the number of points Writes results in csv to file "ft.txt" Using ESP32 board support V3.0.3 compiling for Dfrobot Firebettle 2 ESP32-E */ /* * (c)2024 Forward Computing and Control Pty. Ltd. * NSW Australia, www.forward.com.au * This code is not warranted to be fit for any purpose. You may only use it at your own risk. * This generated code may be freely used for both private and commercial use * provided this copyright is maintained. */ #include "ESP_I2S.h" #include "FS.h" #include "SD.h" #include "SPI.h" #include "parseWAV.h" #include "Goertzel.h" const char ftFilename[] = "/ft.txt";//The name of the FT results file const char wavFilename[] = "/sound.wav"; // name of input file float startTimeOffset = 0; // in sec from start, where to read the 0.1sec interval from in the wav file size_t noOfFTpoints = 800; // number of frequency point between 0 and the nyquist freq. == 2000Hz, 800 => 4 times what a normal FFT would do const float printScaleFactor = 1e-5; // scales output prints by this number as print(float) prints ovf for numbers > 4294967040 // for SD card NOTE: do not use const int SD_CS_pin = 13; // D7; //SD cs pin #define SAMPLE_FREQ (16000) const int16_t DOWNSAMPLED_FREQ = SAMPLE_FREQ / 4; #define DATA_BIT_WIDTH (I2S_DATA_BIT_WIDTH_32BIT) const size_t bytesPerSample = (DATA_BIT_WIDTH / 8); const size_t processBuffer_sampleSize = (DOWNSAMPLED_FREQ / 10); // number of bytes for 400 samples 0.1sec downsampled for FT int32_t processBufferInside[processBuffer_sampleSize]; pcm_wav_header_t wave_header; bool SD_started = false; void setup() { // Initialize the serial port Serial.begin(115200); for (int i = 10; i > 0; i--) { delay(500); // wait 5sec to allow use to open plotter/monitor } if (DATA_BIT_WIDTH != I2S_DATA_BIT_WIDTH_32BIT) { Serial.println("ERROR: Only works with 32bit data"); while (1) { delay(3000); } } if (!SD.begin(SD_CS_pin)) { Serial.println("SD begin failed"); // allow to run without an SD card SD_started = false; } else { SD_started = true; } while (!SD.begin(SD_CS_pin)) { Serial.print("."); delay(500); } // open input file File inFile = SD.open(wavFilename); if (!inFile) { while (1) { Serial.println("Failed to open "); Serial.println(inFile); delay(5000); } } if (!parseWAV::parse(inFile, wave_header)) { // updates wave_header by reference while (1) { Serial.println("Error while parsing the wav header for file "); Serial.println(wavFilename); delay(5000); } } else { /* print the wave header */ parseWAV::print_header(wave_header, &Serial); } Serial.print("Reading 0.1sec of samples starting at time offset :"); Serial.print(startTimeOffset, 4); Serial.print(" from file "); Serial.println(wavFilename); size_t noSamples = processBuffer_sampleSize; size_t pointsOffset = parseWAV::timeToSamples(wave_header, startTimeOffset); size_t dataRead = parseWAV::read32bitData(inFile, wave_header, processBufferInside, noSamples, pointsOffset); inFile.close(); // finished with file now if (dataRead != noSamples) { while (1) { Serial.print(" Short read of "); Serial.println(dataRead); Serial.print(" samples from file "); Serial.println(wavFilename); delay(5000); } } File outFile = SD.open(ftFilename,FILE_APPEND); if (!outFile) { while (1) { Serial.println("Failed to open "); Serial.println(ftFilename); delay(5000); } } outFile.println(), outFile.println(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); outFile.print(noOfFTpoints); outFile.print(" point FT of 0.1sec of samples starting at time offset :"); outFile.print(startTimeOffset, 4); outFile.print(" from file "); outFile.println(wavFilename); float result[noOfFTpoints]; Goertzel::setPrintScaleFactor(printScaleFactor); // scale magitudes by 1e-5 to avoid ovf outputs from Arduino's print(float) Goertzel::GzFt_32bit(processBufferInside, noSamples, DOWNSAMPLED_FREQ, result, noOfFTpoints, &outFile); Serial.print("Wrote FT results to "); Serial.println(ftFilename); } void loop() { // nothing here }