// SPDX-License-Identifier: Unlicense

#include "recorder.h"

#ifdef SHR3D_RECORDER

#include "file.h"
#include "song.h"
#include "global.h"
#include "string_.h"

void Recorder::init()
{
  if (Global::recorderBuffer.size() == 0)
    Global::recorderBuffer.reserve(100000000);
  Global::recorderBuffer.clear();
}

void Recorder::processBlock(const f32* const inBlock[2], i32 blockSize, const bool recordOnlyWhenMusicPlays)
{
  if (recordOnlyWhenMusicPlays && Global::musicPlaybackPosition == I64::max)
    return;

  const u64 oldSize = Global::recorderBuffer.size();
#if RECORD_INT_24BIT
  Global::recorderBuffer.resize(oldSize + blockSize * 2 * 3);
  for (i32 i = 0; i < blockSize; ++i)
  {
    const f32 scaledLeftF = inBlock[0][i] * f32(0x7FFFFFFF);
    const u32 scaledLeftU = u32(scaledLeftF);
    Global::recorderBuffer[oldSize + i * 6 + 0] = u8((scaledLeftU & 0xff00) >> 8);
    Global::recorderBuffer[oldSize + i * 6 + 1] = u8((scaledLeftU & 0xff0000) >> 16);
    Global::recorderBuffer[oldSize + i * 6 + 2] = u8((scaledLeftU & 0xff000000) >> 24);

    const f32 scaledRightF = inBlock[1][i] * f32(0x7FFFFFFF);
    const u32 scaledRightU = u32(scaledRightF);
    Global::recorderBuffer[oldSize + i * 6 + 3] = u8((scaledRightU & 0xff00) >> 8);
    Global::recorderBuffer[oldSize + i * 6 + 4] = u8((scaledRightU & 0xff0000) >> 16);
    Global::recorderBuffer[oldSize + i * 6 + 5] = u8((scaledRightU & 0xff000000) >> 24);
  }
#else
  Global::recorderBuffer.resize(oldSize + blockSize * 2 * sizeof(f32));
  {
    f32* recorderBuffer_as_f32 = reinterpret_cast<f32*>(Global::recorderBuffer.data());
    for (i32 i = 0; i < blockSize; ++i)
    {
      recorderBuffer_as_f32[oldSize / sizeof(f32) + i * 2] = inBlock[0][i];
      recorderBuffer_as_f32[oldSize / sizeof(f32) + i * 2 + 1] = inBlock[1][i];
    }
  }
#endif // RECORD_INT_24BIT
}

void Recorder::saveWavFile(const char8_t* wavFilepath, const i32 sampelRate)
{
  if (Global::recorderBuffer.size() == 0)
    return;

  FILE* file = File::fopen_u8(wavFilepath, true);
  ASSERT(file != nullptr);

  const RIFFWAVE riffWave{
    .ChunkSize = u32(36 + Global::recorderBuffer.size()),
    .SampleRate = u32(sampelRate),
    .ByteRate = u32(sampelRate) * 2 * 32 / 8,
    .Subchunk2Size = u32(Global::recorderBuffer.size())
  };

  fwrite(&riffWave, sizeof(RIFFWAVE), 1, file);
  fwrite(Global::recorderBuffer.data(), Global::recorderBuffer.size(), 1, file);

  ASSERT(Global::recorderBuffer.size() % (2 * 32 / 8) == 0); // check block alignment

  fclose(file);

  Global::recorderBuffer.clear();
}

std::u8string Recorder::generateWavPath(const Song::Info& songInfo)
{
  return Settings::pathRecorder +
    File::fixInvalidCharsInFilepath(songInfo.artistName.c_str()) + u8'/' +
    to_string(songInfo.songYear) + u8"-" +
    File::fixInvalidCharsInFilepath(songInfo.albumName.c_str()) + u8'/' +
    File::fixInvalidCharsInFilepath(songInfo.songName.c_str()) + u8'/';
}

#endif // SHR3D_RECORDER
