static ISoundObj Splice(string infileL, int peakPosL, string infileR, int peakPosR, string outfile) { //int tmp1; //bool tmp2; WaveReader reader1 = new WaveReader(infileL, WaveFormat.IEEE_FLOAT, 32, 1); // reader1.Skip(peakPosL, out tmp1, out tmp2); SoundBuffer buff1 = new SoundBuffer(reader1); buff1.ReadAll(); // Normalize loudness for each channel double g = Loudness.WeightedVolume(buff1); buff1.ApplyGain(1/g); WaveReader reader2 = new WaveReader(infileR, WaveFormat.IEEE_FLOAT, 32, 1); // reader2.Skip(peakPosR, out tmp1, out tmp2); SoundBuffer buff2 = new SoundBuffer(reader2); buff2.ReadAll(); g = Loudness.WeightedVolume(buff2); buff2.ApplyGain(1/g); ChannelSplicer splicer = new ChannelSplicer(); splicer.Add(buff1); splicer.Add(buff2); // General-purpose: // Find the extremities of the DRC impulse, // window asymmetrically. // // But, since we specifically used linear-phase filters on target and mic, // we know that the impulse is centered. // We want an impulse length (_filterLen) // so window the 2048 samples at each end (which are pretty low to begin with - less than -100dB) ISoundObj output; int nCount = (int)(buff1.Count / 2); if (nCount > _filterLen/2) { BlackmanHarris bhw = new BlackmanHarris(nCount, 2048, (nCount / 2) - 2048); bhw.Input = splicer; SampleBuffer sb = new SampleBuffer(bhw); output = sb.Subset(_filterLen/2, _filterLen); } else { output = splicer; } ISoundObj result = output; if (!_noSkew) { // Apply skew to compensate for time alignment in the impulse responses Skewer skewer = new Skewer(true); skewer.Input = output; skewer.Skew = peakPosL - peakPosR; result = skewer; } WaveWriter writer = new WaveWriter(outfile); writer.Input = result; writer.Dither = DitherType.NONE; writer.Format = WaveFormat.IEEE_FLOAT; writer.BitsPerSample = 32; writer.SampleRate = _sampleRate; writer.NumChannels = splicer.NumChannels; if (Double.IsNaN(_gain)) { writer.Normalization = 0; } else { writer.Gain = MathUtil.gain(_gain); } writer.Run(); writer.Close(); reader1.Close(); reader2.Close(); return result; }
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(); } }