/// <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();
        }
Example #5
0
        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);
        }
Example #6
0
        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);
            }
        }
Example #8
0
 public AudioRendererServer(IAudioRenderer impl)
 {
     _impl = impl;
 }
Example #9
0
 private void SetupAudioSourceOutput(IAudioRenderer audioRenderer)
 {
     audioRenderer.SetExceptionHandler(OnErrorCallback);
     audioRenderer.SetFormatCallback(OnAudioSetup);
     audioRenderer.SetCallbacks(null, OnNewSound);
 }