/// <summary> /// Renders the waveform as a monaural signal. /// </summary> /// <param name="renderer">The audio renderer.</param> /// <param name="destination">The destination buffer.</param> /// <remarks> /// This utility method internally uses <see cref="ArrayPool{T}"/>, /// which may result in memory allocation on the first call. /// To completely avoid memory allocation, /// use <see cref="IAudioRenderer.Render(Span{float}, Span{float})"/>. /// </remarks> public static void RenderMono(this IAudioRenderer renderer, Span <float> destination) { if (renderer == null) { throw new ArgumentNullException(nameof(renderer)); } var sampleCount = destination.Length; var bufferLength = 2 * destination.Length; var buffer = ArrayPool <float> .Shared.Rent(bufferLength); try { var left = buffer.AsSpan(0, sampleCount); var right = buffer.AsSpan(sampleCount, sampleCount); renderer.Render(left, right); for (var t = 0; t < sampleCount; t++) { destination[t] = (left[t] + right[t]) / 2; } } finally { ArrayPool <float> .Shared.Return(buffer); } }
/// <summary> /// Renders the waveform as a stereo interleaved signal. /// </summary> /// <param name="renderer">The audio renderer.</param> /// <param name="destination">The destination buffer.</param> /// <remarks> /// This utility method internally uses <see cref="ArrayPool{T}"/>, /// which may result in memory allocation on the first call. /// To completely avoid memory allocation, /// use <see cref="IAudioRenderer.Render(Span{float}, Span{float})"/>. /// </remarks> public static void RenderInterleaved(this IAudioRenderer renderer, Span <float> destination) { if (renderer == null) { throw new ArgumentNullException(nameof(renderer)); } if (destination.Length % 2 != 0) { throw new ArgumentException("The length of the destination buffer must be even.", nameof(destination)); } var sampleCount = destination.Length / 2; var bufferLength = destination.Length; var buffer = ArrayPool <float> .Shared.Rent(bufferLength); try { var left = buffer.AsSpan(0, sampleCount); var right = buffer.AsSpan(sampleCount, sampleCount); renderer.Render(left, right); var pos = 0; for (var t = 0; t < sampleCount; t++) { destination[pos++] = left[t]; destination[pos++] = right[t]; } } finally { ArrayPool <float> .Shared.Return(buffer); } }
/// <summary> /// Renders the waveform as a stereo interleaved signal with 16-bit quantization. /// </summary> /// <param name="renderer">The audio renderer.</param> /// <param name="destination">The destination buffer.</param> /// <remarks> /// Out of range samples will be clipped. /// This utility method internally uses <see cref="ArrayPool{T}"/>, /// which may result in memory allocation on the first call. /// To completely avoid memory allocation, /// use <see cref="IAudioRenderer.Render(Span{float}, Span{float})"/>. /// </remarks> public static void RenderInterleavedInt16(this IAudioRenderer renderer, Span <short> destination) { if (renderer == null) { throw new ArgumentNullException(nameof(renderer)); } if (destination.Length % 2 != 0) { throw new ArgumentException("The length of the destination buffer must be even.", nameof(destination)); } var sampleCount = destination.Length / 2; var bufferLength = destination.Length; var buffer = ArrayPool <float> .Shared.Rent(bufferLength); try { var left = buffer.AsSpan(0, sampleCount); var right = buffer.AsSpan(sampleCount, sampleCount); renderer.Render(left, right); var pos = 0; for (var t = 0; t < sampleCount; t++) { var sampleLeft = (int)(32768 * left[t]); if (sampleLeft < short.MinValue) { sampleLeft = short.MinValue; } else if (sampleLeft > short.MaxValue) { sampleLeft = short.MaxValue; } var sampleRight = (int)(32768 * right[t]); if (sampleRight < short.MinValue) { sampleRight = short.MinValue; } else if (sampleRight > short.MaxValue) { sampleRight = short.MaxValue; } destination[pos++] = (short)sampleLeft; destination[pos++] = (short)sampleRight; } } finally { ArrayPool <float> .Shared.Return(buffer); } }
public void Start() { this.renderer = this.createRenderer(this.rendererType); this.then = DateTime.Now; this.capture = new WasapiLoopbackCapture(); this.capture.DataAvailable += this.capture_DataAvailable; this.capture.RecordingStopped += this.capture_RecordingStopped; this.capture.StartRecording(); }
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle) { ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, context.Memory, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle); if (result == ResultCode.Success) { obj = new AudioRenderer.AudioRenderer(renderer); } else { obj = null; } return(result); }
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle) { var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory; ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle, context.Device.Configuration.AudioVolume); if (result == ResultCode.Success) { obj = new AudioRenderer.AudioRenderer(renderer); } else { obj = null; } return(result); }
/// <summary> /// Renders the waveform as a monaural signal with 16-bit quantization. /// </summary> /// <param name="renderer">The audio renderer.</param> /// <param name="destination">The destination buffer.</param> /// <remarks> /// Out of range samples will be clipped. /// This utility method internally uses <see cref="ArrayPool{T}"/>, /// which may result in memory allocation on the first call. /// To completely avoid memory allocation, /// use <see cref="IAudioRenderer.Render(Span{float}, Span{float})"/>. /// </remarks> public static void RenderMonoInt16(this IAudioRenderer renderer, Span <short> destination) { if (renderer == null) { throw new ArgumentNullException(nameof(renderer)); } var sampleCount = destination.Length; var bufferLength = 2 * destination.Length; var buffer = ArrayPool <float> .Shared.Rent(bufferLength); try { var left = buffer.AsSpan(0, sampleCount); var right = buffer.AsSpan(sampleCount, sampleCount); renderer.Render(left, right); for (var t = 0; t < sampleCount; t++) { var sample = (int)(16384 * (left[t] + right[t])); if (sample < short.MinValue) { sample = short.MinValue; } else if (sample > short.MaxValue) { sample = short.MaxValue; } destination[t] = (short)sample; } } finally { ArrayPool <float> .Shared.Return(buffer); } }
public AudioRendererServer(IAudioRenderer impl) { _impl = impl; }
private void SetupAudioSourceOutput(IAudioRenderer audioRenderer) { audioRenderer.SetExceptionHandler(OnErrorCallback); audioRenderer.SetFormatCallback(OnAudioSetup); audioRenderer.SetCallbacks(null, OnNewSound); }