
// zlib open source license
//
// Copyright (c) 2010 to 2013 David Forsgren Piuva
// 
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// 
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 
//    1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
// 
//    2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
// 
//    3. This notice may not be removed or altered from any source
//    distribution.

int CDFPGECtrl::Sound_Buffer_LoadFromFile_InSB(int NumberOfCopies, bool LoadAs3DSound, bool LoadAsEditable) {
	SoundBuffer_Struct* pResult;
	int Result;
	pResult = NULL;
	Result = -1;
	if (!DGE.m_Running) {
		MQ->InsertMessage(L"Sound_Buffer_LoadFromFile_InSB: You can't create a sound buffer before starting the engine.");
	} else if (NumberOfCopies < 1) {
		MQ->InsertMessage(L"Sound_Buffer_LoadFromFile_InSB: NumberOfCopies < 1.");
	} else {
		Try_Start_Ctrl {
			pResult = DGE.CreateSoundBufferFromFile(StringBuffer,NumberOfCopies,LoadAs3DSound,LoadAsEditable);
			if (pResult) {
				Result = DGE.IDFromPointer(pResult);
			} else {
				swprintf_s( MQ->messageBuffer, L"Sound_Buffer_LoadFromFile_InSB: Could not load the sound %s.", StringBuffer); MQ->InsertMessage(MQ->messageBuffer);
			}
		} Try_Else_Ctrl {
			swprintf_s( MQ->messageBuffer, L"Sound_Buffer_LoadFromFile_InSB: Access violation while loading the sound %s.", StringBuffer); MQ->InsertMessage(MQ->messageBuffer);
		}
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_CreateEmpty(int NumberOfCopies, bool CreateAs3DSound, int SamplesPerSecond, int NumberOfChannels, int NumberOfSamplesPerChannel) {
	SoundBuffer_Struct* pResult;
	int Result;
	pResult = NULL;
	Result = -1;
	if (!DGE.m_Running) {
		MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: You can't create a sound buffer before starting the engine.");
	} else if (NumberOfCopies < 1) {
		MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: NumberOfCopies < 1. You can't play that sound.");
	} else if (SamplesPerSecond < 1) {
		MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: SamplesPerSecond < 1. That would make the sound impossible to play.");
	} else if (NumberOfChannels < 1) {
		MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: NumberOfChannels < 1. You need at least one channel to store sound in.");
	} else if (NumberOfSamplesPerChannel < 1) {
		MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: NumberOfSamplesPerChannel < 2. One sample per channel will not make a real sound.");
	} else if (NumberOfChannels > 1 && CreateAs3DSound) {
		MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: You can not create a 3D sound with multiple channels because each channel need it's own position to make a difference.");
	} else {
		Try_Start_Ctrl {
			pResult = DGE.CreateEmptySoundBuffer(NumberOfCopies,CreateAs3DSound, SamplesPerSecond, NumberOfChannels, NumberOfSamplesPerChannel);
			if (pResult) {
				Result = DGE.IDFromPointer(pResult);
			} else {
				MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: Could not create an empty sound buffer.");
			}
		} Try_Else_Ctrl {
			MQ->InsertMessage(L"Sound_Buffer_CreateEmpty: Access violation while creating the an empty sound buffer.");
		}
	}
	return Result;
}

void CDFPGECtrl::Sound_Buffer_Editable_SaveToFile_InSB(int SoundBuffer) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Editable_SaveToFile_InSB",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Editable_SaveToFile_InSB: The sound buffer does not have an allocation.");
	} else {
		if (!pSoundBuffer->Buffer->Save(StringBuffer)) {
			MQ->InsertMessage(L"Sound_Buffer_Editable_SaveToFile_InSB: The sound could not be saved.");
		}
	}
}

void CDFPGECtrl::Sound_Buffer_Delete(int SoundBuffer) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"SoundBuffer_Delete",SoundBuffer)
	} else {
		DGE.Delete_SoundBuffer(pSoundBuffer);
	}
}

void CDFPGECtrl::Sound_Buffer_Play(int SoundBuffer, int Index, bool FromBeginning, bool Looping) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Play",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Play: The sound buffer does not have an allocation.");
	} else {
		pSoundBuffer->Buffer->Play(Index, FromBeginning, Looping);
	}
}

void CDFPGECtrl::Sound_Buffer_Stop(int SoundBuffer, int Index) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Stop",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Stop: The sound buffer does not have an allocation.");
	} else {
		if (!pSoundBuffer->Buffer->Stop(Index)) {
			MQ->InsertMessage(L"Sound_Buffer_Stop: Could not stop the sound.");
		}
	}
}

int CDFPGECtrl::Sound_Buffer_IsPlaying(int SoundBuffer, int Index) {
	int Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_IsPlaying",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_IsPlaying: The sound buffer does not have an allocation.");
	} else {
		Try_Start_Ctrl {
			if (pSoundBuffer->Buffer->IsPlaying(Index)) {
				Result = 1;
			} else {
				Result = 0;
			}
		} Try_Else_Ctrl {
			MQ->InsertMessage(L"Sound_Buffer_IsPlaying: Access violation while getting the status.");
		}
	}
	return Result;
}

void CDFPGECtrl::Sound_Buffer_SetSpeed(int SoundBuffer, int Index, float Speed) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_SetSpeed",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_SetSpeed: The sound buffer does not have an allocation.");
	} else {
		if (!pSoundBuffer->Buffer->SetSpeed(Index,Speed)) {
			MQ->InsertMessage(L"Sound_Buffer_SetSpeed: Could not set the speed.");
		}
	}
}

float CDFPGECtrl::Sound_Buffer_GetSpeed(int SoundBuffer, int Index) {
	float Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetSpeed",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetSpeed: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->GetSpeed(Index);
	}
	return Result;
}

void CDFPGECtrl::Sound_Buffer_SetVolume(int SoundBuffer, int Index, float Volume) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_SetVolume",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_SetVolume: The sound buffer does not have an allocation.");
	} else {
		if (!pSoundBuffer->Buffer->SetVolume(Index,Volume)) {
			MQ->InsertMessage(L"Sound_Buffer_SetVolume: Could not set the volume.");
		}
	}
}

float CDFPGECtrl::Sound_Buffer_GetVolume(int SoundBuffer, int Index) {
	float Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetVolume",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetVolume: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->GetVolume(Index);
	}
	return Result;
}

void CDFPGECtrl::Sound_Buffer_3D_SetPosition(int SoundBuffer, int Index, float X, float Y, float Z) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_3D_SetPosition",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_3D_SetPosition: The sound buffer does not have an allocation.");
	} else {
		if (!pSoundBuffer->Buffer->Set3DPosition(Index,X,Y,Z)) {
			MQ->InsertMessage(L"Sound_Buffer_3D_SetPosition: Could not set the 3D position.");
		}
	}
}

void CDFPGECtrl::Sound_Buffer_3D_GetPosition_OutV3(int SoundBuffer, int Index) {
	ClearMatrixBuffer();
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_3D_GetPosition_OutV3",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_3D_GetPosition_OutV3: The sound buffer does not have an allocation.");
	} else {
		SetVector3ToMB(pSoundBuffer->Buffer->Get3DPosition(Index));
	}
}

int CDFPGECtrl::Sound_Buffer_GetNumberOfCopies(int SoundBuffer) {
	int Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetNumberOfCopies",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetNumberOfCopies: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->Flag_NumberOfCopies;
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_GetLastPlayedIndex(int SoundBuffer) {
	int Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetLastPlayedIndex",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetLastPlayedIndex: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->LastPlayedIndex;
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_Is3DSound(int SoundBuffer) {
	int Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Is3DSound",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Is3DSound: The sound buffer does not have an allocation.");
	} else {
		if (pSoundBuffer->Buffer->Flag_3DSound) {
			Result = 1;
		} else {
			Result = 0;
		}
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_IsEditable(int SoundBuffer) {
	int Result;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_IsEditable",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_IsEditable: The sound buffer does not have an allocation.");
	} else {
		if (pSoundBuffer->Buffer->Flag_IsEditable) {
			Result = 1;
		} else {
			Result = 0;
		}
	}
	return Result;
}

void CDFPGECtrl::Sound_PlaceGlobalListener(float Pos_X, float Pos_Y, float Pos_Z, float Front_X, float Front_Y, float Front_Z, float Up_X, float Up_Y, float Up_Z) {
	if (DGE.m_Running == true) {
		Try_Start_Ctrl {
			DGE.PlaceListener(DVector3(Pos_X,Pos_Y,Pos_Z),DVector3(Front_X,Front_Y,Front_Z),DVector3(Up_X,Up_Y,Up_Z));
		} Try_Else_Ctrl {
			MQ->InsertMessage(L"Sound_PlaceGlobalListener: Access violation while placing the listener.");
		}
	} else {
		MQ->InsertMessage(L"Sound_PlaceGlobalListener: You can't place the listener before starting the engine.");
	}
}

void CDFPGECtrl::Sound_SetMetersPerDistanceUnit(float Meters) {
	if (DGE.m_Running == true) {
		Try_Start_Ctrl {
			if (Meters < 0.0f) {
				MQ->InsertMessage(L"Sound_SetMetersPerDistanceUnit: The length in meters per length unit is negative.");
				DGE.SetMetersPerDistanceUnit(0.0f);
			} else {
				DGE.SetMetersPerDistanceUnit(Meters);
			}
		} Try_Else_Ctrl {
			MQ->InsertMessage(L"Sound_SetMetersPerDistanceUnit: Access violation while setting the meters per distance.");
		}
	} else {
		MQ->InsertMessage(L"Sound_SetMetersPerDistanceUnit: You can't set the meters per distance before starting the engine.");
	}
}

float CDFPGECtrl::Sound_GetMetersPerDistanceUnit(void) {
	float Result;
	Try_Start_Ctrl {
		Result = DGE.m_Sound_MetersPerDistanceUnit;
	} Try_Else_Ctrl {
		MQ->InsertMessage(L"Sound_GetMetersPerDistanceUnit: Access violation while getting the meters per distance.");
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_GetNumberOfChannels(int SoundBuffer) {
	int Result;
	Result = 0;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetNumberOfChannels",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetNumberOfChannels: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->GetNumberOfChannels();
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_GetNumberOfSamplesPerChannel(int SoundBuffer) {
	int Result;
	Result = 0;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetNumberOfSamplesPerChannel",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetNumberOfSamplesPerChannel: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->GetSamplesPerChannel();
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_GetSamplesPerSecond(int SoundBuffer) {
	int Result;
	Result = 0;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_GetSamplesPerSecond",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_GetSamplesPerSecond: The sound buffer does not have an allocation.");
	} else {
		Result = pSoundBuffer->Buffer->GetSampleRate();
	}
	return Result;
}

int CDFPGECtrl::Sound_Buffer_Editable_Update(int SoundBuffer) {
	int Result;
	Result = 0;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Editable_Update",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Editable_Update: The sound buffer does not have an allocation.");
	} else {
		if (pSoundBuffer->Buffer->UpdateBuffers()) {
			Result = 1;
		} else {
			MQ->InsertMessage(L"Sound_Buffer_Editable_Update: Could not update the buffers.");
		}
	}
	return Result;
}

// Call WriteWaveData
void CDFPGECtrl::Sound_Buffer_Editable_SetSample(int SoundBuffer, int Time, int Channel, float NewValue) {
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Editable_SetSample",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Editable_SetSample: The sound buffer does not have an allocation.");
	} else if (Channel < 0 || Channel >= pSoundBuffer->Buffer->GetNumberOfChannels()) {
		swprintf_s( MQ->messageBuffer, L"Sound_Buffer_Editable_SetSample: Channel %i is out of bound [0..%i].", Channel, pSoundBuffer->Buffer->GetNumberOfChannels() - 1); MQ->InsertMessage(MQ->messageBuffer);
	} else if (Time < 0 || Time >= pSoundBuffer->Buffer->GetSamplesPerChannel()) {
		swprintf_s( MQ->messageBuffer, L"Sound_Buffer_Editable_SetSample: Time %i is out of bound [0..%i].", Channel, pSoundBuffer->Buffer->GetSamplesPerChannel() - 1); MQ->InsertMessage(MQ->messageBuffer);
	} else {
		Try_Start_Ctrl {
			pSoundBuffer->Buffer->WriteWaveData(Time,Channel,NewValue);
		} Try_Else_Ctrl {
			MQ->InsertMessage(L"Sound_Buffer_Editable_SetSample: Access violation while setting a new value for a sample.");
		}
	}
}

// Call ReadWaveData
float CDFPGECtrl::Sound_Buffer_Editable_GetSample(int SoundBuffer, int Time, int Channel) {
	float Result;
	Result = 0.0f;
	GET_FROM_REF(SoundBuffer,SoundBuffer)
	if BAD_REF(SoundBuffer) {
		REPORT_TYPE(SoundBuffer,L"Sound_Buffer_Editable_GetSample",SoundBuffer)
	} else if (pSoundBuffer->Buffer == NULL) {
		MQ->InsertMessage(L"Sound_Buffer_Editable_GetSample: The sound buffer does not have an allocation.");
	} else if (Channel < 0 || Channel >= pSoundBuffer->Buffer->GetNumberOfChannels()) {
		swprintf_s( MQ->messageBuffer, L"Sound_Buffer_Editable_GetSample: Channel %i is out of bound [0..%i].", Channel, pSoundBuffer->Buffer->GetNumberOfChannels() - 1); MQ->InsertMessage(MQ->messageBuffer);
	} else if (Time < 0 || Time >= pSoundBuffer->Buffer->GetSamplesPerChannel()) {
		swprintf_s( MQ->messageBuffer, L"Sound_Buffer_Editable_GetSample: Time %i is out of bound [0..%i].", Channel, pSoundBuffer->Buffer->GetSamplesPerChannel() - 1); MQ->InsertMessage(MQ->messageBuffer);
	} else {
		Try_Start_Ctrl {
			Result = pSoundBuffer->Buffer->ReadWaveData(Time,Channel);
		} Try_Else_Ctrl {
			MQ->InsertMessage(L"Sound_Buffer_Editable_GetSample: Access violation while setting a new value for a sample.");
		}
	}
	return Result;
}
