/* Copyright (c) 2003-2005 Various contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#ifndef MT32EMU_PARTIAL_H
#define MT32EMU_PARTIAL_H

namespace MT32Emu {

class Synth;
struct NoteLookup;

enum EnvelopeType {
	EnvelopeType_amp = 0,
	EnvelopeType_filt = 1,
	EnvelopeType_pitch = 2
};

struct EnvelopeStatus {
	Bit32s envpos;
	Bit32s envstat;
	Bit32s envbase;
	Bit32s envdist;
	Bit32s envsize;

	bool sustaining;
	bool decaying;
	Bit32s prevlevel;

	Bit32s counter;
	Bit32s count;
};

// Class definition of MT-32 partials.  32 in all.
class Partial {
private:
	Synth *synth;

	int ownerPart; // -1 if unassigned
	int mixType;
	int structurePosition; // 0 or 1 of a structure pair
	bool useNoisePair;

	Bit16s myBuffer[MAX_SAMPLE_OUTPUT];

	// Keyfollowed note value
#if MT32EMU_ACCURATENOTES == 1
	NoteLookup noteLookupStorage;
	float noteVal;
#else
	int noteVal;
	int fineShift;
#endif
	const NoteLookup *noteLookup; // LUTs for this noteVal
	const KeyLookup *keyLookup; // LUTs for the clamped (12..108) key

	// Keyfollowed filter values
	int realVal;
	int filtVal;

	// Only used for PCM partials
	int pcmNum;
	PCMWaveEntry *pcmWave;

	int pulsewidth;

	Bit32u lfoPos;
	soundaddr partialOff;

	Bit32u ampEnvVal;
	Bit32u pitchEnvVal;

	float history[32];

	bool pitchSustain;

	int loopPos;

	dpoly *poly;

	int bendShift;

	Bit16s *mixBuffers(Bit16s *buf1, Bit16s *buf2, int len);
	Bit16s *mixBuffersRingMix(Bit16s *buf1, Bit16s *buf2, int len);
	Bit16s *mixBuffersRing(Bit16s *buf1, Bit16s *buf2, int len);
	void mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len);

	Bit32s getFiltEnvelope();
	Bit32u getAmpEnvelope();
	Bit32s getPitchEnvelope();

	void initKeyFollow(int freqNum);

public:
	const PatchCache *patchCache;
	EnvelopeStatus envs[3];
	bool play;

	PatchCache cachebackup;

	Partial *pair;
	bool alreadyOutputed;
	Bit32u age;

	Partial(Synth *synth);
	~Partial();

	int getOwnerPart() const;
	int getKey() const;
	const dpoly *getDpoly() const;
	bool isActive();
	void activate(int part);
	void deactivate(void);
	void startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial);
	void startDecay(EnvelopeType envnum, Bit32s startval);
	void startDecayAll();
	void setBend(float factor);
	bool shouldReverb();

	// Returns true only if data written to buffer
	// This function (unlike the one below it) returns processed stereo samples
	// made from combining this single partial with its pair, if it has one.
	bool produceOutput(Bit16s * partialBuf, long length);

	// This function produces mono sample output using the partial's private internal buffer
	Bit16s *generateSamples(long length);
};

}

#endif