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

#include "data/6.wav.mp3.h"
#include "data/7.wav.mp3.h"
#include "data/8.wav.mp3.h"
#include "data/9.wav.mp3.h"
#include "data/10.wav.mp3.h"
#include "data/11.wav.mp3.h"
#include "data/12.wav.mp3.h"
#include "data/13.wav.mp3.h"
#include "data/14.wav.mp3.h"
#include "data/15.wav.mp3.h"
#include "data/16.wav.mp3.h"
#include "data/17.wav.mp3.h"
#include "data/18.wav.mp3.h"
#include "data/19.wav.mp3.h"
#include "data/20.wav.mp3.h"
#include "data/21.wav.mp3.h"
#include "data/22.wav.mp3.h"
#include "data/23.wav.mp3.h"




typedef struct {
 int pos, len;
} num_t;

#include <mad.h>

#include "decrunch.h"

unsigned short *store;
int total;

struct buffer {
 unsigned char *start;
 unsigned int length;
};

sample_t samples[18];

const float freq_tab[3] = { 1.0f, 0.48f, 0.45f };

float pull(sample_t *in) {
 float ret;
 if(in->pos == -1.0f) return 0.0f;
 ret = in->data[(int)in->pos];
 in->pos += in->speed;
 if(in->pos > (float)in->len)
  in->pos = -1.0f; 
 return ret;
}

void trigger(int note, sample_t *in) {
 in->pos = 0.0f;
 in->speed = freq_tab[note];
}

enum mad_flow input(void *data, struct mad_stream *stream) {
 struct buffer *buffer = data;
 if(!buffer->length)
  return MAD_FLOW_STOP;
 mad_stream_buffer(stream, buffer->start, buffer->length);
 buffer->length = 0;
 return MAD_FLOW_CONTINUE;
}

unsigned short scale(mad_fixed_t sample) {
 sample+=(1L << (MAD_F_FRACBITS - 16));
 if(sample>=MAD_F_ONE)
  sample = MAD_F_ONE - 1;
 else if(sample < -MAD_F_ONE) 
  sample = -MAD_F_ONE;
 return sample >> (MAD_F_FRACBITS +1 - 16);
}

enum mad_flow output(void *data, struct mad_header *header, struct mad_pcm *pcm) {
 unsigned int nchannels, nsamples;
 mad_fixed_t *left_ch, *right_ch;
 signed int sample;
 nchannels = pcm->channels;
 nsamples = pcm->length;
 left_ch = pcm->samples[0];
 right_ch =pcm->samples[1];
 while(nsamples--) 
  store[total++] = scale(*left_ch++);

 return MAD_FLOW_CONTINUE;
}

void to_float(unsigned short *in, int len, float *out) {
 int i;
 signed short dat;
 for(i = 0;i<len;i++) {
  dat = (signed short)in[i];
  out[i] = (float)dat/20000;
 }
}

void decode(unsigned char *start, unsigned int len, sample_t *out) {
 struct buffer buffer;
 struct mad_decoder decoder;

 buffer.start = start;
 buffer.length = len;
 total = 0;
 
 mad_decoder_init(&decoder, &buffer, input, 0, 0, output,0 , 0);
 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
 mad_decoder_finish(&decoder);

 out->data = (float *)malloc(sizeof(float)*total);
 to_float(store, total, out->data);
 out->len = total;
 out->pos = -1.0f;
}

int get_size(unsigned char *in) {
 int i;
 for(i=0;;i++) {
  if((in[i+1] == 0x41) &&
     (in[i+2] == 0x41) &&
     (in[i+3] == 0x41)) return i;
 }
}


void decrunch(void) {
 int q;
 fflush(stdout); 
 store = (signed short *)malloc(sizeof(signed short) * 6000000);

#define DECODE(X,Y) \
 q = get_size(X); \
 decode(X, q, &samples[Y]);

 DECODE(drum_6, 0);
 DECODE(drum_7, 1);
 DECODE(drum_8, 2);
 DECODE(drum_9, 3);
 DECODE(drum_10, 4);
 DECODE(drum_11, 5);
 DECODE(drum_12, 6);
 DECODE(drum_13, 7);
 DECODE(drum_14, 8);
 DECODE(drum_15, 9);
 DECODE(drum_16, 10);
 DECODE(drum_17, 11);
 DECODE(drum_18, 12);
 DECODE(drum_19, 13);
 DECODE(drum_20, 14);
 DECODE(drum_21, 15);
 DECODE(drum_22, 16);
 DECODE(drum_23, 17);
 free(store);
}



