/// <summary> /// Implements convolution over a plain rectangular array of data values /// </summary> /// <param name="source"></param> /// <param name="dest"></param> /// <param name="convolver"></param> public override void Convolve(T[,] source, T[,] dest, IConvolver <T> convolver) { var majorDimSource = source.GetLength(0); var minorDimSource = source.GetLength(1); var majorDimDest = dest.GetLength(0); var minorDimDest = dest.GetLength(1); var nullValue = convolver.Accumulator.NullValue; if (majorDimSource != majorDimDest || minorDimSource != minorDimDest) { throw new ArgumentException("Dimensions of source and destination data are not the same"); } convolver.Convolve(majorDimSource, minorDimSource, (x, y) => { if (x < 0 || y < 0 || x >= majorDimSource || y >= minorDimSource) { return(nullValue); } return(source[x, y]); }, (x, y, v) => dest[x, y] = v); }
public WicConvolution(IWICBitmapSource source, KernelMap <TWeight> mapx, KernelMap <TWeight> mapy, bool bufferSource = false) : base(source) { if (Format.FormatGuid == Consts.GUID_WICPixelFormat32bppPBGRA) { Processor = new Convolver4ChanByte(); } else if (Format.FormatGuid == Consts.GUID_WICPixelFormat32bppBGRA) { Processor = new ConvolverBgraByte(); } else if (Format.FormatGuid == Consts.GUID_WICPixelFormat24bppBGR) { Processor = new ConvolverBgrByte(); } else if (Format.FormatGuid == Consts.GUID_WICPixelFormat16bppCbCr) { Processor = new Convolver2ChanByte(); } else if (Format.FormatGuid == Consts.GUID_WICPixelFormat8bppGray || Format.FormatGuid == Consts.GUID_WICPixelFormat8bppY) { Processor = new Convolver1ChanByte(); } else if (Format == PixelFormat.Pbgra64BppLinearUQ15) { Processor = new Convolver4ChanUQ15(); } else if (Format == PixelFormat.Bgra64BppLinearUQ15) { Processor = new ConvolverBgraUQ15(); } else if (Format == PixelFormat.Bgr48BppLinearUQ15) { Processor = new ConvolverBgrUQ15(); } else if (Format == PixelFormat.Grey16BppLinearUQ15 || Format == PixelFormat.Y16BppLinearUQ15) { Processor = new Convolver1ChanUQ15(); } else if (Format == PixelFormat.Pbgra128BppLinearFloat || Format == PixelFormat.Pbgra128BppFloat) { Processor = new Convolver4ChanFloat(); } else if (Format == PixelFormat.Bgr96BppLinearFloat || Format == PixelFormat.Bgr96BppFloat) { Processor = new Convolver3ChanFloat(); } else if (Format == PixelFormat.CbCr64BppFloat) { Processor = new Convolver2ChanFloat(); } else if (Format == PixelFormat.Grey32BppLinearFloat || Format.FormatGuid == Consts.GUID_WICPixelFormat32bppGrayFloat || Format == PixelFormat.Y32BppLinearFloat || Format == PixelFormat.Y32BppFloat) { Processor = new Convolver1ChanFloat(); } else { throw new NotSupportedException("Unsupported pixel format"); } BufferSource = bufferSource; OutWidth = (uint)mapx.OutPixels; OutHeight = (uint)mapy.OutPixels; SourceRect = new WICRect { Width = (int)Width, Height = 1 }; XMap = mapx; YMap = mapy; IntBpp = Bpp / Unsafe.SizeOf <TPixel>() * Unsafe.SizeOf <TWeight>(); IntStride = mapy.Samples * IntBpp; IntStartLine = -mapy.Samples; int lineBuffLen = (bufferSource ? mapy.Samples : 1) * (int)Stride; int intBuffLen = mapx.OutPixels * IntStride; LineBuff = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(lineBuffLen), 0, lineBuffLen); IntBuff = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(intBuffLen), 0, intBuffLen); }
protected ConvolutionTransform(PixelSource source, KernelMap <TWeight> mapx, KernelMap <TWeight> mapy, bool lumaMode = false) : base(source) { var infmt = source.Format; var workfmt = infmt; if (lumaMode) { if (infmt.ColorRepresentation != PixelColorRepresentation.Grey && infmt.ColorRepresentation != PixelColorRepresentation.Bgr) { throw new NotSupportedException("Unsupported pixel format: " + infmt.Name); } workfmt = infmt.NumericRepresentation == PixelNumericRepresentation.Float ? PixelFormat.Grey32BppFloat : infmt.NumericRepresentation == PixelNumericRepresentation.Fixed ? PixelFormat.Grey16BppUQ15 : infmt.NumericRepresentation == PixelNumericRepresentation.UnsignedInteger ? PixelFormat.Grey8Bpp : throw new NotSupportedException("Unsupported pixel format: " + infmt.Name); } if (!ProcessorMap.TryGetValue(workfmt, out XProcessor !)) { throw new NotSupportedException("Unsupported pixel format: " + workfmt.Name); } if (workfmt == PixelFormat.Bgr96BppLinearFloat) { Format = workfmt = PixelFormat.Bgrx128BppLinearFloat; } else if (workfmt == PixelFormat.Bgr96BppFloat) { Format = workfmt = PixelFormat.Bgrx128BppFloat; } else { Format = infmt; } YProcessor = ProcessorMap[workfmt]; if (HWIntrinsics.IsSupported && (mapx.Samples * mapx.Channels & 3) == 0 && XProcessor is IVectorConvolver vcx) { XProcessor = vcx.IntrinsicImpl; } if (HWIntrinsics.IsSupported && (mapy.Samples * mapy.Channels & 3) == 0 && YProcessor is IVectorConvolver vcy) { YProcessor = vcy.IntrinsicImpl; } XMap = mapx; YMap = mapy; if (XMap.Channels != XProcessor.MapChannels || YMap.Channels != YProcessor.MapChannels) { throw new NotSupportedException("Map and Processor channel counts don't match"); } Width = mapx.Pixels; Height = mapy.Pixels; int bpp = workfmt.BytesPerPixel / Unsafe.SizeOf <TPixel>() * Unsafe.SizeOf <TWeight>(); IntBuff = new PixelBuffer(mapy.Samples, bpp, true, mapy.Samples * mapx.Pixels * bpp); if (bufferSource = lumaMode) { SrcBuff = new PixelBuffer(mapy.Samples, BufferStride, true); if (workfmt.IsBinaryCompatibleWith(infmt)) { WorkBuff = SrcBuff; } else { WorkBuff = new PixelBuffer(mapy.Samples, MathUtil.PowerOfTwoCeiling(source.Width * workfmt.BytesPerPixel, IntPtr.Size), true); } } else { lineBuff = BufferPool.Rent(BufferStride, true); } }
public UnsharpMaskTransform(PixelSource source, KernelMap <TWeight> mapx, KernelMap <TWeight> mapy, UnsharpMaskSettings ss) : base(source, mapx, mapy, true) { sharpenSettings = ss; processor = ProcessorMap[Format.FormatGuid]; blurBuff = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(WorkStride), 0, WorkStride); }
public virtual void Convolve(GenericLeafSubGrid <T> leaf, GenericLeafSubGrid <T> smoothedLeaf, IConvolver <T> convolver) { throw new NotImplementedException($"Convolve({nameof(GenericLeafSubGrid<T>)} leaf, ...) not implemented in this convolution tools class"); }
public virtual void Convolve(T[,] source, T[,] dest, IConvolver <T> convolver) { throw new NotImplementedException("Convolve(T[,] source, ...) not implemented in this convolution tools class"); }
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(); } }
/// <summary> /// Implements convolution over a sub grid tree in <T> /// </summary> /// <param name="leaf"></param> /// <param name="smoothedLeaf"></param> /// <param name="convolver"></param> public override void Convolve(GenericLeafSubGrid <T> leaf, GenericLeafSubGrid <T> smoothedLeaf, IConvolver <T> convolver) { var context = new ConvolutionSubGridContext <GenericLeafSubGrid <T>, T>(leaf, convolver.Accumulator.NullValue); convolver.Convolve(SubGridTreeConsts.SubGridTreeDimension, SubGridTreeConsts.SubGridTreeDimension, (x, y) => context.Value(x, y), (x, y, v) => smoothedLeaf.Items[x, y] = v); }