/*
** aiffwrite.c for aiffwrite in sourcemac
**
** Made by Averous Julien-Pierre
** Login   <j.averous@free.fr>
**
** Started on  Fri Apr 13 19:18:56 2007 Averous Julien-Pierre
** Last update Fri Apr 13 20:59:23 2007 Averous Julien-Pierre
*/

/*
**  To compile, use this in your shell :
**  'gcc aiffwrite.c -W -Wall -Werror -framework CoreServices -o aiffwrite'
*/

#include <stdio.h>
#include <stdlib.h>
#include <CoreServices/CoreServices.h>

/* Total second generated in the AIFF file */
#define TIME 10

/* Foo used to write the header of the AIFF file */
void WriteAIFFHeader(FILE *fp, unsigned int frames, short channels, short bits, double rate);


/* Main function : do us AIFF file */
int main ()
{
  FILE		*f;
  unsigned int	framecount = 0;
  int		i;
  short int	value_left, value_right;
  float		v1 = 0, t1 = 0, v2 = 0, t2 = 0;

  /* Open the out file, and go out if something go wrong */
  if ((f = fopen ("out.aiff", "w")) == NULL)
  {
    fprintf(stderr, "Can't create the output file\n");
    return 1;
  }

  /* Write a white header to reserv the place on the start of the file */
  WriteAIFFHeader(f, 0, 0, 0, 0);

  /* Here to show how write PCM data on the file. You should optimize that by using an array */
  for (i = 1; i < 44100 * TIME; i++) /* 44100 frame by second * TIME = TIME seconds of AIFF audio */
  {
    /* Calculate in big endian the left and right channel */
    value_left = EndianS16_NtoB (sin(t1) * 32767.5);
    value_right = EndianS16_NtoB (sin(t2) * 32767.5);
    t1 += 0.1 + v1;
    t2 += 0.1 + v2;
    v1 += sin(t1) * 0.02;
    v2 += sin(t2) * 0.02;

    /*  Write this left and right channel */
    fwrite(&value_left, sizeof (short int), 1, f);
    fwrite(&value_right, sizeof (short int), 1, f);

    /* We had done one frame : count it */
    framecount++;
  }

  /* Write the final header of the AIFF file */
  WriteAIFFHeader(f, framecount, 2, 16, 44100);

  /* Cleaning */
  fclose (f);
  return 0;
}



void WriteAIFFHeader(FILE *fp, unsigned int frames, short channels, short bits, double rate)
{
  extended80 v80;

  dtox80(&rate, &v80);

  fseek (fp, 0, SEEK_SET);

  struct
  {
    unsigned char	ckID[4];
    long		ckSize;
    short		numChannels;
    unsigned long	numSampleFrames;
    short		sampleSize;
    extended80		sampleRate;
  } __attribute__ ((packed)) commonChunk = { {'C','O','M','M'},
					     EndianS32_NtoB(18),
					     EndianS16_NtoB(channels),
					     EndianU32_NtoB(frames),
					     EndianS16_NtoB(bits),
					     v80 };



  struct
  {
    unsigned char	ckID[4];
    long		ckSize;
    unsigned long	offset;
    unsigned long	blockSize;
  } __attribute__ ((packed)) soundDataChunk = { {'S','S','N','D'},
						EndianS32_NtoB (2 * frames * channels + 8),
						EndianU32_NtoB (0),
						EndianU32_NtoB (0) };

  struct
  {
    unsigned char	ckID[4];
    long		ckSize;
    unsigned char	formType[4];
  } __attribute__ ((packed)) formAIFF = { {'F','O','R','M'},
					  EndianS32_NtoB (2 * frames * channels + 46),
					  {'A','I','F','F'} };

  /* Write the AIFF header, previously initilized */
  fwrite (&formAIFF, sizeof (formAIFF), 1, fp);
  fwrite (&commonChunk, sizeof (commonChunk), 1, fp);
  fwrite (&soundDataChunk, sizeof (soundDataChunk), 1, fp);
}
