/*
 *  ACM for Windows : an air combat simulator
 *  Copyright (C) 1997  Web Simulations, Inc.
 *
 *  This program is not free software, but you can redistribute it and/or
 *  modify it under the terms of the Web Simulations End User License
 *  dated September, 1997.  A copy of this license may be found in the
 *  LICENSE.TXT file.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 *  Information describing how to contact the author can be found in the
 *  README.TXT  file.
 */
#include "stdafx.h"
#include "acm.h"

static CSoundManager *g_pSoundManager;
static CStaticSoundBuffer *g_sound[NUM_SOUNDS];

#define SECTION "Sound"
#define MAIN_SOUND_KEY "MainSounds"
#define BACKGROUND_SOUND_KEY "BackgroundSounds"

extern "C" {
    int WaveLoadFile(
        char *pszFileName,                      // (IN)
        UINT *cbSize,                           // (OUT)
        DWORD *pcSamples,                       // (OUT)
        WAVEFORMATEX **ppwfxInfo,				// (OUT)
        BYTE **ppbData                          // (OUT)
        );
    
    //  These are glue routines to allow the original ACM code to call
    //  the C++-based sound manager.
    //
    //  borrowed from src/audio.c
    
    static char	*files[] = {
		"engine.wav",
		"crash.wav",
		"gear_up.wav",
		"gear_dn.wav",
		"missile.wav",
		"cannon.wav",
		"crash.wav",
		"screetch.wav",
		"stall.wav",
		"rwr.wav",
		"apglock.wav"
    };
    
    static BOOL bSoundsLoaded = FALSE;
    
    int
		initializeAudio(craft *c, viewer *v, char *p)
		
    {
		char szSoundPath[256];
		int result = 0;
		
		if (bSoundsLoaded == FALSE) {
			bSoundsLoaded = TRUE;
			
			for (int i=0; i<NUM_SOUNDS; ++i) {
				g_sound[i] = new CStaticSoundBuffer (g_pSoundManager);
				strcpy (szSoundPath, "..\\objects\\");
				strcat (szSoundPath, files[i]);
				if (g_sound[i]->LoadWaveFile(szSoundPath) == FALSE) {
					TRACE(_T("Load of file \"%s\" failed\n"), szSoundPath);
					//delete g_sound[i];
					//g_sound[i] = NULL;
					result = -2;
				}
			}
		}
		return result;
    }
    
    void
		shutdownAudio(craft *c, viewer *v)
    {
    }
    
    void
		playSound (craft *c, int id)
    {
		if (c->type == CT_PLANE) {
			g_sound[id]->SetCurrentPosition( 0 );
			g_sound[id]->Play( FALSE );
		}
    }
    
    void
		playContinuousSound (craft *c, int id)
    {
		if (c->type == CT_PLANE) {
			g_sound[id]->Play( TRUE );
			c->vl->flow[id] = 1;
		}
    }
    
    void
		stopSound(craft *c, int id)
    {
		if (c->type == CT_PLANE) {
			g_sound[id]->Stop();
			c->vl->flow[id] = 0;
		}
    }
	
	static int g_bEngineOn = 0;
	static double g_dLastRPM = 0.0;
	
	void
		setBackgroundSound (craft *c, double dThtlPercent,
		BOOL bABFlag, double dDynamicPressure)
	{
		BOOL bMain, bBackground;
		
		g_pSoundManager->GetSoundState (&bMain,
			&bBackground);
		
		if (bBackground && c->type == CT_PLANE) {
			if (g_bEngineOn == FALSE) {
				g_sound[SoundEngine]->SetVolume ( -3000 );
				playContinuousSound ( c, SoundEngine );
				g_bEngineOn = TRUE;
			}
			if (g_dLastRPM != c->rpm) {
				if (c->rpm == 0.0) {
					stopSound (c, SoundEngine);
				}
				else {
					//int dB = -40 + (int) (20.0 * c->rpm + 0.5);
					g_sound[SoundEngine]->SetFrequency ( (int) (c->rpm * 15000.0 + 0.5) );
				}
				g_dLastRPM = c->rpm;
			}
		}
	}
    
};

//*******************************************************************
//
//  Now, back to C++ ...
//
//*******************************************************************

CSoundManager::CSoundManager()
{
	CAcmApp * pApp = (CAcmApp *) AfxGetApp();
	
    m_lpDirectSound = NULL;
    m_hr = DS_OK;
	m_bMainSounds = pApp->GetProfileInt(SECTION,
		MAIN_SOUND_KEY, (int) TRUE);
	m_bBackgroundSounds = pApp->GetProfileInt(SECTION,
		BACKGROUND_SOUND_KEY, (int) TRUE);
}

CSoundManager::~CSoundManager()
{
	StopBackgroundSounds();
	StopMainSounds();
	
    if (m_lpDirectSound) {
		m_lpDirectSound->Release();
		m_lpDirectSound = NULL;
    }
}

BOOL CSoundManager::Create(void)
{
	g_pSoundManager = this;
    if((m_hr = DirectSoundCreate(NULL, &m_lpDirectSound, NULL)) != DS_OK) {
		m_lpDirectSound = NULL;
		return FALSE;
    }
    if (AfxGetMainWnd()) {
		if (SetMainWindow() == FALSE) {
			return FALSE;
		}
    }
    return TRUE;
}

BOOL CSoundManager::SetMainWindow(CWnd *pWnd /* = NULL */)
{
    if (pWnd == NULL) {
		pWnd = AfxGetMainWnd();
    }
	if (m_lpDirectSound == NULL) {
		return FALSE;
	}
    ASSERT (pWnd);
    if ((m_hr = m_lpDirectSound->SetCooperativeLevel(pWnd->m_hWnd, DSSCL_NORMAL))
		!= DS_OK) {
		return FALSE;
    }
    return TRUE;
}

HRESULT CSoundManager::GetResultCode()
{
    return m_hr;
}

CSoundBuffer::CSoundBuffer(CSoundManager *pSM /* = NULL */ )
{
    m_pSM = pSM;
    m_lpDPSB = NULL;
    ZeroMemory (&m_desc, sizeof(m_desc));
    m_hr = DS_OK;
}

CSoundBuffer::~CSoundBuffer()
{
    if (m_lpDPSB) {
		m_lpDPSB->Release();
		m_lpDPSB = NULL;
    }
}

CStaticSoundBuffer::CStaticSoundBuffer(CSoundManager *pSM) :
CSoundBuffer(pSM)
{
}

BOOL CStaticSoundBuffer::LoadWaveFile(LPTSTR pFileName)
{
    UINT size;
    unsigned char *pData;
    
    BYTE            *pbData         = NULL;
    BYTE            *pbData2        = NULL;
    DWORD           dwLength;
    DWORD           dwLength2;
    
	if (m_pSM->m_lpDirectSound == NULL) {
		goto FAILURE;
	}

    if (WaveLoadFile(pFileName, &size, &m_dwSamples, &m_pFormat, &pData) != 0) {
		m_hr = DS_OK;
		goto FAILURE;
    }
    
    m_desc.dwSize = sizeof(DSBUFFERDESC);
    m_desc.dwFlags = 0;
    m_desc.dwFlags |= DSBCAPS_STATIC;
    m_desc.dwFlags |= DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2;
    m_desc.dwFlags |= DSBCAPS_STICKYFOCUS;
    m_desc.dwBufferBytes = size;
    m_desc.lpwfxFormat   = m_pFormat;
    if ((m_hr = m_pSM->m_lpDirectSound->CreateSoundBuffer( &m_desc,
		&m_lpDPSB, NULL )) != DS_OK) {
		goto FAILURE;
    }
    
    if ((m_hr = m_lpDPSB->Lock(0,
		size,
		&pbData,
		&dwLength,
		&pbData2,
		&dwLength2, 0L)) != DS_OK) {
		goto FAILURE;
    }
    
    ASSERT(pbData != NULL);
    memcpy(pbData, pData, size);
    
    // Ok, now unlock the buffer, we don't need it anymore.
    if ((m_hr = m_lpDPSB->Unlock( pbData, size, NULL, 0)) != DS_OK) {
		goto FAILURE;
    }
    
    pbData = NULL;
    
    // Set maximum volume (0 dB attenuation) and Mid-pan
    
    if ((m_hr = m_lpDPSB->SetVolume(0)) != DS_OK) {
		goto FAILURE;
    }
    
    if ((m_hr = m_lpDPSB->SetPan(0)) != DS_OK) {
		goto FAILURE;
    }
    
    return TRUE;
    
FAILURE:
    if (m_lpDPSB && pbData) {
		m_lpDPSB->Unlock( pbData, size, NULL, 0);
    }
    if (m_lpDPSB) {
		m_lpDPSB->Release();
    }
    m_lpDPSB = NULL;
    return FALSE;
}

BOOL CSoundBuffer::Play(BOOL bContinuous)
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return FALSE;
	}
    ASSERT (m_lpDPSB);
    m_hr = m_lpDPSB->Play( 0, 0, bContinuous ? DSBPLAY_LOOPING : 0 );
	return (m_hr == DS_OK) ? TRUE : FALSE;
}

BOOL CSoundBuffer::Stop()
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return FALSE;
	}
    ASSERT (m_lpDPSB);
    if ((m_hr = m_lpDPSB->Stop()) != DS_OK) {
		return FALSE;
    }
    return TRUE;
}

HRESULT CSoundBuffer::GetResultCode()
{
    return m_hr;
}

long CSoundBuffer::GetVolume()
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return 0;
	}
    long lResult = 0;
    ASSERT (m_lpDPSB);
    m_lpDPSB->GetVolume(&lResult);
    return lResult;
}

void CSoundBuffer::SetVolume(long lVol)
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return;
	}
    ASSERT (m_lpDPSB);
    m_lpDPSB->SetVolume(lVol);
}

DWORD CSoundBuffer::GetFrequency()
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return 0;
	}
    DWORD dwFreq;
    ASSERT (m_lpDPSB);
    m_lpDPSB->GetFrequency(&dwFreq);
    return dwFreq;
}

void CSoundBuffer::SetFrequency(DWORD dwFreq)
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return;
	}
    ASSERT (m_lpDPSB);
    m_lpDPSB->SetFrequency(dwFreq);
}

void CSoundBuffer::SetCurrentPosition(DWORD dwPos)
{
	if (m_pSM->m_lpDirectSound == NULL) {
		return;
	}
    ASSERT (m_lpDPSB);
    m_lpDPSB->SetCurrentPosition(0);
}

void CSoundBuffer::GetStatus(DWORD * lpdwStatus)
{
	if (m_pSM->m_lpDirectSound == NULL) {
		*lpdwStatus = 0;
		return;
	}
	ASSERT (m_lpDPSB);
    m_lpDPSB->GetStatus (lpdwStatus);
}

void CSoundManager::SetSoundState(BOOL bMain, BOOL bBackground)
{
	CAcmApp * pApp = (CAcmApp *) AfxGetApp();
	
	if (m_bBackgroundSounds == TRUE && bBackground == FALSE) {
		StopBackgroundSounds ();
		g_bEngineOn = FALSE;
		g_dLastRPM = 0.0;
	}
	if (m_bMainSounds == TRUE && bMain == FALSE) {
		StopMainSounds ();
	}
	m_bMainSounds = bMain;
	m_bBackgroundSounds = bBackground;
	
	pApp->WriteProfileInt(SECTION,
		MAIN_SOUND_KEY, (int) m_bMainSounds);
	pApp->WriteProfileInt(SECTION,
		BACKGROUND_SOUND_KEY, (int) m_bBackgroundSounds);
}

void CSoundManager::GetSoundState(BOOL * pbMain, BOOL * pbBackground)
{
	ASSERT (pbMain);
	ASSERT (pbBackground);
	*pbMain = m_bMainSounds;
	*pbBackground = m_bBackgroundSounds;
}

void CSoundManager::StopMainSounds()
{
	DWORD dwStatus;

	if (m_lpDirectSound == NULL) {
		return;
	}
	
	for (int i=0; i<NUM_SOUNDS; ++i) {
		if (i == SoundEngine)
			continue;
		if (g_sound[i]) {
			g_sound[i]->GetStatus(&dwStatus);
			if (dwStatus & DSBSTATUS_PLAYING) {
				g_sound[i]->Play( FALSE );
			}
		}
	}
}

void CSoundManager::StopBackgroundSounds()
{
	DWORD dwStatus;
	int i = SoundEngine;

	if (m_lpDirectSound == NULL) {
		return;
	}
	
	if (g_sound[i]) {
		g_sound[i]->GetStatus(&dwStatus);
		if (dwStatus & DSBSTATUS_PLAYING) {
			g_sound[i]->Play( FALSE );
		}
	}
}

