#include <stdio.h>
#include <math.h>
#include <stdlib.h>

// Fréquence d'échantillonage
#define FS 44100 
// Temps d'échantillonage
#define TS 0.05
// Nombre d'échantillions
#define NS (FS*TS)
// Amplitude du signal
#define A 32767 
// Fréquence de la porteuse
#define FC 400 

// Fonction de concaténation deux tableau
double* concat_tab(double **t, int a, int b) {
    double* tf = malloc(sizeof(double) * a * b);

    int pos = 0;
    for (int i = 0; i < b; i++) {
        for (int j = 0; j < a; j++) {
            tf[pos] = t[i][j];
            pos++;
        }
    }

    return tf;
}

// Fontion permetant la modulation d'un bit
double* modulation_unique(int b) {
    double* s = (double*)malloc(NS * sizeof(double));

    // Phase de 0 pour un bit de 0 et phase de pi pour un bit de 1
    int p = (b == 0) ? 0 : M_PI;
    
    for (int n = 0; n < NS; n++) {
        s[n] = A * cos(2 * M_PI * FC * ((double)n / (double)FS) + p);
    }
    return s;
}

// Fonction permetant la modulation d'un suite de bits
double* modulation(int* b, int bs) {
    double** s = (double**)malloc(sizeof(double*) * bs);
    
    for (int k = 0; k < bs; k++) {
        //s[k] = (double*)malloc(sizeof(double) * NS);
        s[k] = modulation_unique(b[k]);
    }

    //double* sf = (double*)malloc(sizeof(double) * NS * bs);
    double *sf = concat_tab(s, NS, bs);

    for (int i = 0; i < bs; i++) {
        free(s[i]);
    }
    free(s);

    return sf;
}

// Demodulation bpsk en connaissant le nombre d'échantillions et la fréquence de la porteuse (et donc la fréquence d'échantillonage)
int* demodulation(double* r, int rsize) {
    int bs = rsize; // A MODIFIER QUAND LE TRUC DU MAIN MARCHERA !
    int* b = (int*)malloc(sizeof(int) * bs);

    int k = 0, i = 0; 
    while (i < NS * bs) {
        double tmp = 0;
        for (int n = 0; n < NS; n++) {
            tmp += r[k * (int)NS + n] * cos(2 * M_PI * FC * ((double)n / (double)FS));
        }
        // Developper le produit de cos et appliquer un filtre passe bas pour trouver un equivalent de tmp
        b[k] = (tmp > 0.0) ? 0 : 1;
        i += NS;
        k++;
    }
    return b;
}

// Fonction pour écrire un fichier WAV 16 bits PCM
void write_wav(const char* filename, double* data, int len) {
    FILE* f = fopen(filename, "wb");
    if (!f) {
        return;
    }

    int32_t chunk_size = 36 + len * 2;
    int16_t audio_format = 1; // PCM
    int16_t num_channels = 1;
    int32_t sample_rate = FS;
    int32_t byte_rate = FS * num_channels * 2;
    int16_t block_align = num_channels * 2;
    int16_t bits_per_sample = 16;
    int32_t subchunk2_size = len * 2;

    // En-tête WAV
    fwrite("RIFF", 1, 4, f);
    fwrite(&chunk_size, 4, 1, f);
    fwrite("WAVE", 1, 4, f);
    fwrite("fmt ", 1, 4, f);

    int32_t subchunk1_size = 16;
    fwrite(&subchunk1_size, 4, 1, f);
    fwrite(&audio_format, 2, 1, f);
    fwrite(&num_channels, 2, 1, f);
    fwrite(&sample_rate, 4, 1, f);
    fwrite(&byte_rate, 4, 1, f);
    fwrite(&block_align, 2, 1, f);
    fwrite(&bits_per_sample, 2, 1, f);

    fwrite("data", 1, 4, f);
    fwrite(&subchunk2_size, 4, 1, f);

    for (int i = 0; i < len; i++) {
        int16_t sample = (int16_t)(data[i]);
        fwrite(&sample, sizeof(int16_t), 1, f);
    }

    fclose(f);
}


double* read_wav(const char* filename, int* out_len) {
    FILE* f = fopen(filename, "rb");
    if (!f) {
        perror("Erreur ouverture WAV");
        return NULL;
    }

    fseek(f, 0, SEEK_END);
    long filesize = ftell(f);
    fseek(f, 0, SEEK_SET);

    fseek(f, 44, SEEK_SET);

    int len = (filesize - 44) / 2;
    double* data = malloc(sizeof(double) * len);
    int16_t sample;

    for (int i = 0; i < len; i++) {
        fread(&sample, sizeof(int16_t), 1, f);
        data[i] = (double)sample;
    }

    fclose(f);

    *out_len = len;
    return data;
}

int main() {
    int bits[] = {0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1};

    int bs = sizeof(bits) / sizeof(bits[0]);

    for (int i = 0; i < bs; i++) {
       printf("%d ", bits[i]);
    }
    printf("\n");

    double* sf = modulation(bits, bs);

    write_wav("signal.wav", sf, NS * bs);
    
    /*
    FILE *f = fopen("signal.csv", "w");

    if (!f) {
        perror("Erreur ouverture fichier");
        free(sf);
        return 1;
    }

    for (int i = 0; i < NS * bs; i++) {
        fprintf(f, "%d,%f\n", i, sf[i]); 
    }

    fclose(f);
    */

    // NE MARCHE PAS RENVOIE 1 !
    //int rsize = (sizeof(sf) / (int)sizeof(sf[0]));
    
    int wav_len;
    double* wav_data = read_wav("signal3.wav", &wav_len);

    int* dbits = demodulation(wav_data, bs);

    for (int i = 0; i < bs; i++) {
       printf("%d ", dbits[i]);
    }
    printf("\n");

    free(sf);
    return 0;
}
