//For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life

#include "windows.h"
#include "mmsystem.h"
#include "mmreg.h"
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
// some song information
#include "Synth.h"
#define INCLUDE_NODES
#include <cstdio>

#include "64k2Patch.h"
#include "64k2Song.h"

#define SAMPLE_RATE 44100
#define SAMPLE_TYPE float
SAMPLE_TYPE lpSoundBuffer[MAX_SAMPLES*2 + 44100*60]; // add safety buffer for 60s 
HWAVEOUT hWaveOut;

/////////////////////////////////////////////////////////////////////////////////
// initialized data
/////////////////////////////////////////////////////////////////////////////////

WAVEFORMATEX WaveFMT =
{
	WAVE_FORMAT_IEEE_FLOAT,
	2, // channels
	SAMPLE_RATE, // samples per sec
	SAMPLE_RATE*sizeof(SAMPLE_TYPE)*2, // bytes per sec
	sizeof(SAMPLE_TYPE)*2, // block alignment;
	sizeof(SAMPLE_TYPE)*8, // bits per sample
	0 // extension not needed
};
typedef struct
{
	INT32 riff_marker_aleluya;
	INT32 size_minus_8_aleluya;
	INT32 wave_marker_aleluya;
	INT32 fmt_marker_aleluya;
	INT32 fmt_len_is_16_aleluya;
	INT16 wave_type_aleluya;
	INT16 num_channels_aleluya;
	INT32 sample_rate_aleluya;
	INT32 mult_aleluya;  //' (Sample Rate * Bit Size * Channels) / 8
	INT16 mult2_aleluya; //(Bit Size * Channels) / 8
	INT16 bits_per_sample_aleluya; //(=Bit Size * Samples)
	INT32 data_marker_aleluya;
	INT32 size_minus_44_aleluya;
} WaveFile_aleluya;

/*
Put #1, 1, "RIFF"        ' RIFF marker
Put #1, 5, CInt(0)       ' file-size (equals file-size - 8)
Put #1, 9, "WAVE"        ' Mark it as type "WAVE"
Put #1, 13, "fmt "        ' Mark the format section.
Put #1, 17, CLng(16)      ' Length of format data.  Always 16
Put #1, 21, CInt(1)       ' Wave type PCM
Put #1, 23, CInt(2)       ' 2 channels
Put #1, 25, CLng(44100)   ' 44.1 kHz Sample Rate (CD-Quality)
Put #1, 29, CLng(88200)   ' (Sample Rate * Bit Size * Channels) / 8
Put #1, 33, CInt(2)       ' (Bit Size * Channels) / 8
Put #1, 35, CInt(16)      ' Bits per sample (=Bit Size * Samples)
Put #1, 37, "data"        ' "data" marker
Put #1, 41, CInt(0)       ' data-size (equals file-size - 44).
*/
WAVEHDR WaveHDR = 
{
	(LPSTR)lpSoundBuffer, 
	MAX_SAMPLES*sizeof(SAMPLE_TYPE)*2,			// MAX_SAMPLES*sizeof(float)*2(stereo)
	0, 
	0, 
	0, 
	0, 
	0, 
	0
};

MMTIME MMTime = 
{ 
	TIME_SAMPLES,
	0
};

/////////////////////////////////////////////////////////////////////////////////
// crt emulation
/////////////////////////////////////////////////////////////////////////////////

extern "C" 
{
	int _fltused = 1;
}


void writeWavFile_aleluya()
{
	HANDLE file_aleluya = CreateFile(
		TEXT("out_aleluya.wav"),
		GENERIC_WRITE,
		0,
		NULL,
		OPEN_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);

	WaveFile_aleluya waveFile_aleluya = {
		NULL,
		NULL,
		NULL,
		NULL,
		16,
		3,
		2,
		44100,
		352800,
		8,
		32,
		NULL,
		NULL
	};
	char riff_marker_aleluya[] = "RIFF";
	char wave_marker_aleluya[] = "WAVE";
	char fmt__marker_aleluya[] = "fmt ";
	char data_marker_aleluya[] = "data";

	memcpy(&waveFile_aleluya.riff_marker_aleluya, riff_marker_aleluya, 4);
	memcpy(&waveFile_aleluya.wave_marker_aleluya, wave_marker_aleluya, 4);
	memcpy(&waveFile_aleluya.fmt_marker_aleluya, fmt__marker_aleluya, 4);
	memcpy(&waveFile_aleluya.data_marker_aleluya, data_marker_aleluya, 4);
	waveFile_aleluya.size_minus_8_aleluya = sizeof(SAMPLE_TYPE) * MAX_SAMPLES * 2 - 8;
	waveFile_aleluya.size_minus_44_aleluya = sizeof(SAMPLE_TYPE) * MAX_SAMPLES * 2 - 44;
	WriteFile(
		file_aleluya,
		&waveFile_aleluya,
		sizeof(waveFile_aleluya),
		NULL,
		NULL
	);
	WriteFile(
		file_aleluya,
		lpSoundBuffer,
		sizeof(SAMPLE_TYPE) * MAX_SAMPLES * 2,
		NULL,
		NULL
	);

	CloseHandle(file_aleluya);
}

/////////////////////////////////////////////////////////////////////////////////
// entry point for the executable if msvcrt is not used
/////////////////////////////////////////////////////////////////////////////////
const char yesArg_aleluya[] = "Hallelujah,\r\n\r\nSo Holy / Gospel\r\nRe-imagining the 1861 song by John B. Dykes\r\nBuilt with 64klang, petite, renoise, visual studio.\r\n\r\nWe will (over)write a wav file after song ends (in about 3 minutes God willing).\r\nESC Exits.\r\n\r\n1 Corinthians 15:1-4:\r\nNow I declare to you, brothers, the Good News which I preached to you, which also you received, in which you also stand, by which also you are saved, if you hold firmly the word which I preached to you—unless you believed in vain. For I delivered to you first of all that which I also received: that Christ died for our sins according to the Scriptures, that he was buried, that he was raised on the third day according to the Scriptures -WEB";
const char noArg_aleluya[] = "Hallelujah,\r\n\r\nSo Holy / Gospel\r\nRe-imagining the 1861 song by John B. Dykes\r\nBuilt with 64klang, petite, renoise, visual studio.\r\n\r\nPlease place any argument after the executable to (over)write a WAV file(~54MB).\r\nSong will exit in around 3 minutes.\r\nESC Exits.\r\n\r\n1 Corinthians 15:1-4:\r\nNow I declare to you, brothers, the Good News which I preached to you, which also you received, in which you also stand, by which also you are saved, if you hold firmly the word which I preached to you—unless you believed in vain. For I delivered to you first of all that which I also received: that Christ died for our sins according to the Scriptures, that he was buried, that he was raised on the third day according to the Scriptures -WEB";
#if defined _DEBUG
void main(void)
#else
void mainCRTStartup(void)
#endif
{
	// init synth and start filling the buffer
	int numArg_aleluya;
	BOOL doWriteWav_aleluya = false;


	CommandLineToArgvW(
		GetCommandLineW(),
		&numArg_aleluya
	);

	if (numArg_aleluya > 1) {
		doWriteWav_aleluya = true;
		WriteFile(
			GetStdHandle(STD_OUTPUT_HANDLE),
			yesArg_aleluya,
			sizeof(yesArg_aleluya),
			NULL,
			NULL
		);
	}
	else {
		WriteFile(
			GetStdHandle(STD_OUTPUT_HANDLE),
			noArg_aleluya			,
			sizeof(noArg_aleluya),
			NULL,
			NULL
		);
	}

	_64klang_Init(SynthStream, SynthNodes, SynthMonoConstantOffset, SynthStereoConstantOffset, SynthMaxOffset);
#if 1
	// threaded buffer fill with 5 seconds heads up
	CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_64klang_Render, lpSoundBuffer, 0, 0);
	Sleep(5000);
#else
	// sequential (blocking) buffer fill aka precalc
	_64klang_Render(lpSoundBuffer);
#endif
	
	// start audio playback
	waveOutOpen(&hWaveOut, WAVE_MAPPER, &WaveFMT, NULL, 0, CALLBACK_NULL);
	waveOutPrepareHeader(hWaveOut, &WaveHDR, sizeof(WaveHDR));
	waveOutWrite(hWaveOut, &WaveHDR, sizeof(WaveHDR));
	do
	{
		waveOutGetPosition(hWaveOut, &MMTime, sizeof(MMTIME));
		Sleep(128);
	} while ((MMTime.u.sample < MAX_SAMPLES) && !GetAsyncKeyState(VK_ESCAPE));
	

	if (doWriteWav_aleluya) writeWavFile_aleluya();

	// done
	ExitProcess(0);
}
