//
// Created by Alberto on 2020-05-06.
//

#include "FileFunctions.h"

int ReadWavHeader(WAVHeader *Header, FILE *fp)
{
    unsigned int tmp, channels, sample_rate, byte_rate, block_align, bits_per_sample;
    char *buffer=NULL;

    unsigned int LEIDOS=4;

    if (fread(Header->header, WAVHeaderLength, 1, fp) != 1)
    { fclose(fp); return ErrReadFile; }


#ifdef TALK
    tmp = (Header->header[4-LEIDOS])     | (Header->header[5-LEIDOS]<<8) |
          (Header->header[6-LEIDOS]<<16) | (Header->header[7-LEIDOS]<<24);
    printf("(04-07) Overall file size %u bytes\n", tmp);
#endif

#ifdef TALK
    printf("(08-11) wave string: %s\n", strndup((const char *)&Header->header[8-LEIDOS], 4));
#endif

#ifdef TALK
    printf("(12-15) fmt string: %s\n", strndup((const char *)&Header->header[12-LEIDOS], 4));
#endif

    tmp = (Header->header[16-LEIDOS])     | (Header->header[17-LEIDOS]<<8) |
          (Header->header[18-LEIDOS]<<16) | (Header->header[19-LEIDOS]<<24);
#ifdef TALK
    printf("(16-19) Length of the format data: %u bytes\n", tmp);
#endif
    if (tmp != 16)
    {
        printf("Fmt data length not equal to 16, not supported. End\n");
        fclose(fp);
        return ErrWavFormat;
    }

    tmp = Header->header[20-LEIDOS] | (Header->header[21-LEIDOS]<<8);
#ifdef TALK
    printf("(20-21) Format type: %u (1 is PCM) \n", tmp);
#endif
    if (tmp != 1)
    {
        printf("Format type not equal to PCM, not supported. End\n");
        fclose(fp);
        return ErrWavFormat;
    }

    channels = Header->header[22-LEIDOS] | (Header->header[23-LEIDOS]<<8);
#ifdef TALK
    printf("(22-23) Number of channels: %u\n", channels);
#endif
    if (channels != 1)
    {
        printf("Number of channels not equal to 1 (mono), not supported. End\n");
        fclose(fp);
        return ErrWavFormat;
    }

    sample_rate = (Header->header[24-LEIDOS])     | (Header->header[25-LEIDOS]<<8) |
                  (Header->header[26-LEIDOS]<<16) | (Header->header[27-LEIDOS]<<24);
#ifdef TALK
    printf("(24-27) Sample rate: %u\n", sample_rate);
#endif

    byte_rate = (Header->header[28-LEIDOS])     | (Header->header[29-LEIDOS]<<8) |
                (Header->header[30-LEIDOS]<<16) | (Header->header[31-LEIDOS]<<24);
#ifdef TALK
    printf("(28-31) Byte Rate: %u\n", byte_rate);
#endif

    block_align = Header->header[32-LEIDOS] | (Header->header[33-LEIDOS]<<8);
#ifdef TALK
    printf("(32-33) Block Alignment: %u\n", block_align);
#endif

    bits_per_sample = Header->header[34-LEIDOS] | (Header->header[35-LEIDOS]<<8);
#ifdef TALK
    printf("(34-35) Bits per sample: %u\n", bits_per_sample);
#endif
    if (byte_rate != (sample_rate * channels * bits_per_sample / 8))
    {
        printf("byte rate is not equal to (sample_rate * channels * bits_per_sample), not supported. End\n");
        fclose(fp);
        return ErrWavFormat;
    }

    buffer=strndup((const char *)&Header->header[36-LEIDOS], 4);
#ifdef TALK
    printf("(36-39) String DATA: %s\n", buffer);
#endif
    if (strncasecmp("data", buffer, 4) != 0)
    {
        printf("Not standard wav file header size (44 bytes), not supported. End\n");
        fclose(fp);
        return ErrWavFormat;
    }

    tmp = (Header->header[40-LEIDOS])     | (Header->header[41-LEIDOS]<<8) |
          (Header->header[42-LEIDOS]<<16) | (Header->header[43-LEIDOS]<<24);
#ifdef TALK
    printf("(40-43) size of data section is %u bytes\n", tmp);
#endif

    Header->num_samples = tmp / block_align;
#ifdef TALK
    printf("Number of samples: %lu\n", Header->num_samples);
#endif
    if (Header->num_samples != (8*tmp) / (channels*bits_per_sample))
    {
        printf("(data_size / block_align) not equal to ((8*data_size) / (channels*bits_per_sample)). End\n");
        fclose(fp);
        return ErrWavFormat;
    }

    tmp = (bits_per_sample * channels) / 8;
#ifdef TALK
    printf("Number of bytes per sample: %u\n", tmp);
#endif
    if (tmp != 2)
    {
        printf("Byte per sample is not equal to 2. End\n");
        fclose(fp);
        return ErrWavFormat;
    }
    return OK;
}


int ReadAudio(const int n, MyType *audio, FILE *fp) {
    if (fread(audio, sizeof(MyType), n, fp) != n) { fclose(fp); return ErrReadFile; }
    return OK;
}


int ReadAudioWav(const int n, short *wavAudio, MyType *audio, FILE *fp) {
    int   i;

    if (fread(wavAudio, sizeof(short), n, fp) != n) { fclose(fp); return ErrReadFile; }

    for(i=0; i<n; i++)
        audio[i]=wavAudio[i]/32768.0;
    return OK;
}


int WriteAudio(const int n, const int m, MyType *dest, const MyFFTcompl *src, FILE *fp)
{
    int i;

    memset(dest, 0, n);

    for(i=0;i<m;i++)
        dest[i]=creal(src[i]);

    if (fwrite(dest, sizeof(MyType), n, fp) != n) { fclose(fp); return ErrReadFile; }
    return OK;
}


int WriteAudioWav(const int n, const int m, short *dest, const MyFFTcompl *src, FILE *fp)
{
    int i;

    memset(dest, 0, n);

    for(i=0;i<m;i++)
        dest[i]=(short)(creal(src[i])*32768.0);

    if (fwrite(dest, sizeof(short), n, fp) != n) { fclose(fp); return ErrReadFile; }
    return OK;
}


int WriteWavHeader(const unsigned char *Header, const unsigned char *RIFF, FILE *fp)
{
    if (fwrite(RIFF,   sizeof(unsigned char),               4, fp) != 4)               { fclose(fp); return ErrReadFile; }
    if (fwrite(Header, sizeof(unsigned char), WAVHeaderLength, fp) != WAVHeaderLength) { fclose(fp); return ErrReadFile; }
    return OK;
}
