Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 21 of 21

Thread: Recorder Example Queue Object

  1. #1
    Junior Member
    Join Date
    Sep 2020
    Posts
    17

    Recorder Example Queue Object

    Hi all, I hope this message finds you well...

    I am recording using the Examples > Audio > Recorder (to be more specific, I am actually using the WavFilerWriter from Foaly https://github.com/Foaly/WavFileWriter)... I am trying to implement a digital filter using this equation in order to high pass at a cutoff frequency of 100 Hz to eliminate the low frequency components(0-100Hz) which causes noise in my recordings.
    Click image for larger version. 

Name:	1.png 
Views:	18 
Size:	37.4 KB 
ID:	22116
    In my code, I am taking the contents of m_buffer ( size m_buffer[512]) and applying the formula, but I am not getting the expected results.
    Click image for larger version. 

Name:	2.JPG 
Views:	22 
Size:	44.2 KB 
ID:	22117
    I suspect that I am not applying the formula the right way or to the right values from the queue object. All that I get out is extreme harsh noise. Any advice?

    Thanks in advance!

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    Posting code as an image makes it extremely difficult to help you.
    Cut and paste it as text into your message, preferably within code tags (use the # icon).

    Have you tried the unmodified WavFileWriter code to make sure that it is creating the file correctly using unmodified data?

    Pete

  3. #3
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Dear Pete
    Firstly, thank you for the response!
    Quote Originally Posted by el_supremo View Post

    Have you tried the unmodified WavFileWriter code to make sure that it is creating the file correctly using unmodified data?

    Pete
    Could you elaborate more on this? I ran WavFilerWriter.ino and it worked, but since then I have only been modifying WavFileWriter.Ino. The picture up there (apologies) is from WavFileWriter.cpp which I am trying to change... I will post the code now!
    Code:
    /*
      - PROJECT (E) 448 (SKIPSIE == FINAL YEAR PROJECT)
      - Jonathan Paul Hendricks, University of Stellenbosch, 2020
      - TOPIC: Long term-low cost acoustic monitor
      - Monitor dolphin sounds and other marine fauna.
    */
    
    //Includes & Declarations & Constants
    
    #include "WavFileWriter.hpp"
    #include <SerialFlash.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <TimeLib.h>
    #define FILE_BASE_NAME "REC"
    #include <OpenAudio_ArduinoLibrary.h>
    
    
    const int Fs = 44100;       // Frequency to sample
    const int myMic = AUDIO_INPUT_MIC;        // Mic input
    unsigned long prevMil = 0;
    unsigned long prevMil2 = 0;
    unsigned long prevMil3 = 0;
    const long interval = 15000;
    const long a = 12000;
    int flag;
    int flag2;
    int flag3;
    const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
    char fileName[] = FILE_BASE_NAME "00.wav";
    int buttonState = 0;
    const int buttonPin = 1;
    
    AudioPlaySdWav        kingSD;        //Kingston SD Card
    AudioInputI2S         audioIn;       //Audio Connection
    AudioOutputI2S        audioOut;      //Audio Connection
    AudioRecordQueue      queue1;        //To write data to SD Card
    AudioConnection       patchCord1(audioIn, 0, queue1, 0);   //-Record data and queue it
    AudioConnection       patchCord2(kingSD, 0, audioOut, 0);  //-perform read/write functions to save
    AudioConnection       patchCord3(kingSD, 0, audioOut, 1);  // data and play through Audio Connection output
    AudioControlSGTL5000_Extended  AudioShield;
    
    WavFileWriter wavWriter(queue1);
    
    
    
    // ---------------
    
    // Initial setup run at start of program
    
    void setup() {
    
      SdFile::dateTimeCallback(dateTime);
      Serial.begin(9600);
      AudioMemory(60);
      AudioShield.enable();
      AudioShield.inputSelect(myMic);
      AudioShield.micGain(63);          //0-63
      AudioShield.volume(0.75);         //0-1
      AudioShield.adcHighPassFilterDisable();
      AudioShield.micBiasEnable(1.25);
      setSyncProvider(getTeensy3Time); //Initialise this
      Serial.println("Powered up & Ready to go!");
      pinMode(buttonPin, INPUT);
    
    
    }
    
    // ---------------
    
    //loop function
    
    void loop() {
    
      if (digitalRead(buttonPin) == LOW) {
        unsigned long currMil = millis();
        if (flag3 == 0) {
          flag3 = 1;
          Serial.println("Start Recording");
          wavWriter.open(fileName, Fs, 1);
        }
        if (currMil - prevMil >= interval) {
          while (SD.exists(fileName)) {
            if (fileName[BASE_NAME_SIZE + 1] != '9') {
              fileName[BASE_NAME_SIZE + 1]++;
            } else if (fileName[BASE_NAME_SIZE] != '9') {
              fileName[BASE_NAME_SIZE + 1] = '0';
              fileName[BASE_NAME_SIZE]++;
            } else {
              Serial.println(F("Can't create file name"));
              return;
            }
          }
          prevMil = currMil;
          Serial.println("Start Recording!");
          wavWriter.open(fileName, Fs, 1);
        }
        if (currMil - prevMil2 >= a + interval) {
          prevMil2 = currMil - a;
          wavWriter.close();
          Serial.println("Stop Recording");
          digitalClockDisplay();
        }
        if ((currMil - prevMil3) >= a && flag2 == 1) {
    
          Serial.println("Stop recording");
          wavWriter.close();
          flag2 = 0;
          digitalClockDisplay();
        }
        if (wavWriter.isWriting()) {
          wavWriter.update();
        }
      } else {
        unsigned long currMil = millis();
        prevMil = currMil;
        prevMil2 = currMil;
        prevMil3 = currMil;
        flag2 = 1;
        flag3 = 0;
        wavWriter.close();
        delay(500);
      }
    }
    
    
    // ---------------
    
    /*Additional functions for implementation of acoustic monitor*/
    
    //Timing functions
    
    time_t getTeensy3Time() {
      return Teensy3Clock.get();
    }
    
    void digitalClockDisplay() {
      // digital clock display of the time
      Serial.print(hour());
      printDigits(minute());
      printDigits(second());
      Serial.print(" ");
      Serial.print(day());
      Serial.print(" ");
      Serial.print(month());
      Serial.print(" ");
      Serial.print(year());
      Serial.println();
    }
    
    /*  code to process time sync messages from the serial port   */
    #define TIME_HEADER  "T"   // Header tag for serial time sync message
    
    unsigned long processSyncMessage() {
      unsigned long pctime = 0L;
      const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013
    
      if (Serial.find(TIME_HEADER)) {
        pctime = Serial.parseInt();
        return pctime;
        if ( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
          pctime = 0L; // return 0 to indicate that the time is not valid
        }
      }
      return pctime;
    }
    
    void printDigits(int digits) {
      // utility function for digital clock display: prints preceding colon and leading 0
      Serial.print(":");
      if (digits < 10)
        Serial.print('0');
      Serial.print(digits);
    }
    
    void dateTime(uint16_t* date, uint16_t* time)
    {
      *date = FAT_DATE(year(), month(), day());
      *time = FAT_TIME(hour(), minute(), second());
    }
    That is my code for WavFileWriter.Ino, where I simply do some scheduling operations to be able to record every interval for a certain amount of time and store the data to an SD card in wav format (process starts when pressing a lock-button).

    Code:
    ////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////
    //
    // This code was inspired by the Recorder example of Paul Stoffregens Audio library
    // and the SFML SoundFileWriterWav class
    // Copyright (C) 2018 Maximilian Wagenbach (aka Foaly)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
    
    #include "WavFileWriter.hpp"
    
    #include <SPI.h>
    
    namespace {
    
    // Teensy Audio Shield Defaults
    const uint8_t SDcard_CS_Pin    = 10;
    const uint8_t SDcard_MOSI_Pin  =  11;
    const uint8_t SDcard_SCK_Pin   = 13;
    
    // Use these with the Teensy 3.5 & 3.6 SD card (Should work, but not yet tested)
    //const uint8_t SDcard_CS_Pin    = BUILTIN_SDCARD
    //const uint8_t SDcard_MOSI_Pin  = 11  // not actually used
    //const uint8_t SDcard_SCK_Pin   = 13  // not actually used
    
    // Use these for the SD+Wiz820 or other adaptors (Should work, but not yet tested)
    //const uint8_t SDcard_CS_Pin    =  4
    //const uint8_t SDcard_MOSI_Pin  = 11
    //const uint8_t SDcard_SCK_Pin   = 13
    
    // The following functions takes integers in host byte order
    // and writes them to a stream as little endian
    
    void encode(File& file, uint16_t value) {
      uint8_t bytes[] =
      {
        static_cast<uint8_t>(value & 0xFF),
        static_cast<uint8_t>(value >> 8)
      };
      file.write(reinterpret_cast<const uint8_t*>(bytes), sizeof(bytes));
    }
    
    void encode(File& file, uint32_t value) {
      uint8_t bytes[] =
      {
        static_cast<uint8_t> (value & 0x000000FF),
        static_cast<uint8_t>((value & 0x0000FF00) >>  8),
        static_cast<uint8_t>((value & 0x00FF0000) >> 16),
        static_cast<uint8_t>((value & 0xFF000000) >> 24),
      };
      file.write(reinterpret_cast<const uint8_t*>(bytes), sizeof(bytes));
    }
    }
    
    
    WavFileWriter::WavFileWriter(AudioRecordQueue& queue) :
      m_isWriting(false),
      m_queue(queue)
    {
    
    }
    
    
    bool WavFileWriter::open(const char *fileName, unsigned int sampleRate, unsigned int channelCount) {
      if (m_isWriting) {
        Serial.println("Cannot write WAV file. Already writing one.");
        return false;
      }
    
    
      // Initialize the SD card
      SPI.setMOSI(SDcard_MOSI_Pin);
      SPI.setSCK(SDcard_SCK_Pin);
      if (!(SD.begin(SDcard_CS_Pin))) {
        Serial.println("Unable to access the SD card while trying to write WAV file.");
        return false;
      }
    
      if (SD.exists(fileName)) {
        SD.remove(fileName);
      }
    
      m_file = SD.open(fileName, FILE_WRITE);
      if (!m_file) {
        Serial.println("Could not open file while trying to write WAV file.");
        return false;
      }
    
      m_queue.begin();
      m_isWriting = true;
      m_totalBytesWritten = 0;
    
      writeHeader(sampleRate, channelCount);
      return true;
    }
    
    
    bool WavFileWriter::isWriting() {
      return m_isWriting;
    }
    
    
    void WavFileWriter::writeHeader(unsigned int sampleRate, unsigned int channelCount) {
      // Write the main chunk ID
      uint8_t mainChunkId[4] = {'R', 'I', 'F', 'F'};
      m_file.write(mainChunkId, sizeof(mainChunkId));
    
      // Write the main chunk header
      uint32_t mainChunkSize = 0; // placeholder, will be written on closing
      encode(m_file, mainChunkSize);
      uint8_t mainChunkFormat[4] = {'W', 'A', 'V', 'E'};
      m_file.write(mainChunkFormat, sizeof(mainChunkFormat));
    
      // Write the sub-chunk 1 ("format") id and size
      uint8_t fmtChunkId[4] = {'f', 'm', 't', ' '};
      m_file.write(fmtChunkId, sizeof(fmtChunkId));
      uint32_t fmtChunkSize = 16;
      encode(m_file, fmtChunkSize);
    
      // Write the format (PCM)
      uint16_t format = 1;
      encode(m_file, format);
    
      // Write the sound attributes
      encode(m_file, static_cast<uint16_t>(channelCount));
      encode(m_file, static_cast<uint32_t>(sampleRate));
      uint32_t byteRate = sampleRate * channelCount * 2;
      encode(m_file, byteRate);
      uint16_t blockAlign = channelCount * 2;
      encode(m_file, blockAlign);
      uint16_t bitsPerSample = 16;
      encode(m_file, bitsPerSample);
    
      // Write the sub-chunk 2 ("data") id and size
      uint8_t dataChunkId[4] = {'d', 'a', 't', 'a'};
      m_file.write(dataChunkId, sizeof(dataChunkId));
      uint32_t dataChunkSize = 0; // placeholder, will be written on closing
      encode(m_file, dataChunkSize);
    
      m_totalBytesWritten += 44;
    }
    
    
    bool WavFileWriter::update() {
      if (!m_isWriting)
        return false;
    
      if (m_queue.available() < 2)
        return false;
    
      // Fetch 2 blocks from the audio library and copy
      // into a 512 byte buffer.  The Arduino SD library
      // is most efficient when full 512 byte sector size
      // writes are used.
      memcpy(m_buffer, m_queue.readBuffer(), 256);
      m_queue.freeBuffer();
      memcpy(m_buffer + 256, m_queue.readBuffer(), 256);
      m_queue.freeBuffer();
      for (int k = 0; k < 512; k++) {
        m_smooth = 0.985f * (m_smooth + m_buffer[k] - m_buffer[k - 1]) ;
        m_out[k] = m_smooth;
      }
      // write all 512 bytes to the SD card
      //elapsedMicros usec = 0;
    
      m_file.write(m_out, 512);
      // Uncomment these lines to see how long SD writes
      // are taking. A pair of audio blocks arrives every
      // 5802 microseconds, so hopefully most of the writes
      // take well under 5802 us. Some will take more, as
      // the SD library also must write to the FAT tables
      // and the SD card controller manages media erase and
      // wear leveling. The m_queue object can buffer
      // approximately 301700 us of audio, to allow time
      // for occasional high SD card latency, as long as
      // the average write time is under 5802 us.
      //Serial.print("SD write, us=");
      //    Serial.println(usec);
    
      m_totalBytesWritten += 512;
      return true;
    }
    
    
    bool WavFileWriter::close() {
      if (!m_isWriting)
        return false;
    
      m_queue.end();
      while (m_queue.available() > 0) {
        m_file.write(reinterpret_cast<const uint8_t*>(m_queue.readBuffer()), 256);
        m_queue.freeBuffer();
        m_totalBytesWritten += 256;
      }
    
      Serial.print("Done! Max no. of audio blocks used: ");
      Serial.println(AudioMemoryUsageMax());
      Serial.print("Bytes written: ");
      Serial.println(m_totalBytesWritten);
    
      m_file.flush();
    
      // Update the main chunk size and data sub-chunk size
      uint32_t mainChunkSize = m_totalBytesWritten - 8;  // 8 bytes RIFF header
      uint32_t dataChunkSize = m_totalBytesWritten - 44; // 44 bytes RIFF + WAVE headers
      m_file.seek(4);
      encode(m_file, mainChunkSize);
      m_file.seek(40);
      encode(m_file, dataChunkSize);
    
      m_file.close();
    
      m_isWriting = false;
      return true;
    }
    And that is the code I am currently trying to work on, specifically at "WavFileWriter::update() " where I want to alter the data before saving it to the SD card. I was busy trying to do the peak detection in order to vary the gain as well, but I first want to figure out how to alter the data received in the queue object... I hope it makes sense now? Let me know if I can provide more?

    EDIT: Here is my WavFilerWriter.hpp
    Code:
    #include <SD.h>
    
    ////////////////////////////////////////////////////////////
    //
    // This code was inspired by the Recorder example of Paul Stoffregens Audio library
    // and the SFML SoundFileWriterWav class
    // Copyright (C) 2018 Maximilian Wagenbach (aka Foaly)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
    
    #ifndef WAVFILEWRITER_INCLUDE
    #define WAVFILEWRITER_INCLUDE
    
    #include <SD.h>
    #include <SD_t3.h>
    #include "utility/SdFat.h"
    #include <record_queue.h>
    
    class WavFileWriter
    {
    public:
        WavFileWriter(AudioRecordQueue& queue);
        bool open(const char *fileName, unsigned int sampleRate, unsigned int channelCount);
        bool isWriting();
        bool update();
        bool close();
    
    private:
        void writeHeader(unsigned int sampleRate, unsigned int channelCount);
    
        bool                  m_isWriting;
        File                  m_file;
        AudioRecordQueue&     m_queue;
        uint32_t              m_totalBytesWritten;
        uint8_t               m_buffer[512];
        uint8_t               m_out[512];
        float                 m_smooth;
    };
    
    #endif // WAVFILEWRITER_INCLUDE
    Last edited by jono_ph; 10-18-2020 at 08:13 PM.

  4. #4
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Quote Originally Posted by el_supremo View Post
    Posting code as an image makes it extremely difficult to help you.
    Cut and paste it as text into your message, preferably within code tags (use the # icon).

    Pete
    I should've used the hashtag! Great stuff Also, to be more clear, everything works, just the part where I now want to apply a digital filter at WavFileWriter.cpp is where I am getting headaches... Feel free to comment out the for loop after the second "freebuffer()" at the "WavFileWriter::update()" to test it...

    EDIT: I am not using Utils.hpp
    Last edited by jono_ph; 10-18-2020 at 08:04 PM.

  5. #5
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    I can also send you a version of WavFilerWriter.ino where I use the serial monitor instead of a lock-button? Just to demonstrate the recording process

  6. #6
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    Code:
        uint8_t               m_buffer[512];
    That is your biggest problem. Samples are int16_t. When you calculate this:
    Code:
        m_smooth = 0.985f * (m_smooth + m_buffer[k] - m_buffer[k - 1]) ;
    it is done with the wrong datatype.
    It should be:
    Code:
        int16_t               m_buffer[AUDIO_BLOCK_SAMPLES * 2];
    The rest of your code then has to be adjusted to use the correct number of samples or bytes as appropriate.
    Something like this:
    Code:
      // Copy AUDIO_BLOCK_SAMPLES samples (= AUDIO_BLOCK_SAMPLES * 2 BYTES) into m_buffer.
      memcpy(m_buffer, m_queue.readBuffer(), AUDIO_BLOCK_SAMPLES * 2);
      m_queue.freeBuffer();
      memcpy(m_buffer + 256, m_queue.readBuffer(), AUDIO_BLOCK_SAMPLES * 2);
      m_queue.freeBuffer();
      for (int k = 0; k < AUDIO_BLOCK_SAMPLES * 2; k++) {
        m_smooth = 0.985f * (m_smooth + m_buffer[k] - m_buffer[k - 1]) ;
        m_out[k] = m_smooth;
      }
      // write all 512 bytes to the SD card
      //elapsedMicros usec = 0;
      // Write TWO buffers of AUDIO_BLOCK_SAMPLES samples each
      m_file.write(m_out, AUDIO_BLOCK_SAMPLES * 2 * 2);
    There's another problem in the for loop
    Code:
        m_smooth = 0.985f * (m_smooth + m_buffer[k] - m_buffer[k - 1]) ;
    When k is zero m_buffer[k-1] references m_buffer[-1] which is outside the buffer.
    You should be saving the last sample in the buffer and passing it in to be used in place of m_buffer[-1].
    It will probably not cause any major noise in the signal so, for now, let's get the basic sample processing working. Then we can refine it.

    Pete

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    P.S. You can also speed up things by changing the floating point computations to use int16_t instead. We'll also handle that once the basic code works.

    Pete

  8. #8
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Hi, I've updated the code...
    Code:
    ////////////////////////////////////////////////////////////
    //
    // This code was inspired by the Recorder example of Paul Stoffregens Audio library
    // and the SFML SoundFileWriterWav class
    // Copyright (C) 2018 Maximilian Wagenbach (aka Foaly)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
    
    #include "WavFileWriter.hpp"
    
    #include <SPI.h>
    
    namespace {
    
    // Teensy Audio Shield Defaults
    const uint8_t SDcard_CS_Pin    = 10;
    const uint8_t SDcard_MOSI_Pin  =  11;
    const uint8_t SDcard_SCK_Pin   = 13;
    
    // Use these with the Teensy 3.5 & 3.6 SD card (Should work, but not yet tested)
    //const uint8_t SDcard_CS_Pin    = BUILTIN_SDCARD
    //const uint8_t SDcard_MOSI_Pin  = 11  // not actually used
    //const uint8_t SDcard_SCK_Pin   = 13  // not actually used
    
    // Use these for the SD+Wiz820 or other adaptors (Should work, but not yet tested)
    //const uint8_t SDcard_CS_Pin    =  4
    //const uint8_t SDcard_MOSI_Pin  = 11
    //const uint8_t SDcard_SCK_Pin   = 13
    
    // The following functions takes integers in host byte order
    // and writes them to a stream as little endian
    
    void encode(File& file, uint16_t value) {
      uint8_t bytes[] =
      {
        static_cast<uint8_t>(value & 0xFF),
        static_cast<uint8_t>(value >> 8)
      };
      file.write(reinterpret_cast<const uint8_t*>(bytes), sizeof(bytes));
    }
    
    void encode(File& file, uint32_t value) {
      uint8_t bytes[] =
      {
        static_cast<uint8_t> (value & 0x000000FF),
        static_cast<uint8_t>((value & 0x0000FF00) >>  8),
        static_cast<uint8_t>((value & 0x00FF0000) >> 16),
        static_cast<uint8_t>((value & 0xFF000000) >> 24),
      };
      file.write(reinterpret_cast<const uint8_t*>(bytes), sizeof(bytes));
    }
    }
    
    
    WavFileWriter::WavFileWriter(AudioRecordQueue& queue) :
      m_isWriting(false),
      m_queue(queue)
    {
    
    }
    
    
    bool WavFileWriter::open(const char *fileName, unsigned int sampleRate, unsigned int channelCount) {
      if (m_isWriting) {
        Serial.println("Cannot write WAV file. Already writing one.");
        return false;
      }
    
    
      // Initialize the SD card
      SPI.setMOSI(SDcard_MOSI_Pin);
      SPI.setSCK(SDcard_SCK_Pin);
      if (!(SD.begin(SDcard_CS_Pin))) {
        Serial.println("Unable to access the SD card while trying to write WAV file.");
        return false;
      }
    
      if (SD.exists(fileName)) {
        SD.remove(fileName);
      }
    
      m_file = SD.open(fileName, FILE_WRITE);
      if (!m_file) {
        Serial.println("Could not open file while trying to write WAV file.");
        return false;
      }
    
      m_queue.begin();
      m_isWriting = true;
      m_totalBytesWritten = 0;
    
      writeHeader(sampleRate, channelCount);
      return true;
    }
    
    
    bool WavFileWriter::isWriting() {
      return m_isWriting;
    }
    
    
    void WavFileWriter::writeHeader(unsigned int sampleRate, unsigned int channelCount) {
      // Write the main chunk ID
      uint8_t mainChunkId[4] = {'R', 'I', 'F', 'F'};
      m_file.write(mainChunkId, sizeof(mainChunkId));
    
      // Write the main chunk header
      uint32_t mainChunkSize = 0; // placeholder, will be written on closing
      encode(m_file, mainChunkSize);
      uint8_t mainChunkFormat[4] = {'W', 'A', 'V', 'E'};
      m_file.write(mainChunkFormat, sizeof(mainChunkFormat));
    
      // Write the sub-chunk 1 ("format") id and size
      uint8_t fmtChunkId[4] = {'f', 'm', 't', ' '};
      m_file.write(fmtChunkId, sizeof(fmtChunkId));
      uint32_t fmtChunkSize = 16;
      encode(m_file, fmtChunkSize);
    
      // Write the format (PCM)
      uint16_t format = 1;
      encode(m_file, format);
    
      // Write the sound attributes
      encode(m_file, static_cast<uint16_t>(channelCount));
      encode(m_file, static_cast<uint32_t>(sampleRate));
      uint32_t byteRate = sampleRate * channelCount * 2;
      encode(m_file, byteRate);
      uint16_t blockAlign = channelCount * 2;
      encode(m_file, blockAlign);
      uint16_t bitsPerSample = 16;
      encode(m_file, bitsPerSample);
    
      // Write the sub-chunk 2 ("data") id and size
      uint8_t dataChunkId[4] = {'d', 'a', 't', 'a'};
      m_file.write(dataChunkId, sizeof(dataChunkId));
      uint32_t dataChunkSize = 0; // placeholder, will be written on closing
      encode(m_file, dataChunkSize);
    
      m_totalBytesWritten += 44;
    }
    
    
    bool WavFileWriter::update() {
      if (!m_isWriting)
        return false;
    
      if (m_queue.available() < 2)
        return false;
    
      // Fetch 2 blocks from the audio library and copy
      // into a 512 byte buffer.  The Arduino SD library
      // is most efficient when full 512 byte sector size
      // writes are used.
      memcpy(m_buffer, m_queue.readBuffer(), AUDIO_BLOCK_SAMPLES * 2);
      m_queue.freeBuffer();
      memcpy(m_buffer + 256, m_queue.readBuffer(), AUDIO_BLOCK_SAMPLES * 2);
      m_queue.freeBuffer();
      for (int k = 0; k < AUDIO_BLOCK_SAMPLES * 2; k++) {
        m_smooth = 0.985f * (m_smooth + m_buffer[k] - m_buffer[k - 1]) ;
        m_out[k] = m_smooth;
      }
      // write all 512 bytes to the SD card
      //elapsedMicros usec = 0;
    
      m_file.write(m_out, AUDIO_BLOCK_SAMPLES * 2 * 2);
      // Uncomment these lines to see how long SD writes
      // are taking. A pair of audio blocks arrives every
      // 5802 microseconds, so hopefully most of the writes
      // take well under 5802 us. Some will take more, as
      // the SD library also must write to the FAT tables
      // and the SD card controller manages media erase and
      // wear leveling. The m_queue object can buffer
      // approximately 301700 us of audio, to allow time
      // for occasional high SD card latency, as long as
      // the average write time is under 5802 us.
      //Serial.print("SD write, us=");
      //    Serial.println(usec);
    
      m_totalBytesWritten += 512;
      return true;
    }
    
    
    bool WavFileWriter::close() {
      if (!m_isWriting)
        return false;
    
      m_queue.end();
      while (m_queue.available() > 0) {
        m_file.write(reinterpret_cast<const uint8_t*>(m_queue.readBuffer()), 256);
        m_queue.freeBuffer();
        m_totalBytesWritten += 256;
      }
    
      Serial.print("Done! Max no. of audio blocks used: ");
      Serial.println(AudioMemoryUsageMax());
      Serial.print("Bytes written: ");
      Serial.println(m_totalBytesWritten);
    
      m_file.flush();
    
      // Update the main chunk size and data sub-chunk size
      uint32_t mainChunkSize = m_totalBytesWritten - 8;  // 8 bytes RIFF header
      uint32_t dataChunkSize = m_totalBytesWritten - 44; // 44 bytes RIFF + WAVE headers
      m_file.seek(4);
      encode(m_file, mainChunkSize);
      m_file.seek(40);
      encode(m_file, dataChunkSize);
    
      m_file.close();
    
      m_isWriting = false;
      return true;
    }
    that is .cpp where I did the recommendations...
    Code:
    #include <SD.h>
    
    ////////////////////////////////////////////////////////////
    //
    // This code was inspired by the Recorder example of Paul Stoffregens Audio library
    // and the SFML SoundFileWriterWav class
    // Copyright (C) 2018 Maximilian Wagenbach (aka Foaly)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
    
    #ifndef WAVFILEWRITER_INCLUDE
    #define WAVFILEWRITER_INCLUDE
    
    #include <SD.h>
    #include <SD_t3.h>
    #include "utility/SdFat.h"
    #include <record_queue.h>
    
    class WavFileWriter
    {
      public:
        WavFileWriter(AudioRecordQueue& queue);
        bool open(const char *fileName, unsigned int sampleRate, unsigned int channelCount);
        bool isWriting();
        bool update();
        bool close();
    
      private:
        void writeHeader(unsigned int sampleRate, unsigned int channelCount);
    
        bool                  m_isWriting;
        File                  m_file;
        AudioRecordQueue&     m_queue;
        uint32_t              m_totalBytesWritten;
        int16_t               m_buffer[AUDIO_BLOCK_SAMPLES * 2];
        uint8_t               m_out[512];
        float                 m_smooth;
    };
    
    #endif // WAVFILEWRITER_INCLUDE
    that is .hpp where I did the recommendations... Things started happening Not the best though... Still noise, but in between that noise I can hear my whistle that I do at the start(before it was just noise)... You can listen here(just dont put it too loud or immediately against your ear) https://www.dropbox.com/s/4xb9b1f710...REC00.WAV?dl=0

  9. #9
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Quote Originally Posted by el_supremo View Post
    P.S. You can also speed up things by changing the floating point computations to use int16_t instead. We'll also handle that once the basic code works.

    Pete
    Thanks for the help so far I am trying that now!

    EDIT: I changed "float m_smooth" to "int16_t m_smooth" on WavFileWriter.hpp(not posting the full code again since I did above with the other recommendations), still similar noise but I can hear myself whisteling!

  10. #10
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    I missed (at least) one thing. The m_out array also needs to be int16_t;
    Code:
        int16_t               m_out[AUDIO_BLOCK_SAMPLES * 2];
    Which Teensy are you using? (T3.2 ?)

    Pete

  11. #11
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    I tried that the first time around, but it gave me an error so I left it.. This is the error when I change m_out from
    Code:
        uint8_t               m_out[512]
    to
    Code:
    int16_t               m_out[AUDIO_BLOCK_SAMPLES * 2]
    Click image for larger version. 

Name:	3.jpg 
Views:	7 
Size:	78.1 KB 
ID:	22125

  12. #12
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Quote Originally Posted by el_supremo View Post

    Which Teensy are you using? (T3.2 ?)

    Pete
    I am using the T4.1

    Jono

  13. #13
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    Try this:
    Code:
      m_file.write((const char *)m_out, AUDIO_BLOCK_SAMPLES * 2 * 2);
    And, you can also copy and paste error messages as text too.

    Pete

  14. #14
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    That made my program run again! Let me share the audio (you can't hear that clear but I am saying thanks) https://www.dropbox.com/s/4xb9b1f710...REC00.WAV?dl=0 .

    EDIT: smoothing factor alpha was 0.995 here (Fc =35Hz).

    Jono

  15. #15
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Just for reference, this is my usual output...https://www.dropbox.com/s/let7mf20qj...%20dB.WAV?dl=0

  16. #16
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Quote Originally Posted by el_supremo View Post
    [code]
    When k is zero m_buffer[k-1] references m_buffer[-1] which is outside the buffer.
    You should be saving the last sample in the buffer and passing it in to be used in place of m_buffer[-1].
    It will probably not cause any major noise in the signal so, for now, let's get the basic sample processing working. Then we can refine it.

    Pete
    I am working on this now.. Hopefully this is what needs refinement for the recording to sound better? But it doesn't sound to great at the moment but I have made more progress in a few hours than a full two days (not proud of that..)

  17. #17
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    Fixing the m_buffer[-1] problem and changing floating point to fixed-point arithmetic won't make significant changes to the audio.
    There is something else that is having a more profound effect.
    One thing that looks odd is that you appear to be processing audio input from the microphone (via a queue) and writing it to the SD card, while at the same time reading a file from the SD card and playing it. If so, that will make the SD card too busy.

    Post all three files again so I can see the current "state of the art"

    Pete

  18. #18
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Code:
    /*
      - PROJECT (E) 448 (SKIPSIE == FINAL YEAR PROJECT)
      - Jonathan Paul Hendricks, University of Stellenbosch, 2020
      - TOPIC: Long term-low cost acoustic monitor
      - Monitor dolphin sounds and other marine fauna.
    */
    
    //Includes & Declarations & Constants
    
    #include "WavFileWriter.hpp"
    #include <SerialFlash.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <TimeLib.h>
    #define FILE_BASE_NAME "REC"
    #include <OpenAudio_ArduinoLibrary.h>
    
    
    const int Fs = 44100;       // Frequency to sample
    const int myMic = AUDIO_INPUT_MIC;        // Mic input
    unsigned long prevMil = 0;
    unsigned long prevMil2 = 0;
    unsigned long prevMil3 = 0;
    const long interval = 15000;
    const long a = 12000;
    int flag;
    int flag2;
    int flag3;
    const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
    char fileName[] = FILE_BASE_NAME "00.wav";
    int buttonState = 0;
    const int buttonPin = 1;
    
    AudioPlaySdWav        kingSD;        //Kingston SD Card
    AudioInputI2S         audioIn;       //Audio Connection
    AudioOutputI2S        audioOut;      //Audio Connection
    AudioRecordQueue      queue1;        //To write data to SD Card
    AudioConnection       patchCord1(audioIn, 0, queue1, 0);   //-Record data and queue it
    AudioConnection       patchCord2(kingSD, 0, audioOut, 0);  //-perform read/write functions to save
    AudioConnection       patchCord3(kingSD, 0, audioOut, 1);  // data and play through Audio Connection output
    AudioControlSGTL5000_Extended  AudioShield;
    
    WavFileWriter wavWriter(queue1);
    
    
    
    // ---------------
    
    // Initial setup run at start of program
    
    void setup() {
    
      SdFile::dateTimeCallback(dateTime);
      Serial.begin(9600);
      AudioMemory(60);
      AudioShield.enable();
      AudioShield.inputSelect(myMic);
      AudioShield.micGain(63);          //0-63
      AudioShield.volume(0.75);         //0-1
      AudioShield.adcHighPassFilterDisable();
      AudioShield.micBiasEnable(1.25);
      setSyncProvider(getTeensy3Time); //Initialise this
      Serial.println("Powered up & Ready to go!");
      pinMode(buttonPin, INPUT);
    
    
    }
    
    // ---------------
    
    //loop function
    
    void loop() {
    
      if (digitalRead(buttonPin) == LOW) {
        unsigned long currMil = millis();
        if (flag3 == 0) {
          flag3 = 1;
          Serial.println("Start Recording");
          wavWriter.open(fileName, Fs, 1);
        }
        if (currMil - prevMil >= interval) {
          while (SD.exists(fileName)) {
            if (fileName[BASE_NAME_SIZE + 1] != '9') {
              fileName[BASE_NAME_SIZE + 1]++;
            } else if (fileName[BASE_NAME_SIZE] != '9') {
              fileName[BASE_NAME_SIZE + 1] = '0';
              fileName[BASE_NAME_SIZE]++;
            } else {
              Serial.println(F("Can't create file name"));
              return;
            }
          }
          prevMil = currMil;
          Serial.println("Start Recording!");
          wavWriter.open(fileName, Fs, 1);
        }
        if (currMil - prevMil2 >= a + interval) {
          prevMil2 = currMil - a;
          wavWriter.close();
          Serial.println("Stop Recording");
          digitalClockDisplay();
        }
        if ((currMil - prevMil3) >= a && flag2 == 1) {
    
          Serial.println("Stop recording");
          wavWriter.close();
          flag2 = 0;
          digitalClockDisplay();
        }
        if (wavWriter.isWriting()) {
          wavWriter.update();
        }
      } else {
        unsigned long currMil = millis();
        prevMil = currMil;
        prevMil2 = currMil;
        prevMil3 = currMil;
        flag2 = 1;
        flag3 = 0;
        wavWriter.close();
        delay(500);
      }
    }
    
    
    // ---------------
    
    /*Additional functions for implementation of acoustic monitor*/
    
    //Timing functions
    
    time_t getTeensy3Time() {
      return Teensy3Clock.get();
    }
    
    void digitalClockDisplay() {
      // digital clock display of the time
      Serial.print(hour());
      printDigits(minute());
      printDigits(second());
      Serial.print(" ");
      Serial.print(day());
      Serial.print(" ");
      Serial.print(month());
      Serial.print(" ");
      Serial.print(year());
      Serial.println();
    }
    
    /*  code to process time sync messages from the serial port   */
    #define TIME_HEADER  "T"   // Header tag for serial time sync message
    
    unsigned long processSyncMessage() {
      unsigned long pctime = 0L;
      const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013
    
      if (Serial.find(TIME_HEADER)) {
        pctime = Serial.parseInt();
        return pctime;
        if ( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
          pctime = 0L; // return 0 to indicate that the time is not valid
        }
      }
      return pctime;
    }
    
    void printDigits(int digits) {
      // utility function for digital clock display: prints preceding colon and leading 0
      Serial.print(":");
      if (digits < 10)
        Serial.print('0');
      Serial.print(digits);
    }
    
    void dateTime(uint16_t* date, uint16_t* time)
    {
      *date = FAT_DATE(year(), month(), day());
      *time = FAT_TIME(hour(), minute(), second());
    }
    that is my WavFileWriter.ino
    Code:
    ////////////////////////////////////////////////////////////
    //
    // This code was inspired by the Recorder example of Paul Stoffregens Audio library
    // and the SFML SoundFileWriterWav class
    // Copyright (C) 2018 Maximilian Wagenbach (aka Foaly)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
    
    #include "WavFileWriter.hpp"
    
    #include <SPI.h>
    
    namespace {
    
    // Teensy Audio Shield Defaults
    const uint8_t SDcard_CS_Pin    = 10;
    const uint8_t SDcard_MOSI_Pin  =  11;
    const uint8_t SDcard_SCK_Pin   = 13;
    
    // Use these with the Teensy 3.5 & 3.6 SD card (Should work, but not yet tested)
    //const uint8_t SDcard_CS_Pin    = BUILTIN_SDCARD
    //const uint8_t SDcard_MOSI_Pin  = 11  // not actually used
    //const uint8_t SDcard_SCK_Pin   = 13  // not actually used
    
    // Use these for the SD+Wiz820 or other adaptors (Should work, but not yet tested)
    //const uint8_t SDcard_CS_Pin    =  4
    //const uint8_t SDcard_MOSI_Pin  = 11
    //const uint8_t SDcard_SCK_Pin   = 13
    
    // The following functions takes integers in host byte order
    // and writes them to a stream as little endian
    
    void encode(File& file, uint16_t value) {
      uint8_t bytes[] =
      {
        static_cast<uint8_t>(value & 0xFF),
        static_cast<uint8_t>(value >> 8)
      };
      file.write(reinterpret_cast<const uint8_t*>(bytes), sizeof(bytes));
    }
    
    void encode(File& file, uint32_t value) {
      uint8_t bytes[] =
      {
        static_cast<uint8_t> (value & 0x000000FF),
        static_cast<uint8_t>((value & 0x0000FF00) >>  8),
        static_cast<uint8_t>((value & 0x00FF0000) >> 16),
        static_cast<uint8_t>((value & 0xFF000000) >> 24),
      };
      file.write(reinterpret_cast<const uint8_t*>(bytes), sizeof(bytes));
    }
    }
    
    
    WavFileWriter::WavFileWriter(AudioRecordQueue& queue) :
      m_isWriting(false),
      m_queue(queue)
    {
    
    }
    
    
    bool WavFileWriter::open(const char *fileName, unsigned int sampleRate, unsigned int channelCount) {
      if (m_isWriting) {
        Serial.println("Cannot write WAV file. Already writing one.");
        return false;
      }
    
    
      // Initialize the SD card
      SPI.setMOSI(SDcard_MOSI_Pin);
      SPI.setSCK(SDcard_SCK_Pin);
      if (!(SD.begin(SDcard_CS_Pin))) {
        Serial.println("Unable to access the SD card while trying to write WAV file.");
        return false;
      }
    
      if (SD.exists(fileName)) {
        SD.remove(fileName);
      }
    
      m_file = SD.open(fileName, FILE_WRITE);
      if (!m_file) {
        Serial.println("Could not open file while trying to write WAV file.");
        return false;
      }
    
      m_queue.begin();
      m_isWriting = true;
      m_totalBytesWritten = 0;
    
      writeHeader(sampleRate, channelCount);
      return true;
    }
    
    
    bool WavFileWriter::isWriting() {
      return m_isWriting;
    }
    
    
    void WavFileWriter::writeHeader(unsigned int sampleRate, unsigned int channelCount) {
      // Write the main chunk ID
      uint8_t mainChunkId[4] = {'R', 'I', 'F', 'F'};
      m_file.write(mainChunkId, sizeof(mainChunkId));
    
      // Write the main chunk header
      uint32_t mainChunkSize = 0; // placeholder, will be written on closing
      encode(m_file, mainChunkSize);
      uint8_t mainChunkFormat[4] = {'W', 'A', 'V', 'E'};
      m_file.write(mainChunkFormat, sizeof(mainChunkFormat));
    
      // Write the sub-chunk 1 ("format") id and size
      uint8_t fmtChunkId[4] = {'f', 'm', 't', ' '};
      m_file.write(fmtChunkId, sizeof(fmtChunkId));
      uint32_t fmtChunkSize = 16;
      encode(m_file, fmtChunkSize);
    
      // Write the format (PCM)
      uint16_t format = 1;
      encode(m_file, format);
    
      // Write the sound attributes
      encode(m_file, static_cast<uint16_t>(channelCount));
      encode(m_file, static_cast<uint32_t>(sampleRate));
      uint32_t byteRate = sampleRate * channelCount * 2;
      encode(m_file, byteRate);
      uint16_t blockAlign = channelCount * 2;
      encode(m_file, blockAlign);
      uint16_t bitsPerSample = 16;
      encode(m_file, bitsPerSample);
    
      // Write the sub-chunk 2 ("data") id and size
      uint8_t dataChunkId[4] = {'d', 'a', 't', 'a'};
      m_file.write(dataChunkId, sizeof(dataChunkId));
      uint32_t dataChunkSize = 0; // placeholder, will be written on closing
      encode(m_file, dataChunkSize);
    
      m_totalBytesWritten += 44;
    }
    
    
    bool WavFileWriter::update() {
      if (!m_isWriting)
        return false;
    
      if (m_queue.available() < 2)
        return false;
    
      // Fetch 2 blocks from the audio library and copy
      // into a 512 byte buffer.  The Arduino SD library
      // is most efficient when full 512 byte sector size
      // writes are used.
      memcpy(m_buffer, m_queue.readBuffer(), AUDIO_BLOCK_SAMPLES * 2);
      m_queue.freeBuffer();
      memcpy(m_buffer + 256, m_queue.readBuffer(), AUDIO_BLOCK_SAMPLES * 2);
      m_queue.freeBuffer();
      for (int k = 0; k < AUDIO_BLOCK_SAMPLES * 2; k++) {
        m_smooth = 0.995f * (m_smooth + m_buffer[k] - m_buffer[k - 1]) ;
        m_out[k] = m_smooth;
      }
      // write all 512 bytes to the SD card
      //elapsedMicros usec = 0;
    
       m_file.write((const char *)m_out, AUDIO_BLOCK_SAMPLES * 2 * 2);
      // Uncomment these lines to see how long SD writes
      // are taking. A pair of audio blocks arrives every
      // 5802 microseconds, so hopefully most of the writes
      // take well under 5802 us. Some will take more, as
      // the SD library also must write to the FAT tables
      // and the SD card controller manages media erase and
      // wear leveling. The m_queue object can buffer
      // approximately 301700 us of audio, to allow time
      // for occasional high SD card latency, as long as
      // the average write time is under 5802 us.
      //Serial.print("SD write, us=");
      //    Serial.println(usec);
    
      m_totalBytesWritten += 512;
      return true;
    }
    
    
    bool WavFileWriter::close() {
      if (!m_isWriting)
        return false;
    
      m_queue.end();
      while (m_queue.available() > 0) {
        m_file.write(reinterpret_cast<const uint8_t*>(m_queue.readBuffer()), 256);
        m_queue.freeBuffer();
        m_totalBytesWritten += 256;
      }
    
      Serial.print("Done! Max no. of audio blocks used: ");
      Serial.println(AudioMemoryUsageMax());
      Serial.print("Bytes written: ");
      Serial.println(m_totalBytesWritten);
    
      m_file.flush();
    
      // Update the main chunk size and data sub-chunk size
      uint32_t mainChunkSize = m_totalBytesWritten - 8;  // 8 bytes RIFF header
      uint32_t dataChunkSize = m_totalBytesWritten - 44; // 44 bytes RIFF + WAVE headers
      m_file.seek(4);
      encode(m_file, mainChunkSize);
      m_file.seek(40);
      encode(m_file, dataChunkSize);
    
      m_file.close();
    
      m_isWriting = false;
      return true;
    }
    That is my WavFileWriter.cpp
    Code:
    #include <SD.h>
    
    ////////////////////////////////////////////////////////////
    //
    // This code was inspired by the Recorder example of Paul Stoffregens Audio library
    // and the SFML SoundFileWriterWav class
    // Copyright (C) 2018 Maximilian Wagenbach (aka Foaly)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
    
    #ifndef WAVFILEWRITER_INCLUDE
    #define WAVFILEWRITER_INCLUDE
    
    #include <SD.h>
    #include <SD_t3.h>
    #include "utility/SdFat.h"
    #include <record_queue.h>
    
    class WavFileWriter
    {
      public:
        WavFileWriter(AudioRecordQueue& queue);
        bool open(const char *fileName, unsigned int sampleRate, unsigned int channelCount);
        bool isWriting();
        bool update();
        bool close();
    
      private:
        void writeHeader(unsigned int sampleRate, unsigned int channelCount);
    
        bool                  m_isWriting;
        File                  m_file;
        AudioRecordQueue&     m_queue;
        uint32_t              m_totalBytesWritten;
        int16_t               m_buffer[AUDIO_BLOCK_SAMPLES * 2];
        int16_t               m_out[AUDIO_BLOCK_SAMPLES * 2];
        int16_t               m_smooth;
    };
    
    #endif // WAVFILEWRITER_INCLUDE
    That is my WavFileWriter.hpp

    Thanks for still helping so far

    Jono

  19. #19
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Quote Originally Posted by el_supremo View Post
    One thing that looks odd is that you appear to be processing audio input from the microphone (via a queue) and writing it to the SD card, while at the same time reading a file from the SD card and playing it. If so, that will make the SD card too busy.
    Pete
    What part of the code are you referring to here?

    Jono

  20. #20
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,489
    I've been playing with the filter and produced this sketch which you might find useful.
    It generates a tonesweeep from 100-10000Hz over 5 seconds. The output of the sweep is fed to the queue so that the sketch can apply your filter and then put it back in the queue. That is then passed into the FFT. The code just adds each successive FFT scan into an array and sends the data to the Serial Plotter when the tonesweep ends. There are probably much better ways of processing the final data ready for display.

    Code:
    /* Derived from the FFT audio example and heavily
        modified by Pete (El Supremo)
    
    This outputs to Serial PLOTTER
                           ^^^^^^^
    201025
    _4
      - Clean up to post to forum.
      
    201024
    _3
      - Output a graph to Serial Plotter
    _2
      - In theory, modify to send the tonesweep
        output through the queue and play, so
        that the filter can process the tonesweep
        and then let the FFT have it.
        THEN improve the display
    _1
      - Modify FFT example to use tonesweep as
        input and stop once the sweep is done.
      - Not pretty, but IT WORKS
    */
    
    // FFT Test
    // This example code is in the public domain.
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // Create the Audio components.  These should be created in the
    // order data flows, inputs/sources -> processing -> outputs
    //
    AudioInputI2S          audioInput;  // audio shield: mic or line-in NOT USED
    AudioSynthToneSweep    ts;          // tonesweep object
    AudioRecordQueue       Q_in_L;      // sample blocks input to the sketch
    AudioAnalyzeFFT1024    myFFT;       // 1024 point FFT
    AudioPlayQueue         Q_out_L;     // sample blocks sent to audio device
    AudioOutputI2S         audioOutput; // audio shield: headphones & line-out
    
    // Connect output of tonesweep to the queue
    AudioConnection patchCord1(ts, 0, Q_in_L, 0);
    // Connect the queue to FFT
    AudioConnection patchCord3(Q_out_L, 0, myFFT, 0);
    AudioControlSGTL5000 audioShield;
    
    // Intermediate buffer for queue processing
    short buf_L[AUDIO_BLOCK_SAMPLES];
    int16_t l_smooth = 0;
    int16_t l_lastsample = 0;
    
    // Final output from FFT
    float sumbins[512];
    
    // When defined, use the floating point version
    #define ALPHA f_alpha
    
    // When defined, use the integer version which
    // DOES NOT WORK YET
    //#define ALPHA alpha
    
    const float f_alpha = 0.9f;
    const int16_t alpha = (32767)*f_alpha;
    const float bin_width = 44100./1024.;
    
    void setup()
    {
      Serial.begin(9600);
      while(!Serial);
      // Audio connections require memory to work.  For more
      // detailed information, see the MemoryAndCpuUsage example
      AudioMemory(12);
    
      // Enable the audio shield and set the output volume.
      audioShield.enable();
      audioShield.volume(0.5);
    
      // Configure the FFT window algorithm to use
      myFFT.windowFunction(AudioWindowHanning1024);
    
      // Start the tonesweep
      if(!ts.play(.5,100,10000,5.0)) {
        Serial.println("AudioSynthToneSweep - begin failed");
        while(1);
      }
      // Make sure the tonesweep has started
      while(!ts.isPlaying());
      Q_in_L.begin();
      for(int i = 0; i < 512; i++)sumbins[i] = 0;
    }
    
    void loop()
    {
      float n;
      int i;
      short *bp_L;
      
      if(ts.isPlaying()) {
        if(Q_in_L.available() >= 1) {
          bp_L = Q_in_L.readBuffer();
    
          // Copy the audio buffer to our memory
          for(int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
            buf_L[i] = bp_L[i];
          }
          // Free the input audio buffer
          Q_in_L.freeBuffer();
          // Get a pointer to an "empty" output buffer
          bp_L = Q_out_L.getBuffer();
          // Do the first sample in the buffer which requires
          // input from the last sample in the previous buffer
          l_smooth = ALPHA * (l_smooth + buf_L[0] - l_lastsample);
          bp_L[0] = l_smooth;
          // Do the rest of the buffer
          for (int k = 1; k < AUDIO_BLOCK_SAMPLES; k++) {
            l_smooth = ALPHA * (l_smooth + buf_L[k] - buf_L[k - 1]);
            bp_L[k] = l_smooth;
          }
          // Save the last sample for the next pass
          l_lastsample = buf_L[AUDIO_BLOCK_SAMPLES-1];
          Q_out_L.playBuffer();
        }
        if (myFFT.available()) {
          for(int j = 0; j < 512; j++) {
            float sample = myFFT.read(j); 
    //        if(sample > sumbins[j]) sumbins[j] = sample;
            sumbins[j] += sample;
          }
        }
      } else {
        // tonesweep has finished.
        for(i = 0; i < 512; i++) {
          // Output to Serial Plotter
          Serial.printf("%2d\n",(int)(sumbins[i]*100));    
        }
        // Nothing more to be done
        while(1);
      }
    }
    The attached image shows the Serial Plotter graph for alpha = 0.9 which corresponds to a corner frequency of 780Hz.
    Click image for larger version. 

Name:	FFT_tonesweep_4_screencap.jpg 
Views:	6 
Size:	32.4 KB 
ID:	22200
    I tested this on a T4.0 (T4.1 will work too) - but T3.x won't because this uses floating point computations.

    Pete

  21. #21
    Junior Member
    Join Date
    Sep 2020
    Posts
    17
    Hi Pete

    This looks interesting, I will give it a shout and get back to you. The output looks pretty neat I am still having problems with my audio board so I am hoping to get a new one this week and then I will try and implement it. For now I will play around with the example

    Jono

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •