// SPDX-License-Identifier: Unlicense

#include "hexfin.h"
#include "amalgamated_q.h"
#include "wavreader.h"

#include <assert.h>
#include <chrono>
#include <stdlib.h>

#define BLOCK_SIZE 128

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

static const float lowest_frequency = 27.5f; // Note A0
static const float highest_frequency = 1567.98206f; // Note G6

int main(int argc, char* argv[])
{
  const char* wav_filepath = "res/guitar-input.wav";

  if (argc >= 2)
    wav_filepath = argv[1];

  unsigned int sample_rate = 0;
  unsigned int data_bytes = 0;
  FILE* file = fopen_wav_file_seek_to_audio_data(wav_filepath, &sample_rate, &data_bytes);
  if (file == NULL || data_bytes == 0)
  {
    fprintf(stderr, "Error: File reading aborted.\n");
    return -1;
  }

  float* rawF32Audio = (float*)malloc(data_bytes);
  const size_t sample_count = fread(rawF32Audio, sizeof(float), data_bytes / sizeof(float), file);

  fclose(file);

  const float sample_rate_f = (float)sample_rate;

  float accum_freq_hexfin = 0.0f;
  {
    struct hexfin_context ctx = hexfin_create_context(sample_rate_f, lowest_frequency, highest_frequency);
    const auto start = std::chrono::high_resolution_clock::now();
    for (unsigned int sample = 0; sample < sample_count; sample += BLOCK_SIZE)
    {
      const unsigned int capped_block_size = MIN(sample_count - sample, BLOCK_SIZE);
      accum_freq_hexfin += hexfin_processBlock(&ctx, &rawF32Audio[sample], capped_block_size, sample_rate_f, lowest_frequency, highest_frequency);
    }
    const long long nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - start).count();
    printf("hexfin:     %lld ns\n", nanoseconds);
    hexfin_destroy_context(&ctx);
  }

  float accum_freq_tuner = 0.0f;
  {
    const auto start = std::chrono::high_resolution_clock::now();
    for (unsigned int sample = 0; sample < sample_count; sample += BLOCK_SIZE)
    {
      const unsigned int capped_block_size = MIN(sample_count - sample, BLOCK_SIZE);
      accum_freq_tuner += amalgamated_q_processBlock(&rawF32Audio[sample], capped_block_size, sample_rate_f, lowest_frequency, highest_frequency);
    }
    const long long nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - start).count();
    printf("reference:  %lld ns\n", nanoseconds);
  }

  if (accum_freq_hexfin != accum_freq_tuner)
    fprintf(stderr, "Benchmarks failed. Hexfin result differs.\n");

  free(rawF32Audio);

  return 0;
}
