private ISample _next(ISample sample, out bool err)
{
try
{
// if (_gain == 0) Gain = 1;
_sampleCount++;
if (!_ignoreclipping && (_sampleCount % _sr == 0))
{
// Every second, check for clipping and wind back the gain by 0.5dB if so
bool clipped = false;
for (int n = 0; n < _nc; n++)
{
if (_ditherProcessors[n].clipping)
{
clipped = true;
}
}
if (clipped)
{
// Reduce gain by 0.5dB to back off from clipping
Gain = _gain * 0.94406087628592338036438049660227;
// Trace.WriteLine("Gain {0} dB", MathUtil.dB(_gain));
for (int n = 0; n < _nc; n++)
{
_ditherProcessors[n].clipping = false;
}
}
}
for (int n = 0; n < _nc; n++)
{
// dither processor does the float-to-PCM conversion
// (dither is not applied to 32-f output, only to PCM)
double val = sample[n];
if (_gain != 0 && !double.IsNaN(_gain))
{
val *= _gain;
}
if (_gains != null && !double.IsNaN(_gains[n]))
{
val *= _gains[n];
}
switch (_bitsPerSample)
{
case 8:
_w.Write((byte)(_ditherProcessors[n].process(val) + 127));
break;
case 16:
_w.Write((short)_ditherProcessors[n].process(val));
break;
case 24:
// Little-endian, signed 24-bit
int c = _ditherProcessors[n].process(val);
_w.Write((ushort)(c & 0xFFFF));
_w.Write((sbyte)(c >> 16 & 0xFF));
break;
case 32:
if (_audioFormat == WaveFormat.PCM || _audioFormat == WaveFormat.EXTENSIBLE)
{
_w.Write((int)_ditherProcessors[n].process(val));
}
else if (_audioFormat == WaveFormat.IEEE_FLOAT)
{
// Internals are double; just cast to float and discard any extra resolution
// (really we should dither here too, to approx 24 bits?)
_w.Write((float)val);
}
break;
case 64:
// we only do float, not PCM, 64-bits
_w.Write((double)val);
break;
default:
throw new Exception(String.Format("Bits per sample cannot be {0}", BitsPerSample));
}
}
err = false;
if (_isConsole)
{
// Check the stdout stream is still alive
int Err = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
if (Err != 0)
{
// Err 997: "Overlapped I/O is in progress" (don't know cause)
// Err 183: cannot create a file... caused in Trace
// Err 2: cannot find a file... caused in Trace
if (Err != 997 && Err != 183 && Err != 2)
{
System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(Err);
Trace.WriteLine("Write fault " + Err + ": " + e.Message);
err = true;// yield break;
}
}
}
}
catch (Exception e)
{
if (DSPUtil.IsMono() && e.Message.Contains("Write fault on path"))
{
// This is the usual end-of-stream error on Mono
Trace.WriteLine("Write finished; " + e.Message);
err = true; // yield break
}
else if (e.GetHashCode() == 33574638)
{
// "The specified network name is no longer available", from softsqueeze
Trace.WriteLine("Write finished; " + e.Message);
err = true; // yield break
}
else
{
// Trace.WriteLine("Interrupted: " + e.Message);
throw e;
}
}
return sample;
}