Sona 0.50 Source

Sona 0.50/tools/wav2swav/sonawave.c

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
#include "sonawave.h"

// Target sample rate
#define SONA_SAMPLE_RATE      10650

//***************************************************************************
// save_sonawave
// Takes in the loaded waveform and generates a SonaWave file out of it.
//---------------------------------------------------------------------------
// param filename ... file name to save into
// param wave ....... pointer to waveform data
//---------------------------------------------------------------------------
// return ........... 0 on success, -1 on failure
//***************************************************************************

int save_sonawave(const char *filename, const Waveform *wave)
{
   // Create new file
   FILE *file = fopen(filename, "wb");
   if (file == NULL) {
      fprintf(stderr, "Error[\"%s\"]: can't create SonaWave file\n",
                      filename);
      return -1;
   }
   
   // Go through entire waveform and store it into the file
   // We use Bresenham's algorithm (or something close enough to it) to
   // resample it to the target sample rate regardless of whatever the
   // WAV file originally was.
   size_t pos = 0;            // Current position within waveform
   size_t written = 0;        // Number of written bytes so far
   size_t accum = 0;          // Accumulated advance for resampling
   
   while (pos < wave->len) {
      // Fetch sample that we're gonna write
      // 0xFF is not a valid value, so we change it to something safer (this
      // makes the conversion a bit lossy but shouldn't be noticeable)
      uint8_t byte = wave->data[pos];
      if (byte == 0xFF) byte = 0xFE;
      
      // Write sample into the file
      fputc(byte, file);
      if (ferror(file)) goto write_error;
      written++;
      
      // Advance forwards accounting for sample rate
      // (this is where we resample to Sona's sample rate)
      accum += wave->rate;
      if (accum >= SONA_SAMPLE_RATE) {
         size_t advance = accum / SONA_SAMPLE_RATE;
         accum -= advance * SONA_SAMPLE_RATE;
         pos += advance;
      }
   }
   
   // Pad with the silence to the next 32 byte boundary
   while ((written & 0x1F) != 0x00) {
      fputc(0x7F, file);
      written++;
   }
   if (ferror(file)) {
      goto write_error;
   }
   
   // Write terminator block
   for (int i = 0; i < 32; i++)
      fputc(0xFF, file);
   if (ferror(file))
      goto write_error;
   
   // We're done
   fclose(file);
   return 0;

// We reach here if something went wrong trying to write the file
// (hardware disconnected? out of space?)
write_error:
   fprintf(stderr, "Error[\"%s\"]: problem writing SonaWave file\n",
                   filename);
   fclose(file);
   return -1;
}