audio.cpp
上传用户:May-22
上传日期:2015-07-19
资源大小:7113k
文件大小:14k
源码类别:

DirextX编程

开发平台:

Visual C++

  1. //--------------------------------------------------------------------------------------
  2. // File: audio.cpp
  3. //
  4. // Copyright (c) Microsoft Corporation. All rights reserved.
  5. //--------------------------------------------------------------------------------------
  6. #include "DXUT.h"
  7. #include "DXUTcamera.h"
  8. #include "DXUTsettingsdlg.h"
  9. #include "SDKmisc.h"
  10. #include "SDKwavefile.h"
  11. #include "audio.h"
  12. //--------------------------------------------------------------------------------------
  13. // Global variables
  14. //--------------------------------------------------------------------------------------
  15. AUDIO_STATE g_audioState;
  16. // Must match order of g_PRESET_NAMES
  17. XAUDIO2FX_REVERB_I3DL2_PARAMETERS g_PRESET_PARAMS[ NUM_PRESETS ] =
  18. {
  19.     XAUDIO2FX_I3DL2_PRESET_DEFAULT,
  20.     XAUDIO2FX_I3DL2_PRESET_GENERIC,
  21.     XAUDIO2FX_I3DL2_PRESET_PADDEDCELL,
  22.     XAUDIO2FX_I3DL2_PRESET_ROOM,
  23.     XAUDIO2FX_I3DL2_PRESET_BATHROOM,
  24.     XAUDIO2FX_I3DL2_PRESET_LIVINGROOM,
  25.     XAUDIO2FX_I3DL2_PRESET_STONEROOM,
  26.     XAUDIO2FX_I3DL2_PRESET_AUDITORIUM,
  27.     XAUDIO2FX_I3DL2_PRESET_CONCERTHALL,
  28.     XAUDIO2FX_I3DL2_PRESET_CAVE,
  29.     XAUDIO2FX_I3DL2_PRESET_ARENA,
  30.     XAUDIO2FX_I3DL2_PRESET_HANGAR,
  31.     XAUDIO2FX_I3DL2_PRESET_CARPETEDHALLWAY,
  32.     XAUDIO2FX_I3DL2_PRESET_HALLWAY,
  33.     XAUDIO2FX_I3DL2_PRESET_STONECORRIDOR,
  34.     XAUDIO2FX_I3DL2_PRESET_ALLEY,
  35.     XAUDIO2FX_I3DL2_PRESET_FOREST,
  36.     XAUDIO2FX_I3DL2_PRESET_CITY,
  37.     XAUDIO2FX_I3DL2_PRESET_MOUNTAINS,
  38.     XAUDIO2FX_I3DL2_PRESET_QUARRY,
  39.     XAUDIO2FX_I3DL2_PRESET_PLAIN,
  40.     XAUDIO2FX_I3DL2_PRESET_PARKINGLOT,
  41.     XAUDIO2FX_I3DL2_PRESET_SEWERPIPE,
  42.     XAUDIO2FX_I3DL2_PRESET_UNDERWATER,
  43.     XAUDIO2FX_I3DL2_PRESET_SMALLROOM,
  44.     XAUDIO2FX_I3DL2_PRESET_MEDIUMROOM,
  45.     XAUDIO2FX_I3DL2_PRESET_LARGEROOM,
  46.     XAUDIO2FX_I3DL2_PRESET_MEDIUMHALL,
  47.     XAUDIO2FX_I3DL2_PRESET_LARGEHALL,
  48.     XAUDIO2FX_I3DL2_PRESET_PLATE,
  49. };
  50. //-----------------------------------------------------------------------------------------
  51. // Initialize the audio by creating the XAudio2 device, mastering voice, etc.
  52. //-----------------------------------------------------------------------------------------
  53. HRESULT InitAudio()
  54. {
  55.     // Clear struct
  56.     ZeroMemory( &g_audioState, sizeof(AUDIO_STATE) );
  57.     //
  58.     // Initialize XAudio2
  59.     //
  60.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  61.     UINT32 flags = 0;
  62. #ifdef _DEBUG
  63.     flags |= XAUDIO2_DEBUG_ENGINE;
  64. #endif
  65.     HRESULT hr;
  66.     if ( FAILED(hr = XAudio2Create( &g_audioState.pXAudio2, flags ) ) )
  67.         return hr;
  68.     //
  69.     // Create a mastering voice
  70.     //
  71.     if ( FAILED(hr = g_audioState.pXAudio2->CreateMasteringVoice( &g_audioState.pMasteringVoice ) ) )
  72.     {
  73.         SAFE_RELEASE( g_audioState.pXAudio2 );
  74.         return hr;
  75.     }
  76.     // Check device details to make sure it's within our sample supported parameters
  77.     XAUDIO2_DEVICE_DETAILS details;
  78.     if ( FAILED(hr = g_audioState.pXAudio2->GetDeviceDetails( 0, &details ) ) )
  79.     {
  80.         SAFE_RELEASE( g_audioState.pXAudio2 );
  81.         return hr;
  82.     }
  83.     if ( details.OutputFormat.Format.nChannels > OUTPUTCHANNELS )
  84.     {
  85.         SAFE_RELEASE( g_audioState.pXAudio2 );
  86.         return E_FAIL;
  87.     }
  88.     g_audioState.dwChannelMask = details.OutputFormat.dwChannelMask;
  89.     g_audioState.nChannels = details.OutputFormat.Format.nChannels;
  90.     //
  91.     // Create reverb effect
  92.     //
  93.     flags = 0;
  94. #ifdef _DEBUG
  95.     flags |= XAUDIO2FX_DEBUG;
  96. #endif
  97.     if ( FAILED(hr = XAudio2CreateReverb( &g_audioState.pReverbEffect, flags ) ) )
  98.     {
  99.         SAFE_RELEASE( g_audioState.pXAudio2 );
  100.         return hr;
  101.     }
  102.     //
  103.     // Create a submix voice
  104.     //
  105.     // Reverb effect in XAudio2 currently only supports mono channel count
  106.     const XAUDIO2_EFFECT_DESCRIPTOR effects[] = { { g_audioState.pReverbEffect, TRUE, 1 } };
  107.     const XAUDIO2_EFFECT_CHAIN effectChain = { 1, effects };
  108.     
  109.     if( FAILED(hr = g_audioState.pXAudio2->CreateSubmixVoice( &g_audioState.pSubmixVoice, 1,
  110.                           details.OutputFormat.Format.nSamplesPerSec, 0, 0, NULL, &effectChain ) ) )
  111.     {
  112.         SAFE_RELEASE( g_audioState.pXAudio2 );
  113.         SAFE_RELEASE( g_audioState.pReverbEffect );
  114.         return hr;
  115.     }
  116.     // Set default FX params
  117.     XAUDIO2FX_REVERB_PARAMETERS native;
  118.     ReverbConvertI3DL2ToNative( &g_PRESET_PARAMS[0], &native );
  119.     g_audioState.pSubmixVoice->SetEffectParameters( 0, &native, sizeof(native) );
  120.     //
  121.     // Initialize X3DAudio
  122.     //  Speaker geometry configuration on the final mix, specifies assignment of channels
  123.     //  to speaker positions, defined as per WAVEFORMATEXTENSIBLE.dwChannelMask
  124.     //
  125.     //  SpeedOfSound - speed of sound in user-defined world units/second, used
  126.     //  only for doppler calculations, it must be >= FLT_MIN
  127.     //
  128.     const float SPEEDOFSOUND = X3DAUDIO_SPEED_OF_SOUND;
  129.     X3DAudioInitialize( details.OutputFormat.dwChannelMask, SPEEDOFSOUND, g_audioState.x3DInstance );
  130.     g_audioState.vListenerPos = D3DXVECTOR3(0,0, float(ZMIN));
  131.     g_audioState.vEmitterPos = D3DXVECTOR3(0,0,0);
  132.     g_audioState.fListenerAngle = 0;
  133.     //
  134.     // Setup 3D audio structs
  135.     //
  136.     g_audioState.listener.Position              = g_audioState.vListenerPos;
  137.     g_audioState.listener.OrientFront           = D3DXVECTOR3(0,0,1);
  138.     g_audioState.listener.OrientTop             = D3DXVECTOR3(0,1,0);
  139.     g_audioState.emitter.Position               = g_audioState.vEmitterPos;
  140.     g_audioState.emitter.OrientFront            = D3DXVECTOR3(0,0,1);
  141.     g_audioState.emitter.OrientTop              = D3DXVECTOR3(0,1,0);
  142.     g_audioState.emitter.ChannelCount           = INPUTCHANNELS;
  143.     g_audioState.emitter.ChannelRadius          = 1.0f;
  144.     g_audioState.emitter.CurveDistanceScaler    = 14.0f;
  145.     g_audioState.emitter.DopplerScaler          = 1.0f;
  146.     g_audioState.emitter.pCone                  = &g_audioState.emitterCone;
  147.     g_audioState.emitter.pCone->InnerAngle      = 0.0f;
  148.                                             // Setting the inner cone angles to X3DAUDIO_2PI and
  149.                                             // outer cone other than 0 causes
  150.                                             // the emitter to act like a point emitter using the
  151.                                             // INNER cone settings only.
  152.     g_audioState.emitter.pCone->OuterAngle      = 0.0f;
  153.                                             // Setting the outer cone angles to zero causes
  154.                                             // the emitter to act like a point emitter using the
  155.                                             // OUTER cone settings only.
  156.     g_audioState.emitter.pCone->InnerVolume     = 0.0f;
  157.     g_audioState.emitter.pCone->OuterVolume     = 1.0f;
  158.     g_audioState.emitter.pCone->InnerLPF        = 0.0f;
  159.     g_audioState.emitter.pCone->OuterLPF        = 1.0f;
  160.     g_audioState.emitter.pCone->InnerReverb     = 0.0f;
  161.     g_audioState.emitter.pCone->OuterReverb     = 1.0f;
  162.     g_audioState.emitter.ChannelCount           = INPUTCHANNELS;
  163.     g_audioState.emitter.CurveDistanceScaler    = 14.0f;
  164.     g_audioState.emitter.DopplerScaler          = 1.0f;
  165.     g_audioState.emitter.pChannelAzimuths       = g_audioState.emitterAzimuths;
  166.     g_audioState.dspSettings.SrcChannelCount    = INPUTCHANNELS;
  167.     g_audioState.dspSettings.DstChannelCount    = g_audioState.nChannels;
  168.     g_audioState.dspSettings.pMatrixCoefficients = g_audioState.matrixCoefficients;
  169.     //
  170.     // Done
  171.     //
  172.     g_audioState.bInitialized = true;
  173.     return S_OK;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Prepare a looping wave
  177. //-----------------------------------------------------------------------------
  178. HRESULT PrepareAudio( const LPWSTR wavname )
  179. {
  180.     if( !g_audioState.bInitialized )
  181.         return E_FAIL;
  182.     if ( g_audioState.pSourceVoice )
  183.     {
  184.         g_audioState.pSourceVoice->Stop( 0 );
  185.         g_audioState.pSourceVoice->DestroyVoice();
  186.         g_audioState.pSourceVoice = 0;
  187.     }
  188.     //
  189.     // Search for media
  190.     //
  191.     WCHAR strFilePath[ MAX_PATH ];
  192.     WCHAR wavFilePath[ MAX_PATH ];
  193.     StringCchCopy( wavFilePath, MAX_PATH, L"Media\Wavs\" );
  194.     StringCchCat( wavFilePath, MAX_PATH, wavname );
  195.     HRESULT hr;
  196.     V_RETURN( DXUTFindDXSDKMediaFileCch( strFilePath, MAX_PATH, wavFilePath ) );
  197.     //
  198.     // Read in the wave file
  199.     //
  200.     CWaveFile wav;
  201.     V_RETURN( wav.Open( strFilePath, NULL, WAVEFILE_READ ) );
  202.     // Get format of wave file
  203.     WAVEFORMATEX* pwfx = wav.GetFormat();
  204.     // Calculate how many bytes and samples are in the wave
  205.     DWORD cbWaveSize = wav.GetSize();
  206.     // Read the sample data into memory
  207.     SAFE_DELETE_ARRAY( g_audioState.pbSampleData );
  208.     g_audioState.pbSampleData = new BYTE[ cbWaveSize ];
  209.     V_RETURN( wav.Read( g_audioState.pbSampleData, cbWaveSize, &cbWaveSize ) );
  210.     //
  211.     // Play the wave using a XAudio2SourceVoice
  212.     //
  213.     const IXAudio2Voice* voices[] = { g_audioState.pMasteringVoice, g_audioState.pSubmixVoice };
  214.     const XAUDIO2_VOICE_SENDS sendList = { 2, (IXAudio2Voice**)voices };
  215.     // Create the source voice
  216.     V_RETURN( g_audioState.pXAudio2->CreateSourceVoice( &g_audioState.pSourceVoice, pwfx, 0,
  217.                           XAUDIO2_DEFAULT_FREQ_RATIO, NULL, &sendList ) );
  218.     // Submit the wave sample data using an XAUDIO2_BUFFER structure
  219.     XAUDIO2_BUFFER buffer = {0};
  220.     buffer.pAudioData = g_audioState.pbSampleData;
  221.     buffer.Flags = XAUDIO2_END_OF_STREAM;
  222.     buffer.AudioBytes = cbWaveSize;
  223.     buffer.LoopCount = XAUDIO2_LOOP_INFINITE; 
  224.     V_RETURN( g_audioState.pSourceVoice->SubmitSourceBuffer( &buffer ) );
  225.     V_RETURN( g_audioState.pSourceVoice->Start( 0 ) );
  226.     g_audioState.nFrameToApply3DAudio = 0;
  227.     return S_OK;
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Perform per-frame update of audio
  231. //-----------------------------------------------------------------------------
  232. HRESULT UpdateAudio( float fElapsedTime )
  233. {
  234.     if( !g_audioState.bInitialized )
  235.         return S_FALSE;
  236.     if( g_audioState.nFrameToApply3DAudio == 0 )
  237.     {
  238.         // Calculate listener orientation in x-z plane
  239.         if( g_audioState.vListenerPos.x != g_audioState.listener.Position.x
  240.             || g_audioState.vListenerPos.z != g_audioState.listener.Position.z )
  241.         {
  242.             D3DXVECTOR3 vDelta = g_audioState.vListenerPos - g_audioState.listener.Position;
  243.             g_audioState.fListenerAngle = float( atan2( vDelta.x, vDelta.z ) );
  244.             vDelta.y = 0.0f;
  245.             D3DXVec3Normalize( &vDelta, &vDelta );
  246.             g_audioState.listener.OrientFront.x = vDelta.x;
  247.             g_audioState.listener.OrientFront.y = 0.f;
  248.             g_audioState.listener.OrientFront.z = vDelta.z;
  249.         }
  250.         if ( fElapsedTime > 0 )
  251.         {
  252.             D3DXVECTOR3 lVelocity = ( g_audioState.vListenerPos - g_audioState.listener.Position ) / fElapsedTime;
  253.             g_audioState.listener.Position = g_audioState.vListenerPos;
  254.             g_audioState.listener.Velocity = lVelocity;
  255.             D3DXVECTOR3 eVelocity = ( g_audioState.vEmitterPos - g_audioState.emitter.Position ) / fElapsedTime;
  256.             g_audioState.emitter.Position = g_audioState.vEmitterPos;
  257.             g_audioState.emitter.Velocity = eVelocity;
  258.         }
  259.         const DWORD dwCalcFlags = X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER 
  260.                                   | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_LPF_REVERB 
  261.                                   | X3DAUDIO_CALCULATE_REVERB;
  262.         X3DAudioCalculate( g_audioState.x3DInstance, &g_audioState.listener, &g_audioState.emitter, dwCalcFlags,
  263.                            &g_audioState.dspSettings );
  264.         IXAudio2SourceVoice* voice = g_audioState.pSourceVoice;
  265.         if ( voice )
  266.         {
  267.             voice->SetFrequencyRatio( g_audioState.dspSettings.DopplerFactor );
  268.             voice->SetOutputMatrix( g_audioState.pMasteringVoice, INPUTCHANNELS, g_audioState.nChannels, 
  269.                                     g_audioState.matrixCoefficients );
  270.         }
  271.     }
  272.     g_audioState.nFrameToApply3DAudio++;
  273.     g_audioState.nFrameToApply3DAudio %= 2;
  274.     return S_OK;
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Set reverb effect
  278. //-----------------------------------------------------------------------------
  279. HRESULT SetReverb( int nReverb )
  280. {
  281.     if( !g_audioState.bInitialized )
  282.         return S_FALSE;
  283.     if ( nReverb < 0 || nReverb >= NUM_PRESETS )
  284.         return E_FAIL;
  285.     if ( g_audioState.pSubmixVoice )
  286.     {
  287.         XAUDIO2FX_REVERB_PARAMETERS native;
  288.         ReverbConvertI3DL2ToNative( &g_PRESET_PARAMS[ nReverb ], &native );
  289.         g_audioState.pSubmixVoice->SetEffectParameters( 0, &native, sizeof(native) );
  290.     }
  291.     return S_OK;
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Pause audio playback
  295. //-----------------------------------------------------------------------------
  296. VOID PauseAudio( bool resume )
  297. {
  298.     if( !g_audioState.bInitialized )
  299.         return;
  300.     if (resume)
  301.         g_audioState.pXAudio2->StartEngine();
  302.     else
  303.         g_audioState.pXAudio2->StopEngine();
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Releases XAudio2
  307. //-----------------------------------------------------------------------------
  308. VOID CleanupAudio()
  309. {
  310.     if( !g_audioState.bInitialized )
  311.         return;
  312.     if (g_audioState.pSourceVoice)
  313.     {
  314.         g_audioState.pSourceVoice->DestroyVoice();
  315.         g_audioState.pSourceVoice=NULL;
  316.     }
  317.     if (g_audioState.pSubmixVoice)
  318.     {
  319.         g_audioState.pSubmixVoice->DestroyVoice();
  320.         g_audioState.pSubmixVoice=NULL;
  321.     }
  322.     if (g_audioState.pMasteringVoice)
  323.     {
  324.         g_audioState.pMasteringVoice->DestroyVoice();
  325.         g_audioState.pMasteringVoice=NULL;
  326.     }
  327.     g_audioState.pXAudio2->StopEngine();
  328.     SAFE_RELEASE( g_audioState.pXAudio2 );
  329.     SAFE_RELEASE( g_audioState.pReverbEffect );
  330.     SAFE_DELETE_ARRAY( g_audioState.pbSampleData );
  331.     CoUninitialize();
  332.     g_audioState.bInitialized = false;
  333. }