using NAudio.Wave; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Projector { // Custom ISampleProvider to mix 4 channels to stereo public class FourChannelToStereoSampleProvider : ISampleProvider { private readonly ISampleProvider _source; private float offTransition = 1f; private float _voiceVolume = 0f; private bool goingOff = false; public WaveFormat WaveFormat { get; } public void SetOff() { goingOff = true; } public bool IsOff => goingOff && offTransition == 0f; public float VoiceVolume { get { return _voiceVolume; } set { _voiceVolume = Math.Clamp(value, 0f, 1f); } } public FourChannelToStereoSampleProvider(ISampleProvider source) { if (source.WaveFormat.Channels != 4) throw new ArgumentException("Source must have 4 channels"); if (source.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat) throw new ArgumentException("Source must be IEEE float format"); _source = source; WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(source.WaveFormat.SampleRate, 2); } public int Read(float[] buffer, int offset, int count) { int samplesNeeded = (count / 2) * 4; float[] sourceBuffer = new float[samplesNeeded]; int samplesRead = _source.Read(sourceBuffer, 0, samplesNeeded); int stereoSamples = samplesRead / 4 * 2; int outIndex = offset; if (goingOff && offTransition > 0f) { offTransition -= 0.2f; if (offTransition <= 0f) { offTransition = 0f; } } float musicVolume = 1f - VoiceVolume; float voiceVolume = VoiceVolume; for (int i = 0; i < samplesRead; i += 4) { // Mix channel 0 and 2 to left, 1 and 3 to right float left = (sourceBuffer[i] * musicVolume) + (sourceBuffer[i + 2] * voiceVolume); float right = (sourceBuffer[i + 1] * musicVolume) + (sourceBuffer[i + 3] * voiceVolume); buffer[outIndex++] = left * offTransition; buffer[outIndex++] = right * offTransition; } return stereoSamples; } } }