/*
sample.wav
16bit
1ch
*/

#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DATA_READ_LENGTH		50000
#define WAVE_OUT_LENGTH			(44100 / 60)

// ヘッダ情報
typedef struct {
	char riff_chunk_ID[4];
	long riff_chunk_size;
	char riff_form_type[4];
	char fmt_chunk_ID[4];
	long fmt_chunk_size;
	short fmt_wave_format_type;
	short fmt_channel;
	long fmt_samples_per_sec;
	long fmt_bytes_per_sec;
	short fmt_block_size;
	short fmt_bits_per_sample;
	char data_chunk_ID[4];
	long data_chunk_size;
} WAVEFILE_HEADER;

// 自己相関関数を用いて波形周期を算出
int CalculateWavePeriod(short s[], int template_length, int min_lag, int max_lag) {
	int m, n, p = min_lag;
	double r, r_max = 0.0;

	for (m = min_lag; m < max_lag; m++) {
		r = 0.0;
		for (n = 0; n < template_length; n++) r += s[n] * s[m + n];
		if (r > r_max) {
			r_max = r;
			p = m;
		}
	}

	return p;
}

int main() {
	FILE *fp_read, *fp_write;
	WAVEFILE_HEADER waveFileHeader;
	int n, template_size, p, q, pmin, pmax, offset = 0, read_cnt = 0;
	short read_buf_16[DATA_READ_LENGTH] = {0};
	short write_buf_16[DATA_READ_LENGTH] = {0};
	short play_buf_16[WAVE_OUT_LENGTH] = {0};	// 疑似出力バッファ
	double rate;

	char read_file[] = "sample.wav";
	char write_file[] = "sample_out.wav";

	if ((fp_read = fopen(read_file, "rb")) == NULL) {
		printf("読み込みwavファイルのオープンに失敗\n");
		exit(EXIT_FAILURE);
	}
	
	if ((fp_write = fopen(write_file, "wb")) == NULL) {
		printf("書き込みwavファイルのオープンに失敗\n");
		exit(EXIT_FAILURE);
	}

	fread(&waveFileHeader, sizeof(WAVEFILE_HEADER), 1, fp_read);

	printf("\n");
	printf("ビットレート \t%d\n", waveFileHeader.fmt_bits_per_sample);
	printf("チャンネル数 \t%d\n", waveFileHeader.fmt_channel);
	printf("標本化周波数 \t%d\n", waveFileHeader.fmt_samples_per_sec);

	// pmax + qmax < DATA_READ_LENGTH になるように
	rate = 1.3;
	if (rate <= 0.0 || rate == 1.0) {
		printf("不正レート\n");
		exit(EXIT_FAILURE);
	}
	template_size = (int)(waveFileHeader.fmt_samples_per_sec * 0.012);		// 12ms
	pmin = (int)(waveFileHeader.fmt_samples_per_sec * 0.002);						// 2ms
	pmax = (int)(waveFileHeader.fmt_samples_per_sec * 0.060);						// 60ms
	p = pmin;
	q = rate > 1.0 ? (int)(p / (rate - 1.0) + 0.5) : (int)(p * rate / (1.0 - rate) + 0.5);

	printf("\n");
	printf("レート \t\tx %f\n", rate);
	printf("デフォルト周期 \t%d\n", template_size);
	printf("最小基本周期 \t%d\n", pmin);
	printf("最大基本周期 \t%d\n", pmax);
	if (rate > 1.0) {
		printf("q min \t\t%d\n", (int)(pmin / (rate - 1.0) + 0.5));
		printf("q max \t\t%d\n", (int)(pmax / (rate - 1.0) + 0.5));
	} else {
		printf("q min \t\t%d\n", (int)(pmin * rate / (1.0 - rate) + 0.5));
		printf("q max \t\t%d\n", (int)(pmax * rate / (1.0 - rate) + 0.5));
	}

	waveFileHeader.data_chunk_size = (long)(waveFileHeader.data_chunk_size / rate);
	fwrite(&waveFileHeader, sizeof(WAVEFILE_HEADER), 1, fp_write);

	printf("\n");
	printf("ファイルサイズ \t%d Byte\n", waveFileHeader.data_chunk_size);

	do {
		while (1) {
			// スピーカー出力を考慮
			if (offset > WAVE_OUT_LENGTH) {
				memcpy(play_buf_16, write_buf_16, sizeof(short) * WAVE_OUT_LENGTH);
				for (n = 0; n < DATA_READ_LENGTH - WAVE_OUT_LENGTH; n++) write_buf_16[n] = write_buf_16[WAVE_OUT_LENGTH + n];
				offset -= WAVE_OUT_LENGTH;
				break;
			}

			if (rate > 1.0) {
				for (n = 0; n < DATA_READ_LENGTH - (p + q); n++) read_buf_16[n] = read_buf_16[p + q + n];
				read_cnt = fread(&read_buf_16[DATA_READ_LENGTH - (p + q)], sizeof(short), p + q, fp_read);

				p = CalculateWavePeriod(read_buf_16, template_size, pmin, pmax);
				q = (int)(p / (rate - 1.0) + 0.5);
				for (n = 0; n < p; n++) write_buf_16[offset + n] = read_buf_16[n] * (p - n) / p + read_buf_16[p + n] * n / p;
				for (n = p; n < q; n++) write_buf_16[offset + n] = read_buf_16[p + n];

				offset += q;
			} else {
				for (n = 0; n < DATA_READ_LENGTH - q; n++) read_buf_16[n] = read_buf_16[q + n];
				read_cnt = fread(&read_buf_16[DATA_READ_LENGTH - q], sizeof(short), q, fp_read);

				p = CalculateWavePeriod(read_buf_16, template_size, pmin, pmax);
				q = (int)(p * rate / (1.0 - rate) + 0.5);
				for (n = 0; n < p; n++) write_buf_16[offset +n] = read_buf_16[n];
				for (n = 0; n < p; n++) write_buf_16[offset +p + n] = read_buf_16[p + n] * (p - n) / p + read_buf_16[n] * n / p;
				for (n = p; n < q; n++) write_buf_16[offset +p + n] = read_buf_16[n];

				offset += p + q;
			}
		}

		fwrite(play_buf_16, sizeof(short), WAVE_OUT_LENGTH, fp_write);
	} while (read_cnt != 0);

	fclose(fp_read);
	fclose(fp_write);

	return 0;
}
