starting audio implementation
						commit
						9ca745e5e0
					
				|  | @ -0,0 +1,192 @@ | |||
| using System; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonWorks.Audio | ||||
| { | ||||
|     public class AudioDevice | ||||
|     { | ||||
|         public IntPtr Handle { get; } | ||||
|         public byte[] Handle3D { get; } | ||||
|         public IntPtr MasteringVoice { get; } | ||||
|         public FAudio.FAudioDeviceDetails DeviceDetails { get; } | ||||
|         public IntPtr ReverbVoice { get; } | ||||
| 
 | ||||
|         public float CurveDistanceScalar = 1f; | ||||
|         public float DopplerScale = 1f; | ||||
|         public float SpeedOfSound = 343.5f; | ||||
| 
 | ||||
|         private FAudio.FAudioVoiceSends reverbSends; | ||||
| 
 | ||||
|         public unsafe AudioDevice() | ||||
|         { | ||||
|             FAudio.FAudioCreate(out var handle, 0, 0); | ||||
|             Handle = handle; | ||||
| 
 | ||||
|             /* Find a suitable device */ | ||||
| 
 | ||||
|             FAudio.FAudio_GetDeviceCount(Handle, out var devices); | ||||
| 
 | ||||
|             if (devices == 0) | ||||
|             { | ||||
|                 Logger.LogError("No audio devices found!"); | ||||
|                 Handle = IntPtr.Zero; | ||||
|                 FAudio.FAudio_Release(Handle); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             FAudio.FAudioDeviceDetails deviceDetails; | ||||
| 
 | ||||
|             uint i = 0; | ||||
|             for (i = 0; i < devices; i++) | ||||
|             { | ||||
|                 FAudio.FAudio_GetDeviceDetails( | ||||
|                     Handle, | ||||
|                     i, | ||||
|                     out deviceDetails | ||||
|                 ); | ||||
|                 if ((deviceDetails.Role & FAudio.FAudioDeviceRole.FAudioDefaultGameDevice) == FAudio.FAudioDeviceRole.FAudioDefaultGameDevice) | ||||
|                 { | ||||
|                     DeviceDetails = deviceDetails; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (i == devices) | ||||
|             { | ||||
|                 i = 0; /* whatever we'll just use the first one I guess */ | ||||
|                 FAudio.FAudio_GetDeviceDetails( | ||||
|                     Handle, | ||||
|                     i, | ||||
|                     out deviceDetails | ||||
|                 ); | ||||
|                 DeviceDetails = deviceDetails; | ||||
|             } | ||||
| 
 | ||||
|             /* Init Mastering Voice */ | ||||
|             IntPtr masteringVoice; | ||||
| 
 | ||||
|             if (FAudio.FAudio_CreateMasteringVoice( | ||||
|                 Handle, | ||||
|                 out masteringVoice, | ||||
|                 FAudio.FAUDIO_DEFAULT_CHANNELS, | ||||
|                 FAudio.FAUDIO_DEFAULT_SAMPLERATE, | ||||
|                 0, | ||||
|                 i, | ||||
|                 IntPtr.Zero | ||||
|             ) != 0) | ||||
|             { | ||||
|                 Logger.LogError("No mastering voice found!"); | ||||
|                 Handle = IntPtr.Zero; | ||||
|                 FAudio.FAudio_Release(Handle); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             MasteringVoice = masteringVoice; | ||||
| 
 | ||||
|             /* Init 3D Audio */ | ||||
| 
 | ||||
|             Handle3D = new byte[FAudio.F3DAUDIO_HANDLE_BYTESIZE]; | ||||
|             FAudio.F3DAudioInitialize( | ||||
|                 DeviceDetails.OutputFormat.dwChannelMask, | ||||
|                 SpeedOfSound, | ||||
|                 Handle3D | ||||
|             ); | ||||
| 
 | ||||
|             /* Init reverb */ | ||||
| 
 | ||||
|             IntPtr reverbVoice; | ||||
| 
 | ||||
|             IntPtr reverb; | ||||
|             FAudio.FAudioCreateReverb(out reverb, 0); | ||||
| 
 | ||||
|             IntPtr chainPtr; | ||||
|             chainPtr = Marshal.AllocHGlobal( | ||||
|                 Marshal.SizeOf<FAudio.FAudioEffectChain>() | ||||
|             ); | ||||
| 
 | ||||
|             FAudio.FAudioEffectChain* reverbChain = (FAudio.FAudioEffectChain*) chainPtr; | ||||
|             reverbChain->EffectCount = 1; | ||||
|             reverbChain->pEffectDescriptors = Marshal.AllocHGlobal( | ||||
|                 Marshal.SizeOf<FAudio.FAudioEffectDescriptor>() | ||||
|             ); | ||||
| 
 | ||||
|             FAudio.FAudioEffectDescriptor* reverbDescriptor = | ||||
|                 (FAudio.FAudioEffectDescriptor*) reverbChain->pEffectDescriptors; | ||||
| 
 | ||||
|             reverbDescriptor->InitialState = 1; | ||||
|             reverbDescriptor->OutputChannels = (uint) ( | ||||
|                 (DeviceDetails.OutputFormat.Format.nChannels == 6) ? 6 : 1 | ||||
|             ); | ||||
|             reverbDescriptor->pEffect = reverb; | ||||
| 
 | ||||
|             FAudio.FAudio_CreateSubmixVoice( | ||||
|                 Handle, | ||||
|                 out reverbVoice, | ||||
|                 1, /* omnidirectional reverb */ | ||||
|                 DeviceDetails.OutputFormat.Format.nSamplesPerSec, | ||||
|                 0, | ||||
|                 0, | ||||
|                 IntPtr.Zero, | ||||
|                 chainPtr | ||||
|             ); | ||||
|             FAudio.FAPOBase_Release(reverb); | ||||
| 
 | ||||
|             Marshal.FreeHGlobal(reverbChain->pEffectDescriptors); | ||||
|             Marshal.FreeHGlobal(chainPtr); | ||||
| 
 | ||||
|             ReverbVoice = reverbVoice; | ||||
| 
 | ||||
|             /* Init reverb params */ | ||||
|             // Defaults based on FAUDIOFX_I3DL2_PRESET_GENERIC | ||||
| 
 | ||||
|             IntPtr reverbParamsPtr = Marshal.AllocHGlobal( | ||||
|                 Marshal.SizeOf<FAudio.FAudioFXReverbParameters>() | ||||
|             ); | ||||
| 
 | ||||
|             FAudio.FAudioFXReverbParameters* reverbParams = (FAudio.FAudioFXReverbParameters*) reverbParamsPtr; | ||||
|             reverbParams->WetDryMix = 100.0f; | ||||
|             reverbParams->ReflectionsDelay = 7; | ||||
|             reverbParams->ReverbDelay = 11; | ||||
|             reverbParams->RearDelay = FAudio.FAUDIOFX_REVERB_DEFAULT_REAR_DELAY; | ||||
|             reverbParams->PositionLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION; | ||||
|             reverbParams->PositionRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION; | ||||
|             reverbParams->PositionMatrixLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX; | ||||
|             reverbParams->PositionMatrixRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX; | ||||
|             reverbParams->EarlyDiffusion = 15; | ||||
|             reverbParams->LateDiffusion = 15; | ||||
|             reverbParams->LowEQGain = 8; | ||||
|             reverbParams->LowEQCutoff = 4; | ||||
|             reverbParams->HighEQGain = 8; | ||||
|             reverbParams->HighEQCutoff = 6; | ||||
|             reverbParams->RoomFilterFreq = 5000f; | ||||
|             reverbParams->RoomFilterMain = -10f; | ||||
|             reverbParams->RoomFilterHF = -1f; | ||||
|             reverbParams->ReflectionsGain = -26.0200005f; | ||||
|             reverbParams->ReverbGain = 10.0f; | ||||
|             reverbParams->DecayTime = 1.49000001f; | ||||
|             reverbParams->Density = 100.0f; | ||||
|             reverbParams->RoomSize = FAudio.FAUDIOFX_REVERB_DEFAULT_ROOM_SIZE; | ||||
|             FAudio.FAudioVoice_SetEffectParameters( | ||||
|                 ReverbVoice, | ||||
|                 0, | ||||
|                 reverbParamsPtr, | ||||
|                 (uint) Marshal.SizeOf<FAudio.FAudioFXReverbParameters>(), | ||||
|                 0 | ||||
|             ); | ||||
|             Marshal.FreeHGlobal(reverbParamsPtr); | ||||
| 
 | ||||
|             /* Init reverb sends */ | ||||
| 
 | ||||
|             reverbSends = new FAudio.FAudioVoiceSends(); | ||||
|             reverbSends.SendCount = 2; | ||||
|             reverbSends.pSends = Marshal.AllocHGlobal( | ||||
|                 2 * Marshal.SizeOf<FAudio.FAudioSendDescriptor>() | ||||
|             ); | ||||
|             FAudio.FAudioSendDescriptor* sendDesc = (FAudio.FAudioSendDescriptor*) reverbSends.pSends; | ||||
|             sendDesc[0].Flags = 0; | ||||
|             sendDesc[0].pOutputVoice = MasteringVoice; | ||||
|             sendDesc[1].Flags = 0; | ||||
|             sendDesc[1].pOutputVoice = ReverbVoice; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,36 @@ | |||
| using System; | ||||
| using System.IO; | ||||
| 
 | ||||
| namespace MoonWorks.Audio | ||||
| { | ||||
|     // for streaming long playback | ||||
|     public class Song | ||||
|     { | ||||
|         public IntPtr Handle { get; } | ||||
|         public FAudio.stb_vorbis_info Info { get; } | ||||
|         public uint BufferSize { get; } | ||||
|         public bool Loop { get; set; } | ||||
|         private readonly float[] buffer; | ||||
|         private const int bufferShrinkFactor = 8; | ||||
| 
 | ||||
|         public TimeSpan Duration { get; set; } | ||||
| 
 | ||||
|         public Song(FileInfo fileInfo) | ||||
|         { | ||||
|             var filePointer = FAudio.stb_vorbis_open_filename(fileInfo.FullName, out var error, IntPtr.Zero); | ||||
| 
 | ||||
|             if (error != 0) | ||||
|             { | ||||
|                 throw new AudioLoadException("Error loading file!"); | ||||
|             } | ||||
| 
 | ||||
|             Info = FAudio.stb_vorbis_get_info(filePointer); | ||||
|             BufferSize = (uint)(Info.sample_rate * Info.channels) / bufferShrinkFactor; | ||||
| 
 | ||||
|             buffer = new float[BufferSize]; | ||||
| 
 | ||||
| 
 | ||||
|             FAudio.stb_vorbis_close(filePointer); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,73 @@ | |||
| using System; | ||||
| using System.IO; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonWorks.Audio | ||||
| { | ||||
|     public class Sound | ||||
|     { | ||||
|         internal FAudio.FAudioBuffer Handle; | ||||
|         internal FAudio.FAudioWaveFormatEx Format; | ||||
| 
 | ||||
|         public uint LoopStart { get; set; } = 0; | ||||
|         public uint LoopLength { get; set; } = 0; | ||||
| 
 | ||||
|         public static Sound FromFile(FileInfo fileInfo) | ||||
|         { | ||||
|             var filePointer = FAudio.stb_vorbis_open_filename(fileInfo.FullName, out var error, IntPtr.Zero); | ||||
| 
 | ||||
|             if (error != 0) | ||||
|             { | ||||
|                 throw new AudioLoadException("Error loading file!"); | ||||
|             } | ||||
|             var info = FAudio.stb_vorbis_get_info(filePointer); | ||||
|             var bufferSize =  (uint)(info.sample_rate * info.channels); | ||||
|             var buffer = new float[bufferSize]; | ||||
|             var align = (ushort) (4 * info.channels); | ||||
| 
 | ||||
|             FAudio.stb_vorbis_close(filePointer); | ||||
| 
 | ||||
|             return new Sound( | ||||
|                 buffer, | ||||
|                 0, | ||||
|                 (ushort) info.channels, | ||||
|                 info.sample_rate, | ||||
|                 align | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         /* we only support float decoding! WAV sucks! */ | ||||
|         public Sound( | ||||
|             float[] buffer, | ||||
|             uint bufferOffset, | ||||
|             ushort channels, | ||||
|             uint samplesPerSecond, | ||||
|             ushort blockAlign | ||||
|         ) { | ||||
|             var bufferLength = 4 * buffer.Length; | ||||
| 
 | ||||
|             Format = new FAudio.FAudioWaveFormatEx(); | ||||
|             Format.wFormatTag = 3; | ||||
|             Format.wBitsPerSample = 32; | ||||
|             Format.nChannels = channels; | ||||
|             Format.nBlockAlign = (ushort) (4 * Format.nChannels); | ||||
|             Format.nSamplesPerSec = samplesPerSecond; | ||||
|             Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec; | ||||
|             Format.nBlockAlign = blockAlign; | ||||
|             Format.cbSize = 0; | ||||
| 
 | ||||
|             Handle = new FAudio.FAudioBuffer(); | ||||
|             Handle.Flags = FAudio.FAUDIO_END_OF_STREAM; | ||||
|             Handle.pContext = IntPtr.Zero; | ||||
|             Handle.AudioBytes = (uint) bufferLength; | ||||
|             Handle.pAudioData = Marshal.AllocHGlobal((int) bufferLength); | ||||
|             Marshal.Copy(buffer, (int) bufferOffset, Handle.pAudioData, (int) bufferLength); | ||||
|             Handle.PlayBegin = 0; | ||||
|             Handle.PlayLength = ( | ||||
|                 Handle.AudioBytes / | ||||
|                 (uint) Format.nChannels / | ||||
|                 (uint) (Format.wBitsPerSample / 8) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,308 @@ | |||
| using System; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonWorks.Audio | ||||
| { | ||||
|     public abstract class SoundInstance : IDisposable | ||||
|     { | ||||
|         protected AudioDevice Device { get; } | ||||
|         internal IntPtr Handle { get; } | ||||
|         protected Sound Parent { get; } | ||||
|         protected FAudio.F3DAUDIO_DSP_SETTINGS dspSettings; | ||||
|         public SoundState State { get; protected set; } | ||||
| 
 | ||||
|         protected bool is3D; | ||||
| 
 | ||||
|         private float _pan = 0; | ||||
|         private bool IsDisposed; | ||||
| 
 | ||||
|         public float Pan | ||||
|         { | ||||
|             get => _pan; | ||||
|             set | ||||
|             { | ||||
|                 _pan = value; | ||||
| 
 | ||||
|                 if (_pan < -1f) | ||||
|                 { | ||||
|                     _pan = -1f; | ||||
|                 } | ||||
|                 if (_pan > 1f) | ||||
|                 { | ||||
|                     _pan = 1f; | ||||
|                 } | ||||
| 
 | ||||
|                 if (is3D) { return; } | ||||
| 
 | ||||
|                 SetPanMatrixCoefficients(); | ||||
|                 FAudio.FAudioVoice_SetOutputMatrix( | ||||
|                     Handle, | ||||
|                     Device.MasteringVoice, | ||||
|                     dspSettings.SrcChannelCount, | ||||
|                     dspSettings.DstChannelCount, | ||||
|                     dspSettings.pMatrixCoefficients, | ||||
|                     0 | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private float _pitch = 1; | ||||
|         public float Pitch | ||||
|         { | ||||
|             get => _pitch; | ||||
|             set | ||||
|             { | ||||
|                 float doppler; | ||||
|                 if (!is3D || Device.DopplerScale == 0f) | ||||
|                 { | ||||
|                     doppler = 1f; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     doppler = dspSettings.DopplerFactor * Device.DopplerScale; | ||||
|                 } | ||||
| 
 | ||||
|                 _pitch = value; | ||||
|                 FAudio.FAudioSourceVoice_SetFrequencyRatio( | ||||
|                     Handle, | ||||
|                     (float) Math.Pow(2.0, _pitch) * doppler, | ||||
|                     0 | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private float _volume = 1; | ||||
|         public float Volume | ||||
|         { | ||||
|             get => _volume; | ||||
|             set | ||||
|             { | ||||
|                 _volume = value; | ||||
|                 FAudio.FAudioVoice_SetVolume(Handle, _volume, 0); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private float _reverb; | ||||
|         public unsafe float Reverb | ||||
|         { | ||||
|             get => _reverb; | ||||
|             set | ||||
|             { | ||||
|                 _reverb = value; | ||||
| 
 | ||||
|                 float* outputMatrix = (float*) dspSettings.pMatrixCoefficients; | ||||
|                 outputMatrix[0] = _reverb; | ||||
|                 if (dspSettings.SrcChannelCount == 2) | ||||
|                 { | ||||
|                     outputMatrix[1] = _reverb; | ||||
|                 } | ||||
| 
 | ||||
|                 FAudio.FAudioVoice_SetOutputMatrix( | ||||
|                     Handle, | ||||
|                     Device.ReverbVoice, | ||||
|                     dspSettings.SrcChannelCount, | ||||
|                     1, | ||||
|                     dspSettings.pMatrixCoefficients, | ||||
|                     0 | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private float _lowPassFilter; | ||||
|         public float LowPassFilter | ||||
|         { | ||||
|             get => _lowPassFilter; | ||||
|             set | ||||
|             { | ||||
|                 _lowPassFilter = value; | ||||
| 
 | ||||
|                 FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters(); | ||||
|                 p.Type = FAudio.FAudioFilterType.FAudioLowPassFilter; | ||||
|                 p.Frequency = _lowPassFilter; | ||||
|                 p.OneOverQ = 1f; | ||||
|                 FAudio.FAudioVoice_SetFilterParameters( | ||||
|                     Handle, | ||||
|                     ref p, | ||||
|                     0 | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private float _highPassFilter; | ||||
|         public float HighPassFilter | ||||
|         { | ||||
|             get => _highPassFilter; | ||||
|             set | ||||
|             { | ||||
|                 _highPassFilter = value; | ||||
| 
 | ||||
|                 FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters(); | ||||
|                 p.Type = FAudio.FAudioFilterType.FAudioHighPassFilter; | ||||
|                 p.Frequency = _highPassFilter; | ||||
|                 p.OneOverQ = 1f; | ||||
|                 FAudio.FAudioVoice_SetFilterParameters( | ||||
|                     Handle, | ||||
|                     ref p, | ||||
|                     0 | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private float _bandPassFilter; | ||||
|         public float BandPassFilter | ||||
|         { | ||||
|             get => _bandPassFilter; | ||||
|             set | ||||
|             { | ||||
|                 _bandPassFilter = value; | ||||
| 
 | ||||
|                 FAudio.FAudioFilterParameters p = new FAudio.FAudioFilterParameters(); | ||||
|                 p.Type = FAudio.FAudioFilterType.FAudioBandPassFilter; | ||||
|                 p.Frequency = _bandPassFilter; | ||||
|                 p.OneOverQ = 1f; | ||||
|                 FAudio.FAudioVoice_SetFilterParameters( | ||||
|                     Handle, | ||||
|                     ref p, | ||||
|                     0 | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public SoundInstance(AudioDevice device, Sound parent, bool is3D) | ||||
|         { | ||||
|             Device = device; | ||||
|             Parent = parent; | ||||
| 
 | ||||
|             FAudio.FAudioWaveFormatEx format = Parent.Format; | ||||
| 
 | ||||
|             FAudio.FAudio_CreateSourceVoice( | ||||
|                 Device.Handle, | ||||
|                 out var handle, | ||||
|                 ref format, | ||||
|                 FAudio.FAUDIO_VOICE_USEFILTER, | ||||
|                 FAudio.FAUDIO_DEFAULT_FREQ_RATIO, | ||||
|                 IntPtr.Zero, | ||||
|                 IntPtr.Zero, | ||||
|                 IntPtr.Zero | ||||
|             ); | ||||
| 
 | ||||
|             if (handle == IntPtr.Zero) | ||||
|             { | ||||
|                 Logger.LogError("SoundInstance failed to initialize!"); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             Handle = handle; | ||||
|             this.is3D = is3D; | ||||
|             InitDSPSettings(Parent.Format.nChannels); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private void InitDSPSettings(uint srcChannels) | ||||
|         { | ||||
|             dspSettings = new FAudio.F3DAUDIO_DSP_SETTINGS(); | ||||
|             dspSettings.DopplerFactor = 1f; | ||||
|             dspSettings.SrcChannelCount = srcChannels; | ||||
|             dspSettings.DstChannelCount = Device.DeviceDetails.OutputFormat.Format.nChannels; | ||||
| 
 | ||||
|             int memsize = ( | ||||
|                 4 * | ||||
|                 (int) dspSettings.SrcChannelCount * | ||||
|                 (int) dspSettings.DstChannelCount | ||||
|             ); | ||||
| 
 | ||||
|             dspSettings.pMatrixCoefficients = Marshal.AllocHGlobal(memsize); | ||||
|             unsafe | ||||
|             { | ||||
|                 byte* memPtr = (byte*) dspSettings.pMatrixCoefficients; | ||||
|                 for (int i = 0; i < memsize; i += 1) | ||||
|                 { | ||||
|                     memPtr[i] = 0; | ||||
|                 } | ||||
|             } | ||||
|             SetPanMatrixCoefficients(); | ||||
|         } | ||||
| 
 | ||||
|         // Taken from https://github.com/FNA-XNA/FNA/blob/master/src/Audio/SoundEffectInstance.cs | ||||
|         private unsafe void SetPanMatrixCoefficients() | ||||
|         { | ||||
|             /* Two major things to notice: | ||||
| 			 * 1. The spec assumes any speaker count >= 2 has Front Left/Right. | ||||
| 			 * 2. Stereo panning is WAY more complicated than you think. | ||||
| 			 *    The main thing is that hard panning does NOT eliminate an | ||||
| 			 *    entire channel; the two channels are blended on each side. | ||||
| 			 * -flibit | ||||
| 			 */ | ||||
| 			float* outputMatrix = (float*) dspSettings.pMatrixCoefficients; | ||||
| 			if (dspSettings.SrcChannelCount == 1) | ||||
| 			{ | ||||
| 				if (dspSettings.DstChannelCount == 1) | ||||
| 				{ | ||||
| 					outputMatrix[0] = 1.0f; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					outputMatrix[0] = (_pan > 0.0f) ? (1.0f - _pan) : 1.0f; | ||||
| 					outputMatrix[1] = (_pan < 0.0f) ? (1.0f  + _pan) : 1.0f; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (dspSettings.DstChannelCount == 1) | ||||
| 				{ | ||||
| 					outputMatrix[0] = 1.0f; | ||||
| 					outputMatrix[1] = 1.0f; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if (_pan <= 0.0f) | ||||
| 					{ | ||||
| 						// Left speaker blends left/right channels | ||||
| 						outputMatrix[0] = 0.5f * _pan + 1.0f; | ||||
| 						outputMatrix[1] = 0.5f * -_pan; | ||||
| 						// Right speaker gets less of the right channel | ||||
| 						outputMatrix[2] = 0.0f; | ||||
| 						outputMatrix[3] = _pan + 1.0f; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						// Left speaker gets less of the left channel | ||||
| 						outputMatrix[0] = -_pan + 1.0f; | ||||
| 						outputMatrix[1] = 0.0f; | ||||
| 						// Right speaker blends right/left channels | ||||
| 						outputMatrix[2] = 0.5f * _pan; | ||||
| 						outputMatrix[3] = 0.5f * -_pan + 1.0f; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|         } | ||||
| 
 | ||||
|         protected virtual void Dispose(bool disposing) | ||||
|         { | ||||
|             if (!IsDisposed) | ||||
|             { | ||||
|                 if (disposing) | ||||
|                 { | ||||
|                     // dispose managed state (managed objects) | ||||
|                 } | ||||
| 
 | ||||
|                 FAudio.FAudioVoice_DestroyVoice(Handle); | ||||
|                 Marshal.FreeHGlobal(dspSettings.pMatrixCoefficients); | ||||
|                 IsDisposed = true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ~SoundInstance() | ||||
|         { | ||||
|             // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
|             Dispose(disposing: false); | ||||
|         } | ||||
| 
 | ||||
|         public void Dispose() | ||||
|         { | ||||
|             // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
|             Dispose(disposing: true); | ||||
|             GC.SuppressFinalize(this); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,9 @@ | |||
| namespace MoonWorks.Audio | ||||
| { | ||||
|     public enum SoundState | ||||
|     { | ||||
|         Playing, | ||||
|         Paused, | ||||
|         Stopped | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,70 @@ | |||
| using System; | ||||
| 
 | ||||
| namespace MoonWorks.Audio | ||||
| { | ||||
|     public class StaticSoundInstance : SoundInstance | ||||
|     { | ||||
|         public bool Loop { get; protected set; } | ||||
| 
 | ||||
|         public StaticSoundInstance( | ||||
|             AudioDevice device, | ||||
|             Sound parent, | ||||
|             bool is3D | ||||
|         ) : base(device, parent, is3D) { } | ||||
| 
 | ||||
|         public void Play(bool loop = false) | ||||
|         { | ||||
|             if (State == SoundState.Playing) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (loop) | ||||
|             { | ||||
|                 Loop = true; | ||||
|                 Parent.Handle.LoopCount = 255; | ||||
|                 Parent.Handle.LoopBegin = 0; | ||||
|                 Parent.Handle.LoopLength = Parent.LoopLength; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Loop = false; | ||||
|                 Parent.Handle.LoopCount = 0; | ||||
|                 Parent.Handle.LoopBegin = 0; | ||||
|                 Parent.Handle.LoopLength = 0; | ||||
|             } | ||||
| 
 | ||||
|             FAudio.FAudioSourceVoice_SubmitSourceBuffer( | ||||
|                 Handle, | ||||
|                 ref Parent.Handle, | ||||
|                 IntPtr.Zero | ||||
|             ); | ||||
| 
 | ||||
|             FAudio.FAudioSourceVoice_Start(Handle, 0, 0); | ||||
|             State = SoundState.Playing; | ||||
|         } | ||||
| 
 | ||||
|         public void Pause() | ||||
|         { | ||||
|             if (State == SoundState.Paused) | ||||
|             { | ||||
|                 FAudio.FAudioSourceVoice_Stop(Handle, 0, 0); | ||||
|                 State = SoundState.Paused; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void Stop(bool immediate = true) | ||||
|         { | ||||
|             if (immediate) | ||||
|             { | ||||
|                 FAudio.FAudioSourceVoice_Stop(Handle, 0, 0); | ||||
|                 FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle); | ||||
|                 State = SoundState.Stopped; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 FAudio.FAudioSourceVoice_ExitLoop(Handle, 0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue