/*
  mp3.c
  -----
  Part of the Shine MP3 encoder for MidiCon
  16/9/2025

  saves the midi file as an mp3
*/

#include "main.h"
#include "lib.h"
#include "types.h"
#include "table1.h" // declared here but only used by coder (asm or 'c' version)

config_t config;
int cutoff;

void (*L3_window_filter_subband)(unsigned long **buffer, long s[SBLIMIT], int k);
void (*L3_mdct_sub)(long sb_sample[2][3][18][SBLIMIT],
                 long mdct_freq[2][2][samp_per_frame2]);
int (*quantize)(int ix[samp_per_frame2], int stepsize);

extern void L3_window_filter_subband_a(unsigned long **buffer, long s[SBLIMIT], int k);
extern void L3_mdct_sub_a(long sb_sample[2][3][18][SBLIMIT],
                 long mdct_freq[2][2][samp_per_frame2]);
extern int quantize_a(int ix[samp_per_frame2], int stepsize);

extern void L3_window_filter_subband_sa(unsigned long **buffer, long s[SBLIMIT], int k);
extern void L3_mdct_sub_sa(long sb_sample[2][3][18][SBLIMIT],
                 long mdct_freq[2][2][samp_per_frame2]);
extern int quantize_sa(int ix[samp_per_frame2], int stepsize);


extern int main_data_begin; // loop.c L3_iteration_loop, clear before every file decode
extern long *xr, xrabs[samp_per_frame2], xrmax; // loop.c
extern long int x[2][HAN_SIZE], z[512]; // coder.c


int *scalefac_band_long;

/* Scalefactor bands. */
static int sfBandIndex[4][3][23] =
{
  { /* MPEG-2.5 11.025 kHz */
    {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576},
    /* MPEG-2.5 12 kHz */
    {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576},
    /* MPEG-2.5 8 kHz */
    {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576}
  },
  {
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  },
  { /* Table B.2.b: 22.05 kHz */
    {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576},
    /* Table B.2.c: 24 kHz */
    {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,332,394,464,540,576},
    /* Table B.2.a: 16 kHz */
    {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}
  },
  { /* Table B.8.b: 44.1 kHz */
    {0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576},
    /* Table B.8.c: 48 kHz */
    {0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576},
    /* Table B.8.a: 32 kHz */
    {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576}
  }
};

static unsigned long *buffer[2];
static long remainder_;
static long bytes_per_frame;
static long lag;
static int  sideinfo_len;
static int  l3_enc[2][2][samp_per_frame2];
static long l3_sb_sample[2][3][18][SBLIMIT];
static long mdct_freq[2][2][samp_per_frame2];
static L3_side_info_t side_info;

static int req;


unsigned long midiSynth_sample(void); // kbd.c


/*
 * wave_get
 * --------
 * This takes tyhe place of the normal "wave_get" from a wav file.
 */
static unsigned long int *wave_get(int req)
{
  static unsigned long ibuff[samp_per_frame];  // input buffer

  int i;

  if(!rec_active())
    return 0;

  for(i =0; i<req; i++)
    ibuff[i] = midiSynth_sample();

  return ibuff;
}


/*
 * find_samplerate_index:
 * ----------------------
 */
static int find_samplerate_index(long freq)
{
  static long sr[4][3] = {{11025, 12000,  8000},   // mpeg 2.5
                          {    0,     0,     0},   // reserved
                          {22050, 24000, 16000},   // mpeg 2
                          {44100, 48000, 32000}};  // mpeg 1
  int i, j;

  for(j=0; j<4; j++)
    for(i=0; i<3; i++)
      if((freq == sr[j][i]) && (j != 1))
      {
        config.mpeg.type = j;
        return i;
      }

  return -1; // Invalid samplerate
}


/*
 * find_bitrate_index:
 * -------------------
 */
static int find_bitrate_index(int bitr)
{
  static long br[2][15] =
    {{0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160},   // mpeg 2/2.5
     {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}};  // mpeg 1
  int i;

  for(i=1; i<15; i++)
    if(bitr==br[config.mpeg.type & 1][i]) return i;

  return -1; // Invalid bitrate
}


/*
 * set_cutoff
 * ----------
 */
int set_cutoff(void)
{
  static int cutoff_tab[3][2][15] =
  {
    { // 44.1k, 22.05k, 11.025k
      {100,104,131,157,183,209,261,313,365,418,418,418,418,418,418}, // stereo
      {183,209,261,313,365,418,418,418,418,418,418,418,418,418,418}  // mono
    },
    { // 48k, 24k, 12k
      {100,104,131,157,183,209,261,313,384,384,384,384,384,384,384}, // stereo
      {183,209,261,313,365,384,384,384,384,384,384,384,384,384,384}  // mono
    },
    { // 32k, 16k, 8k
      {100,104,131,157,183,209,261,313,365,418,522,576,576,576,576}, // stereo
      {183,209,261,313,365,418,522,576,576,576,576,576,576,576,576}  // mono
    }
  };

  return cutoff_tab[config.mpeg.samplerate_index]
                   [config.mpeg.mode == MODE_MONO]
                   [config.mpeg.bitrate_index];
}


/*
 * mp3_init
 * --------
 */
int mp3_init(opt_t *o)
{
  config.mpeg.type = MPEG1;
  config.mpeg.layr = LAYER_3;
  config.mpeg.mode = (o->mono) ? MODE_MONO : MODE_DUAL_CHANNEL;
  config.mpeg.bitr = o->bitrate;
  config.mpeg.psyc = 0;
  config.mpeg.emph = 0;
  config.mpeg.crc  = 0;
  config.mpeg.ext  = 0;
  config.mpeg.mode_ext  = 0;
  config.mpeg.copyright = 0;
  config.mpeg.original  = 1;
  config.mpeg.channels = (o->mono) ? 1 : 2;
  config.mpeg.granules = 2;
  config.wave.samplerate = o->sample_rate;
  config.wave.channels = 2; // synth always produces 2 channels

  // set pointers to use SA functions
  L3_window_filter_subband = L3_window_filter_subband_sa;
  L3_mdct_sub = L3_mdct_sub_sa;
  quantize = quantize_sa;

  int n;
  if((n = find_samplerate_index(config.wave.samplerate)) < 0)
    return -INVALID_SAMPLE_RATE;
  config.mpeg.samplerate_index = n;
  if((n = find_bitrate_index(config.mpeg.bitr)) < 0)
    return -INVALID_BITRATE;
  config.mpeg.bitrate_index = n;
  cutoff = set_cutoff();

  return 0;
}

/*
 * player_save_mp3
 * ---------------
 */
int player_save_mp3(char *filename)
{
  int err;

  strcat(filename, "/mp3");

  // clear all data arrays, this to avoid a noisy first frame due to
  // the last time the encoder was used.
  main_data_begin = 0;
  xr = 0;
  xrmax = 0;
  memset(xrabs, 0, sizeof(xrabs));
  memset(x, 0, sizeof(x));
  memset(z, 0, sizeof(z));
  memset(&side_info, 0, sizeof(side_info));
  memset(&l3_enc, 0, sizeof(l3_enc));
  memset(&l3_sb_sample, 0, sizeof(l3_sb_sample));
  memset(&mdct_freq, 0, sizeof(mdct_freq));

  if(config.mpeg.type == MPEG1)
  {
    config.mpeg.granules = 2;
    config.mpeg.samples_per_frame = samp_per_frame;
    config.mpeg.resv_limit = ((1<<9)-1)<<3;
    sideinfo_len = (config.mpeg.channels == 1) ? 168 : 288;
  }
  else // mpeg 2/2.5
  {
    config.mpeg.granules = 1;
    config.mpeg.samples_per_frame = samp_per_frame2;
    config.mpeg.resv_limit = ((1<<8)-1)<<3;
    sideinfo_len = (config.mpeg.channels == 1) ? 104 : 168;
  }
  scalefac_band_long = sfBandIndex[config.mpeg.type][config.mpeg.samplerate_index];

#ifdef NO_RESERVOIR
  config.mpeg.resv_limit = 0;
#endif

  { // find number of whole bytes per frame and the remainder
    long x = config.mpeg.samples_per_frame * config.mpeg.bitr * (1000/8);
    bytes_per_frame = x / config.wave.samplerate;
    remainder_  = x % config.wave.samplerate;
  }

  // check if enough room on disc
  unsigned int size = (song_duration * config.mpeg.bitr * (1000/CLK_RES)) / 8;
  err = check_disc_space(filename, size);
  if(err !=  0) // not enough disc space or user cancelled
    return err;

  lag = 0;
  req = config.mpeg.samples_per_frame >> (2 - config.wave.channels);

  if((err = open_bit_stream(filename)) < 0)
    return err;

  set_filetype(filename, ro.converting = AMPEG);
  set_rec_active();

  return player_start((1<<FILE_PLAY) | (1<<QUIET)); // start playback
}

/*
 * mp3_recording
 * -------------
 */
void mp3_recording(void)
{
  int ch, i, gr, mean_bits;

  // encode a frame of the pcm audio data
  if((buffer[0] = buffer[1] = wave_get(req)) != 0)
  {
    // sort out padding
    config.mpeg.padding = (lag += remainder_) >= config.wave.samplerate;
    if (config.mpeg.padding)
      lag -= config.wave.samplerate;
    config.mpeg.bits_per_frame = 8*(bytes_per_frame + config.mpeg.padding);

    // bits per channel per granule
    mean_bits = (config.mpeg.bits_per_frame - sideinfo_len) >>
                      (config.mpeg.granules + config.mpeg.channels - 2);

    // polyphase filtering
    for(gr=0; gr<config.mpeg.granules; gr++)
      for(ch=0; ch<config.mpeg.channels; ch++)
        for(i=0;i<18;i++)
          L3_window_filter_subband(&buffer[ch], &l3_sb_sample[ch][gr+1][i][0] ,ch);

    // apply mdct to the polyphase output
    L3_mdct_sub(l3_sb_sample, mdct_freq);

    // bit and noise allocation
    L3_iteration_loop(mdct_freq, &side_info, l3_enc, mean_bits);

    // write the frame to the bitstream
    L3_format_bitstream(l3_enc, &side_info);
  }

  if(!rec_active())
  {
    close_bit_stream();
    ro.converting = 0;
  }
}
