home *** CD-ROM | disk | FTP | other *** search
/ Game Audio Programming / GameAudioProgramming.iso / Game_Audio / audio_sdk / src / AudioScript / SoundScape.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-07-15  |  15.0 KB  |  536 lines

  1. /***********************************************************\
  2. Copyright (C) James Boer, 2002. 
  3. All rights reserved worldwide.
  4.  
  5. This software is provided "as is" without express or implied
  6. warranties. You may freely copy and compile this source into
  7. applications you distribute provided that the copyright text
  8. below is included in the resulting source code, for example:
  9. "Portions Copyright (C) James Boer, 2002"
  10. \***********************************************************/
  11.  
  12. #include "SoundScape.h"
  13. #include "SoundMgr.h"
  14.  
  15. using namespace Audio;
  16.  
  17.  
  18. IMPLEMENT_POOL(SoundScape);
  19.  
  20.  
  21. //------------------------------------------------------------------------//
  22. SoundScape::SoundScape()
  23. {
  24.     FN("SoundScape::SoundScape()");
  25.     Clear();
  26. }
  27.  
  28. //------------------------------------------------------------------------//
  29. SoundScape::~SoundScape()
  30. {
  31.     FN("SoundScape::~SoundScape()");
  32.     Term();
  33. }
  34.  
  35. //------------------------------------------------------------------------//
  36. void SoundScape::Term()
  37. {
  38.     FN("SoundScape::Term()");
  39.     Stop();
  40.     Unload();
  41.  
  42.     CRITICAL_FUNCTION(&CSoundMgr()->GetUpdateCS());
  43.     int i;
  44.     for(i = 0; i < m_aBackground.size(); i++)
  45.         m_aBackground[i].m_Init.m_pSound->Destroy();
  46.     for(i = 0; i < m_aPeriodic.size(); i++)
  47.         m_aPeriodic[i].m_Init.m_pSound3D->Destroy();
  48.     m_aBackground.clear();
  49.     m_aPeriodic.clear();
  50.  
  51.     Clear();
  52. }
  53.  
  54. //------------------------------------------------------------------------//
  55. void SoundScape::Destroy()
  56. {
  57.     FN("SoundScape::Destroy()");
  58.     Term();
  59.     SoundScape::DestroyObject(this);
  60. }
  61.  
  62.  
  63.  
  64.  
  65. //------------------------------------------------------------------------//
  66. void SoundScape::Clear()
  67. {
  68.     FN("SoundScape::Clear()");
  69.     m_bInitialized = false;
  70.     m_bLoaded = false;
  71.     m_bPlaying = false;
  72.     m_bPaused = false;
  73.     m_aBackground.clear();
  74.     m_aPeriodic.clear();
  75.     m_bFirstUpdate = false;
  76.     m_fCurrentTime = 0.0f;
  77.     m_fVolume = 1.0f;
  78.     m_bVolumeChanged = false;
  79. }
  80.  
  81.  
  82. //------------------------------------------------------------------------//
  83. bool SoundScape::Init()
  84. {
  85.     FN("SoundScape::Init()");
  86.     m_bInitialized = true;
  87.     m_bFirstUpdate = true;
  88.     // You may want to trim this down if you have a LOT of soundscapes to create,
  89.     // but it's probably best initially to try to avoid additional allocations.
  90.     // You'll need an awful lot of them before it really makes a dent in the
  91.     // memory of any modern gaming system.
  92.     m_aBackground.reserve(2);
  93.     m_aPeriodic.reserve(15);
  94.     return true;
  95. }
  96.  
  97.  
  98. //------------------------------------------------------------------------//
  99. bool SoundScape::InternalInit(SoundScapeInternalInit& init)
  100. {
  101.     FN("SoundScape::InternalInit()");
  102.     if(!Init())
  103.         return false;
  104.  
  105.     ISound* pSound;
  106.     ISound3D* pSound3D;
  107.     SoundInit sndinit;
  108.     Sound3DInit snd3Dinit;
  109.  
  110.     int i;
  111.     for(i = 0; i < init.m_aBackground.size(); i++)
  112.     {
  113.         if(!AudioMgr()->CreateSound(pSound))
  114.             return false;
  115.         if(!SoundMgr()->GetSoundInit(init.m_aBackground[i].m_sSoundID, sndinit))
  116.             return false;
  117.         if(!pSound->Init(sndinit))
  118.             return false;
  119.         init.m_aBackground[i].m_Init.m_pSound = pSound;
  120.         if(!AddElement(init.m_aBackground[i].m_Init))
  121.             return false;
  122.     }
  123.     for(i = 0; i < init.m_aPeriodic.size(); i++)
  124.     {
  125.         if(!AudioMgr()->CreateSound3D(pSound3D))
  126.             return false;
  127.         if(!SoundMgr()->GetSound3DInit(init.m_aPeriodic[i].m_sSound3DID, snd3Dinit))
  128.             return false;
  129.         if(!pSound3D->Init(snd3Dinit))
  130.             return false;
  131.         init.m_aPeriodic[i].m_Init.m_pSound3D = pSound3D;
  132.         if(!AddElement(init.m_aPeriodic[i].m_Init))
  133.             return false;
  134.     }
  135.     
  136.     return true;
  137. }
  138.  
  139.  
  140. //------------------------------------------------------------------------//
  141. bool SoundScape::AddElement(const BackgroundInit& init)
  142. {
  143.     FN("SoundScape::AddElement()");
  144.     BackgroundElement element;
  145.     element.m_Init = init;
  146.     m_aBackground.push_back(element);
  147.     return true;
  148. }
  149.  
  150.  
  151. //------------------------------------------------------------------------//
  152. bool SoundScape::AddElement(const PeriodicInit& init)
  153. {
  154.     FN("SoundScape::AddElement()");
  155.     PeriodicElement element;
  156.     element.m_Init = init;
  157.     m_aPeriodic.push_back(element);
  158.     return true;
  159. }
  160.  
  161.  
  162. //------------------------------------------------------------------------//
  163. bool SoundScape::Load()
  164. {
  165.     FN("SoundScape::Load()");
  166.     int i;
  167.     for(i = 0; i < m_aBackground.size(); i++)
  168.         m_aBackground[i].m_Init.m_pSound->Load();
  169.  
  170.     for(i = 0; i < m_aPeriodic.size(); i++)
  171.         m_aPeriodic[i].m_Init.m_pSound3D->Load();
  172.  
  173.     m_bLoaded = true;
  174.  
  175.     return true;
  176. }
  177.  
  178. //------------------------------------------------------------------------//
  179. bool SoundScape::Unload()
  180. {
  181.     FN("SoundScape::Unload()");
  182.  
  183.     Stop();
  184.  
  185.     int i;
  186.     for(i = 0; i < m_aBackground.size(); i++)
  187.         m_aBackground[i].m_Init.m_pSound->Unload();
  188.  
  189.     for(i = 0; i < m_aPeriodic.size(); i++)
  190.         m_aPeriodic[i].m_Init.m_pSound3D->Unload();
  191.  
  192.     m_bLoaded = false;
  193.  
  194.     return true;
  195. }
  196.  
  197. //------------------------------------------------------------------------//
  198. bool SoundScape::IsLoaded() const
  199. {
  200.     FN("SoundScape::IsLoaded()");
  201.     return m_bLoaded;
  202. }
  203.  
  204.  
  205. //------------------------------------------------------------------------//
  206. bool SoundScape::Play()
  207. {
  208.     FN("SoundScape::Play()");
  209.     if(m_bPlaying)
  210.         return true;
  211.  
  212.     int i;
  213.     for(i = 0; i < m_aBackground.size(); i++)
  214.     {
  215.         float fVolume = GetRandom(
  216.             m_aBackground[i].m_Init.m_fMinVolume,
  217.             m_aBackground[i].m_Init.m_fMaxVolume);
  218.         m_aBackground[i].m_fCurrentVolume = fVolume * m_fVolume;
  219.         m_aBackground[i].m_Init.m_pSound->SetVolume(m_aBackground[i].m_fCurrentVolume);
  220.         float fPitch = GetRandom(
  221.             m_aBackground[i].m_Init.m_fMinPitch,
  222.             m_aBackground[i].m_Init.m_fMaxPitch);
  223.         m_aBackground[i].m_fCurrentPitch = fPitch;
  224.         m_aBackground[i].m_Init.m_pSound->SetPitch(fPitch);
  225.         m_aBackground[i].m_Init.m_pSound->Play();
  226.     }
  227.  
  228.     for(i = 0; i < m_aPeriodic.size(); i++)
  229.         if(m_aPeriodic[i].m_Init.m_pSound3D->IsPaused())
  230.             m_aPeriodic[i].m_Init.m_pSound3D->Play();
  231.  
  232.     CSoundMgr()->InsertSoundScape(this);
  233.  
  234.     m_bPlaying = true;
  235.     m_bPaused = false;
  236.  
  237.     m_bFirstUpdate = true;
  238.  
  239.     return true;
  240. }
  241.  
  242. //------------------------------------------------------------------------//
  243. bool SoundScape::Stop()
  244. {
  245.     FN("SoundScape::Stop()");
  246.     if(!m_bPlaying && !m_bPaused)
  247.         return true;
  248.  
  249.     CSoundMgr()->RemoveSoundScape(this);
  250.  
  251.     int i;
  252.     for(i = 0; i < m_aBackground.size(); i++)
  253.         m_aBackground[i].m_Init.m_pSound->Stop();
  254.  
  255.     for(i = 0; i < m_aPeriodic.size(); i++)
  256.         m_aPeriodic[i].m_Init.m_pSound3D->Stop();
  257.  
  258.     m_bPlaying = false;
  259.     m_bPaused = false;
  260.  
  261.  
  262.     return true;
  263. }
  264.  
  265. //------------------------------------------------------------------------//
  266. bool SoundScape::Pause()
  267. {
  268.     FN("SoundScape::Pause()");
  269.  
  270.     CSoundMgr()->RemoveSoundScape(this);
  271.  
  272.     int i;
  273.     for(i = 0; i < m_aBackground.size(); i++)
  274.         m_aBackground[i].m_Init.m_pSound->Pause();
  275.  
  276.     for(i = 0; i < m_aPeriodic.size(); i++)
  277.         m_aPeriodic[i].m_Init.m_pSound3D->Pause();
  278.  
  279.     m_bPlaying = false;
  280.     m_bPaused = true;
  281.  
  282.     return true;
  283. }
  284.  
  285.  
  286. //------------------------------------------------------------------------//
  287. bool SoundScape::IsPlaying() const
  288. {
  289.     FN("SoundScape::IsPlaying()");
  290.     return m_bPlaying;
  291. }
  292.  
  293. //------------------------------------------------------------------------//
  294. bool SoundScape::IsPaused() const
  295. {
  296.     FN("SoundScape::IsPaused()");
  297.     return m_bPaused;
  298. }
  299.  
  300.  
  301. //------------------------------------------------------------------------//
  302. bool SoundScape::IsLooping() const
  303. {
  304.     FN("SoundScape::IsLooping()");
  305.     return true;
  306. }
  307.  
  308.  
  309. //------------------------------------------------------------------------//
  310. bool SoundScape::SetVolume(float fVolume)
  311. {
  312.     FN("SoundScape::SetVolume()");
  313.     m_fVolume = Clamp<float>(fVolume, VOLUME_MIN, VOLUME_MAX);
  314.     m_bVolumeChanged = true;
  315.     return true;
  316. }
  317.  
  318. //------------------------------------------------------------------------//
  319. bool SoundScape::GetVolume(float &fVolume) const
  320. {
  321.     FN("SoundScape::GetVolume()");
  322.     fVolume = m_fVolume;
  323.     return true;
  324. }
  325.  
  326.  
  327. //------------------------------------------------------------------------//
  328. void SoundScape::Update()
  329. {
  330.     FN("SoundScape::Update()");
  331.  
  332.     // We track local time for each soundscape since we don't want
  333.     // time to elapse when the object is paused or stopped.
  334.     m_fCurrentTime += CSoundMgr()->GetFrameTime();
  335.  
  336.     // Update all background elements
  337.     UpdateBackground();
  338.     // Update all periodic elements
  339.     UpdatePeriodic();
  340.  
  341.     m_bFirstUpdate = false;
  342.     m_bVolumeChanged = false;
  343. }
  344.  
  345.  
  346. void SoundScape::UpdateBackground()
  347. {
  348.     // Update all background sounds
  349.     for(int i = 0; i < m_aBackground.size(); i++)
  350.     {
  351.         // Determine if this sound has modulating volume
  352.         if(m_aBackground[i].m_Init.m_fMinVolume != m_aBackground[i].m_Init.m_fMaxVolume)
  353.         {
  354.             // Adjust volume target if necessary
  355.             if((m_fCurrentTime >= m_aBackground[i].m_fTargetVolumeTime) || m_bFirstUpdate)
  356.             {
  357.                 float fTime = GetRandom(
  358.                     m_aBackground[i].m_Init.m_fMinVolumeTime,
  359.                     m_aBackground[i].m_Init.m_fMaxVolumeTime);
  360.                 float fVolume = GetRandom(
  361.                     m_aBackground[i].m_Init.m_fMinVolume,
  362.                     m_aBackground[i].m_Init.m_fMaxVolume);
  363.                 float fRate = (fVolume - m_aBackground[i].m_fCurrentVolume) / fTime;
  364.                 m_aBackground[i].m_fTargetVolumeTime = fTime + m_fCurrentTime;
  365.                 m_aBackground[i].m_fCurrentVolumeChangeRate = fRate;
  366.             }
  367.  
  368.             // Adjust volume
  369.             m_aBackground[i].m_fCurrentVolume += 
  370.                 (m_aBackground[i].m_fCurrentVolumeChangeRate * CSoundMgr()->GetFrameTime());
  371.             m_aBackground[i].m_Init.m_pSound->SetVolume(m_aBackground[i].m_fCurrentVolume * m_fVolume);
  372.         }
  373.         else if(m_bVolumeChanged)
  374.         {
  375.             m_aBackground[i].m_Init.m_pSound->SetVolume(m_aBackground[i].m_Init.m_fMaxVolume * m_fVolume);
  376.         }
  377.  
  378.         // Determine if this sound has modulating pitch
  379.         if(m_aBackground[i].m_Init.m_fMinPitch != m_aBackground[i].m_Init.m_fMaxPitch)
  380.         {
  381.             // Adjust pitch target if necessary
  382.             if(m_fCurrentTime >= m_aBackground[i].m_fTargetPitchTime)
  383.             {
  384.                 float fTime = GetRandom(
  385.                     m_aBackground[i].m_Init.m_fMinPitchTime,
  386.                     m_aBackground[i].m_Init.m_fMaxPitchTime);
  387.                 float fPitch = GetRandom(
  388.                     m_aBackground[i].m_Init.m_fMinPitch,
  389.                     m_aBackground[i].m_Init.m_fMaxPitch);
  390.                 float fRate = (fPitch - m_aBackground[i].m_fCurrentPitch) / fTime;
  391.                 m_aBackground[i].m_fTargetPitchTime = fTime + m_fCurrentTime;
  392.                 m_aBackground[i].m_fCurrentPitchChangeRate = fRate;
  393.             }
  394.  
  395.             // Adjust pitch
  396.             m_aBackground[i].m_fCurrentPitch += 
  397.                 (m_aBackground[i].m_fCurrentPitchChangeRate * CSoundMgr()->GetFrameTime());
  398.             m_aBackground[i].m_Init.m_pSound->SetPitch(m_aBackground[i].m_fCurrentPitch);
  399.         }
  400.     }
  401. }
  402.  
  403.  
  404. void SoundScape::UpdatePeriodic()
  405. {
  406.     IListener* pListener;
  407.     if(!AudioMgr()->GetListener(pListener))
  408.         return;
  409.  
  410.     AUDIOVECTOR vListenerPos;
  411.     pListener->GetPosition(vListenerPos);
  412.  
  413.     AUDIOVECTOR vSoundPos;
  414.  
  415.     // Update all periodic sound effects
  416.     for(int i = 0; i < m_aPeriodic.size(); i++)
  417.     {
  418.         // If enough time has elapsed, change all the settings
  419.         if(m_aPeriodic[i].m_fNextPlay <= m_fCurrentTime)
  420.         {
  421.             // Set a new position relative to the listener
  422.             m_aPeriodic[i].m_vPosition.x = GetRandom(
  423.                 -1 * (m_aPeriodic[i].m_Init.m_fXRange), 
  424.                 m_aPeriodic[i].m_Init.m_fXRange); 
  425.             m_aPeriodic[i].m_vPosition.y = GetRandom(
  426.                 -1 * (m_aPeriodic[i].m_Init.m_fYRange), 
  427.                 m_aPeriodic[i].m_Init.m_fYRange); 
  428.             m_aPeriodic[i].m_vPosition.z = GetRandom(
  429.                 -1 * (m_aPeriodic[i].m_Init.m_fZRange), 
  430.                 m_aPeriodic[i].m_Init.m_fZRange); 
  431.  
  432.             // Ensure the new position axis values are outside the min range 
  433.             if(m_aPeriodic[i].m_vPosition.x < 0.0f)
  434.                 m_aPeriodic[i].m_vPosition.x = ClampMax<float>(
  435.                     m_aPeriodic[i].m_vPosition.x, 
  436.                     -(m_aPeriodic[i].m_Init.m_fMinDistance));
  437.             else
  438.                 m_aPeriodic[i].m_vPosition.x = ClampMin<float>(
  439.                     m_aPeriodic[i].m_vPosition.x, 
  440.                     m_aPeriodic[i].m_Init.m_fMinDistance);
  441.             if(m_aPeriodic[i].m_vPosition.y < 0.0f)
  442.                 m_aPeriodic[i].m_vPosition.y = ClampMax<float>(
  443.                     m_aPeriodic[i].m_vPosition.y, 
  444.                     -(m_aPeriodic[i].m_Init.m_fMinDistance));
  445.             else
  446.                 m_aPeriodic[i].m_vPosition.y = ClampMin<float>(
  447.                     m_aPeriodic[i].m_vPosition.y, 
  448.                     m_aPeriodic[i].m_Init.m_fMinDistance);
  449.             if(m_aPeriodic[i].m_vPosition.z < 0.0f)
  450.                 m_aPeriodic[i].m_vPosition.z = ClampMax<float>(
  451.                     m_aPeriodic[i].m_vPosition.z, 
  452.                     -(m_aPeriodic[i].m_Init.m_fMinDistance));
  453.             else
  454.                 m_aPeriodic[i].m_vPosition.z = ClampMin<float>(
  455.                     m_aPeriodic[i].m_vPosition.z, 
  456.                     m_aPeriodic[i].m_Init.m_fMinDistance);
  457.  
  458.             // Hold the sound's position relative to the listener
  459.             vSoundPos.x = vListenerPos.x + m_aPeriodic[i].m_vPosition.x;
  460.             vSoundPos.y = vListenerPos.y + m_aPeriodic[i].m_vPosition.y;
  461.             vSoundPos.z = vListenerPos.z + m_aPeriodic[i].m_vPosition.z;
  462.             m_aPeriodic[i].m_Init.m_pSound3D->SetPosition(vSoundPos);
  463.             DebugOut(1, "New position is x: %f, y: %f, z: %f", vSoundPos.x, vSoundPos.y, vSoundPos.z);
  464.  
  465.             // Determine the pitch of the new sound
  466.             float fPitch = GetRandom(m_aPeriodic[i].m_Init.m_fMinPitch, 
  467.                 m_aPeriodic[i].m_Init.m_fMaxPitch);
  468.             m_aPeriodic[i].m_Init.m_pSound3D->SetPitch(fPitch);
  469.             DebugOut(5, "New sound pitch is: %f rate of original sound.", fPitch);
  470.  
  471.             // Calculate the next time for the sound to play
  472.             float fRand = GetRandom(m_aPeriodic[i].m_Init.m_fMinDelay, 
  473.                 m_aPeriodic[i].m_Init.m_fMaxDelay);
  474.             DebugOut(5, "3D Sound should play again in %f seconds.", fRand);
  475.             m_aPeriodic[i].m_fNextPlay = m_fCurrentTime + fRand;
  476.  
  477.             // If this isn't the first update, play the sound
  478.             if(!m_bFirstUpdate)
  479.             {
  480.                 DebugOut(1, "Setting volume to %f", m_fVolume);
  481.                 m_aPeriodic[i].m_Init.m_pSound3D->SetVolume(m_fVolume);
  482.                 m_aPeriodic[i].m_Init.m_pSound3D->Play();
  483.             }
  484.         }
  485.         else
  486.         {
  487.             // Hold the sound's position relative to the listener
  488.             vSoundPos.x = vListenerPos.x + m_aPeriodic[i].m_vPosition.x;
  489.             vSoundPos.y = vListenerPos.y + m_aPeriodic[i].m_vPosition.y;
  490.             vSoundPos.z = vListenerPos.z + m_aPeriodic[i].m_vPosition.z;
  491.             m_aPeriodic[i].m_Init.m_pSound3D->SetPosition(vSoundPos);
  492.         }
  493.         if(m_bVolumeChanged)
  494.         {
  495.             DebugOut(1, "Setting volume to %f", m_fVolume);
  496.             m_aPeriodic[i].m_Init.m_pSound3D->SetVolume(m_fVolume);
  497.         }
  498.     }
  499. }
  500.  
  501.  
  502.  
  503. //------------------------------------------------------------------------//
  504. // Generic property support (for driver-specific extensions)
  505. // Technically, these could be set for individual sounds, but
  506. // they are not implemented for this version of the library.
  507. // Generic property support (for driver-specific extensions)
  508. bool SoundScape::QuerySupport(const GUID& guid, uint32 nID, uint32* pTypeSupport)
  509. {
  510.     FN("SoundScape::QuerySupport()");
  511.     return false;
  512. }
  513.  
  514. //------------------------------------------------------------------------//
  515. bool SoundScape::Get(const GUID& guidProperty, uint32 nID, void* pInstanceData,
  516.         uint32 nInstanceLength, void* pPropData, 
  517.     uint32 nPropLength, uint32* pBytesReturned)
  518. {
  519.     FN("SoundScape::Get()");
  520.     return false;
  521. }
  522.  
  523. //------------------------------------------------------------------------//
  524. bool SoundScape::Set(const GUID& guidProperty, uint32 nID, void* pInstanceData,
  525.         uint32 nInstanceLength, void* pPropData, 
  526.     uint32 nPropLength, bool bStoreProperty)
  527. {
  528.     FN("SoundScape::Set()");
  529.     return false;
  530. }
  531.  
  532.  
  533.  
  534.  
  535.  
  536.