/// <summary> /// Initializes the audio renderer. /// Call the Play Method to start reading samples /// </summary> private void Initialize() { Destroy(); if (SoundTouch.IsAvailable) { AudioProcessor = new SoundTouch { Channels = (uint)WaveFormat.Channels, SampleRate = (uint)WaveFormat.SampleRate }; } AudioDevice = new WavePlayer(this) { DesiredLatency = 200, NumberOfBuffers = 2, }; SyncThesholdMilliseconds = 0.05 * DesiredLatency.TotalMilliseconds; // ~5% sync threshold for audio samples BytesPerSample = WaveFormat.BitsPerSample / 8; SampleBlockSize = BytesPerSample * WaveFormat.Channels; var bufferLength = WaveFormat.ConvertLatencyToByteSize(AudioDevice.DesiredLatency) * MediaElement.Blocks[MediaType.Audio].Capacity / 2; AudioBuffer = new CircularBuffer(bufferLength); AudioDevice.Init(this); AudioDevice.Play(); }
private bool Synchronize(byte[] targetBuffer, int targetBufferOffset, int requestedBytes) { var audioLatency = Latency; if (audioLatency.TotalMilliseconds > SyncThesholdMilliseconds / 2d) { // a positive audio latency means we are rendering audio behind (after) the clock (skip some samples) // and therefore we need to advance the buffer before we read from it. MediaElement.Container?.Logger?.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: LATENCY: {audioLatency.Format()} | SKIP (samples being rendered too late)"); // skip some samples from the buffer. var audioLatencyBytes = WaveFormat.ConvertLatencyToByteSize((int)Math.Ceiling(audioLatency.TotalMilliseconds)); AudioBuffer.Skip(Math.Min(audioLatencyBytes, AudioBuffer.ReadableCount)); } else if (audioLatency.TotalMilliseconds < -2d * SyncThesholdMilliseconds) { // a negative audio latency means we are rendering audio ahead (before) the clock // and therefore we need to render some silence until the clock catches up MediaElement.Container?.Logger?.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: LATENCY: {audioLatency.Format()} | WAIT (samples being rendered too early)"); // render silence for the wait time and return Array.Clear(targetBuffer, targetBufferOffset, requestedBytes); return(false); } return(true); }
/// <summary> /// Initializes the audio renderer. /// Call the Play Method to start reading samples /// </summary> private void Initialize() { Destroy(); if (SoundTouch.IsAvailable) { AudioProcessor = new SoundTouch { Channels = Convert.ToUInt32(WaveFormat.Channels), SampleRate = Convert.ToUInt32(WaveFormat.SampleRate) }; } AudioDevice = new WavePlayer(this) { DesiredLatency = 200, NumberOfBuffers = 2, }; SampleBlockSize = Constants.Audio.BytesPerSample * Constants.Audio.ChannelCount; var bufferLength = WaveFormat.ConvertLatencyToByteSize(AudioDevice.DesiredLatency) * MediaCore.Blocks[MediaType.Audio].Capacity / 2; AudioBuffer = new CircularBuffer(bufferLength); AudioDevice.Init(this); AudioDevice.Play(); }
private void InitialiseDirectSound(IntPtr windowHandle, int sampleRate) { var waveFormat = new WaveFormat(sampleRate, 16, 2); _directSound = new DirectSound(); _directSound.SetCooperativeLevel(windowHandle, CooperativeLevel.Priority); var primaryBufferDescription = new SoundBufferDescription() { Flags = BufferFlags.PrimaryBuffer, AlgorithmFor3D = Guid.Empty, }; _primarySoundBuffer = new PrimarySoundBuffer(_directSound, primaryBufferDescription) { Format = waveFormat }; _soundBufferLength = waveFormat.ConvertLatencyToByteSize(500); var secondaryBufferDescription = new SoundBufferDescription() { Format = waveFormat, Flags = BufferFlags.GetCurrentPosition2 | BufferFlags.GlobalFocus, BufferBytes = _soundBufferLength, AlgorithmFor3D = Guid.Empty, }; _soundBuffer = new SecondarySoundBuffer(_directSound, secondaryBufferDescription); }
/// <summary> /// Initializes the audio renderer. /// Call the Play Method to start reading samples /// </summary> private void Initialize() { Destroy(); if (SoundTouch.IsAvailable) { AudioProcessor = new SoundTouch { Channels = (uint)WaveFormat.Channels, SampleRate = (uint)WaveFormat.SampleRate }; } AudioDevice = new WavePlayer(this) { DesiredLatency = 200, NumberOfBuffers = 2, }; BytesPerSample = WaveFormat.BitsPerSample / 8; SampleBlockSize = BytesPerSample * WaveFormat.Channels; var bufferLength = WaveFormat.ConvertLatencyToByteSize(AudioDevice.DesiredLatency) * MediaCore.Blocks[MediaType.Audio].Capacity / 2; AudioBuffer = new CircularBuffer(bufferLength); AudioDevice.Init(this); AudioDevice.Play(); }
static void Main(string[] args) { DirectSound directSound = new DirectSound(); var form = new Form(); form.Text = "SharpDX - DirectSound Demo"; // Set Cooperative Level to PRIORITY (priority level can call the SetFormat and Compact methods) // directSound.SetCooperativeLevel(form.Handle, CooperativeLevel.Priority); // Create PrimarySoundBuffer var primaryBufferDesc = new SoundBufferDescription(); primaryBufferDesc.Flags = BufferFlags.PrimaryBuffer; primaryBufferDesc.AlgorithmFor3D = Guid.Empty; var primarySoundBuffer = new PrimarySoundBuffer(directSound, primaryBufferDesc); // Play the PrimarySound Buffer primarySoundBuffer.Play(0, PlayFlags.Looping); // Default WaveFormat Stereo 44100 16 bit WaveFormat waveFormat = new WaveFormat(); // Create SecondarySoundBuffer var secondaryBufferDesc = new SoundBufferDescription(); secondaryBufferDesc.BufferBytes = waveFormat.ConvertLatencyToByteSize(60000); secondaryBufferDesc.Format = waveFormat; secondaryBufferDesc.Flags = BufferFlags.GetCurrentPosition2 | BufferFlags.ControlPositionNotify | BufferFlags.GlobalFocus | BufferFlags.ControlVolume | BufferFlags.StickyFocus; secondaryBufferDesc.AlgorithmFor3D = Guid.Empty; var secondarySoundBuffer = new SecondarySoundBuffer(directSound, secondaryBufferDesc); // Get Capabilties from secondary sound buffer var capabilities = secondarySoundBuffer.Capabilities; // Lock the buffer DataStream dataPart2; var dataPart1 =secondarySoundBuffer.Lock(0, capabilities.BufferBytes, LockFlags.EntireBuffer, out dataPart2); // Fill the buffer with some sound int numberOfSamples = capabilities.BufferBytes/waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { double vibrato = Math.Cos(2 * Math.PI * 10.0 * i /waveFormat.SampleRate); short value = (short) (Math.Cos(2*Math.PI*(220.0 + 4.0 * vibrato)*i/waveFormat.SampleRate)*16384); // Not too loud dataPart1.Write(value); dataPart1.Write(value); } // Unlock the buffer secondarySoundBuffer.Unlock(dataPart1, dataPart2); // Play the song secondarySoundBuffer.Play(0, PlayFlags.Looping); Application.Run(form); }
static void Main(string[] args) { Console.WriteLine("1 - Direct sound"); Console.WriteLine("2 - Windows media player"); Console.WriteLine("Twój wybór:"); string wartosc = Console.ReadLine(); if (wartosc == "1") { Console.Write("Podaj nazwe pliku z pulpitu: "); string nazwa_pliku = Console.ReadLine(); var path = "C:\\Users\\lab\\Desktop\\" + nazwa_pliku; DirectSound directSound = new DirectSound(); var primaryBufferDesc = new SoundBufferDescription(); primaryBufferDesc.Flags = BufferFlags.PrimaryBuffer; var primarySoundBuffer = new PrimarySoundBuffer(directSound, primaryBufferDesc); primarySoundBuffer.Play(0, PlayFlags.Looping); WaveFormat waveFormat = new WaveFormat(); var secondaryBufferDesc = new SoundBufferDescription(); secondaryBufferDesc.BufferBytes = waveFormat.ConvertLatencyToByteSize(60000); secondaryBufferDesc.Format = waveFormat; secondaryBufferDesc.Flags = BufferFlags.GetCurrentPosition2 | BufferFlags.ControlPositionNotify | BufferFlags.GlobalFocus | BufferFlags.ControlVolume | BufferFlags.StickyFocus; secondaryBufferDesc.AlgorithmFor3D = Guid.Empty; var secondarySoundBuffer = new SecondarySoundBuffer(directSound, secondaryBufferDesc); var capabilities = secondarySoundBuffer.Capabilities; //Stream stream = File.Open(path, FileMode.Open); //byte[] arrayTest = ReadFully(stream); byte[] array = File.ReadAllBytes(path); DataStream dataPart2; var dataPart1 = secondarySoundBuffer.Lock(0, capabilities.BufferBytes, LockFlags.EntireBuffer, out dataPart2); dataPart1.Read(array, 0, array.Length); int numberOfSamples = capabilities.BufferBytes / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { double vibrato = Math.Cos(2 * Math.PI * 10.0 * i / waveFormat.SampleRate); short value = (short)(Math.Cos(2 * Math.PI * (220.0 + 4.0 * vibrato) * i / waveFormat.SampleRate) * 16384); // Not too loud dataPart1.Write(value); } secondarySoundBuffer.Unlock(dataPart1, dataPart2); secondarySoundBuffer.Play(0, PlayFlags.None); } else { Console.Write("Podaj nazwe pliku z pulpitu: "); string nazwa_pliku = Console.ReadLine(); player = new WindowsMediaPlayer(); player.URL = "C:\\Users\\lab\\Desktop\\" + nazwa_pliku; player.controls.play(); } }
public Sound(IntPtr handle) { test[1] = test[0] + 2; test[2] = test[1] + 2; test[3] = test[2] + 1; test[4] = test[3] + 2; test[5] = test[4] + 2; test[6] = test[5] + 2; DirectSound directSound = new DirectSound(); // Set Cooperative Level to PRIORITY (priority level can call the SetFormat and Compact methods) // directSound.SetCooperativeLevel(handle, CooperativeLevel.Priority); // Create PrimarySoundBuffer var primaryBufferDesc = new SoundBufferDescription(); primaryBufferDesc.Flags = BufferFlags.PrimaryBuffer; primaryBufferDesc.AlgorithmFor3D = Guid.Empty; var primarySoundBuffer = new PrimarySoundBuffer(directSound, primaryBufferDesc); // Play the PrimarySound Buffer primarySoundBuffer.Play(0, PlayFlags.Looping); // Default WaveFormat Stereo 44100 16 bit waveFormat = new WaveFormat(); // Create SecondarySoundBuffer var secondaryBufferDesc = new SoundBufferDescription(); secondaryBufferDesc.BufferBytes = waveFormat.ConvertLatencyToByteSize(10000); secondaryBufferDesc.Format = waveFormat; secondaryBufferDesc.Flags = BufferFlags.GetCurrentPosition2 | BufferFlags.ControlPositionNotify | BufferFlags.GlobalFocus | BufferFlags.ControlVolume | BufferFlags.StickyFocus; secondaryBufferDesc.AlgorithmFor3D = Guid.Empty; secondarySoundBuffer = new SecondarySoundBuffer(directSound, secondaryBufferDesc); // Get Capabilties from secondary sound buffer capabilities = secondarySoundBuffer.Capabilities; sounds = new short[capabilities.BufferBytes / waveFormat.BlockAlign]; // Play the song secondarySoundBuffer.Play(0, PlayFlags.Looping); for (int i = 0; i < sounds.Length; i++) { sounds[i] = 0; } }
public SourceVoiceEx(SourceVoice sourceVoice, Guid id, WaveFormat waveFormat, int operationId) { SourceVoice = sourceVoice; Id = id; WaveFormat = waveFormat; _bufferSize = WaveFormat.ConvertLatencyToByteSize(8); OperationId = operationId; PreviousWorkItem = new PlayWorkItem { Pan = Double.MinValue, Pitch = Double.MinValue, Volume = Double.MinValue }; }
/// <summary> /// Initializes the audio renderer. /// Call the Play Method to start reading samples /// </summary> private void Initialize() { Destroy(); AudioDevice = new WavePlayer() { DesiredLatency = 200, NumberOfBuffers = 2, }; var bufferLength = WaveFormat.ConvertLatencyToByteSize(AudioDevice.DesiredLatency) * MediaElement.Blocks[MediaType.Audio].Capacity / 2; AudioBuffer = new CircularBuffer(bufferLength); AudioDevice.Init(this); }
public PlayForm() { InitializeComponent(); // Initalize XAudio2 xaudio2 = new XAudio2(XAudio2Flags.None, ProcessorSpecifier.DefaultProcessor); masteringVoice = new MasteringVoice(xaudio2); var waveFormat = new WaveFormat(44100, 32, 2); sourceVoice = new SourceVoice(xaudio2, waveFormat); int bufferSize = waveFormat.ConvertLatencyToByteSize(60000); DataStream dataStream = new DataStream(bufferSize, true, true); // Prepare the initial sound to modulate int numberOfSamples = bufferSize / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { float value = (float)(Math.Cos(2 * Math.PI * 220.0 * i / waveFormat.SampleRate) * 0.5); dataStream.Write(value); dataStream.Write(value); } dataStream.Position = 0; audioBuffer = new AudioBuffer { Stream = dataStream, Flags = BufferFlags.EndOfStream, AudioBytes = bufferSize, LoopBegin = 0, LoopLength = numberOfSamples, LoopCount = AudioBuffer.LoopInfinite }; // Set the effect on the source ModulatorEffect = new ModulatorEffect(); modulatorDescriptor = new EffectDescriptor(ModulatorEffect); reverb = new Reverb(); effectDescriptor = new EffectDescriptor(reverb); //sourceVoice.SetEffectChain(modulatorDescriptor, effectDescriptor); sourceVoice.SetEffectChain(modulatorDescriptor); //sourceVoice.EnableEffect(0); this.Closed += new EventHandler(PlayForm_Closed); }
public AudioCapture() { try { directSoundCapture = new DirectSoundCapture(); } catch { throw new AudioCaptureException("Could not open recording device"); } //var directSoundCaps = directSoundCapture.Capabilities; // Default 44.1kHz 16-bit stereo PCM waveFormat = new WaveFormat(); // Set the buffer size. // Note that the buffer position will roll over to 0 when the buffer fills up, // so set the notification position's offset to one less than the buffer size. bufferSize = waveFormat.ConvertLatencyToByteSize(latency); numberOfSamples = bufferSize / waveFormat.BlockAlign; // Create audio capture buffer captureBufferDesc = new CaptureBufferDescription(); captureBufferDesc.Format = waveFormat; captureBufferDesc.BufferBytes = bufferSize; captureBuffer = new CaptureBuffer(directSoundCapture, captureBufferDesc); // Wait events allow the thread to wait asynchronously for the buffer to fill var evt = new AutoResetEvent(false); fullEvent = new WaitHandle[] { evt }; // Notify the thread when the buffer is full var nf = new NotificationPosition(); nf.Offset = bufferSize - 1; nf.WaitHandle = fullEvent[0]; var nfs = new NotificationPosition[] { nf }; captureBuffer.SetNotificationPositions(nfs); // Start the processing thread thread = new Thread(new ThreadStart(Process)); thread.IsBackground = true; // Allow application to exit thread.Start(); }
/// <summary> /// SharpDX XAudio2 sample. Plays a generated sound with some reverb. /// </summary> static void Main(string[] args) { var xaudio2 = new XAudio2(); var masteringVoice = new MasteringVoice(xaudio2); var waveFormat = new WaveFormat(44100, 32, 2); var sourceVoice = new SourceVoice(xaudio2, waveFormat); int bufferSize = waveFormat.ConvertLatencyToByteSize(60000); var dataStream = new DataStream(bufferSize, true, true); int numberOfSamples = bufferSize / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { // cos(2 * PI * (220 + 4 * cos(2 * PI * 10 * t)) * t) * 0.5 double vibrato = Math.Cos(2 * Math.PI * 10.0 * i / waveFormat.SampleRate); float value = (float)(Math.Cos(2 * Math.PI * (220.0 + 4.0 * vibrato) * i / waveFormat.SampleRate) * 0.5); dataStream.Write(value); dataStream.Write(value); } dataStream.Position = 0; var audioBuffer = new AudioBuffer { Stream = dataStream, Flags = BufferFlags.EndOfStream, AudioBytes = bufferSize }; var reverb = new Reverb(xaudio2); var effectDescriptor = new EffectDescriptor(reverb); sourceVoice.SetEffectChain(effectDescriptor); sourceVoice.EnableEffect(0); sourceVoice.SubmitSourceBuffer(audioBuffer, null); sourceVoice.Start(); Console.WriteLine("Play sound"); for (int i = 0; i < 60; i++) { Console.Write("."); Console.Out.Flush(); Thread.Sleep(1000); } }
public SineGenerator() { _xaudio2 = new XAudio2(); _masteringVoice = new MasteringVoice(_xaudio2); _waveFormat = new WaveFormat(44100, 32, 2); _sourceVoice = new SourceVoice(_xaudio2, _waveFormat); _bufferSize = _waveFormat.ConvertLatencyToByteSize(7); _dataStream = new DataStream(_bufferSize, true, true); _sourceVoice.BufferEnd += sourceVoice_BufferEnd; _sourceVoice.Start(); _isConvolutionOn = false; _horizontalAngle = 0; _elevation = 0; _bufferEndEvent = new AutoResetEvent(false); _valueRate = 20; _valueAmp = 0.5f; _nextBuffer = 0; _playEvent = new ManualResetEventSlim(); _log = new List <string>(); // Pre-allocate buffers _audioBuffersRing = new AudioBuffer[3]; _memBuffers = new DataPointer[_audioBuffersRing.Length]; for (int i = 0; i < _audioBuffersRing.Length; i++) { _audioBuffersRing[i] = new AudioBuffer(); _memBuffers[i].Size = _bufferSize; _memBuffers[i].Pointer = Utilities.AllocateMemory(_memBuffers[i].Size); } _playSoundTask = Task.Factory.StartNew(PlaySoundAsync, TaskCreationOptions.LongRunning); }
public BeatDetector(WaveFormat waveFormat, int historyLength, int bufferSize) { //this.bufferSize = bufferSize; this.historyLength = historyLength; // Number of history buffers needed to be equivalent to historyLength (milliseconds) historySize = waveFormat.ConvertLatencyToByteSize(historyLength) / bufferSize; beatsSize = historySize; history = new float[historySize]; historyIndex = 0; beats = new float[beatsSize]; beatIndex = 0; fft = new FastFourierTransform(beatsSize, 1); InstantaneousEnergy = 0.0f; AverageEnergy = 0.0f; }
/// <summary> /// Initializes a new instance of the <see cref="AudioPlayer" /> class. /// </summary> /// <param name="xaudio2">The xaudio2 engine.</param> /// <param name="audioStream">The input audio stream.</param> public AudioPlayer(XAudio2 xaudio2, Stream audioStream) { _xaudio2 = xaudio2; var audioDecoder = new AudioDecoder(audioStream); audioStream.Seek(0, SeekOrigin.Begin); _indDataStream = ConverStreamToIeeeFloat(new SoundStream(audioStream).ToDataStream()); _waveFormat = new WaveFormat(audioDecoder.WaveFormat.SampleRate, 32, audioDecoder.WaveFormat.Channels); audioDecoder.Dispose(); _sourceVoice = new SourceVoice(xaudio2, _waveFormat); _bufferSize = _waveFormat.ConvertLatencyToByteSize(7); _isConvolutionOn = false; _horizontalAngle = 0f; _elevation = 0f; _sourceVoice.BufferEnd += sourceVoice_BufferEnd; _sourceVoice.Start(); _bufferEndEvent = new AutoResetEvent(false); _playEvent = new ManualResetEvent(false); _convolution = new Convolution(); // Pre-allocate buffers _audioBuffersRing = new AudioBuffer[3]; _memBuffers = new DataPointer[_audioBuffersRing.Length]; for (int i = 0; i < _audioBuffersRing.Length; i++) { _audioBuffersRing[i] = new AudioBuffer(); _memBuffers[i].Size = 32 * 1024; // default size 32Kb _memBuffers[i].Pointer = Utilities.AllocateMemory(_memBuffers[i].Size); } // Initialize to stopped State = PlayerState.Stopped; // Starts the playing thread _playingTask = Task.Factory.StartNew(PlayAsync, TaskCreationOptions.LongRunning); }
/// <summary> /// Initializes the audio renderer. /// Call the Play Method to start reading samples /// </summary> private void Initialize() { Destroy(); if (SoundTouch.IsAvailable) { AudioProcessor = new SoundTouch { Channels = Convert.ToUInt32(WaveFormat.Channels), SampleRate = Convert.ToUInt32(WaveFormat.SampleRate) }; } AudioDevice = MediaElement.RendererOptions.UseLegacyAudioOut ? new LegacyAudioPlayer(this, MediaElement.RendererOptions.LegacyAudioDevice?.DeviceId ?? -1) as IWavePlayer : new DirectSoundPlayer(this, MediaElement.RendererOptions.DirectSoundDevice?.DeviceId ?? DirectSoundPlayer.DefaultPlaybackDeviceId); SampleBlockSize = Constants.Audio.BytesPerSample * Constants.Audio.ChannelCount; var bufferLength = WaveFormat.ConvertLatencyToByteSize(AudioDevice.DesiredLatency) * MediaCore.Blocks[MediaType.Audio].Capacity / 2; AudioBuffer = new CircularBuffer(bufferLength); AudioDevice.Start(); }
public void Generate() { var xaudio2 = new XAudio2(); var masteringVoice = new MasteringVoice(xaudio2); var waveFormat = new WaveFormat(44100, 32, 2); var sourceVoice = new SourceVoice(xaudio2, waveFormat); int bufferSize = waveFormat.ConvertLatencyToByteSize(60000); var dataStream = new DataStream(bufferSize, true, true); int numberOfSamples = bufferSize / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { float value = (float)(Math.Cos(2 * Math.PI * (220.0 + 4.0) * i / waveFormat.SampleRate) * 0.5); dataStream.Write(value); dataStream.Write(value); } dataStream.Position = 0; var audioBuffer = new AudioBuffer { Stream = dataStream, Flags = BufferFlags.EndOfStream, AudioBytes = bufferSize }; sourceVoice.SubmitSourceBuffer(audioBuffer, null); sourceVoice.Start(); Console.WriteLine("Play sound"); for (int i = 0; i < 60; i++) { Console.Write("."); Console.Out.Flush(); Thread.Sleep(1000); } }
/// <summary> /// SharpDX X3DAudio sample. Plays a generated sound rotating around the listener. /// </summary> static void Main(string[] args) { var xaudio2 = new XAudio2(); using (var masteringVoice = new MasteringVoice(xaudio2)) { // Instantiate X3DAudio var x3dAudio = new X3DAudio(Speakers.Stereo); var emitter = new Emitter { ChannelCount = 1, CurveDistanceScaler = float.MinValue, OrientFront = new Vector3(0, 0, 1), OrientTop = new Vector3(0, 1, 0), Position = new Vector3(0, 0, 0), Velocity = new Vector3(0, 0, 0) }; var listener = new Listener { OrientFront = new Vector3(0, 0, 1), OrientTop = new Vector3(0, 1, 0), Position = new Vector3(0, 0, 0), Velocity = new Vector3(0, 0, 0) }; var waveFormat = new WaveFormat(44100, 32, 1); var sourceVoice = new SourceVoice(xaudio2, waveFormat); int bufferSize = waveFormat.ConvertLatencyToByteSize(60000); var dataStream = new DataStream(bufferSize, true, true); int numberOfSamples = bufferSize / waveFormat.BlockAlign; for (int i = 0; i < numberOfSamples; i++) { float value = (float)(Math.Cos(2 * Math.PI * 220.0 * i / waveFormat.SampleRate) * 0.5); dataStream.Write(value); } dataStream.Position = 0; var audioBuffer = new AudioBuffer { Stream = dataStream, Flags = BufferFlags.EndOfStream, AudioBytes = bufferSize }; //var reverb = new Reverb(); //var effectDescriptor = new EffectDescriptor(reverb); //sourceVoice.SetEffectChain(effectDescriptor); //sourceVoice.EnableEffect(0); sourceVoice.SubmitSourceBuffer(audioBuffer, null); sourceVoice.Start(); Console.WriteLine("Play a sound rotating around the listener"); for (int i = 0; i < 1200; i++) { // Rotates the emitter var rotateEmitter = Matrix.RotationY(i / 5.0f); var newPosition = Vector3.Transform(new Vector3(0, 0, 1000), rotateEmitter); var newPositionVector3 = new Vector3(newPosition.X, newPosition.Y, newPosition.Z); emitter.Velocity = (newPositionVector3 - emitter.Position) / 0.05f; emitter.Position = newPositionVector3; // Calculate X3DAudio settings var dspSettings = x3dAudio.Calculate(listener, emitter, CalculateFlags.Matrix | CalculateFlags.Doppler, 1, 2); // Modify XAudio2 source voice settings sourceVoice.SetOutputMatrix(1, 2, dspSettings.MatrixCoefficients); sourceVoice.SetFrequencyRatio(dspSettings.DopplerFactor); // Wait for 50ms Thread.Sleep(50); } } }
static void Main() { var initError = EVRInitError.None; system = OpenVR.Init(ref initError); if (initError != EVRInitError.None) { return; } compositor = OpenVR.Compositor; compositor.CompositorBringToFront(); compositor.FadeGrid(5.0f, false); count = OpenVR.k_unMaxTrackedDeviceCount; currentPoses = new TrackedDevicePose_t[count]; nextPoses = new TrackedDevicePose_t[count]; controllers = new List <uint>(); controllerModels = new RenderModel_t[count]; controllerTextures = new RenderModel_TextureMap_t[count]; controllerTextureViews = new ShaderResourceView[count]; controllerVertexBuffers = new SharpDX.Direct3D11.Buffer[count]; controllerIndexBuffers = new SharpDX.Direct3D11.Buffer[count]; controllerVertexBufferBindings = new VertexBufferBinding[count]; controllerEmitters = new Emitter[count]; controllerVoices = new SourceVoice[count]; for (uint device = 0; device < count; device++) { var deviceClass = system.GetTrackedDeviceClass(device); switch (deviceClass) { case ETrackedDeviceClass.HMD: headset = device; break; case ETrackedDeviceClass.Controller: controllers.Add(device); break; } } uint width = 0; uint height = 0; system.GetRecommendedRenderTargetSize(ref width, ref height); headsetSize = new Size((int)width, (int)height); windowSize = new Size(960, 540); var leftEyeProjection = Convert(system.GetProjectionMatrix(EVREye.Eye_Left, 0.01f, 1000.0f)); var rightEyeProjection = Convert(system.GetProjectionMatrix(EVREye.Eye_Right, 0.01f, 1000.0f)); var leftEyeView = Convert(system.GetEyeToHeadTransform(EVREye.Eye_Left)); var rightEyeView = Convert(system.GetEyeToHeadTransform(EVREye.Eye_Right)); foreach (var controller in controllers) { var modelName = new StringBuilder(255, 255); var propertyError = ETrackedPropertyError.TrackedProp_Success; var length = system.GetStringTrackedDeviceProperty(controller, ETrackedDeviceProperty.Prop_RenderModelName_String, modelName, 255, ref propertyError); if (propertyError == ETrackedPropertyError.TrackedProp_Success) { var modelName2 = modelName.ToString(); while (true) { var pointer = IntPtr.Zero; var modelError = EVRRenderModelError.None; modelError = OpenVR.RenderModels.LoadRenderModel_Async(modelName2, ref pointer); if (modelError == EVRRenderModelError.Loading) { continue; } if (modelError == EVRRenderModelError.None) { var renderModel = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_t>(pointer); controllerModels[controller] = renderModel; break; } } while (true) { var pointer = IntPtr.Zero; var textureError = EVRRenderModelError.None; textureError = OpenVR.RenderModels.LoadTexture_Async(controllerModels[controller].diffuseTextureId, ref pointer); if (textureError == EVRRenderModelError.Loading) { continue; } if (textureError == EVRRenderModelError.None) { var texture = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_TextureMap_t>(pointer); controllerTextures[controller] = texture; break; } } } } int adapterIndex = 0; system.GetDXGIOutputInfo(ref adapterIndex); using (var form = new Form()) using (var factory = new Factory4()) { form.ClientSize = windowSize; var adapter = factory.GetAdapter(adapterIndex); var swapChainDescription = new SwapChainDescription { BufferCount = 1, Flags = SwapChainFlags.None, IsWindowed = true, ModeDescription = new ModeDescription { Format = Format.B8G8R8A8_UNorm, Width = form.ClientSize.Width, Height = form.ClientSize.Height, RefreshRate = new Rational(60, 1) }, OutputHandle = form.Handle, SampleDescription = new SampleDescription(1, 0), SwapEffect = SwapEffect.Discard, Usage = Usage.RenderTargetOutput }; SharpDX.Direct3D11.Device.CreateWithSwapChain(adapter, DeviceCreationFlags.None, swapChainDescription, out device, out swapChain); factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.None); context = device.ImmediateContext; using (var backBuffer = swapChain.GetBackBuffer <Texture2D>(0)) backBufferView = new RenderTargetView(device, backBuffer); var depthBufferDescription = new Texture2DDescription { Format = Format.D16_UNorm, ArraySize = 1, MipLevels = 1, Width = form.ClientSize.Width, Height = form.ClientSize.Height, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default, BindFlags = BindFlags.DepthStencil, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.None }; using (var depthBuffer = new Texture2D(device, depthBufferDescription)) depthStencilView = new DepthStencilView(device, depthBuffer); // Create Eye Textures var eyeTextureDescription = new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.RenderTarget, CpuAccessFlags = CpuAccessFlags.None, Format = Format.B8G8R8A8_UNorm, Width = headsetSize.Width, Height = headsetSize.Height, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default }; var leftEyeTexture = new Texture2D(device, eyeTextureDescription); var rightEyeTexture = new Texture2D(device, eyeTextureDescription); var leftEyeTextureView = new RenderTargetView(device, leftEyeTexture); var rightEyeTextureView = new RenderTargetView(device, rightEyeTexture); // Create Eye Depth Buffer eyeTextureDescription.BindFlags = BindFlags.DepthStencil; eyeTextureDescription.Format = Format.D32_Float; var eyeDepth = new Texture2D(device, eyeTextureDescription); var eyeDepthView = new DepthStencilView(device, eyeDepth); Shapes.Cube.Load(device); Shapes.Sphere.Load(device); Shaders.Load(device); // Load Controller Models foreach (var controller in controllers) { var model = controllerModels[controller]; controllerVertexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rVertexData, new BufferDescription { BindFlags = BindFlags.VertexBuffer, SizeInBytes = (int)model.unVertexCount * 32 }); controllerVertexBufferBindings[controller] = new VertexBufferBinding(controllerVertexBuffers[controller], 32, 0); controllerIndexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rIndexData, new BufferDescription { BindFlags = BindFlags.IndexBuffer, SizeInBytes = (int)model.unTriangleCount * 3 * 2 }); var texture = controllerTextures[controller]; using (var texture2d = new Texture2D(device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.ShaderResource, Format = Format.R8G8B8A8_UNorm, Width = texture.unWidth, Height = texture.unHeight, MipLevels = 1, SampleDescription = new SampleDescription(1, 0) }, new DataRectangle(texture.rubTextureMapData, texture.unWidth * 4))) controllerTextureViews[controller] = new ShaderResourceView(device, texture2d); } var controllerVertexShaderByteCode = SharpDX.D3DCompiler.ShaderBytecode.Compile(Properties.Resources.NormalTextureShader, "VS", "vs_5_0"); controllerVertexShader = new VertexShader(device, controllerVertexShaderByteCode); controllerPixelShader = new PixelShader(device, SharpDX.D3DCompiler.ShaderBytecode.Compile(Properties.Resources.NormalTextureShader, "PS", "ps_5_0")); var controllerLayout = new InputLayout(device, SharpDX.D3DCompiler.ShaderSignature.GetInputSignature(controllerVertexShaderByteCode), new InputElement[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0), new InputElement("NORMAL", 0, Format.R32G32B32_Float, 12, 0), new InputElement("TEXCOORD", 0, Format.R32G32_Float, 24, 0) }); worldViewProjectionBuffer = new SharpDX.Direct3D11.Buffer(device, Utilities.SizeOf <Matrix>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); var rasterizerStateDescription = RasterizerStateDescription.Default(); //rasterizerStateDescription.FillMode = FillMode.Wireframe; rasterizerStateDescription.IsFrontCounterClockwise = true; //rasterizerStateDescription.CullMode = CullMode.None; rasterizerState = new RasterizerState(device, rasterizerStateDescription); var blendStateDescription = BlendStateDescription.Default(); blendStateDescription.RenderTarget[0].BlendOperation = BlendOperation.Add; blendStateDescription.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha; blendStateDescription.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha; blendStateDescription.RenderTarget[0].IsBlendEnabled = false; blendState = new BlendState(device, blendStateDescription); var depthStateDescription = DepthStencilStateDescription.Default(); depthStateDescription.DepthComparison = Comparison.LessEqual; depthStateDescription.IsDepthEnabled = true; depthStateDescription.IsStencilEnabled = false; depthStencilState = new DepthStencilState(device, depthStateDescription); var samplerStateDescription = SamplerStateDescription.Default(); samplerStateDescription.Filter = Filter.MinMagMipLinear; samplerStateDescription.AddressU = TextureAddressMode.Wrap; samplerStateDescription.AddressV = TextureAddressMode.Wrap; samplerState = new SamplerState(device, samplerStateDescription); startTime = DateTime.Now; frame = 0; windowSize = form.ClientSize; backgroundColor = new RawColor4(0.1f, 0.1f, 0.1f, 1); var vrEvent = new VREvent_t(); var eventSize = (uint)Utilities.SizeOf <VREvent_t>(); head = Matrix.Identity; // Initialize Audio audio = new XAudio2(); var voice = new MasteringVoice(audio); audio3d = new X3DAudio(Speakers.Stereo); foreach (var controller in controllers) { controllerEmitters[controller] = new Emitter { ChannelCount = 1, CurveDistanceScaler = 0.15f, OrientFront = Vector3.ForwardLH, OrientTop = Vector3.Up, Position = new Vector3(0, 0, 1000), //Velocity = Vector3.Zero }; } listener = new Listener { OrientFront = Vector3.ForwardLH, OrientTop = Vector3.Up, Position = new Vector3(0, 0, 1000) }; var audioFormat = new WaveFormat(44100, 32, 1); //var audioSource = new SourceVoice(audio, audioFormat); var audioBufferSize = audioFormat.ConvertLatencyToByteSize(1000); var audioStream = new DataStream(audioBufferSize, true, true); var audioSamples = audioBufferSize / audioFormat.BlockAlign; var random = new Random(); for (var sample = 0; sample < audioSamples; sample++) { audioStream.Write((float)random.NextFloat(-1, 1)); } audioStream.Position = 0; var audioBuffer = new AudioBuffer { Stream = audioStream, AudioBytes = audioBufferSize, LoopCount = 255 }; var audioSettings = new DspSettings(1, 2); foreach (var controller in controllers) { var audioSource = new SourceVoice(audio, audioFormat); audioSource.SubmitSourceBuffer(audioBuffer, null); audio3d.Calculate(listener, controllerEmitters[controller], CalculateFlags.Matrix, audioSettings); audioSource.SetOutputMatrix(1, 2, audioSettings.MatrixCoefficients); audioSource.Start(); controllerVoices[controller] = audioSource; } RenderLoop.Run(form, () => { while (system.PollNextEvent(ref vrEvent, eventSize)) { switch ((EVREventType)vrEvent.eventType) { case EVREventType.VREvent_TrackedDeviceActivated: var controller = vrEvent.trackedDeviceIndex; controllers.Add(controller); var modelName = new StringBuilder(255, 255); var propertyError = ETrackedPropertyError.TrackedProp_Success; var length = system.GetStringTrackedDeviceProperty(controller, ETrackedDeviceProperty.Prop_RenderModelName_String, modelName, 255, ref propertyError); if (propertyError == ETrackedPropertyError.TrackedProp_Success) { var modelName2 = modelName.ToString(); while (true) { var pointer = IntPtr.Zero; var modelError = EVRRenderModelError.None; modelError = OpenVR.RenderModels.LoadRenderModel_Async(modelName2, ref pointer); if (modelError == EVRRenderModelError.Loading) { continue; } if (modelError == EVRRenderModelError.None) { var renderModel = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_t>(pointer); controllerModels[controller] = renderModel; // Load Controller Model var model = controllerModels[controller]; controllerVertexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rVertexData, new BufferDescription { BindFlags = BindFlags.VertexBuffer, SizeInBytes = (int)model.unVertexCount * 32 }); controllerVertexBufferBindings[controller] = new VertexBufferBinding(controllerVertexBuffers[controller], 32, 0); controllerIndexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rIndexData, new BufferDescription { BindFlags = BindFlags.IndexBuffer, SizeInBytes = (int)model.unTriangleCount * 3 * 2 }); break; } } while (true) { var pointer = IntPtr.Zero; var textureError = EVRRenderModelError.None; textureError = OpenVR.RenderModels.LoadTexture_Async(controllerModels[controller].diffuseTextureId, ref pointer); if (textureError == EVRRenderModelError.Loading) { continue; } if (textureError == EVRRenderModelError.None) { var textureMap = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_TextureMap_t>(pointer); controllerTextures[controller] = textureMap; using (var texture2d = new Texture2D(device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.ShaderResource, Format = Format.R8G8B8A8_UNorm, Width = textureMap.unWidth, Height = textureMap.unHeight, MipLevels = 1, SampleDescription = new SampleDescription(1, 0) }, new DataRectangle(textureMap.rubTextureMapData, textureMap.unWidth * 4))) controllerTextureViews[controller] = new ShaderResourceView(device, texture2d); break; } } controllerEmitters[controller] = new Emitter { ChannelCount = 1, CurveDistanceScaler = 0.15f, OrientFront = Vector3.ForwardLH, OrientTop = Vector3.Up, Position = new Vector3(0, 0, 1000), //Velocity = Vector3.Zero }; var audioSource = new SourceVoice(audio, audioFormat); audioSource.SubmitSourceBuffer(audioBuffer, null); audio3d.Calculate(listener, controllerEmitters[controller], CalculateFlags.Matrix, audioSettings); audioSource.SetOutputMatrix(1, 2, audioSettings.MatrixCoefficients); audioSource.Start(); controllerVoices[controller] = audioSource; } break; case EVREventType.VREvent_TrackedDeviceDeactivated: controllers.RemoveAll(c => c == vrEvent.trackedDeviceIndex); break; default: System.Diagnostics.Debug.WriteLine((EVREventType)vrEvent.eventType); break; } } if (form.ClientSize != windowSize) { Utilities.Dispose(ref backBufferView); if (form.ClientSize.Width != 0 && form.ClientSize.Height != 0) { swapChain.ResizeBuffers(1, form.ClientSize.Width, form.ClientSize.Height, Format.B8G8R8A8_UNorm, SwapChainFlags.None); using (var backBuffer = swapChain.GetBackBuffer <Texture2D>(0)) backBufferView = new RenderTargetView(device, backBuffer); } windowSize = form.ClientSize; } // Update Device Tracking compositor.WaitGetPoses(currentPoses, nextPoses); if (currentPoses[headset].bPoseIsValid) { Convert(ref currentPoses[headset].mDeviceToAbsoluteTracking, ref head); // Update Audio Listener listener.Position = head.TranslationVector * new Vector3(1, 1, -1); listener.OrientFront = head.Forward * new Vector3(1, 1, -1); listener.OrientTop = head.Up * new Vector3(1, 1, -1); } foreach (var controller in controllers) { var controllerMatrix = Matrix.Identity; Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref controllerMatrix); var position = controllerMatrix.TranslationVector * new Vector3(1, 1, -1); controllerEmitters[controller].Position = position; audio3d.Calculate(listener, controllerEmitters[controller], CalculateFlags.Matrix, audioSettings); controllerVoices[controller].SetOutputMatrix(1, 2, audioSettings.MatrixCoefficients); } // Render Left Eye context.Rasterizer.SetViewport(0, 0, headsetSize.Width, headsetSize.Height); context.OutputMerger.SetTargets(eyeDepthView, leftEyeTextureView); context.OutputMerger.SetDepthStencilState(depthStencilState); context.ClearRenderTargetView(leftEyeTextureView, backgroundColor); context.ClearDepthStencilView(eyeDepthView, DepthStencilClearFlags.Depth, 1.0f, 0); Shaders.Apply(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); var ratio = (float)headsetSize.Width / (float)headsetSize.Height; var projection = leftEyeProjection; var view = Matrix.Invert(leftEyeView * head); var world = Matrix.Scaling(0.5f) * Matrix.Translation(0, 1.0f, 0); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); //Shapes.Cube.Begin(context); //Shapes.Cube.Draw(context); Shapes.Sphere.Begin(context); Shapes.Sphere.Draw(context); // Draw Controllers context.InputAssembler.InputLayout = controllerLayout; context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; context.VertexShader.Set(controllerVertexShader); context.PixelShader.Set(controllerPixelShader); context.GeometryShader.Set(null); context.DomainShader.Set(null); context.HullShader.Set(null); context.PixelShader.SetSampler(0, samplerState); foreach (var controller in controllers) { context.InputAssembler.SetVertexBuffers(0, controllerVertexBufferBindings[controller]); context.InputAssembler.SetIndexBuffer(controllerIndexBuffers[controller], Format.R16_UInt, 0); context.PixelShader.SetShaderResource(0, controllerTextureViews[controller]); Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref world); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); context.DrawIndexed((int)controllerModels[controller].unTriangleCount * 3 * 4, 0, 0); } var texture = new Texture_t { eType = ETextureType.DirectX, eColorSpace = EColorSpace.Gamma, handle = leftEyeTextureView.Resource.NativePointer }; var bounds = new VRTextureBounds_t { uMin = 0.0f, uMax = 1.0f, vMin = 0.0f, vMax = 1.0f, }; var submitError = compositor.Submit(EVREye.Eye_Left, ref texture, ref bounds, EVRSubmitFlags.Submit_Default); if (submitError != EVRCompositorError.None) { System.Diagnostics.Debug.WriteLine(submitError); } // Render Right Eye context.Rasterizer.SetViewport(0, 0, headsetSize.Width, headsetSize.Height); context.OutputMerger.SetTargets(eyeDepthView, rightEyeTextureView); context.OutputMerger.SetDepthStencilState(depthStencilState); context.ClearRenderTargetView(rightEyeTextureView, backgroundColor); context.ClearDepthStencilView(eyeDepthView, DepthStencilClearFlags.Depth, 1.0f, 0); Shaders.Apply(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); projection = rightEyeProjection; view = Matrix.Invert(rightEyeView * head); world = Matrix.Scaling(0.5f) * Matrix.Translation(0, 1.0f, 0); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); //Shapes.Cube.Begin(context); //Shapes.Cube.Draw(context); Shapes.Sphere.Begin(context); Shapes.Sphere.Draw(context); // Draw Controllers context.InputAssembler.InputLayout = controllerLayout; context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; context.VertexShader.Set(controllerVertexShader); context.PixelShader.Set(controllerPixelShader); context.GeometryShader.Set(null); context.DomainShader.Set(null); context.HullShader.Set(null); context.PixelShader.SetSampler(0, samplerState); foreach (var controller in controllers) { context.InputAssembler.SetVertexBuffers(0, controllerVertexBufferBindings[controller]); context.InputAssembler.SetIndexBuffer(controllerIndexBuffers[controller], Format.R16_UInt, 0); context.PixelShader.SetShaderResource(0, controllerTextureViews[controller]); Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref world); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); context.DrawIndexed((int)controllerModels[controller].unTriangleCount * 3 * 4, 0, 0); } texture.handle = rightEyeTextureView.Resource.NativePointer; submitError = compositor.Submit(EVREye.Eye_Right, ref texture, ref bounds, EVRSubmitFlags.Submit_Default); if (submitError != EVRCompositorError.None) { System.Diagnostics.Debug.WriteLine(submitError); } // Render Window context.Rasterizer.SetViewport(0, 0, windowSize.Width, windowSize.Height); context.OutputMerger.SetTargets(depthStencilView, backBufferView); context.OutputMerger.SetDepthStencilState(depthStencilState); context.ClearRenderTargetView(backBufferView, backgroundColor); context.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0); Shaders.Apply(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); ratio = (float)form.ClientSize.Width / (float)form.ClientSize.Height; projection = Matrix.PerspectiveFovRH(3.14F / 3.0F, ratio, 0.01f, 1000); view = Matrix.Invert(head); world = Matrix.Scaling(0.5f) * Matrix.Translation(0, 1.0f, 0); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); //Shapes.Cube.Begin(context); //Shapes.Cube.Draw(context); Shapes.Sphere.Begin(context); Shapes.Sphere.Draw(context); // Draw Controllers context.InputAssembler.InputLayout = controllerLayout; context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; context.VertexShader.Set(controllerVertexShader); context.PixelShader.Set(controllerPixelShader); context.GeometryShader.Set(null); context.DomainShader.Set(null); context.HullShader.Set(null); context.PixelShader.SetSampler(0, samplerState); foreach (var controller in controllers) { context.InputAssembler.SetVertexBuffers(0, controllerVertexBufferBindings[controller]); context.InputAssembler.SetIndexBuffer(controllerIndexBuffers[controller], Format.R16_UInt, 0); Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref world); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); context.DrawIndexed((int)controllerModels[controller].unTriangleCount * 3 * 4, 0, 0); } // Show Backbuffer swapChain.Present(0, PresentFlags.None); }); audio.Dispose(); } }
private bool Synchronize(byte[] targetBuffer, int targetBufferOffset, int requestedBytes, double speedRatio) { /* * Wikipedia says: * For television applications, audio should lead video by no more than 15 milliseconds and audio should * lag video by no more than 45 milliseconds. For film, acceptable lip sync is considered to be no more * than 22 milliseconds in either direction. * * The Media and Acoustics Perception Lab says: * The results of the experiment determined that the average audio leading threshold for a/v sync * detection was 185.19 ms, with a standard deviation of 42.32 ms * * The ATSC says: * At first glance it seems loose: +90 ms to -185 ms as a Window of Acceptability * - Undetectable from -100 ms to +25 ms * - Detectable at -125 ms & +45 ms * - Becomes unacceptable at -185 ms & +90 ms * * NOTE: (- Sound delayed, + Sound advanced) */ var audioLatencyMs = Latency.TotalMilliseconds; var isBeyondThreshold = false; var readableCount = AudioBuffer.ReadableCount; var rewindableCount = AudioBuffer.RewindableCount; if (audioLatencyMs > SyncThresholdLagging) { isBeyondThreshold = true; // a positive audio latency means we are rendering audio behind (after) the clock (skip some samples) // and therefore we need to advance the buffer before we read from it. if (speedRatio == 1.0) { MediaCore.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: LATENCY: {Latency.Format()} | SKIP (samples being rendered too late)"); } // skip some samples from the buffer. var audioLatencyBytes = WaveFormat.ConvertLatencyToByteSize(Convert.ToInt32(Math.Ceiling(audioLatencyMs))); AudioBuffer.Skip(Math.Min(audioLatencyBytes, readableCount)); } else if (audioLatencyMs < SyncThresholdLeading) { isBeyondThreshold = true; // Compute the latency in bytes var audioLatencyBytes = WaveFormat.ConvertLatencyToByteSize(Convert.ToInt32(Math.Ceiling(Math.Abs(audioLatencyMs)))); // audioLatencyBytes = requestedBytes; // uncomment this line to enable rewinding. if (audioLatencyBytes > requestedBytes && audioLatencyBytes < rewindableCount) { // This means we have the audio pointer a little too ahead of time and we need to // rewind it the requested amount of bytes. AudioBuffer.Rewind(Math.Min(audioLatencyBytes, rewindableCount)); } else { // a negative audio latency means we are rendering audio ahead (before) the clock // and therefore we need to render some silence until the clock catches up if (speedRatio == 1.0) { MediaCore.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: LATENCY: {Latency.Format()} | WAIT (samples being rendered too early)"); } // render silence for the wait time and return Array.Clear(targetBuffer, targetBufferOffset, requestedBytes); return(false); } } // Perform minor adjustments until the delay is less than 10ms in either direction if (MediaCore.State.HasVideo && speedRatio == 1.0 && isBeyondThreshold == false && Math.Abs(audioLatencyMs) > SyncThresholdPerfect) { var stepDurationMillis = Convert.ToInt32(Math.Min(SyncThresholdMaxStep, Math.Abs(audioLatencyMs))); var stepDurationBytes = WaveFormat.ConvertLatencyToByteSize(stepDurationMillis); if (audioLatencyMs > SyncThresholdPerfect) { AudioBuffer.Skip(Math.Min(stepDurationBytes, readableCount)); } else if (audioLatencyMs < -SyncThresholdPerfect) { AudioBuffer.Rewind(Math.Min(stepDurationBytes, rewindableCount)); } } return(true); }
private bool Synchronize(byte[] targetBuffer, int targetBufferOffset, int requestedBytes, double speedRatio) { #region Documentation /* * Wikipedia says: * For television applications, audio should lead video by no more than 15 milliseconds and audio should * lag video by no more than 45 milliseconds. For film, acceptable lip sync is considered to be no more * than 22 milliseconds in either direction. * * The Media and Acoustics Perception Lab says: * The results of the experiment determined that the average audio leading threshold for a/v sync * detection was 185.19 ms, with a standard deviation of 42.32 ms * * The ATSC says: * At first glance it seems loose: +90 ms to -185 ms as a Window of Acceptability * - Undetectable from -100 ms to +25 ms * - Detectable at -125 ms & +45 ms * - Becomes unacceptable at -185 ms & +90 ms * * NOTE: (- Sound delayed, + Sound advanced) */ #endregion #region Private State var audioLatencyMs = Latency.TotalMilliseconds; var isBeyondThreshold = false; var readableCount = AudioBuffer.ReadableCount; var rewindableCount = AudioBuffer.RewindableCount; #endregion #region Sync Give-up Conditions if (MediaElement.RendererOptions.AudioDisableSync) { return(true); } // Determine if we should continue to perform syncs. // Some live, non-seekable streams will send out-of-sync audio packets // and after trying too many times we simply give up. // The Sync conditions are reset in the Update method. if ((MediaCore?.State?.IsSeekable ?? true) == false && PlaySyncGaveUp.Value == false) { // 1. Determine if a sync is required if (audioLatencyMs > SyncThresholdLagging || audioLatencyMs < SyncThresholdLeading || Math.Abs(audioLatencyMs) > SyncThresholdPerfect) { PlaySyncCount++; } // 2. Compute the variables to determine give-up conditions var playbackElapsedSeconds = PlaySyncStartTime.HasValue == false ? 0 : DateTime.UtcNow.Subtract(PlaySyncStartTime.Value).TotalSeconds; var syncsPerSecond = PlaySyncCount / playbackElapsedSeconds; // 3. Determine if we need to give up if (playbackElapsedSeconds >= 3 && syncsPerSecond >= 3) { MediaCore.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: GIVE UP | SECS: {playbackElapsedSeconds:0.00}; SYN: {PlaySyncCount}; RATE: {syncsPerSecond:0.00} SYN/s; LAT: {audioLatencyMs} ms."); PlaySyncGaveUp.Value = true; } } // Detect if we have given up if (PlaySyncGaveUp.Value == true) { return(true); } #endregion #region Large Latency Handling if (audioLatencyMs > SyncThresholdLagging) { isBeyondThreshold = true; // a positive audio latency means we are rendering audio behind (after) the clock (skip some samples) // and therefore we need to advance the buffer before we read from it. if (speedRatio == 1.0) { MediaCore.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: LATENCY: {audioLatencyMs} ms. | SKIP (samples being rendered too late)"); } // skip some samples from the buffer. var audioLatencyBytes = WaveFormat.ConvertLatencyToByteSize(Convert.ToInt32(Math.Ceiling(audioLatencyMs))); AudioBuffer.Skip(Math.Min(audioLatencyBytes, readableCount)); } else if (audioLatencyMs < SyncThresholdLeading) { isBeyondThreshold = true; // Compute the latency in bytes var audioLatencyBytes = WaveFormat.ConvertLatencyToByteSize(Convert.ToInt32(Math.Ceiling(Math.Abs(audioLatencyMs)))); // audioLatencyBytes = requestedBytes; // uncomment this line to enable rewinding. if (audioLatencyBytes > requestedBytes && audioLatencyBytes < rewindableCount) { // This means we have the audio pointer a little too ahead of time and we need to // rewind it the requested amount of bytes. AudioBuffer.Rewind(Math.Min(audioLatencyBytes, rewindableCount)); } else { // a negative audio latency means we are rendering audio ahead (before) the clock // and therefore we need to render some silence until the clock catches up if (speedRatio == 1.0) { MediaCore.Log(MediaLogMessageType.Warning, $"SYNC AUDIO: LATENCY: {audioLatencyMs} ms. | WAIT (samples being rendered too early)"); } // render silence for the wait time and return Array.Clear(targetBuffer, targetBufferOffset, requestedBytes); return(false); } } #endregion #region Small Latency Handling // Perform minor adjustments until the delay is less than 10ms in either direction if (MediaCore.State.HasVideo && speedRatio == 1.0 && isBeyondThreshold == false && Math.Abs(audioLatencyMs) > SyncThresholdPerfect) { var stepDurationMillis = Convert.ToInt32(Math.Min(SyncThresholdMaxStep, Math.Abs(audioLatencyMs))); var stepDurationBytes = WaveFormat.ConvertLatencyToByteSize(stepDurationMillis); if (audioLatencyMs > SyncThresholdPerfect) { AudioBuffer.Skip(Math.Min(stepDurationBytes, readableCount)); } else if (audioLatencyMs < -SyncThresholdPerfect) { AudioBuffer.Rewind(Math.Min(stepDurationBytes, rewindableCount)); } } #endregion return(true); }
static void Main() { const int samples = 512; const int latency = 24; var devices = DirectSoundCapture.GetDevices(); //var capture = new DirectSoundCapture(devices.OrderByDescending(d => d.Description.Contains("Mic")).First().DriverGuid); var capture = new DirectSoundCapture(devices.OrderByDescending(d => d.Description.Contains("Mix")).First().DriverGuid); var audioFormat = new WaveFormat(); var audioBuffer = new CaptureBuffer(capture, new CaptureBufferDescription { BufferBytes = audioFormat.ConvertLatencyToByteSize(latency), Format = audioFormat }); audioBuffer.Start(true); using (var form = new Form()) using (var factory = new Factory4()) { form.Text = "AudioDX"; form.ClientSize = new System.Drawing.Size(1024, 768); form.StartPosition = FormStartPosition.CenterScreen; Device11 device; SwapChain swapChain; Device11.CreateWithSwapChain( DriverType.Hardware, DeviceCreationFlags.None, new SwapChainDescription { IsWindowed = true, BufferCount = 1, OutputHandle = form.Handle, SampleDescription = new SampleDescription(1, 0), ModeDescription = new ModeDescription(form.ClientSize.Width, form.ClientSize.Height, new Rational(60, 1), Format.B8G8R8A8_UNorm), Usage = Usage.RenderTargetOutput, SwapEffect = SwapEffect.Discard }, out device, out swapChain); var context = device.ImmediateContext; var backBuffer = swapChain.GetBackBuffer <Texture2D>(0); var backBufferView = new RenderTargetView(device, backBuffer); backBuffer.Dispose(); var depthBuffer = new Texture2D(device, new Texture2DDescription { Format = Format.D16_UNorm, ArraySize = 1, MipLevels = 1, Width = form.ClientSize.Width, Height = form.ClientSize.Height, SampleDescription = new SampleDescription(1, 0), BindFlags = BindFlags.DepthStencil }); var depthBufferView = new DepthStencilView(device, depthBuffer); depthBuffer.Dispose(); Shapes.Sphere.Load(device); Shapes.Cube.Load(device); Shapes.Billboard.Load(device); Shaders.Normal.Load(device); Shaders.Color.Load(device); var rasterizerStateDescription = RasterizerStateDescription.Default(); //rasterizerStateDescription.FillMode = FillMode.Wireframe; //rasterizerStateDescription.IsFrontCounterClockwise = true; //rasterizerStateDescription.CullMode = CullMode.Back; var rasterizerState = new RasterizerState(device, rasterizerStateDescription); var blendStateDescription = BlendStateDescription.Default(); //blendStateDescription.RenderTarget[0] = new RenderTargetBlendDescription(true, BlendOption.SourceAlpha, BlendOption.InverseSourceAlpha, BlendOperation.Add, BlendOption.SourceAlpha, BlendOption.DestinationAlpha, BlendOperation.Add, ColorWriteMaskFlags.All); var blendState = new BlendState(device, blendStateDescription); var depthStateDescription = DepthStencilStateDescription.Default(); depthStateDescription.DepthComparison = Comparison.LessEqual; depthStateDescription.IsDepthEnabled = true; depthStateDescription.IsStencilEnabled = false; var depthStencilState = new DepthStencilState(device, depthStateDescription); var samplerStateDescription = SamplerStateDescription.Default(); samplerStateDescription.Filter = Filter.MinMagMipLinear; samplerStateDescription.AddressU = TextureAddressMode.Wrap; samplerStateDescription.AddressV = TextureAddressMode.Wrap; var samplerState = new SamplerState(device, samplerStateDescription); var startTime = DateTime.Now; var frame = 0; var size = form.ClientSize; var audioData = new byte[audioFormat.ConvertLatencyToByteSize(latency)]; var audioIndex = 0; var leftWaveForm = new float[samples * 8]; var rightWaveForm = new float[samples * 8]; for (var sample = 0; sample < samples; sample++) { leftWaveForm[(sample * 8) + 0] = -1.0f + ((float)sample / (samples - 1) * 2.0f); rightWaveForm[(sample * 8) + 0] = -1.0f + ((float)sample / (samples - 1) * 2.0f); } var waveFormBufferDescription = new BufferDescription { BindFlags = BindFlags.VertexBuffer, SizeInBytes = leftWaveForm.Length * sizeof(float), CpuAccessFlags = CpuAccessFlags.Write, Usage = ResourceUsage.Dynamic }; //var leftWaveFormVertexBuffer = Buffer11.Create(device, leftWaveForm, waveFormBufferDescription); //var rightWaveFormVertexBuffer = Buffer11.Create(device, rightWaveForm, waveFormBufferDescription); //var leftWaveFormVertexBufferBinding = new VertexBufferBinding(leftWaveFormVertexBuffer, 8 * sizeof(float), 0); //var rightWaveFormVertexBufferBinding = new VertexBufferBinding(rightWaveFormVertexBuffer, 8 * sizeof(float), 0); var leftFrequencies = new float[samples]; var rightFrequencies = new float[samples]; //var rotation = 0.0f; RenderLoop.Run(form, () => { if (audioBuffer.CurrentCapturePosition != audioBuffer.CurrentRealPosition) { audioBuffer.Read(audioData, 0, audioData.Length, 0, LockFlags.None); //for (var sample = 0; sample < samples; sample++) //{ // leftWaveForm[(sample * 8) + 1] = -BitConverter.ToInt16(audioData, sample * 4) / (float)short.MinValue; // rightWaveForm[(sample * 8) + 1] = -BitConverter.ToInt16(audioData, (sample * 4) + 2) / (float)short.MinValue; //} //DataStream stream; //context.MapSubresource(leftWaveFormVertexBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); //stream.WriteRange(leftWaveForm); //context.UnmapSubresource(leftWaveFormVertexBuffer, 0); //stream.Dispose(); //context.MapSubresource(rightWaveFormVertexBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); //stream.WriteRange(rightWaveForm); //context.UnmapSubresource(rightWaveFormVertexBuffer, 0); //stream.Dispose(); for (var sample = 0; sample < samples; sample++) { leftFrequencies[sample] = 0.0f; rightFrequencies[sample] = 0.0f; for (var sample2 = 0; sample2 < samples; sample2++) { var theta = -2.0f * MathUtil.Pi * (float)sample2 * (float)sample / (samples << 1); var value = (float)Math.Cos(theta); leftFrequencies[sample] += value * (-BitConverter.ToInt16(audioData, sample2 * 4) / (float)short.MinValue); rightFrequencies[sample] += value * (-BitConverter.ToInt16(audioData, (sample2 * 4) + 2) / (float)short.MinValue); } } //for (var sample = 0; sample < samples; sample++) //{ // leftWaveForm[(sample * 8) + 1] = Math.Abs(leftFrequencies[sample]); // rightWaveForm[(sample * 8) + 1] = Math.Abs(rightFrequencies[sample]); //var angle = ((float)sample / (float)samples) * MathUtil.TwoPi; //var sin = (float)Math.Sin(angle); //var cos = (float)Math.Cos(angle); //leftWaveForm[(sample * 8) + 0] = (Math.Abs(leftFrequencies[sample]) + 10.0f) * sin * -0.01f; //leftWaveForm[(sample * 8) + 1] = (Math.Abs(leftFrequencies[sample]) + 10.0f) * cos * -0.01f; //rightWaveForm[(sample * 8) + 0] = (Math.Abs(rightFrequencies[sample]) + 10.0f) * sin * 0.01f; //rightWaveForm[(sample * 8) + 1] = (Math.Abs(rightFrequencies[sample]) + 10.0f) * cos * -0.01f; //} //context.MapSubresource(leftWaveFormVertexBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); //stream.WriteRange(leftWaveForm); //context.UnmapSubresource(leftWaveFormVertexBuffer, 0); //stream.Dispose(); //context.MapSubresource(rightWaveFormVertexBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); //stream.WriteRange(rightWaveForm); //context.UnmapSubresource(rightWaveFormVertexBuffer, 0); //stream.Dispose(); } if (form.ClientSize != size) { Utilities.Dispose(ref backBufferView); Utilities.Dispose(ref depthBufferView); if (form.ClientSize.Width != 0 && form.ClientSize.Height != 0) { swapChain.ResizeBuffers(1, form.ClientSize.Width, form.ClientSize.Height, Format.B8G8R8A8_UNorm, SwapChainFlags.None); backBuffer = swapChain.GetBackBuffer <Texture2D>(0); backBufferView = new RenderTargetView(device, backBuffer); backBuffer.Dispose(); depthBuffer = new Texture2D(device, new Texture2DDescription { Format = Format.D16_UNorm, ArraySize = 1, MipLevels = 1, Width = form.ClientSize.Width, Height = form.ClientSize.Height, SampleDescription = new SampleDescription(1, 0), BindFlags = BindFlags.DepthStencil }); depthBufferView = new DepthStencilView(device, depthBuffer); depthBuffer.Dispose(); } size = form.ClientSize; } var ratio = (float)form.ClientSize.Width / (float)form.ClientSize.Height; var projection = Matrix.PerspectiveFovRH(3.14f / 3.0f, ratio, 0.01f, 1000); var view = Matrix.LookAtRH(new Vector3(0, 2, 50), Vector3.Zero, Vector3.UnitY); //var world = Matrix.Scaling(1.0f + Math.Abs(((leftWaveForm[audioIndex + 1]) * 0.01f))) * Matrix.RotationY(Environment.TickCount / 2000.0f); //var world = Matrix.RotationY(rotation); //var world = Matrix.Scaling(1.0f + ((audioData[audioIndex] + audioData[audioIndex + 1] << 8) * 0.00001f)) * Matrix.RotationY(Environment.TickCount / 1000.0f); //audioIndex += 8; //if (audioIndex >= leftWaveForm.Length) // audioIndex = 0; //rotation += 0.01f; //var worldViewProjection = world * view * projection; //var diffuse = new Vector4(1, 0, 0, 0.5f); //Shaders.Color.WorldViewProjection(context, ref worldViewProjection); //Shaders.Color.Emissive(context, ref diffuse); context.Rasterizer.SetViewport(0, 0, form.ClientSize.Width, form.ClientSize.Height); context.OutputMerger.SetTargets(depthBufferView, backBufferView); context.ClearRenderTargetView(backBufferView, new RawColor4(0, 0, 0, 1)); context.ClearDepthStencilView(depthBufferView, DepthStencilClearFlags.Depth, 1.0f, 0); //Shaders.Color.Apply(context); //Shapes.Sphere.Begin(context); //Shapes.Cube.Begin(context); //Shapes.Billboard.Begin(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); context.PixelShader.SetShaderResource(0, null); //Shapes.Sphere.Draw(context); //Shapes.Cube.Draw(context); //Shapes.Billboard.Draw(context); // Draw Waveforms //diffuse = new Vector4(0, 0, 1, 0.5f); //Shaders.Color.Apply(context); //worldViewProjection = Matrix.Scaling(1, 0.1f, 1) * Matrix.Translation(0, 0.1f, 0); //worldViewProjection = Matrix.Scaling(1, 1, 1) * Matrix.Translation(-0.5f, 0, 0); //Shaders.Color.WorldViewProjection(context, ref worldViewProjection); //Shaders.Color.Emissive(context, ref diffuse); //context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip; //context.InputAssembler.SetVertexBuffers(0, leftWaveFormVertexBufferBinding); //context.Draw(samples, 0); //worldViewProjection = Matrix.Scaling(1, 0.1f, 1) * Matrix.Translation(0, -0.1f, 0); //Shaders.Color.WorldViewProjection(context, ref worldViewProjection); //context.InputAssembler.SetVertexBuffers(0, rightWaveFormVertexBufferBinding); //context.Draw(samples, 0); // Draw Frequencies Shapes.Billboard.Begin(context); Shaders.Color.Apply(context); var emissive = new Vector4(0.2f, 0.2f, 0.8f, 1); Shaders.Color.Emissive(context, ref emissive); for (var sample = 0; sample < samples; sample++) { var volume = 1 + (int)(Math.Abs(leftFrequencies[sample]) * 10.0f); for (var pixel = 0; pixel < volume; pixel++) { //var worldViewProjection = Matrix.Scaling(0.5f) * Matrix.Translation(-256.0f + sample, Math.Abs(leftFrequencies[sample]) * 10.0f, 0) * view * projection; var worldViewProjection = Matrix.Scaling(0.5f) * Matrix.Translation(-50.0f + sample, pixel, 0) * view * projection; Shaders.Color.WorldViewProjection(context, ref worldViewProjection); emissive = new Vector4(pixel * 0.06f, 0.0f, 0.8f - (pixel * 0.02f), 1); Shaders.Color.Emissive(context, ref emissive); Shapes.Billboard.Draw(context); } } swapChain.Present(1, PresentFlags.None); frame++; }); MessageBox.Show((frame / DateTime.Now.Subtract(startTime).TotalSeconds).ToString() + " FPS"); } }
static void Main() { var initError = EVRInitError.None; system = OpenVR.Init(ref initError); if (initError != EVRInitError.None) { return; } compositor = OpenVR.Compositor; compositor.CompositorBringToFront(); compositor.FadeGrid(5.0f, false); count = OpenVR.k_unMaxTrackedDeviceCount; currentPoses = new TrackedDevicePose_t[count]; nextPoses = new TrackedDevicePose_t[count]; controllers = new List <uint>(); controllerModels = new RenderModel_t[count]; controllerTextures = new RenderModel_TextureMap_t[count]; controllerTextureViews = new ShaderResourceView[count]; controllerVertexBuffers = new SharpDX.Direct3D11.Buffer[count]; controllerIndexBuffers = new SharpDX.Direct3D11.Buffer[count]; controllerVertexBufferBindings = new VertexBufferBinding[count]; for (uint device = 0; device < count; device++) { var deviceClass = system.GetTrackedDeviceClass(device); switch (deviceClass) { case ETrackedDeviceClass.HMD: headset = device; break; case ETrackedDeviceClass.Controller: controllers.Add(device); break; } } uint width = 0; uint height = 0; system.GetRecommendedRenderTargetSize(ref width, ref height); headsetSize = new Size((int)width, (int)height); windowSize = new Size(960, 540); var leftEyeProjection = Convert(system.GetProjectionMatrix(EVREye.Eye_Left, 0.01f, 1000.0f)); var rightEyeProjection = Convert(system.GetProjectionMatrix(EVREye.Eye_Right, 0.01f, 1000.0f)); var leftEyeView = Convert(system.GetEyeToHeadTransform(EVREye.Eye_Left)); var rightEyeView = Convert(system.GetEyeToHeadTransform(EVREye.Eye_Right)); foreach (var controller in controllers) { var modelName = new StringBuilder(255, 255); var propertyError = ETrackedPropertyError.TrackedProp_Success; var length = system.GetStringTrackedDeviceProperty(controller, ETrackedDeviceProperty.Prop_RenderModelName_String, modelName, 255, ref propertyError); if (propertyError == ETrackedPropertyError.TrackedProp_Success) { var modelName2 = modelName.ToString(); while (true) { var pointer = IntPtr.Zero; var modelError = EVRRenderModelError.None; modelError = OpenVR.RenderModels.LoadRenderModel_Async(modelName2, ref pointer); if (modelError == EVRRenderModelError.Loading) { continue; } if (modelError == EVRRenderModelError.None) { var renderModel = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_t>(pointer); controllerModels[controller] = renderModel; break; } } while (true) { var pointer = IntPtr.Zero; var textureError = EVRRenderModelError.None; textureError = OpenVR.RenderModels.LoadTexture_Async(controllerModels[controller].diffuseTextureId, ref pointer); if (textureError == EVRRenderModelError.Loading) { continue; } if (textureError == EVRRenderModelError.None) { var texture = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_TextureMap_t>(pointer); controllerTextures[controller] = texture; break; } } } } int adapterIndex = 0; system.GetDXGIOutputInfo(ref adapterIndex); using (var form = new Form()) using (var factory = new Factory4()) { form.ClientSize = windowSize; var adapter = factory.GetAdapter(adapterIndex); var swapChainDescription = new SwapChainDescription { BufferCount = 1, Flags = SwapChainFlags.None, IsWindowed = true, ModeDescription = new ModeDescription { Format = Format.B8G8R8A8_UNorm, Width = form.ClientSize.Width, Height = form.ClientSize.Height, RefreshRate = new Rational(60, 1) }, OutputHandle = form.Handle, SampleDescription = new SampleDescription(1, 0), SwapEffect = SwapEffect.Discard, Usage = Usage.RenderTargetOutput }; SharpDX.Direct3D11.Device.CreateWithSwapChain(adapter, DeviceCreationFlags.None, swapChainDescription, out device, out swapChain); factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.None); context = device.ImmediateContext; using (var backBuffer = swapChain.GetBackBuffer <Texture2D>(0)) backBufferView = new RenderTargetView(device, backBuffer); var depthBufferDescription = new Texture2DDescription { Format = Format.D16_UNorm, ArraySize = 1, MipLevels = 1, Width = form.ClientSize.Width, Height = form.ClientSize.Height, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default, BindFlags = BindFlags.DepthStencil, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.None }; using (var depthBuffer = new Texture2D(device, depthBufferDescription)) depthStencilView = new DepthStencilView(device, depthBuffer); // Create Eye Textures var eyeTextureDescription = new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.RenderTarget, CpuAccessFlags = CpuAccessFlags.None, Format = Format.B8G8R8A8_UNorm, Width = headsetSize.Width, Height = headsetSize.Height, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default }; var leftEyeTexture = new Texture2D(device, eyeTextureDescription); var rightEyeTexture = new Texture2D(device, eyeTextureDescription); var leftEyeTextureView = new RenderTargetView(device, leftEyeTexture); var rightEyeTextureView = new RenderTargetView(device, rightEyeTexture); // Create Eye Depth Buffer eyeTextureDescription.BindFlags = BindFlags.DepthStencil; eyeTextureDescription.Format = Format.D32_Float; var eyeDepth = new Texture2D(device, eyeTextureDescription); var eyeDepthView = new DepthStencilView(device, eyeDepth); Shapes.Cube.Load(device); Shapes.Sphere.Load(device); Shaders.Position.Load(device); Shaders.Normal.Load(device); Shaders.NormalTexture.Load(device); // Load Controller Models foreach (var controller in controllers) { var model = controllerModels[controller]; controllerVertexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rVertexData, new BufferDescription { BindFlags = BindFlags.VertexBuffer, SizeInBytes = (int)model.unVertexCount * 32 }); controllerVertexBufferBindings[controller] = new VertexBufferBinding(controllerVertexBuffers[controller], 32, 0); controllerIndexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rIndexData, new BufferDescription { BindFlags = BindFlags.IndexBuffer, SizeInBytes = (int)model.unTriangleCount * 3 * 2 }); var texture = controllerTextures[controller]; using (var texture2d = new Texture2D(device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.ShaderResource, Format = Format.R8G8B8A8_UNorm, Width = texture.unWidth, Height = texture.unHeight, MipLevels = 1, SampleDescription = new SampleDescription(1, 0) }, new DataRectangle(texture.rubTextureMapData, texture.unWidth * 4))) controllerTextureViews[controller] = new ShaderResourceView(device, texture2d); } worldViewProjectionBuffer = new SharpDX.Direct3D11.Buffer(device, Utilities.SizeOf <Matrix>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); var rasterizerStateDescription = RasterizerStateDescription.Default(); //rasterizerStateDescription.FillMode = FillMode.Wireframe; rasterizerStateDescription.IsFrontCounterClockwise = true; //rasterizerStateDescription.CullMode = CullMode.None; rasterizerState = new RasterizerState(device, rasterizerStateDescription); var blendStateDescription = BlendStateDescription.Default(); blendStateDescription.RenderTarget[0].BlendOperation = BlendOperation.Add; blendStateDescription.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha; blendStateDescription.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha; blendStateDescription.RenderTarget[0].IsBlendEnabled = false; blendState = new BlendState(device, blendStateDescription); var depthStateDescription = DepthStencilStateDescription.Default(); depthStateDescription.DepthComparison = Comparison.LessEqual; depthStateDescription.IsDepthEnabled = true; depthStateDescription.IsStencilEnabled = false; depthStencilState = new DepthStencilState(device, depthStateDescription); var samplerStateDescription = SamplerStateDescription.Default(); samplerStateDescription.Filter = Filter.MinMagMipLinear; samplerStateDescription.AddressU = TextureAddressMode.Wrap; samplerStateDescription.AddressV = TextureAddressMode.Wrap; samplerState = new SamplerState(device, samplerStateDescription); startTime = DateTime.Now; frame = 0; windowSize = form.ClientSize; backgroundColor = new RawColor4(0.1f, 0.1f, 0.1f, 1); var vrEvent = new VREvent_t(); var eventSize = (uint)Utilities.SizeOf <VREvent_t>(); head = Matrix.Identity; // Initialize Audio var audioSamples = 1024; var audioDevices = DirectSoundCapture.GetDevices(); //var audioCapture = new DirectSoundCapture(devices.OrderByDescending(d => d.Description.Contains("Mic")).First().DriverGuid); var audioCapture = new DirectSoundCapture(audioDevices.OrderByDescending(d => d.Description.Contains("Mix")).First().DriverGuid); var audioFormat = new WaveFormat(); var audioLength = audioFormat.ConvertLatencyToByteSize(24); var audioData = new byte[audioLength]; var audioPosition = 0; var leftWaveForm = new float[1024 * 8]; var rightWaveForm = new float[1024 * 8]; for (var sample = 0; sample < 1024; sample++) { leftWaveForm[(sample * 8) + 0] = -1.0f + ((float)sample / 512.0f); rightWaveForm[(sample * 8) + 0] = -1.0f + ((float)sample / 512.0f); } var audioBuffer = new CaptureBuffer(audioCapture, new CaptureBufferDescription { BufferBytes = audioLength, Format = audioFormat }); audioBuffer.Start(true); var waveFormBufferDescription = new BufferDescription { BindFlags = BindFlags.VertexBuffer, SizeInBytes = leftWaveForm.Length * sizeof(float), CpuAccessFlags = CpuAccessFlags.Write, Usage = ResourceUsage.Dynamic }; var leftWaveFormVertexBuffer = SharpDX.Direct3D11.Buffer.Create(device, leftWaveForm, waveFormBufferDescription); var rightWaveFormVertexBuffer = SharpDX.Direct3D11.Buffer.Create(device, rightWaveForm, waveFormBufferDescription); var leftWaveFormVertexBufferBinding = new VertexBufferBinding(leftWaveFormVertexBuffer, 8 * sizeof(float), 0); var rightWaveFormVertexBufferBinding = new VertexBufferBinding(rightWaveFormVertexBuffer, 8 * sizeof(float), 0); RenderLoop.Run(form, () => { if (audioBuffer.CurrentCapturePosition != audioBuffer.CurrentRealPosition) { audioBuffer.Read(audioData, 0, audioData.Length, 0, LockFlags.None); for (var sample = 0; sample < 1024; sample++) { leftWaveForm[(sample * 8) + 1] = -BitConverter.ToInt16(audioData, sample * 4) / (float)short.MinValue; rightWaveForm[(sample * 8) + 1] = -BitConverter.ToInt16(audioData, (sample * 4) + 2) / (float)short.MinValue; } DataStream stream; context.MapSubresource(leftWaveFormVertexBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); stream.WriteRange(leftWaveForm); context.UnmapSubresource(leftWaveFormVertexBuffer, 0); stream.Dispose(); context.MapSubresource(rightWaveFormVertexBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream); stream.WriteRange(rightWaveForm); context.UnmapSubresource(rightWaveFormVertexBuffer, 0); stream.Dispose(); } audioPosition += 8; if (audioPosition >= leftWaveForm.Length) { audioPosition = 0; } while (system.PollNextEvent(ref vrEvent, eventSize)) { switch ((EVREventType)vrEvent.eventType) { case EVREventType.VREvent_TrackedDeviceActivated: var controller = vrEvent.trackedDeviceIndex; controllers.Add(controller); var modelName = new StringBuilder(255, 255); var propertyError = ETrackedPropertyError.TrackedProp_Success; var length = system.GetStringTrackedDeviceProperty(controller, ETrackedDeviceProperty.Prop_RenderModelName_String, modelName, 255, ref propertyError); if (propertyError == ETrackedPropertyError.TrackedProp_Success) { var modelName2 = modelName.ToString(); while (true) { var pointer = IntPtr.Zero; var modelError = EVRRenderModelError.None; modelError = OpenVR.RenderModels.LoadRenderModel_Async(modelName2, ref pointer); if (modelError == EVRRenderModelError.Loading) { continue; } if (modelError == EVRRenderModelError.None) { var renderModel = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_t>(pointer); controllerModels[controller] = renderModel; // Load Controller Model var model = controllerModels[controller]; controllerVertexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rVertexData, new BufferDescription { BindFlags = BindFlags.VertexBuffer, SizeInBytes = (int)model.unVertexCount * 32 }); controllerVertexBufferBindings[controller] = new VertexBufferBinding(controllerVertexBuffers[controller], 32, 0); controllerIndexBuffers[controller] = new SharpDX.Direct3D11.Buffer(device, model.rIndexData, new BufferDescription { BindFlags = BindFlags.IndexBuffer, SizeInBytes = (int)model.unTriangleCount * 3 * 2 }); break; } } while (true) { var pointer = IntPtr.Zero; var textureError = EVRRenderModelError.None; textureError = OpenVR.RenderModels.LoadTexture_Async(controllerModels[controller].diffuseTextureId, ref pointer); if (textureError == EVRRenderModelError.Loading) { continue; } if (textureError == EVRRenderModelError.None) { var textureMap = System.Runtime.InteropServices.Marshal.PtrToStructure <RenderModel_TextureMap_t>(pointer); controllerTextures[controller] = textureMap; using (var texture2d = new Texture2D(device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.ShaderResource, Format = Format.R8G8B8A8_UNorm, Width = textureMap.unWidth, Height = textureMap.unHeight, MipLevels = 1, SampleDescription = new SampleDescription(1, 0) }, new DataRectangle(textureMap.rubTextureMapData, textureMap.unWidth * 4))) controllerTextureViews[controller] = new ShaderResourceView(device, texture2d); break; } } } break; case EVREventType.VREvent_TrackedDeviceDeactivated: controllers.RemoveAll(c => c == vrEvent.trackedDeviceIndex); break; default: System.Diagnostics.Debug.WriteLine((EVREventType)vrEvent.eventType); break; } } if (form.ClientSize != windowSize) { Utilities.Dispose(ref backBufferView); if (form.ClientSize.Width != 0 && form.ClientSize.Height != 0) { swapChain.ResizeBuffers(1, form.ClientSize.Width, form.ClientSize.Height, Format.B8G8R8A8_UNorm, SwapChainFlags.None); using (var backBuffer = swapChain.GetBackBuffer <Texture2D>(0)) backBufferView = new RenderTargetView(device, backBuffer); } windowSize = form.ClientSize; } // Update Device Tracking compositor.WaitGetPoses(currentPoses, nextPoses); if (currentPoses[headset].bPoseIsValid) { Convert(ref currentPoses[headset].mDeviceToAbsoluteTracking, ref head); } foreach (var controller in controllers) { var controllerMatrix = Matrix.Identity; Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref controllerMatrix); } // Render Left Eye context.Rasterizer.SetViewport(0, 0, headsetSize.Width, headsetSize.Height); context.OutputMerger.SetTargets(eyeDepthView, leftEyeTextureView); context.OutputMerger.SetDepthStencilState(depthStencilState); context.ClearRenderTargetView(leftEyeTextureView, backgroundColor); context.ClearDepthStencilView(eyeDepthView, DepthStencilClearFlags.Depth, 1.0f, 0); Shaders.Normal.Apply(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); var ratio = (float)headsetSize.Width / (float)headsetSize.Height; var projection = leftEyeProjection; var view = Matrix.Invert(leftEyeView * head); var world = Matrix.Scaling(1.0f + (Math.Abs(leftWaveForm[audioPosition + 1]) * 0.1f)) * Matrix.Translation(0, 1.0f, 0); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); //Shapes.Cube.Begin(context); //Shapes.Cube.Draw(context); Shapes.Sphere.Begin(context); Shapes.Sphere.Draw(context); // Draw Controllers context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; Shaders.NormalTexture.Apply(context); context.PixelShader.SetSampler(0, samplerState); foreach (var controller in controllers) { context.InputAssembler.SetVertexBuffers(0, controllerVertexBufferBindings[controller]); context.InputAssembler.SetIndexBuffer(controllerIndexBuffers[controller], Format.R16_UInt, 0); context.PixelShader.SetShaderResource(0, controllerTextureViews[controller]); Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref world); world = Matrix.Scaling(1.0f + (Math.Abs(leftWaveForm[audioPosition + 1]) * 0.5f)) * world; worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); context.DrawIndexed((int)controllerModels[controller].unTriangleCount * 3 * 4, 0, 0); } // Draw Waveforms Shaders.Position.Apply(context); world = Matrix.Scaling(100, 2.5f, 1) * Matrix.Translation(0, 1, 1); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip; context.InputAssembler.SetVertexBuffers(0, leftWaveFormVertexBufferBinding); context.Draw(1024, 0); world = Matrix.Scaling(100, 2.5f, 1) * Matrix.Translation(0, 1, -1); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.InputAssembler.SetVertexBuffers(0, rightWaveFormVertexBufferBinding); context.Draw(1024, 0); // Present Left Eye var texture = new Texture_t { eType = ETextureType.DirectX, eColorSpace = EColorSpace.Gamma, handle = leftEyeTextureView.Resource.NativePointer }; var bounds = new VRTextureBounds_t { uMin = 0.0f, uMax = 1.0f, vMin = 0.0f, vMax = 1.0f, }; var submitError = compositor.Submit(EVREye.Eye_Left, ref texture, ref bounds, EVRSubmitFlags.Submit_Default); if (submitError != EVRCompositorError.None) { System.Diagnostics.Debug.WriteLine(submitError); } // Render Right Eye context.Rasterizer.SetViewport(0, 0, headsetSize.Width, headsetSize.Height); context.OutputMerger.SetTargets(eyeDepthView, rightEyeTextureView); context.OutputMerger.SetDepthStencilState(depthStencilState); context.ClearRenderTargetView(rightEyeTextureView, backgroundColor); context.ClearDepthStencilView(eyeDepthView, DepthStencilClearFlags.Depth, 1.0f, 0); Shaders.Normal.Apply(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); projection = rightEyeProjection; view = Matrix.Invert(rightEyeView * head); world = Matrix.Scaling(1.0f + (Math.Abs(leftWaveForm[audioPosition + 1]) * 0.1f)) * Matrix.Translation(0, 1.0f, 0); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); //Shapes.Cube.Begin(context); //Shapes.Cube.Draw(context); Shapes.Sphere.Begin(context); Shapes.Sphere.Draw(context); // Draw Controllers context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; Shaders.NormalTexture.Apply(context); context.PixelShader.SetSampler(0, samplerState); foreach (var controller in controllers) { context.InputAssembler.SetVertexBuffers(0, controllerVertexBufferBindings[controller]); context.InputAssembler.SetIndexBuffer(controllerIndexBuffers[controller], Format.R16_UInt, 0); context.PixelShader.SetShaderResource(0, controllerTextureViews[controller]); Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref world); world = Matrix.Scaling(1.0f + (Math.Abs(leftWaveForm[audioPosition + 1]) * 0.5f)) * world; worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); context.DrawIndexed((int)controllerModels[controller].unTriangleCount * 3 * 4, 0, 0); } // Draw Waveforms Shaders.Position.Apply(context); world = Matrix.Scaling(100, 2.5f, 1) * Matrix.Translation(0, 1, 1); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip; context.InputAssembler.SetVertexBuffers(0, leftWaveFormVertexBufferBinding); context.Draw(1024, 0); world = Matrix.Scaling(100, 2.5f, 1) * Matrix.Translation(0, 1, -1); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.InputAssembler.SetVertexBuffers(0, rightWaveFormVertexBufferBinding); context.Draw(1024, 0); // Present Right Eye texture.handle = rightEyeTextureView.Resource.NativePointer; submitError = compositor.Submit(EVREye.Eye_Right, ref texture, ref bounds, EVRSubmitFlags.Submit_Default); if (submitError != EVRCompositorError.None) { System.Diagnostics.Debug.WriteLine(submitError); } // Render Window context.Rasterizer.SetViewport(0, 0, windowSize.Width, windowSize.Height); context.OutputMerger.SetTargets(depthStencilView, backBufferView); context.OutputMerger.SetDepthStencilState(depthStencilState); context.ClearRenderTargetView(backBufferView, backgroundColor); context.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0); Shaders.Normal.Apply(context); context.Rasterizer.State = rasterizerState; context.OutputMerger.SetBlendState(blendState); context.OutputMerger.SetDepthStencilState(depthStencilState); context.PixelShader.SetSampler(0, samplerState); ratio = (float)form.ClientSize.Width / (float)form.ClientSize.Height; projection = Matrix.PerspectiveFovRH(3.14f / 3.0f, ratio, 0.01f, 1000); view = Matrix.Invert(head); world = Matrix.Scaling(1.0f + (Math.Abs(leftWaveForm[audioPosition + 1]) * 0.1f)) * Matrix.Translation(0, 1.0f, 0); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); //Shapes.Cube.Begin(context); //Shapes.Cube.Draw(context); Shapes.Sphere.Begin(context); Shapes.Sphere.Draw(context); // Draw Controllers context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; Shaders.NormalTexture.Apply(context); context.PixelShader.SetSampler(0, samplerState); foreach (var controller in controllers) { context.InputAssembler.SetVertexBuffers(0, controllerVertexBufferBindings[controller]); context.InputAssembler.SetIndexBuffer(controllerIndexBuffers[controller], Format.R16_UInt, 0); Convert(ref currentPoses[controller].mDeviceToAbsoluteTracking, ref world); world = Matrix.Scaling(1.0f + (Math.Abs(leftWaveForm[audioPosition + 1]) * 0.5f)) * world; worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.VertexShader.SetConstantBuffer(0, worldViewProjectionBuffer); context.DrawIndexed((int)controllerModels[controller].unTriangleCount * 3 * 4, 0, 0); } // Draw Waveforms Shaders.Position.Apply(context); world = Matrix.Scaling(100, 2.5f, 1) * Matrix.Translation(0, 1, 1); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip; context.InputAssembler.SetVertexBuffers(0, leftWaveFormVertexBufferBinding); context.Draw(1024, 0); world = Matrix.Scaling(100, 2.5f, 1) * Matrix.Translation(0, 1, -1); worldViewProjection = world * view * projection; context.UpdateSubresource(ref worldViewProjection, worldViewProjectionBuffer); context.InputAssembler.SetVertexBuffers(0, rightWaveFormVertexBufferBinding); context.Draw(1024, 0); // Show Backbuffer swapChain.Present(0, PresentFlags.None); }); } }