Wave-File Header (recording)

Status
Not open for further replies.

Koerby

Member
Hello

Sorry guys, I know this has been answered a lot of times, but I am stucking with writing the wave-header to an recorded raw-file.

As a staring point use the basic Recorder demo from the Audio-lib and add the header data after recording.
The recording itself is ok, but at the end the file is not recognized as a wav file.

Is there a way to check if the header was written in the correct way?

Thanks in advance
Marcus

Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>


// GUItool: begin automatically generated code
AudioInputI2S            i2s2;           //xy=226.75,251.9999988079071
AudioRecordQueue         queue1;         //xy=402.75,251.9999988079071
AudioConnection          patchCord1(i2s2, 0, queue1, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=386.75,400.9999988079071
// GUItool: end automatically generated code

// Bounce objects to easily and reliably read the buttons
Bounce buttonRecord = Bounce(0, 8);
Bounce buttonStop =   Bounce(1, 8);  // 8 = 8 ms debounce time

const int myInput = AUDIO_INPUT_LINEIN;


// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// Remember which mode we're doing
int mode = 0;  // 0=stopped, 1=recording

// The file where data is recorded
File frec;

void setup() {

  Serial.begin(9600);
  // Configure the pushbutton pins
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);

  AudioMemory(60);

  // Enable the audio shield, select input, and enable output
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);

  // Initialize the SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here if no SD card, but print a message
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
}


void loop() {
  buttonRecord.update();
  buttonStop.update();

  if (buttonRecord.fallingEdge()) {
    Serial.println("Record Button Press");
    if (mode == 0) startRecording();
  }
  if (buttonStop.fallingEdge()) {
    Serial.println("Stop Button Press");
    if (mode == 1) stopRecording();
  }

  // If we're playing or recording, carry on...
  if (mode == 1) {
    continueRecording();
  }

  if (mode == 2) {
    Serial.println("Writing Header");
    delay(100);
    writeOutHeader();
  }
}

///////////////////////////////////////////////////////// startRecording /////////////////////////////////////////
void startRecording() {
  Serial.println("startRecording");
  if (SD.exists("RECORD.WAV")) {
    SD.remove("RECORD.RAW");
  }
  frec = SD.open("RECORD.WAV", FILE_WRITE);
  if (frec) {
    queue1.begin();
    mode = 1;
  }
}

///////////////////////////////////////////////////////// continueRecording /////////////////////////////////////////
void continueRecording() {
  if (queue1.available() >= 2) {
    byte buffer[512];
    // writes are used.
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer + 256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    // write all 512 bytes to the SD card
    elapsedMicros usec = 0;
    frec.write(buffer, 512);
  }
}

///////////////////////////////////////////////////////// stopRecording /////////////////////////////////////////////
void stopRecording() {
  Serial.println("stopRecording");
  queue1.end();
  if (mode == 1) {
    while (queue1.available() > 0) {
      frec.write((byte*)queue1.readBuffer(), 256);
      queue1.freeBuffer();
    }
    frec.close();
  }
  mode = 2;
  
}

///////////////////////////////////////////////////////// writeOutHeader ////////////////////////////////////////////
void writeOutHeader() { // update WAV header with final filesize/datasize
  File frec = SD.open("RECORD.WAV");

  int dataSize = frec.size();
  int headerSize = 44;
  int dataChunkSize = dataSize + headerSize - 8;

  int subDataChunkSize = 16;
  byte format = 0x1; //PCM
  byte channels = 0x1; //mono
  int sampleRate = 44100;
  int bytesPerSample = 4;
  int bitsPerSample = 16;

  Serial.write("RIFF");  // 00 - RIFF
  for (int n = 0; n < 4; ++n) Serial.write((byte)((dataChunkSize >> (n * 8)) & 0xFF)); // 04 - how big is the rest of this file?
  Serial.write("WAVE"); // 08 - WAVE
  Serial.write("fmt "); // 12 - fmt
  for (int n = 0; n < 4; ++n) Serial.write((byte)((subDataChunkSize >> (n * 8)) & 0xFF )); // 16 - size of this chunk
  for (int n = 0; n < 2; ++n) Serial.write((byte)((format >> (n * 8)) & 0xFF)); // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
  for (int n = 0; n < 2; ++n) Serial.write((byte)((channels >> (n * 8)) & 0xFF)); // 22 - mono or stereo? 1 or 2? (or 5 or ???)
  for (int n = 0; n < 4; ++n) Serial.write((byte)((sampleRate >> (n * 8)) & 0xFF)); // 24 - samples per second (numbers per second)
  for (int n = 0; n < 4; ++n) Serial.write((byte)(((sampleRate * bytesPerSample) >> (n * 8)) & 0xFF)); // 28 - bytes per second
  for (int n = 0; n < 2; ++n) Serial.write((byte)(((bytesPerSample) >> (n * 8)) & 0xFF )); // 32 - # of bytes in one sample, for all channels
  for (int n = 0; n < 2; ++n) Serial.write((byte)((bitsPerSample >> (n * 8)) & 0xFF)); // 34 - how many bits in a sample(number)? usually 16 or 24
  Serial.write("data"); // 36 - data
  for (int n = 0; n < 4; ++n) Serial.write((byte)((dataSize >> (n * 8)) & 0xFF)); // 40 - how big is this data chunk

  // 44 - the actual data itself
  byte b;
  bool reading = true;
  do {
    if (frec.available()) {
      b = frec.read();
      Serial.write(b);
    }
    else reading = false;
  }
  while (reading);

  frec.close();

  mode = 0;
}
 
You can't write the header until you know the total amount of data.

Probably the simplest way would involve seeking back to the beginning of the file and overwriting the first 44 bytes with the header, after you know exactly how much data was stored.
 
Status
Not open for further replies.
Back
Top