Esempio n. 1
0
int GMSynthDLL::ThreadProc()
{
	if (live)
	{
		if (seqMode & seqPlay)
			ldTm = 0.02;
		else
			ldTm = 0.20;
		OpenWaveDevice();
		inmgr.SetWaveOut(&wvd);
	}
	else
	{
		if (wvf.OpenWaveFile(outFileName, 2))
		{
			OnEvent(SEQEVT_SEQSTOP, NULL);
			return GMSYNTH_ERR_FILEOPEN;
		}
		inmgr.SetWaveOut(&wvf);
	}
	inmgr.Reset();
	seq.SequenceMulti(inmgr, stTime, endTime, seqMode);
	if (live)
	{
		bsInt32 drain = (bsInt32) (synthParams.sampleRate * (ldTm * 4));
		while (--drain > 0)
			inmgr.Tick();
		CloseWaveDevice();
	}
	else
		wvf.CloseWaveFile();
	return GMSYNTH_NOERROR;
}
Esempio n. 2
0
LRESULT CMainDlg::OnSaveWave(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	char fileName[MAX_PATH];
	memset(fileName, 0, sizeof(fileName));
	OPENFILENAME ofn;
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = m_hWnd;
	ofn.lpstrFilter = "Sound Files(*.wav)\0*.wav\0All Files(*.*)\0*.*\0";
	ofn.nFilterIndex = 1;
	ofn.lpstrFile = fileName;
	ofn.lpstrDefExt = ".wav";
	ofn.nMaxFile = MAX_PATH;
	ofn.Flags = OFN_OVERWRITEPROMPT;
	
	if (GetSaveFileName (&ofn))
	{
		double frq = GetFrequency();
		GenWaveI wv;
		wv.InitWT(frq, WT_USR(0));
		EnvGen eg;
		eg.InitEG(1.0, 2.0, 0.05, 0.05);
		WaveFile wvf;
		wvf.OpenWaveFile(fileName, 2);
		long totalSamples = (long) (2.0 * synthParams.sampleRate);
		for (long n = 0; n < totalSamples; n++)
			wvf.Output1(eg.Gen() * wv.Gen());
		wvf.CloseWaveFile();

	}
	return 0;
}
Esempio n. 3
0
LRESULT CMainDlg::OnSave(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	char fileName[MAX_PATH];
	memset(fileName, 0, sizeof(fileName));
	OPENFILENAME ofn;
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = m_hWnd;
	ofn.lpstrFilter = "Sound Files(*.wav)\0*.wav\0All Files(*.*)\0*.*\0";
	ofn.nFilterIndex = 1;
	ofn.lpstrFile = fileName;
	ofn.lpstrDefExt = ".wav";
	ofn.nMaxFile = MAX_PATH;
	ofn.Flags = OFN_OVERWRITEPROMPT;
	
	if (GetSaveFileName (&ofn))
	{
		WaveFile wvf;
		wvf.OpenWaveFile(fileName, 2);
		InitGen();
		long totalSamples = (long) ((durTotal * synthParams.sampleRate) + 0.5);
		long atkSamples = (long) (durAtkSus * synthParams.sampleRate);
		long n;
		for (n = 0; n < atkSamples; n++)
			wvf.Output1(Generate());
		NoteOff();
		while (n++ < totalSamples)
			wvf.Output1(Generate());
		for (n = 0; n < 440; n++)
			wvf.Output1(0);
		wvf.CloseWaveFile();
	}
	return 0;
}
Esempio n. 4
0
int main(int argc, char *argv[])
{
#if defined(USE_MSXML)
	CoInitialize(0);
#endif

	const char *fname = "data.xml";
	if (argc > 1)
		fname = argv[1];

	InitSynthesizer();

	mix.SetChannels(2);
	mix.MasterVolume(1.0, 1.0);
	mix.ChannelOn(0, 1);
	mix.ChannelOn(1, 1);
	mix.ChannelVolume(0, 1.0);
	mix.ChannelVolume(1, 1.0);
#ifdef ADD_REVERB
	mix.SetFxChannels(1);
	mix.FxInit(0, &rvrb, 0.1);
	mix.FxLevel(0, 0, 0.2);
	mix.FxLevel(0, 1, 0.2);
	rvrb.InitReverb(1.0, 2.0);
#endif

	inMgr.Init(&mix, &wvf);

	inMgr.AddType("Tone", ToneInstr::ToneFactory, ToneInstr::ToneEventFactory);
	inMgr.AddType("ToneFM", ToneFM::ToneFMFactory, ToneFM::ToneFMEventFactory);
	inMgr.AddType("AddSynth", AddSynth::AddSynthFactory, AddSynth::AddSynthEventFactory);
	inMgr.AddType("SubSynth", SubSynth::SubSynthFactory, SubSynth::SubSynthEventFactory);
	inMgr.AddType("FMSynth", FMSynth::FMSynthFactory, FMSynth::FMSynthEventFactory);
	inMgr.AddType("MatrixSynth", MatrixSynth::MatrixSynthFactory, MatrixSynth::MatrixSynthEventFactory);
	inMgr.AddType("WFSynth", WFSynth::WFSynthFactory, WFSynth::WFSynthEventFactory);
	inMgr.AddType("Chuffer", Chuffer::ChufferFactory, Chuffer::ChufferEventFactory);
	inMgr.AddType("ModSynth", ModSynth::ModSynthFactory, ModSynth::ModSynthEventFactory);
	inMgr.AddType("BuzzSynth", BuzzSynth::InstrFactory, BuzzSynth::EventFactory);
	InstrMapEntry *ime = 0;
	while ((ime = inMgr.EnumType(ime)) != 0)
		ime->dumpTmplt = DestroyTemplate;

	XmlSynthDoc doc;
	XmlSynthElem rootNode(&doc);
	if (!doc.Open(fname, &rootNode))
	{
		printf("Cannot open file %s\n", fname);
		exit(1);
	}

	// Optional: use LoadInstrLib(inMgr, fname)
	// but we want to discover the inum values
	// and add sequences programaticaly...

	XmlSynthElem elem(&doc);
	XmlSynthElem *inst = rootNode.FirstChild(&elem);
	while (inst != NULL)
	{
		if (inst->TagMatch("instr"))
		{
			InstrConfig *ent = inMgr.LoadInstr(inst);
			if (strcmp(ent->instrType->GetType(), "WFSynth") == 0)
				AddEvent(ent->inum, 48, 1.0);
			else
				AddSequence(ent->inum, 0.25);
		}

		inst = elem.NextSibling(&elem);
	}
	doc.Close();

	if (wvf.OpenWaveFile("example10.wav", 2))
	{
		printf("Cannot open wavefile for output\n");
		exit(1);
	}
	seq.Sequence(inMgr);

#ifdef ADD_REVERB
	// drain the reverb...
	AmpValue lv;
	AmpValue rv;
	long n = synthParams.isampleRate;
	while (n-- > 0)
	{
		mix.Out(&lv, &rv);
		wvf.Output2(lv, rv);
	}
#endif

	wvf.CloseWaveFile();

	///////////////////////////////////////////////////////////////
	// Code to test instrument save functions...
#define TEST_SAVE_INSTR 1
#ifdef TEST_SAVE_INSTR
	doc.NewDoc("instrlib", &rootNode);
	InstrConfig *inc = inMgr.EnumInstr(0);
	while (inc)
	{
		InstrMapEntry *ime = inc->instrType;
		Instrument *ip = (Instrument *)inc->instrTmplt;
		if (ip)
		{
			rootNode.AddChild("instr", &elem);
			elem.SetAttribute("id", inc->inum);
			elem.SetAttribute("type", ime->itype);
			elem.SetAttribute("name", inc->GetName());
			elem.SetAttribute("desc", inc->GetDesc());
			ip->Save(&elem);
		}
		inc = inMgr.EnumInstr(inc);
	}
	bsString outxml(fname);
	bsString outbase;
	bsString outfile;
	outxml.SplitPath(outbase, outfile, 1);
	outxml = outbase;
	outxml += '_';
	outxml += outfile;
	doc.Save(outxml);
#endif
	///////////////////////////////////////////////////////////////

	return 0;
}
Esempio n. 5
0
int main(int argc, char *argv[])
{
	int pitch = 48;  // middle C
	FrqValue duration = 1.0;
	AmpValue lfoAmp = 10;
	bsInt32 tl = 16384;

	if (argc > 1)
		duration = atof(argv[1]);
	if (argc > 2)
		pitch = atoi(argv[2]);
	if (argc > 3)
		tl = atol(argv[3]);

	InitSynthesizer(44100, tl);

	FrqValue frequency = synthParams.GetFrequency(pitch);
	
	if (wvf.OpenWaveFile("example04.wav", 1) < 0)
	{
		printf("Cannot open wavefile for output\n");
		exit(1);
	}

	//EnvGen eg;
	EnvGenExp eg;
	//EnvGenLog eg;
	eg.SetBias(0.2);
	eg.InitEG(0.7, duration, 0.2, 0.3);

	GenWaveWT wv;
	GenWaveI  wvi;
	GenWave32 wv32;
	//GenWave64 wv64;
	GenWaveFM wvfm;
	GenWaveAM wvam;
	GenWaveRM wvrm;

	/////////////////////////////////////////////////
	// 1 - sine wave
	/////////////////////////////////////////////////
	wv.InitWT(frequency, WT_SIN);
	Generate(duration, &wv, &eg);
	//GenerateVib(duration, &wv, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wv, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 2 - sine wave using interpolation
	/////////////////////////////////////////////////
	wvi.InitWT(frequency, WT_SIN);
	Generate(duration, &wvi, &eg);
	//GenerateVib(duration, &wvi, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvi, &eg, lfoAmp);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 3 - fixed summation of sine waves
	/////////////////////////////////////////////////
	wv.InitWT(frequency, WT_SAW);
	Generate(duration, &wv, &eg);
	//GenerateVib(duration, &wv, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wv, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 4 - fixed summation of sine waves using interpolation
	/////////////////////////////////////////////////
	wvi.InitWT(frequency, WT_SAW);
	Generate(duration, &wvi, &eg);
	//GenerateVib(duration, &wvi, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvi, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 5 - 32 bit fixed-point index,
	/////////////////////////////////////////////////
	wv32.InitWT(frequency, WT_SAW);
	Generate(duration, &wv32, &eg);
	//GenerateVib(duration, &wv32, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wv32, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 6 - 64 bit fixed-point index,
	/////////////////////////////////////////////////
	//wv64.InitWT(frequency, WT_SAW);
	//Generate(duration, &wv64, &eg);
	//GenerateVib(duration, &wv64, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wv64, &eg, lfoAmp);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 7 - square wave (summation)
	/////////////////////////////////////////////////
	wv.InitWT(frequency, WT_SQR);
	Generate(duration, &wv, &eg);
	//GenerateVib(duration, &wv, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wv, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 8 - triangle wave (summation)
	/////////////////////////////////////////////////
	wv.InitWT(frequency, WT_TRI);
	Generate(duration, &wv, &eg);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 9 - FM
	/////////////////////////////////////////////////
	wvfm.InitFM(frequency/2, 2.0, 1.0, WT_SIN);
	Generate(duration, &wvfm, &eg);
	wvfm.InitFM(frequency, 2.0, 1.0, WT_SIN);
	Generate(duration, &wvfm, &eg);
	//GenerateVib(duration, &wvfm, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvfm, &eg, lfoAmp);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 10 - Amplitude Modulation
	/////////////////////////////////////////////////
	wvam.InitAM(frequency, frequency*2.5, 1.0, WT_SIN);
	Generate(duration, &wvam, &eg);

	/////////////////////////////////////////////////
	// 11 - Ring Modulation
	/////////////////////////////////////////////////
	wvrm.InitAM(frequency, frequency*2.5, 1.0, WT_SIN);
	Generate(duration, &wvrm, &eg);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 12 - Dynamic summing: sawtooth
	/////////////////////////////////////////////////
	GenWaveSum wvs;
	AmpValue mult[8];
	AmpValue amps[8];
	for (int pnum = 0; pnum < 8; pnum++)
	{
		AmpValue x = (AmpValue)pnum + 1;
		mult[pnum] = x;
		amps[pnum] = 1.0/x;
		if (pnum & 1)
			amps[pnum] = -amps[pnum];
	}
	wvs.InitParts(8, mult, amps, 1);
	wvs.InitWT(frequency, WT_SIN);
	Generate(duration, &wvs, &eg);
	//GenerateVib(duration, &wvs, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvs, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 13 - Dynamic summing: doubling at the fifth
	/////////////////////////////////////////////////
	mult[0] = 1.0f;
	mult[1] = 1.5f;
	amps[0] = 0.5f;
	amps[1] = 0.5f;
	wvs.InitParts(2, mult, amps, 0);
	wvs.InitWT(frequency, WT_SAW);
	Generate(duration, &wvs, &eg);
	//GenerateVib(duration, &wvs, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 14 - Dynamic summing: chorus effect, two notes at slightly different frequency
	/////////////////////////////////////////////////
	mult[0] = 1.0;
	mult[1] = 1.001;
	amps[0] = 0.6;
	amps[1] = 0.4;
	wvs.InitParts(2, mult, amps, 0);
	wvs.InitWT(frequency, WT_SAW);
	Generate(duration, &wvs, &eg);
	//GenerateVib(duration, &wvs, &eg, lfoAmp);

	Silence(0.25);

	// For comparison:

	/////////////////////////////////////////////////
	// 15 - Sine wave Direct
	/////////////////////////////////////////////////
	GenWave wvsin;
	wvsin.Init(1, &frequency);
	Generate(duration, &wvsin, &eg);
	//GenerateVib(duration, &wvsin, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 16 - Sawtooth Direct
	/////////////////////////////////////////////////
	GenWaveSaw wvsaw;
	wvsaw.Init(1, &frequency);
	Generate(duration, &wvsaw, &eg);
	//GenerateVib(duration, &wvsaw, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvsaw, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 17 - Triangle Direct
	/////////////////////////////////////////////////
	GenWaveTri wvtri;
	wvtri.Init(1, &frequency);
	Generate(duration, &wvtri, &eg);
	//GenerateVib(duration, &wvtri, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvtri, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 18 - Square Direct
	/////////////////////////////////////////////////
	GenWaveSqr wvsqr;
	wvsqr.InitSqr(frequency, 50.0);
	Generate(duration, &wvsqr, &eg);
	//GenerateVib(duration, &wvsqr, &eg, lfoAmp);
	//GeneratePhaseVib(duration, &wvsqr, &eg, lfoAmp);

	/////////////////////////////////////////////////
	// 19 - Square Direct Integer
	/////////////////////////////////////////////////
	GenWaveSqr32 wvsqr32;
	wvsqr32.InitSqr(frequency, 50.0);
	Generate(duration, &wvsqr32, &eg);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 20 - White Noise
	/////////////////////////////////////////////////
	GenNoise wvn;
	Generate(duration, &wvn, &eg);

	/////////////////////////////////////////////////
	// 21 - 'H' White Noise (sampled)
	/////////////////////////////////////////////////
	GenNoiseH wvnh;
	float h;
	for (h = 2000.0; h < 10000.0; h += 2000.0)
	{
		wvnh.Init(1, &h);
		Generate(duration, &wvnh, &eg);
	}

	/////////////////////////////////////////////////
	// 21 - 'Interploated' White Noise
	/////////////////////////////////////////////////
	GenNoiseI wvni;
	for (h = 2000.0; h < 10000.0; h += 2000.0)
	{
		wvni.Init(1, &h);
		Generate(duration, &wvni, &eg);
	}

	Silence(0.25);


	/////////////////////////////////////////////////
	// 22 - "Pink-ish" Noise (FIR filter)
	/////////////////////////////////////////////////
	GenNoisePink1 wvp1;
	Generate(duration, &wvp1, &eg);

	/////////////////////////////////////////////////
	// 23 - "Pink-ish" Noise (IIR filter)
	/////////////////////////////////////////////////
	GenNoisePink2 wvp2;
	Generate(duration, &wvp2, &eg);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 23 - Pitched Noise (ring modulation of sine wave and noise)
	/////////////////////////////////////////////////
	GenWaveNZ wvnzp;
	wvnzp.InitNZ(500.0, 400.0, WT_SIN);
	Generate(duration, &wvnzp, &eg);
	wvnzp.InitNZ(800.0, 400.0, WT_SIN);
	Generate(duration, &wvnzp, &eg);

	Silence(0.25);

	/////////////////////////////////////////////////
	// 24 - BUZZ generator
	/////////////////////////////////////////////////
	GenWaveBuzz buzz;
	buzz.InitBuzz(frequency, 20);
	Generate(duration, &buzz, &eg);
	buzz.InitBuzz(frequency, 100);
	Generate(duration, &buzz, &eg);

//	buzz.InitBuzz(frequency, 100);
//	GenerateVib(duration, &buzz, &eg, lfoAmp);
//	GeneratePhaseVib(duration, &buzz, &eg, lfoAmp);

	Silence(0.25);

	GenWaveBuzz2 buzz2;
	buzz2.InitBuzz(frequency, 20);
	Generate(duration, &buzz2, &eg);
	buzz2.InitBuzz(frequency, 100);
	Generate(duration, &buzz2, &eg);

	Silence(0.25);

	GenWaveBuzzA buzza;
//	buzza.SetOscillatorA(new GenWaveI);
//	buzza.SetOscillatorB(new GenWaveI);
	buzza.InitBuzz(frequency, 20);
	Generate(duration, &buzza, &eg);
	buzza.InitBuzz(frequency, 100);
	Generate(duration, &buzza, &eg);

	Silence(0.25);
	
	GenWaveDS ds;
	ds.InitDS(frequency, 0.5);
	Generate(duration, &ds, &eg);
	ds.InitDS(frequency, 0.95);
	Generate(duration, &ds, &eg);

	Silence(0.25);

	GenWaveDSB gbz;
	gbz.InitDSB(frequency, 1, 100, 0.5);
	Generate(duration, &gbz, &eg);
	gbz.InitDSB(frequency, 1, 100, 0.95);
	Generate(duration, &gbz, &eg);

	// Odd harmonics, like square wave
	gbz.InitDSB(frequency, 2, 100, 0.5);
	Generate(duration, &gbz, &eg);
	gbz.InitDSB(frequency, 2, 100, 0.95);
	Generate(duration, &gbz, &eg);

	/////////////////////////////////////////////////
	if (wvf.CloseWaveFile())
		perror("Close");

	return 0;
}
Esempio n. 6
0
int main(int argc, char *argv[])
{
	InitSynthesizer();

	long n;
	int pitch = 48;
	FrqValue duration = 2.75;
	AmpValue value1, value2;

	if (argc > 1)
		duration = atof(argv[1]);
	if (argc > 2)
		pitch = atoi(argv[2]);

	FrqValue frequency = synthParams.GetFrequency(pitch);

	if (wvf.OpenWaveFile("example07b.wav", 2))
	{
		printf("Cannot open wavefile for output\n");
		exit(1);
	}

	GenWaveFM wv;
	wv.InitFM(frequency, 1, 2, WT_SIN);

	EnvGen eg;
	eg.InitEG(0.5f, duration, 0.5f, 0.5f);

	long totalSamples = (long) ((duration * synthParams.sampleRate) + 0.5);

	// reference sound. 
	for (n = 0; n < totalSamples; n++)
	{
		value2 = (eg.Gen() * wv.Gen());
		wvf.Output1(value2);
	}
	Silence(0.25);


	// Flanger #1 varies from 0 to 5ms
	Flanger flng1;
	flng1.InitFlanger(0.5, 0.5, 0, 0.0025, 0.005, 0.15);

	// Flanger #2 varies from 45 to 50ms
	Flanger flng2;
	flng2.InitFlanger(0.5, 0.5, 0, 0.0042, 0.005, 0.15);

	// Flanger #3 is set for a chorus effect
	Flanger flng3;
	flng3.InitFlanger(0.5, 0.5, 0.5, 0.100, 0.001, 0.8);

	for (float snd = 0.5; snd <= 1; snd += 0.5)
	{
		wv.InitFM(frequency*snd, 1, 2, WT_SIN);
		eg.Reset();
		flng1.Clear();
		for (n = 0; n < totalSamples; n++)
		{
			value1 = (eg.Gen() * wv.Gen());
			value2 = flng1.Sample(value1);
			wvf.Output2(value2, value2);
		}
		Silence(0.25);

		eg.Reset();
		flng2.Clear();
		for (n = 0; n < totalSamples; n++)
		{
			value1 = (eg.Gen() * wv.Gen());
			value2 = flng2.Sample(value1);
			wvf.Output2(value2, value2);
		}
		Silence(0.25);

		eg.Reset();
		flng3.Clear();
		for (n = 0; n < totalSamples; n++)
		{
			value1 = (eg.Gen() * wv.Gen());
			value2 = flng3.Sample(value1);
			wvf.Output2(value2, value2);
		}
		Silence(0.25);
	}

	wvf.CloseWaveFile();

	return 0;
}
Esempio n. 7
0
int main(int argc, char *argv[])
{
	int pitch = 48; // Middle C
	FrqValue duration = 1;
	AmpValue peakAmp = 1;

	if (argc > 1)
		duration = atof(argv[1]);
	if (argc > 2)
		pitch = atoi(argv[2]);
	if (argc > 3)
		peakAmp = atof(argv[3]);

	InitSynthesizer();
	FrqValue frequency = synthParams.GetFrequency(pitch);
	PhsAccum phaseIncr = synthParams.frqRad * frequency;
	PhsAccum phase = 0;

	long silence = (long) (synthParams.sampleRate * 0.1);
	long totalSamples = (long) ((synthParams.sampleRate * duration) + 0.5);

	long attackTime = (long) (0.2 * synthParams.sampleRate);
	long decayTime  = (long) (0.4 * synthParams.sampleRate);
	long sustainTime = totalSamples - (attackTime + decayTime);
	long decayStart = totalSamples - decayTime;
	AmpValue envInc = peakAmp / (float) attackTime;
	AmpValue volume = 0;

	long n;

	WaveFile wf;
	if (wf.OpenWaveFile("example02.wav", 1))
	{
		printf("Cannot open wavefile for output\n");
		exit(1);
	}

	/////////////////////////////////////////////////
	// Method 1 - simple integration, linear
	/////////////////////////////////////////////////
	long sampleNumber = 0;
	for (n = 0; n < totalSamples; n++)
	{
		if (n < attackTime || n > decayStart)
			volume += envInc;
		else if (n == attackTime)
			volume = peakAmp;
		else if (n == decayStart)
			envInc = -volume / (float) decayTime;
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 1 - convex exponential (n^2)
	/////////////////////////////////////////////////
	sampleNumber = 0;
	volume = 0;
	phase = 0;
	envInc = peakAmp / (float) attackTime;
	for (n = 0; n < totalSamples; n++)
	{
		if (n < attackTime || n > decayStart)
			volume += envInc;
		else if (n == attackTime)
			volume = peakAmp;
		else if (n == decayStart)
			envInc = -volume / (float) decayTime;
		wf.Output1(volume * volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 1 - variable exponential
	/////////////////////////////////////////////////
	phase = 0;
	volume = 0;
	float expMin = 0.2;
	float expMax = 1.0+expMin;
	float expNow = expMin;
	float expMul = pow(expMax/expMin, 1.0f / (float) attackTime);

	for (n = 0; n < totalSamples; n++)
	{
		if (n < attackTime || n > decayStart)
		{
			expNow *= expMul;
			volume = (expNow - expMin) * peakAmp;
		}
		else if (n == attackTime)
		{
			volume = peakAmp;
			expNow = expMax;
		}
		else if (n == decayStart)
		{
			expMul = pow(expMin/expMax, 1.0f / (float) decayTime);
		}
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0.0);

	/////////////////////////////////////////////////
	// Method 1 - log
	/////////////////////////////////////////////////
	phase = 0;
	volume = 0;
	expNow = expMax;
	expMul = pow(expMin/expMax, 1.0f / (float) attackTime);

	for (n = 0; n < totalSamples; n++)
	{
		if (n < attackTime || n > decayStart)
		{
			expNow *= expMul;
			volume = (1.0f - (expNow - expMin)) * peakAmp;
		}
		else if (n == attackTime)
		{
			volume = peakAmp;
			expNow = expMin;
		}
		else if (n == decayStart)
			expMul = pow(expMax/expMin, 1.0f / (float) decayTime);
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 1 - dB
	/////////////////////////////////////////////////
	phase = 0;
	volume = 0;
	float dbLevel = -96;
	float dbIncr = 96.0 / attackTime;

	for (n = 0; n < totalSamples; n++)
	{
		if (n < attackTime || n > decayStart)
		{
			dbLevel += dbIncr;
			volume = pow(10.0, dbLevel / 20.0);
		}
		else if (n == attackTime)
		{
			volume = 1.0;
			dbLevel = 0.0;
		}
		else if (n == decayStart)
		{
			dbIncr = -96.0 / decayTime;
		}
		wf.Output1(peakAmp * volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 2 - simple state machine
	/////////////////////////////////////////////////
	long envCount = attackTime;
	int  envState = 0;

	envInc = peakAmp / (float) attackTime;

	phase = 0;
	volume = 0;

	for (n = 0; n < totalSamples; n++)
	{
		switch (envState)
		{
		case 0:
			if (envCount > 0)
			{
				volume += envInc;
				envCount--;
			}
			else
			{
				volume = peakAmp;
				envCount = sustainTime;
				envState = 1;
			}
			break;
		case 1:
			if (envCount > 0)
				envCount--;
			else
			{
				envCount = decayTime;
				envInc = volume / (float) decayTime;
				envState = 2;
			}
			break;
		case 2:
			if (envCount > 0)
			{
				volume -= envInc;
				envCount--;
			}
			else
			{
				volume = 0;
				envState = 3;
			}
			break;
		case 3:
			break;
		}
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 3 - multiple segments (ADSR)
	/////////////////////////////////////////////////
	float envPeak;
	float envStep;
	float envLevel[4];
	float envIncr[4];
	long  envTime[4];
	int maxEnvIndex = 4;
	int envIndex = -1;

	envLevel[0] = 1.0 * peakAmp;
	envLevel[1] = 0.7 * peakAmp;
	envLevel[2] = 0.7 * peakAmp;
	envLevel[3] = 0.0;
	envTime[0] = (long) (0.1 * synthParams.sampleRate);
	envTime[1] = (long) (0.2 * synthParams.sampleRate);
	envTime[2] = (long) (0.5 * synthParams.sampleRate);
	envTime[3] = (long) (0.2 * synthParams.sampleRate);

	// pre-calculate increments
	envIncr[0] = envLevel[0] / envTime[0];
	for (n = 1; n < maxEnvIndex; n++)
	{
		if (envTime[n] > 0)
			envIncr[n] = (envLevel[n] - envLevel[n-1]) / envTime[n];
		else
			envIncr[n] = (envLevel[n] - envLevel[n-1]);
	}

	phase = 0;
	volume = 0;
	envCount = 0;
	envPeak = 0;
	envStep = 0;
	for (n = 0; n < totalSamples; n++)
	{
		if (--envCount <= 0)
		{
			volume = envPeak;
			if (++envIndex < maxEnvIndex)
			{
				envCount = envTime[envIndex];
				envStep = envIncr[envIndex];
				envPeak = envLevel[envIndex];
			}
			else
				envStep = 0;
		}
		else
		{
			volume += envStep;
		}
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 4 - multiple segments state machine
	/////////////////////////////////////////////////
	float atkLevel[2];
	float decLevel[2];
	long atkTime[2];
	long decTime[2];
	long atkMaxIndex = 2;
	long decMaxIndex = 2;

	atkLevel[0] = 1.0 * peakAmp;
	atkLevel[1] = 0.7 * peakAmp;
	decLevel[0] = 0.2 * peakAmp;
	decLevel[1] = 0.0;
	atkTime[0] = (long) (0.1 * synthParams.sampleRate);
	atkTime[1] = (long) (0.2 * synthParams.sampleRate);
	decTime[0] = (long) (0.1 * synthParams.sampleRate);
	decTime[1] = (long) (0.2 * synthParams.sampleRate);

	sustainTime = totalSamples - (atkTime[0] + atkTime[1] + decTime[0] + decTime[1]);
	phase = 0;
	volume = 0;
	envCount = 0;
	envIndex = -1;
	envState = 0;
	envPeak = 0;

	for (n = 0; n < totalSamples; n++)
	{
		switch (envState)
		{
		case 0: // attack
			if (--envCount <= 0)
			{
				volume = envPeak;
				if (++envIndex < atkMaxIndex)
				{
					envPeak = atkLevel[envIndex];
					envCount = atkTime[envIndex];
					if (envCount < 1)
						envCount = 1;
					envStep = (envPeak - volume) / envCount;
				}
				else
				{
					envCount = sustainTime;
					envStep = 0.0;
					envState = 1;
				}
			}
			else
				volume += envStep;
			break;
		case 1: // sustain
			if (--envCount <= 0)
			{
				envIndex = -1;
				envState = 2;
			}
			break;
		case 2: // release
			if (--envCount <= 0)
			{
				volume = envPeak;
				if (++envIndex < decMaxIndex)
				{
					envPeak = decLevel[envIndex];
					envCount = decTime[envIndex];
					if (envCount < 1)
						envCount = 1;
					envStep = (envPeak - volume) / envCount;
				}
				else
				{
					envCount = 0;
					envStep = 0.0;
					volume = 0.0;
					envState = 3;
				}
			}
			else
				volume += envStep;
			break;
		case 3:
			break;
		}
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}
	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 5 - constant rate ADSR
	/////////////////////////////////////////////////
	phase = 0;
	volume = 0;
	envState = 0;
	float sustainAmpCR = 0.8;
	float atkTimeCR = 0.1;
	float decTimeCR = 0.5;
	float relTimeCR = 0.5;
	float atkIncrCR = 1.0 / (atkTimeCR * synthParams.sampleRate);
	float decIncrCR = 1.0 / (decTimeCR * synthParams.sampleRate);
	float relIncrCR = 1.0 / (relTimeCR * synthParams.sampleRate);

	float susTimeCR = 0;

	for (n = 0; n < totalSamples; n++)
	{
		switch (envState)
		{
		case 0:
			if ((volume += atkIncrCR) >= 1.0)
			{
				volume = 1.0;
				envState = 1;
			}
			break;
		case 1:
			if ((volume -= decIncrCR) <= sustainAmpCR)
			{
				volume = sustainAmpCR;
				envState = 2;
				// for testing. This type envelope would normally sustain until release signal.
				susTimeCR = totalSamples - n - ((relTimeCR * synthParams.sampleRate) * sustainAmpCR);
			}
			break;
		case 2:
			if (--susTimeCR <= 0)
				envState = 3;
			break;
		case 3:
			if ((volume -= decIncrCR) <= 0)
			{
				volume = 0;
				envState = 4;
			}
			break;
		}
		wf.Output1(volume * volume * sinv(phase)); // convex curve
		//wf.Output1(volume * sinv(phase)); // linear
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}
	for (n = 0; n < silence; n++)
		wf.Output1(0);

	/////////////////////////////////////////////////
	// Method 5 - constant rate ADSR, transformed
	/////////////////////////////////////////////////

	float envTblLen = 960; // 96 dB range
	float envTblNdx = 0;
	float atkTblCR[960];
	float decTblCR[960];
	atkTblCR[0] = 0.0;
	decTblCR[0] = 0.0;
	for (n = 1; n < envTblLen; n++)
	{
		volume = pow(10, (double)(959 - n) / -200.0);
		atkTblCR[n] = volume;
		decTblCR[n] = volume;
	}

	sustainAmpCR = 0.5;
	atkIncrCR = 960.0 / (atkTimeCR * synthParams.sampleRate);
	decIncrCR = 960.0 / (decTimeCR * synthParams.sampleRate);
	relIncrCR = 960.0 / (relTimeCR * synthParams.sampleRate);

	susTimeCR = totalSamples - ((relTimeCR * synthParams.sampleRate) * sustainAmpCR);
	phase = 0;
	volume = 0;
	envState = 0;
	for (n = 0; n < totalSamples; n++)
	{
		switch (envState)
		{
		case 0:
			if ((envTblNdx += atkIncrCR) >= envTblLen)
			{
				envTblNdx = envTblLen-1;
				envState = 1;
			}
			volume = atkTblCR[(int)envTblNdx];
			break;
		case 1:
			if ((envTblNdx -= decIncrCR) < 0)
				envTblNdx = 0;
			volume = decTblCR[(int)envTblNdx];
			if (volume <= sustainAmpCR)
			{
				volume = sustainAmpCR;
				envState = 2;
				susTimeCR = totalSamples - n - ((relTimeCR * synthParams.sampleRate) * sustainAmpCR);
			}
			break;
		case 2:
			if (--susTimeCR <= 0)
				envState = 3;
			break;
		case 3:
			if ((envTblNdx -= decIncrCR) <= 0)
			{
				envTblNdx = 0;
				envState = 4;
			}
			volume = decTblCR[(int)envTblNdx];
			break;
		}
		wf.Output1(volume * sinv(phase));
		if ((phase += phaseIncr) >= twoPI)
			phase -= twoPI;
	}

	for (n = 0; n < silence; n++)
		wf.Output1(0);

	wf.CloseWaveFile();

	int oor = wf.GetOOR();
	if (oor)
		printf("%d Samples out of range...\n", oor);

	return 0;
}