static ISoundObj DecodeBFormatBlumlein(ISoundObj source) { // Pure fig-8 Blumlein decode is simply a shuffle of the X (front-back) and Y (left-right) channels // W and Z are ignored. // No shelf filtering or distance compensation. TwoChannel xy = new TwoChannel(source, 1, 2); Shuffler blum = new Shuffler(); blum.DeltaGain = 1.0; blum.SigmaGain = 1.0; blum.Input = xy; return blum; }
static SoundObj GetMatrixImpulse() { // Load the stereo-matrix filter, if there is one // The matrix impulse needs to be shuffled before we use it Shuffler filterShuffler = new Shuffler(); if (!String.IsNullOrEmpty(_matrixFilter)) { string ignore; WaveReader matrixReader = GetAppropriateImpulseReader(_matrixFilter, out ignore); if (matrixReader != null) { filterShuffler.Input = matrixReader; // Calculate loudness-adjusted volume of the matrix impulse double matrixVolume = Loudness.WeightedVolume(filterShuffler); if (Math.Abs(1 - matrixVolume) > 0.001) { // Adjust the main gain by this for (int j = 0; j < _impulseVolumes.Count; j++) { _impulseVolumes[j] *= matrixVolume; } } } } return filterShuffler; }
static void InguzDSP(bool doRun) { DateTime dtStartRun = DateTime.Now; string sigdesc = null; // We need a few convolvers, of course if (_slow) { _MatrixConvolver = new SlowConvolver(); _MainConvolver = new SlowConvolver(); _EQConvolver = new SlowConvolver(); } else { _MatrixConvolver = new FastConvolver(); _MainConvolver = new FastConvolver(); _EQConvolver = new FastConvolver(); } // Shuffler _widthShuffler = new Shuffler(); // Two skewers _depthSkewer = new Skewer(true); _skewSkewer = new Skewer(true); // Writer if (_outPath == null) { _writer = new WaveWriter(); // stdout } else { _writer = new WaveWriter(_outPath); } _writer.NumChannels = _outChannels; if (_debug) { TimeSpan ts = DateTime.Now.Subtract(dtStartRun); Trace.WriteLine("Setup " + ts.TotalMilliseconds); } /* DateTime exp = DSPUtil.DSPUtil.EXPIRY; if (exp != null) { if (DateTime.Now.CompareTo(exp) >= 0) { Trace.WriteLine("**** THIS EVALUATION VERSION EXPIRED {0}", DSPUtil.DSPUtil.EXPIRY); Trace.WriteLine("**** SEE http://www.inguzaudio.com/DSP/ FOR DETAILS"); _MatrixConvolver.Enabled = false; _MainConvolver.Enabled = false; _EQConvolver.Enabled = false; Show("", "InguzDSP has expired.", 2); } else { Trace.WriteLine("This evaluation version will expire {0}", DSPUtil.DSPUtil.EXPIRY); } } */ // Read the configuration file doRun = LoadConfig2(); // Do any cleanup required before we start CleanUp(); // The main convolver should persist and re-use its leftovers between invocations // under this user's (=squeezebox's) ID _MainConvolver.partitions = _partitions; if (_tail && !IsSigGenNonEQ()) { _MainConvolver.PersistPath = _tempFolder; _MainConvolver.PersistTail = _userID; } // Construct a second convolver for the "tone" (EQ) control. _EQConvolver.partitions = _partitions; if (_tail && !IsSigGenNonEQ()) { _EQConvolver.PersistPath = _tempFolder; _EQConvolver.PersistTail = _userID + ".eq"; } // Make a reader // _inPath is the data stream WaveReader inputReader = null; bool ok = false; try { if (_inStream != null) { inputReader = new WaveReader(_inStream); } else if (_isRawIn) { inputReader = new WaveReader(_inPath, _rawtype, _rawbits, _rawchan, _startTime); } else { inputReader = new WaveReader(_inPath, _startTime); } inputReader.BigEndian = _bigEndian; ok = true; } catch (Exception e) { Trace.WriteLine("Unable to read: " + e.Message); // Just stop (no need to report the stack) } if (ok) { if (inputReader.IsSPDIF) { // The wave file is just a SPDIF (IEC61937) stream, we shouldn't touch it _inputSPDIF = true; _isBypass = true; } if (_isBypass) { // The settings file says bypass, we shouldn't touch it _gain = 0; _dither = DitherType.NONE; } uint sr = _inputSampleRate; // Yes, the commandline overrides the source-file... if (sr == 0) { sr = inputReader.SampleRate; } if (sr == 0) { sr = 44100; } _inputSampleRate = sr; if (WaveFormatEx.AMBISONIC_B_FORMAT_IEEE_FLOAT.Equals(inputReader.FormatEx) || WaveFormatEx.AMBISONIC_B_FORMAT_PCM.Equals(inputReader.FormatEx)) { _isBFormat = true; } } ISoundObj source = inputReader; if (IsSigGen()) { // Signal-generator source instead of music. _isBFormat = false; source = GetSignalGenerator(-12, out sigdesc); Show("Test signal", sigdesc, 20); } if (IsSigGenNonEQ() || _isBypass) { // Signal-generator mode. Overrides everything else! _writer.Input = source; } else { if (ok) { // Load the room correction impulse to the convolver // (NB: don't do this until we've created the reader, otherwise we can't be user of the samplerate yet...) LoadImpulse(); GC.Collect(); } if (ok && _isBFormat) { source = DecodeBFormat(source); } if (ok) { ISoundObj nextSrc; // Perform width (matrix) processing on the signal // - Shuffle the channels // - Convolve if there's a filter // - Apply gain to boost or cut the 'side' channel // - Shuffle back _widthShuffler.Input = source; nextSrc = _widthShuffler; // Use a convolver for the matrix filter if (_matrixFilter != null) { LoadMatrixFilter(); _MatrixConvolver.Input = TwoChannel(nextSrc); nextSrc = _MatrixConvolver as ISoundObj; } // if (_depth != 0) // { // // Time-alignment between the LR and MS // _depthSkewer.Input = nextSrc; // nextSrc = _depthSkewer; // } // Shuffle back again Shuffler shMSLR = new Shuffler(); shMSLR.Input = nextSrc; nextSrc = shMSLR; // Do the room-correction convolution _MainConvolver.Input = TwoChannel(shMSLR); nextSrc = _MainConvolver; if (_skew != 0) { // time-alignment between left and right _skewSkewer.Input = nextSrc; nextSrc = _skewSkewer; } // Splice EQ and non-EQ channels if (IsSigGenEQ()) { ChannelSplicer splice = new ChannelSplicer(); if (IsSigGenEQL()) { splice.Add(new SingleChannel(nextSrc, 0)); } else { splice.Add(new SingleChannel(source, 0)); } if (IsSigGenEQR()) { splice.Add(new SingleChannel(nextSrc, 1)); } else { splice.Add(new SingleChannel(source, 1)); } nextSrc = splice; } // Process externally with aften or equivalent? if (_aftenNeeded && !_isBypass) { nextSrc = AftenProcess(nextSrc); _outFormat = WaveFormat.PCM; _outBits = 16; _dither = DitherType.NONE; } // Finally pipe this to the writer _writer.Input = nextSrc; } } if (ok) { //dt = System.DateTime.Now; // time to here is approx 300ms // Dither and output raw-format override anything earlier in the chain _writer.Dither = _isBypass ? DitherType.NONE : _dither; _writer.Raw = _isRawOut; _writer.Format = (_outFormat == WaveFormat.ANY) ? inputReader.Format : _outFormat; _writer.BitsPerSample = (_outBits == 0 || _isBypass) ? inputReader.BitsPerSample : _outBits; _writer.SampleRate = (_outRate == 0 || _isBypass) ? _inputSampleRate : _outRate; SetWriterGain(); if (IsSigGen()) { Trace.WriteLine("Test signal: {0}, -12dBfs, {1}/{2} {3} {4}", sigdesc, _writer.BitsPerSample, _writer.SampleRate, _writer.Format, _writer.Dither); } string amb1 = ""; string amb2 = ""; if(_isBFormat) { amb1 = "B-Format "; amb2 = _ambiType + " "; } string big = inputReader.BigEndian ? "(Big-Endian) " : ""; if (_inputSPDIF) { Trace.WriteLine("Stream is SPDIF-wrapped; passing through"); } else if (_isBypass) { Trace.WriteLine("Processing is disabled; passing through"); } Trace.WriteLine("{0}/{1} {2}{3} {4}=> {5}/{6} {7}{8} {9}, gain {10} dB", inputReader.BitsPerSample, _inputSampleRate, amb1, inputReader.Format, big, _writer.BitsPerSample, _writer.SampleRate, amb2, _writer.Format, _writer.Dither, _gain); TimeSpan elapsedInit = System.DateTime.Now.Subtract(dtStartRun); int n = _writer.Run(); TimeSpan elapsedTotal = System.DateTime.Now.Subtract(dtStartRun); double realtime = n / _writer.SampleRate; double runtime = elapsedTotal.TotalMilliseconds / 1000; Trace.WriteLine("{0} samples, {1} ms ({2} init), {3} * realtime, peak {4} dBfs", n, elapsedTotal.TotalMilliseconds, elapsedInit.TotalMilliseconds, Math.Round(realtime / runtime, 4), Math.Round(_writer.dbfsPeak, 4)); StopConfigListening(); _writer.Close(); } }