diff --git a/NWaves/Audio/ByteConverter.cs b/NWaves/Audio/ByteConverter.cs index 8bce105..e0b40a7 100644 --- a/NWaves/Audio/ByteConverter.cs +++ b/NWaves/Audio/ByteConverter.cs @@ -1,12 +1,12 @@ namespace NWaves.Audio { /// - /// Static class providing methods for conversion between PCM bytes and float[] data. + /// Provides methods for conversion between PCM bytes and float[] data. /// public static class ByteConverter { /// - /// Convert Pcm_8bit to arrays of . + /// Converts Pcm_8bit to arrays of . /// /// Array of bytes /// Arrays of floats @@ -38,7 +38,7 @@ public static void ToFloats8Bit(byte[] bytes, float[][] floats, bool normalize = } /// - /// Convert arrays of to Pcm_8bit . + /// Converts arrays of to Pcm_8bit . /// /// Array of bytes /// Arrays of floats @@ -70,7 +70,7 @@ public static void FromFloats8Bit(float[][] floats, byte[] bytes, bool normalize } /// - /// Convert Pcm_16bit to arrays of (little-endian or big-endian). + /// Converts Pcm_16bit to arrays of (little-endian or big-endian). /// /// Array of bytes /// Arrays of floats @@ -130,7 +130,7 @@ public static void ToFloats16Bit(byte[] bytes, float[][] floats, bool normalize } /// - /// Convert arrays of to Pcm_16bit (little-endian or big-endian). + /// Converts arrays of to Pcm_16bit (little-endian or big-endian). /// /// Array of bytes /// Arrays of floats diff --git a/NWaves/Audio/Interfaces/IAudioContainer.cs b/NWaves/Audio/Interfaces/IAudioContainer.cs index 1351090..0f6f134 100644 --- a/NWaves/Audio/Interfaces/IAudioContainer.cs +++ b/NWaves/Audio/Interfaces/IAudioContainer.cs @@ -9,12 +9,12 @@ namespace NWaves.Audio.Interfaces public interface IAudioContainer { /// - /// Get the list of discrete signals in container. + /// Gets the list of discrete signals in container. /// List Signals { get; } /// - /// Return container's signal using indexing based on channel type. + /// Gets the signal from container using indexing scheme based on channel type. /// /// Channel (left, right, interleave, sum, average, or ordinary index) DiscreteSignal this[Channels channel] { get; } diff --git a/NWaves/Audio/Interfaces/IAudioPlayer.cs b/NWaves/Audio/Interfaces/IAudioPlayer.cs index 4fe7905..51224e5 100644 --- a/NWaves/Audio/Interfaces/IAudioPlayer.cs +++ b/NWaves/Audio/Interfaces/IAudioPlayer.cs @@ -9,12 +9,12 @@ namespace NWaves.Audio.Interfaces public interface IAudioPlayer { /// - /// Gets or sets sound volume (usually in range [0.0f, 1.0f]). + /// Gets or sets sound volume (usually in range [0..1]). /// float Volume { get; set; } /// - /// Play samples contained in asynchronously. + /// Plays samples contained in asynchronously. /// /// Signal to play /// Index of the first sample to play @@ -23,7 +23,7 @@ public interface IAudioPlayer Task PlayAsync(DiscreteSignal signal, int startPos = 0, int endPos = -1, short bitDepth = 16); /// - /// Play samples contained in WAV file (or some other source) asynchronously. + /// Plays samples contained in WAV file (or some other source) asynchronously. /// /// Path to WAV file (or other source) to play /// Index of the first sample to play @@ -31,17 +31,17 @@ public interface IAudioPlayer Task PlayAsync(string source, int startPos = 0, int endPos = -1); /// - /// Pause playing audio. + /// Pauses playing audio. /// void Pause(); /// - /// Resume playing audio. + /// Resumes playing audio. /// void Resume(); /// - /// Stop playing audio. + /// Stops playing audio. /// void Stop(); } diff --git a/NWaves/Audio/Interfaces/IAudioRecorder.cs b/NWaves/Audio/Interfaces/IAudioRecorder.cs index dac5616..497aed5 100644 --- a/NWaves/Audio/Interfaces/IAudioRecorder.cs +++ b/NWaves/Audio/Interfaces/IAudioRecorder.cs @@ -6,7 +6,7 @@ public interface IAudioRecorder { /// - /// Start recording audio with specific settings. + /// Starts recording audio with specific settings. /// /// Sampling rate /// Number of channels (1=mono, 2=stereo) @@ -14,7 +14,7 @@ public interface IAudioRecorder void StartRecording(int samplingRate, short channelCount, short bitsPerSample); /// - /// Stop recording audio and save recorded sound to file or any other destination. + /// Stops recording audio and saves recorded sound to file or any other destination. /// /// Path to output file (destination) void StopRecording(string destination); diff --git a/NWaves/Audio/Mci/Mci.cs b/NWaves/Audio/Mci/Mci.cs index c29eeea..379cd4b 100644 --- a/NWaves/Audio/Mci/Mci.cs +++ b/NWaves/Audio/Mci/Mci.cs @@ -4,7 +4,7 @@ namespace NWaves.Audio.Mci { /// - /// Static class containing MCI functions imported from winmm.dll + /// Provides MCI functions imported from winmm.dll. /// public static class Mci { diff --git a/NWaves/Audio/Mci/MciAudioPlayer.cs b/NWaves/Audio/Mci/MciAudioPlayer.cs index 82d897f..2ed943a 100644 --- a/NWaves/Audio/Mci/MciAudioPlayer.cs +++ b/NWaves/Audio/Mci/MciAudioPlayer.cs @@ -40,12 +40,12 @@ public class MciAudioPlayer : IAudioPlayer private bool _isPaused; /// - /// Gets or sets audio volume (measured in percents from the range [0.0f, 1.0f]). + /// Gets or sets audio volume (measured in percents from the range [0..1]). /// public float Volume { get; set; } /// - /// Play audio contained in WAV file asynchronously. + /// Plays audio contained in WAV file asynchronously. /// /// Path to WAV file to play /// Index of the first sample to play @@ -137,7 +137,7 @@ public Task PlayAsync(DiscreteSignal signal, int startPos = 0, int endPos = -1, } /// - /// Pause playing audio. + /// Pauses playing audio. /// public void Pause() { @@ -157,7 +157,7 @@ public void Pause() } /// - /// Resume playing audio. + /// Resumes playing audio. /// public void Resume() { @@ -176,7 +176,7 @@ public void Resume() } /// - /// Stop playing audio and close MCI device. + /// Stops playing audio and close MCI device. /// public void Stop() { diff --git a/NWaves/Audio/Mci/MciAudioRecorder.cs b/NWaves/Audio/Mci/MciAudioRecorder.cs index f40290b..27c8a63 100644 --- a/NWaves/Audio/Mci/MciAudioRecorder.cs +++ b/NWaves/Audio/Mci/MciAudioRecorder.cs @@ -11,7 +11,7 @@ namespace NWaves.Audio.Mci public class MciAudioRecorder : IAudioRecorder { /// - /// Start recording audio with specific settings. + /// Starts recording audio with specific settings. /// /// Sampling rate /// Number of channels (1=mono, 2=stereo) @@ -40,7 +40,7 @@ public void StartRecording(int samplingRate = 44100, short channelCount = 1, sho } /// - /// Stop recording audio and save it to WAV file. + /// Stops recording audio and save it to WAV file. /// /// Path to output WAV file containing recorded sound public void StopRecording(string destination) diff --git a/NWaves/Audio/WaveFile.cs b/NWaves/Audio/WaveFile.cs index 770e0ab..213636c 100644 --- a/NWaves/Audio/WaveFile.cs +++ b/NWaves/Audio/WaveFile.cs @@ -11,9 +11,9 @@ namespace NWaves.Audio /// /// PCM WAV container. /// - /// is not intended to be a "wrapper around the stream", or to acquire any resource - /// (it doesn't affect the underlying stream). It's more like a "constructor of signals in memory based on data - /// from the stream" and its lifetime is not synchronized with the stream whatsoever. + /// is not intended to be a wrapper around the stream, or to acquire any resource + /// (it doesn't affect the underlying stream). It's more like a constructor of signals in memory based on data + /// from the stream, and its lifetime is not synchronized with the stream whatsoever. /// The synonym name of this class could be also "WaveContainer". /// /// @@ -25,7 +25,7 @@ public class WaveFile : IAudioContainer public List Signals { get; protected set; } /// - /// WAV header (WAVE format). + /// Gets WAV header (WAVE format). /// public WaveFormat WaveFmt { get; protected set; } @@ -34,6 +34,16 @@ public class WaveFile : IAudioContainer /// public short[] SupportedBitDepths = { 8, 16, 24, 32 }; + /// + /// Constructs WAV container by loading signals from . + /// + /// Input stream + /// Normalize samples + public WaveFile(Stream waveStream, bool normalized = true) + { + ReadWaveStream(waveStream, normalized); + } + /// /// Constructs WAV container by loading signals from a byte array (i.e. byte content of WAV file). /// @@ -62,17 +72,7 @@ public WaveFile(byte[] waveBytes, int index, bool normalized = true) } /// - /// Constructs WAV container by loading signals from . - /// - /// Input stream - /// Normalize samples - public WaveFile(Stream waveStream, bool normalized = true) - { - ReadWaveStream(waveStream, normalized); - } - - /// - /// Read PCM WAV binary data and fill and structure. + /// Reads PCM WAV binary data and fills and structure. /// /// Input stream of PCM WAV binary data /// Normalize samples @@ -241,13 +241,13 @@ protected void ReadWaveStream(Stream waveStream, bool normalized = true) } /// - /// Construct WAV container by loading into it collection of with given . + /// Constructs WAV container by loading into it collection of with given . /// /// Signals to be loaded into container /// Bit depth public WaveFile(IList signals, short bitsPerSample = 16) { - if (signals == null || !signals.Any()) + if (signals is null || !signals.Any()) { throw new ArgumentException("At least one signal must be provided"); } @@ -285,7 +285,7 @@ public WaveFile(IList signals, short bitsPerSample = 16) } /// - /// Construct WAV container by loading into it one with given . + /// Constructs WAV container by loading into it one with given . /// /// Signal to be loaded into container /// Bit depth @@ -294,7 +294,7 @@ public WaveFile(DiscreteSignal signal, short bitsPerSample = 16) : this(new [] { } /// - /// Return the contents of PCM WAV container as array of bytes. + /// Returns the contents of PCM WAV container as array of bytes. /// /// True if samples are normalized public byte[] GetBytes(bool normalized = true) @@ -307,7 +307,7 @@ public byte[] GetBytes(bool normalized = true) } /// - /// Save the contents of PCM WAV container to . + /// Saves the contents of PCM WAV container to . /// /// Output stream /// True if samples are normalized @@ -400,7 +400,7 @@ public void SaveTo(Stream waveStream, bool normalized = true) } /// - /// Return container's signal using indexing based on channel type. Examples + /// Gets the signal from container using indexing scheme based on channel type. Examples /// /// waveFile[Channels.Left] -> waveFile.Signals[0] ///
diff --git a/NWaves/Operations/DynamicsMode.cs b/NWaves/Operations/DynamicsMode.cs index 8275679..03cbfa9 100644 --- a/NWaves/Operations/DynamicsMode.cs +++ b/NWaves/Operations/DynamicsMode.cs @@ -1,24 +1,27 @@ namespace NWaves.Operations { + /// + /// Types (modes) of dynamics processors. + /// public enum DynamicsMode { /// - /// Smaller ratios, like 1:1, 2:1 + /// Smaller ratios, like 1:1, 2:1. /// Compressor, /// - /// Bigger ratios, like 5:1, 10:1 + /// Bigger ratios, like 5:1, 10:1. /// Limiter, /// - /// Smaller ratios, like 1:1, 2:1 + /// Smaller ratios, like 1:1, 2:1. /// Expander, /// - /// Very high ratios, like 5:1 + /// Very high ratios, like 5:1. /// NoiseGate } diff --git a/NWaves/Operations/DynamicsProcessor.cs b/NWaves/Operations/DynamicsProcessor.cs index 4d878a8..8ab6910 100644 --- a/NWaves/Operations/DynamicsProcessor.cs +++ b/NWaves/Operations/DynamicsProcessor.cs @@ -6,52 +6,52 @@ namespace NWaves.Operations { /// - /// Dynamics processor: limiter / compressor / expander / noise gate + /// Represents dynamics processor: limiter or compressor or expander or noise gate. /// public class DynamicsProcessor : IFilter, IOnlineFilter { /// - /// Dynamics processor mode + /// Dynamics processor mode. /// private readonly DynamicsMode _mode; /// - /// Envelope follower + /// Envelope follower. /// private readonly EnvelopeFollower _envelopeFollower; /// - /// Sampling rate + /// Sampling rate. /// private readonly int _fs; /// - /// Min threshold for dB amplitude + /// Min threshold for dB amplitude. /// private readonly float _minAmplitudeDb; /// - /// Attack/Release time coefficient + /// Attack/Release time coefficient. /// private readonly float T = 1 / (float)Math.Log(9); // = approx. 2.2 /// - /// Compression threshold + /// Gets or sets compression/expansion threshold. /// public float Threshold { get; set; } /// - /// Compression ratio + /// Gets or sets compression/expansion ratio. /// public float Ratio { get; set; } /// - /// Makeup gain + /// Gets or sets makeup gain. /// public float MakeupGain { get; set; } /// - /// Attack time + /// Gets or sets attack time. /// public float Attack { @@ -86,7 +86,7 @@ public float Attack } /// - /// Release time + /// Gets or sets release time. /// public float Release { @@ -121,16 +121,16 @@ public float Release } /// - /// Constructor + /// Constructs in given . /// - /// - /// - /// - /// - /// - /// - /// - /// + /// Type (mode) of dynamics processor + /// Sampling rate + /// Compression/expansion threshold + /// Compression/expansion ratio + /// Makeup gain + /// Attack time (in seconds) + /// Release time (in seconds) + /// Min threshold for dB amplitude public DynamicsProcessor(DynamicsMode mode, int samplingRate, float threshold, @@ -152,6 +152,10 @@ public DynamicsProcessor(DynamicsMode mode, Release = release; } + /// + /// Processes one sample. + /// + /// Input sample public float Process(float sample) { var abs = Math.Abs(sample); @@ -183,11 +187,19 @@ public float Process(float sample) return sample * gain; } + /// + /// Resets dynamics processor. + /// public void Reset() { _envelopeFollower.Reset(); } + /// + /// Processes entire and returns new signal (dynamics). + /// + /// Input signal + /// Filtering method public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) => this.FilterOnline(signal); } } diff --git a/NWaves/Operations/EnvelopeFollower.cs b/NWaves/Operations/EnvelopeFollower.cs index daa30fd..c5cdf66 100644 --- a/NWaves/Operations/EnvelopeFollower.cs +++ b/NWaves/Operations/EnvelopeFollower.cs @@ -5,14 +5,13 @@ namespace NWaves.Operations { /// - /// Envelope follower (detector) + /// Represents envelope follower (envelope detector). /// public class EnvelopeFollower : IFilter, IOnlineFilter { /// - /// Attack time + /// Gets or sets attack time (in seconds). /// - private float _attackTime; public float AttackTime { get => _attackTime; @@ -22,11 +21,11 @@ public float AttackTime _ga = value < 1e-20 ? 0 : (float)Math.Exp(-1.0 / (value * _fs)); } } + private float _attackTime; /// - /// Release time + /// Gets or sets release time (in seconds). /// - private float _releaseTime; public float ReleaseTime { get => _releaseTime; @@ -36,33 +35,34 @@ public float ReleaseTime _gr = value < 1e-20 ? 0 : (float)Math.Exp(-1.0 / (value * _fs)); } } + private float _releaseTime; /// - /// Sampling rate + /// Sampling rate. /// private readonly int _fs; /// - /// Current envelope sample + /// Current envelope sample. /// private float _env; /// - /// Attack coefficient + /// Attack coefficient. /// private float _ga; /// - /// Release coefficient + /// Release coefficient. /// private float _gr; /// - /// Constructor + /// Constructs . /// - /// - /// - /// + /// Sampling rate + /// Attack time (in seconds) + /// Release time (in seconds) public EnvelopeFollower(int samplingRate, float attackTime = 0.01f, float releaseTime = 0.05f) { _fs = samplingRate; @@ -71,24 +71,33 @@ public EnvelopeFollower(int samplingRate, float attackTime = 0.01f, float releas } /// - /// Envelope following is essentialy a low-pass filtering + /// Processes one sample. /// - /// - /// - public float Process(float input) + /// Input sample + public float Process(float sample) { - var sample = Math.Abs(input); + // envelope following is essentially a low-pass filtering + + var s = Math.Abs(sample); - _env = _env < sample ? _ga * _env + (1 - _ga) * sample : _gr * _env + (1 - _gr) * sample; + _env = _env < s ? _ga * _env + (1 - _ga) * s : _gr * _env + (1 - _gr) * s; return _env; } + /// + /// Resets envelope follower. + /// public void Reset() { _env = 0; } + /// + /// Processes entire and returns new signal (envelope). + /// + /// Input signal + /// Filtering method public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) => this.FilterOnline(signal); } } diff --git a/NWaves/Operations/GriffinLimReconstructor.cs b/NWaves/Operations/GriffinLimReconstructor.cs index b72126c..d48115e 100644 --- a/NWaves/Operations/GriffinLimReconstructor.cs +++ b/NWaves/Operations/GriffinLimReconstructor.cs @@ -6,18 +6,18 @@ namespace NWaves.Operations { /// - /// Class for reconstructing signal from a given power / magnitude spectrogram + /// Represents reconstructing signal from a given power / magnitude spectrogram /// based on Griffin-Lim iterative algorithm. /// public class GriffinLimReconstructor { /// - /// STFT transformer + /// STFT transformer. /// private readonly Stft _stft; /// - /// Magnitude part of the spectrogram + /// Magnitude part of the spectrogram. /// private readonly List _magnitudes; @@ -54,15 +54,14 @@ public GriffinLimReconstructor(List spectrogram, Stft stft, int power = } /// - /// One iteration of reconstruction + /// Does one iteration of reconstruction and returns reconstructed signal at current step. /// /// Signal reconstructed at previous iteration - /// Reconstructed signal public float[] Iterate(float[] signal = null) { var magPhase = new MagnitudePhaseList() { Magnitudes = _magnitudes }; - if (signal == null) + if (signal is null) { var spectrumSize = _magnitudes[0].Length; @@ -87,10 +86,9 @@ public float[] Iterate(float[] signal = null) } /// - /// Reconstruct iteratively + /// Reconstructs signal from spectrogram iteratively. /// - /// - /// + /// Number of iterations in Griffin-Lim algorithm public float[] Reconstruct(int iterations = 20) { var reconstructed = Iterate(); diff --git a/NWaves/Operations/HarmonicPercussiveSeparator.cs b/NWaves/Operations/HarmonicPercussiveSeparator.cs index 9d6311a..b070ed2 100644 --- a/NWaves/Operations/HarmonicPercussiveSeparator.cs +++ b/NWaves/Operations/HarmonicPercussiveSeparator.cs @@ -6,42 +6,42 @@ namespace NWaves.Operations { + // D.Fitzgerald. Harmonic/percussive separation using median filtering. + // 13th International Conference on Digital Audio Effects (DAFX10), Graz, Austria, 2010. + /// - /// HPS based on median filtering. - /// - /// D.Fitzgerald. Harmonic/percussive separation using median filtering. - /// 13th International Conference on Digital Audio Effects (DAFX10), Graz, Austria, 2010. + /// Represents harmonic/percussive separator based on median filtering. /// public class HarmonicPercussiveSeparator { /// - /// Internal STFT transformer + /// Internal STFT transformer. /// private readonly Stft _stft; /// - /// Masking function + /// Masking function. /// private readonly Func _mask; /// - /// Median filter for time axis + /// Median filter along time axis. /// private readonly MedianFilter _medianHarmonic; /// - /// Median filter for frequency axis + /// Median filter along frequency axis. /// private readonly MedianFilter _medianPercussive; /// - /// Constructor + /// Constructs . /// - /// - /// - /// - /// - /// + /// FFT size + /// Hop length (number of samples) + /// Size of median filter along time axis + /// Size of median filter along frequency axis + /// Masking mode public HarmonicPercussiveSeparator(int fftSize = 2048, int hopSize = 512, int harmonicWinSize = 17, @@ -68,11 +68,9 @@ public HarmonicPercussiveSeparator(int fftSize = 2048, } /// - /// Evaluate harmonic and percussive mag-phase spectrograms from given signal. + /// Evaluates harmonic and percussive mag-phase spectrograms from given . /// Both spectrogram objects share the same phase array. /// - /// - /// public (MagnitudePhaseList, MagnitudePhaseList) EvaluateSpectrograms(DiscreteSignal signal) { // spectrogram memory will be reused for harmonic magnitudes @@ -131,10 +129,8 @@ public HarmonicPercussiveSeparator(int fftSize = 2048, } /// - /// Evaluate harmonic and percussive signals from given signal + /// Extracts harmonic and percussive signals from given . /// - /// - /// Harmonic signal and percussive signal public (DiscreteSignal, DiscreteSignal) EvaluateSignals(DiscreteSignal signal) { var (harmonicSpectrogram, percussiveSpectrogram) = EvaluateSpectrograms(signal); @@ -158,7 +154,7 @@ public HarmonicPercussiveSeparator(int fftSize = 2048, } /// - /// Masking mode for HPS algorithm + /// Masking modes for HPS algorithm. /// public enum HpsMasking { diff --git a/NWaves/Operations/Modulator.cs b/NWaves/Operations/Modulator.cs index da0eaca..c687bda 100644 --- a/NWaves/Operations/Modulator.cs +++ b/NWaves/Operations/Modulator.cs @@ -7,24 +7,22 @@ namespace NWaves.Operations { /// - /// Class providing modulation methods: - /// - /// - ring - /// - amplitude - /// - frequency - /// - phase - /// + /// Provides various modulation methods: + /// + /// ring + /// amplitude + /// frequency + /// phase + /// /// public class Modulator { /// - /// Ring modulation (RM) + /// Does ring modulation (RM) and returns RM signal. /// /// Carrier signal /// Modulator signal - /// RM signal - public DiscreteSignal Ring(DiscreteSignal carrier, - DiscreteSignal modulator) + public static DiscreteSignal Ring(DiscreteSignal carrier, DiscreteSignal modulator) { if (carrier.SamplingRate != modulator.SamplingRate) { @@ -36,15 +34,14 @@ public DiscreteSignal Ring(DiscreteSignal carrier, } /// - /// Amplitude modulation (AM) + /// Does amplitude modulation (AM) and returns AM signal. /// /// Carrier signal /// Modulator frequency /// Modulation index (depth) - /// AM signal - public DiscreteSignal Amplitude(DiscreteSignal carrier, - float modulatorFrequency = 20/*Hz*/, - float modulationIndex = 0.5f) + public static DiscreteSignal Amplitude(DiscreteSignal carrier, + float modulatorFrequency = 20/*Hz*/, + float modulationIndex = 0.5f) { var fs = carrier.SamplingRate; var mf = modulatorFrequency; // just short aliases // @@ -57,17 +54,16 @@ public DiscreteSignal Amplitude(DiscreteSignal carrier, } /// - /// Frequency modulation (FM) + /// Does frequency modulation (FM) and returns FM signal. /// /// Baseband signal /// Carrier amplitude /// Carrier frequency /// Frequency deviation - /// RM signal - public DiscreteSignal Frequency(DiscreteSignal baseband, - float carrierAmplitude, - float carrierFrequency, - float deviation = 0.1f/*Hz*/) + public static DiscreteSignal Frequency(DiscreteSignal baseband, + float carrierAmplitude, + float carrierFrequency, + float deviation = 0.1f/*Hz*/) { var fs = baseband.SamplingRate; var ca = carrierAmplitude; // just short aliases // @@ -82,7 +78,7 @@ public DiscreteSignal Frequency(DiscreteSignal baseband, } /// - /// Sinusoidal frequency modulation (FM) + /// Does sinusoidal frequency modulation (FM) and returns sinusoidal FM signal. /// /// Carrier signal frequency /// Carrier signal amplitude @@ -90,8 +86,7 @@ public DiscreteSignal Frequency(DiscreteSignal baseband, /// Modulation index (depth) /// Length of FM signal /// Sampling rate - /// Sinusoidal FM signal - public DiscreteSignal FrequencySinusoidal( + public static DiscreteSignal FrequencySinusoidal( float carrierFrequency, float carrierAmplitude, float modulatorFrequency, @@ -113,15 +108,14 @@ public DiscreteSignal FrequencySinusoidal( } /// - /// Linear frequency modulation (FM) + /// Does linear frequency modulation (FM) and returns FM signal. /// /// Carrier signal frequency /// Carrier signal amplitude /// Modulation index (depth) /// Length of FM signal /// Sampling rate - /// Sinusoidal FM signal - public DiscreteSignal FrequencyLinear( + public static DiscreteSignal FrequencyLinear( float carrierFrequency, float carrierAmplitude, float modulationIndex, @@ -140,17 +134,16 @@ public DiscreteSignal FrequencyLinear( } /// - /// Phase modulation (PM) + /// Does phase modulation (PM) and returns PM signal. /// /// Baseband signal /// Carrier amplitude /// Carrier frequency /// Frequency deviation - /// RM signal - public DiscreteSignal Phase(DiscreteSignal baseband, - float carrierAmplitude, - float carrierFrequency, - float deviation = 0.8f) + public static DiscreteSignal Phase(DiscreteSignal baseband, + float carrierAmplitude, + float carrierFrequency, + float deviation = 0.8f) { var fs = baseband.SamplingRate; var ca = carrierAmplitude; // just short aliases // @@ -163,57 +156,29 @@ public DiscreteSignal Phase(DiscreteSignal baseband, } /// - /// Simple amplitude demodulation based on Hilbert transform + /// Does simple amplitude demodulation of based on Hilbert transform. /// - /// - /// - public DiscreteSignal DemodulateAmplitude(DiscreteSignal signal) + public static DiscreteSignal DemodulateAmplitude(DiscreteSignal signal) { var ht = new HilbertTransform(signal.Length); - var mag = ht.AnalyticSignal(signal.Samples).Magnitude(); + var mag = ht.AnalyticSignal(signal.Samples).Magnitude; - return new DiscreteSignal(signal.SamplingRate, mag) - 1.0f; + return new DiscreteSignal(signal.SamplingRate, mag.ToFloats()) - 1.0f; } /// - /// Simple frequency demodulation based on Hilbert transform + /// Does simple frequency demodulation pf based on Hilbert transform. /// - /// - /// - public DiscreteSignal DemodulateFrequency(DiscreteSignal signal) + public static DiscreteSignal DemodulateFrequency(DiscreteSignal signal) { var diff = new float[signal.Length]; MathUtils.Diff(signal.Samples, diff); var ht = new HilbertTransform(signal.Length); - var mag = ht.AnalyticSignal(diff).Magnitude(); - - return new DiscreteSignal(signal.SamplingRate, mag) - 1.0f; - } - } - - /// - /// Class with extension methods for . - /// - public static class ModulatorExtensions - { - /// - /// Create array of magnitudes of complex numbers given as tuple of arrays (real and imaginary parts). - /// - /// Tuple of real-valued arrays (real and imaginary parts) - public static float[] Magnitude(this (float[], float[]) signal) - { - var (real, imag) = signal; - - var magnitude = new float[real.Length]; - - for (var i = 0; i < magnitude.Length; i++) - { - magnitude[i] = (float)Math.Sqrt(real[i] * real[i] + imag[i] * imag[i]); - } + var mag = ht.AnalyticSignal(diff).Magnitude; - return magnitude; + return new DiscreteSignal(signal.SamplingRate, mag.ToFloats()) - 1.0f; } } } diff --git a/NWaves/Operations/Operation.cs b/NWaves/Operations/Operation.cs index e7d9c37..9a9ead0 100644 --- a/NWaves/Operations/Operation.cs +++ b/NWaves/Operations/Operation.cs @@ -11,89 +11,72 @@ namespace NWaves.Operations { /// - /// Static class for DSP/audio operations. - /// - /// Main operations implemented: - /// - /// - convolution - /// - cross-correlation - /// - block convolution - /// - deconvolution - /// - resampling - /// - time-stretching - /// - rectification - /// - envelope detection - /// - spectral subtraction - /// - normalization (peak / RMS) - /// - periodogram (Welch / Lomb-Scargle) - /// + /// Provides methods for various DSP/audio operations: + /// + /// convolution + /// cross-correlation + /// block convolution + /// deconvolution + /// resampling + /// time-stretching + /// rectification + /// envelope detection + /// spectral subtraction + /// normalization (peak / RMS) + /// periodogram (Welch / Lomb-Scargle) + /// /// public static class Operation { /// - /// Fast convolution via FFT of real-valued signals. + /// Does fast convolution of with via FFT. /// - /// Signal - /// Convolution kernel - /// Convolution of signal with kernel public static DiscreteSignal Convolve(DiscreteSignal signal, DiscreteSignal kernel) { return new Convolver().Convolve(signal, kernel); } /// - /// Fast convolution via FFT for general complex-valued case + /// Does fast convolution of with via FFT. /// - /// Signal - /// Convolution kernel - /// Convolution of signal with kernel public static ComplexDiscreteSignal Convolve(ComplexDiscreteSignal signal, ComplexDiscreteSignal kernel) { return new ComplexConvolver().Convolve(signal, kernel); } /// - /// Fast convolution for double arrays (used mainly in filter design) + /// Does fast convolution of with via FFT. /// - /// Array of samples - /// Convolution kernel - /// Convolution of signal with kernel - public static double[] Convolve(double[] input, double[] kernel) + public static double[] Convolve(double[] signal, double[] kernel) { - return Convolve(new ComplexDiscreteSignal(1, input), + return Convolve(new ComplexDiscreteSignal(1, signal), new ComplexDiscreteSignal(1, kernel)).Real; } /// - /// Fast cross-correlation via FFT + /// Does fast cross-correlation between and via FFT. /// - /// First signal - /// Second signal - /// Cross-correlation between the first and the second signal public static DiscreteSignal CrossCorrelate(DiscreteSignal signal1, DiscreteSignal signal2) { return new Convolver().CrossCorrelate(signal1, signal2); } /// - /// Fast complex cross-correlation via FFT + /// Does fast cross-correlation between and via FFT. /// - /// First signal - /// Second signal - /// Cross-correlation between the first and the second signal public static ComplexDiscreteSignal CrossCorrelate(ComplexDiscreteSignal signal1, ComplexDiscreteSignal signal2) { return new ComplexConvolver().CrossCorrelate(signal1, signal2); } /// - /// Method implements block convolution of signals (using either OLA or OLS algorithm) + /// Does block convolution of with + /// (using either Overlap-Add or Overlap-Save algorithm). /// /// Signal /// Convolution kernel /// FFT size /// Block convolution method (OverlapAdd / OverlapSave) - /// Result of block convolution of signal with kernel public static DiscreteSignal BlockConvolve(DiscreteSignal signal, DiscreteSignal kernel, int fftSize, @@ -112,81 +95,71 @@ public static DiscreteSignal BlockConvolve(DiscreteSignal signal, return blockConvolver.ApplyTo(signal); } - + /// - /// Deconvolution via FFT for general complex-valued case. - /// - /// NOTE! - /// - /// Deconvolution is an experimental feature. - /// It's problematic due to division by zero. - /// + /// Deconvolves and . /// /// Signal /// Kernel - /// Deconvolved signal public static ComplexDiscreteSignal Deconvolve(ComplexDiscreteSignal signal, ComplexDiscreteSignal kernel) { return new ComplexConvolver().Deconvolve(signal, kernel); } /// - /// Interpolation followed by low-pass filtering + /// Does interpolation of followed by lowpass filtering. /// /// Signal /// Interpolation factor (e.g. factor=2 if 8000 Hz -> 16000 Hz) - /// Low-pass anti-aliasing filter - /// Interpolated signal + /// Lowpass anti-aliasing filter public static DiscreteSignal Interpolate(DiscreteSignal signal, int factor, FirFilter filter = null) { return new Resampler().Interpolate(signal, factor, filter); } /// - /// Decimation preceded by low-pass filtering + /// Does decimation of preceded by lowpass filtering. /// /// Signal /// Decimation factor (e.g. factor=2 if 16000 Hz -> 8000 Hz) - /// Low-pass anti-aliasing filter - /// Decimated signal + /// Lowpass anti-aliasing filter public static DiscreteSignal Decimate(DiscreteSignal signal, int factor, FirFilter filter = null) { return new Resampler().Decimate(signal, factor, filter); } /// - /// Band-limited resampling + /// Does band-limited resampling of . /// /// Signal /// Desired sampling rate - /// Low-pass anti-aliasing filter - /// Resampled signal - public static DiscreteSignal Resample(DiscreteSignal signal, int newSamplingRate, FirFilter filter = null) + /// Lowpass anti-aliasing filter + /// Order + public static DiscreteSignal Resample(DiscreteSignal signal, int newSamplingRate, FirFilter filter = null, int order = 15) { - return new Resampler().Resample(signal, newSamplingRate, filter); + return new Resampler().Resample(signal, newSamplingRate, filter, order); } /// - /// Simple resampling (as the combination of interpolation and decimation) + /// Does simple resampling of (as the combination of interpolation and decimation). /// /// Input signal /// Interpolation factor /// Decimation factor - /// Resampled signal - public static DiscreteSignal ResampleUpDown(DiscreteSignal signal, int up, int down) + /// Lowpass anti-aliasing filter + public static DiscreteSignal ResampleUpDown(DiscreteSignal signal, int up, int down, FirFilter filter = null) { - return new Resampler().ResampleUpDown(signal, up, down); + return new Resampler().ResampleUpDown(signal, up, down, filter); } /// - /// Time stretching with parameters set by user + /// Does time stretching of with parameters set by user. /// /// Signal /// Stretch factor (ratio) /// Window size (for vocoders - FFT size) - /// Hop size - /// Algorithm for TSM (optional) - /// Time stretched signal + /// Hop length + /// Algorithm for TSM public static DiscreteSignal TimeStretch(DiscreteSignal signal, double stretch, int windowSize, @@ -220,12 +193,11 @@ public static DiscreteSignal TimeStretch(DiscreteSignal signal, } /// - /// Time stretching with auto-derived parameters + /// Does time stretching of with auto-derived parameters. /// /// Signal /// Stretch factor (ratio) - /// Algorithm for TSM (optional) - /// Time stretched signal + /// Algorithm for TSM public static DiscreteSignal TimeStretch(DiscreteSignal signal, double stretch, TsmAlgorithm algorithm = TsmAlgorithm.PhaseVocoderPhaseLocking) @@ -259,12 +231,11 @@ public static DiscreteSignal TimeStretch(DiscreteSignal signal, } /// - /// Method for extracting the envelope of a signal + /// Extracts the envelope of . /// /// Signal /// Attack time (in seconds) /// Release time (in seconds) - /// Signal envelope public static DiscreteSignal Envelope(DiscreteSignal signal, float attackTime = 0.01f, float releaseTime = 0.05f) { var envelopeFollower = new EnvelopeFollower(signal.SamplingRate, attackTime, releaseTime); @@ -273,10 +244,8 @@ public static DiscreteSignal Envelope(DiscreteSignal signal, float attackTime = } /// - /// Full rectification + /// Full-rectifies . /// - /// Signal - /// Fully rectified signal public static DiscreteSignal FullRectify(DiscreteSignal signal) { return new DiscreteSignal(signal.SamplingRate, @@ -284,10 +253,8 @@ public static DiscreteSignal FullRectify(DiscreteSignal signal) } /// - /// Half rectification + /// Half-rectifies . /// - /// Signal - /// Half rectified signal public static DiscreteSignal HalfRectify(DiscreteSignal signal) { return new DiscreteSignal(signal.SamplingRate, @@ -295,23 +262,23 @@ public static DiscreteSignal HalfRectify(DiscreteSignal signal) } /// - /// Spectral subtraction + /// De-noises using spectral subtraction. + /// Subtracts from . /// /// Signal /// Noise signal /// FFT size /// Hop size (number of samples) - /// De-noised signal public static DiscreteSignal SpectralSubtract(DiscreteSignal signal, DiscreteSignal noise, int fftSize = 1024, - int hopSize = 410) + int hopSize = 256) { return new SpectralSubtractor(noise, fftSize, hopSize).ApplyTo(signal); } /// - /// Peak normalization + /// Normalizes peak level. /// /// Samples /// Peak level in decibels (dbFS), e.g. -1dB, -3dB, etc. @@ -326,7 +293,7 @@ public static void NormalizePeak(float[] samples, double peakDb) } /// - /// Peak normalization + /// Normalizes peak level. /// /// Signal /// Peak level in decibels (dBFS), e.g. -1dB, -3dB, etc. @@ -338,7 +305,7 @@ public static DiscreteSignal NormalizePeak(DiscreteSignal signal, double peakDb) } /// - /// Change peak level relatively to input samples (in-place) + /// Changes peak level relatively to input (in-place). /// /// Samples /// Peak change in decibels, e.g. -6dB - decrease peak level twice @@ -353,7 +320,7 @@ public static void ChangePeak(float[] samples, double peakDb) } /// - /// Change peak level relatively to input signal + /// Changes peak level relatively to input . /// /// Signal /// Peak change in decibels, e.g. -6dB - decrease peak level twice @@ -365,7 +332,7 @@ public static DiscreteSignal ChangePeak(DiscreteSignal signal, double peakDb) } /// - /// RMS normalization + /// Normalizes RMS. /// /// Samples /// RMS in decibels (dBFS), e.g. -6dB, -18dB, -26dB, etc. @@ -387,7 +354,7 @@ public static void NormalizeRms(float[] samples, double rmsDb) } /// - /// RMS normalization + /// Normalizes RMS. /// /// Signal /// RMS in decibels (dBFS), e.g. -6dB, -18dB, -26dB, etc. @@ -399,7 +366,7 @@ public static DiscreteSignal NormalizeRms(DiscreteSignal signal, double rmsDb) } /// - /// Change RMS relatively to input samples + /// Changes RMS relatively to input . /// /// Samples /// RMS change in decibels, e.g. -6dB - decrease RMS twice @@ -425,7 +392,7 @@ public static void ChangeRms(float[] samples, double rmsDb) } /// - /// Change RMS relatively to input signal + /// Changes RMS relatively to input . /// /// Signal /// RMS change in decibels, e.g. -6dB - decrease RMS twice @@ -437,7 +404,8 @@ public static DiscreteSignal ChangeRms(DiscreteSignal signal, double rmsDb) } /// - /// Welch periodogram + /// Computes periodogram using Welch's method. + /// If =0 then power spectrum is evaluated, otherwise power spectral density is evaluated. /// /// Signal /// Window size (number of samples) @@ -445,7 +413,6 @@ public static DiscreteSignal ChangeRms(DiscreteSignal signal, double rmsDb) /// Windowing function /// FFT size /// If sampling rate=0 then power spectrum is evaluated, otherwise power spectral density is evaluated - /// Welch periodogram public static float[] Welch(DiscreteSignal signal, int windowSize = 1024, int hopSize = 256, @@ -481,14 +448,13 @@ public static float[] Welch(DiscreteSignal signal, } /// - /// Lomb-Scargle periodogram + /// Computes the Lomb-Scargle periodogram. /// /// Sample times /// Signal values at sample times /// Angular frequencies for output periodogram /// Subtract mean from values before periodogram evaluation /// Normalize periodogram by the residuals of the data around a constant reference model(at zero) - /// Lomb-Scargle periodogram public static float[] LombScargle(float[] x, float[] y, float[] freqs, @@ -566,9 +532,6 @@ public static float[] LombScargle(float[] x, /// /// Direct convolution by formula in time domain /// - /// - /// - /// public static DiscreteSignal ConvolveDirect(DiscreteSignal signal1, DiscreteSignal signal2) { var a = signal1.Samples; @@ -594,9 +557,6 @@ public static DiscreteSignal ConvolveDirect(DiscreteSignal signal1, DiscreteSign /// /// Direct cross-correlation by formula in time domain /// - /// - /// - /// public static DiscreteSignal CrossCorrelateDirect(DiscreteSignal signal1, DiscreteSignal signal2) { var a = signal1.Samples; diff --git a/NWaves/Operations/Resampler.cs b/NWaves/Operations/Resampler.cs index b10ec54..106e4ed 100644 --- a/NWaves/Operations/Resampler.cs +++ b/NWaves/Operations/Resampler.cs @@ -7,23 +7,23 @@ namespace NWaves.Operations { /// - /// Class responsible for sampling rate conversion + /// Represents signal resampler (sampling rate converter). /// public class Resampler { /// - /// The order of FIR LP resampling filter (minimally required). - /// This constant should be used for simple up/down ratios. + /// Gets or sets the order of lowpass anti-aliasing FIR filter + /// that will be created automatically if the filter is not specified explicitly. + /// By default, 101. /// - private const int MinResamplingFilterOrder = 101; + public int MinResamplingFilterOrder { get; set; } = 101; /// - /// Interpolation followed by low-pass filtering + /// Does interpolation of followed by lowpass filtering. /// - /// - /// - /// - /// + /// Signal + /// Interpolation factor (e.g. factor=2 if 8000 Hz -> 16000 Hz) + /// Lowpass anti-aliasing filter public DiscreteSignal Interpolate(DiscreteSignal signal, int factor, FirFilter filter = null) { if (factor == 1) @@ -42,7 +42,7 @@ public DiscreteSignal Interpolate(DiscreteSignal signal, int factor, FirFilter f var lpFilter = filter; - if (filter == null) + if (filter is null) { var filterSize = factor > MinResamplingFilterOrder / 2 ? 2 * factor + 1 : @@ -55,12 +55,11 @@ public DiscreteSignal Interpolate(DiscreteSignal signal, int factor, FirFilter f } /// - /// Decimation preceded by low-pass filtering + /// Does decimation of preceded by lowpass filtering. /// - /// - /// - /// - /// + /// Signal + /// Decimation factor (e.g. factor=2 if 16000 Hz -> 8000 Hz) + /// Lowpass anti-aliasing filter public DiscreteSignal Decimate(DiscreteSignal signal, int factor, FirFilter filter = null) { if (factor == 1) @@ -72,11 +71,9 @@ public DiscreteSignal Decimate(DiscreteSignal signal, int factor, FirFilter filt 2 * factor + 1 : MinResamplingFilterOrder; - var lpFilter = filter; - - if (filter == null) + if (filter is null) { - lpFilter = new FirFilter(DesignFilter.FirWinLp(filterSize, 0.5f / factor)); + var lpFilter = new FirFilter(DesignFilter.FirWinLp(filterSize, 0.5f / factor)); signal = lpFilter.ApplyTo(signal); } @@ -94,13 +91,12 @@ public DiscreteSignal Decimate(DiscreteSignal signal, int factor, FirFilter filt } /// - /// Band-limited resampling + /// Does band-limited resampling of . /// - /// - /// - /// - /// - /// + /// Signal + /// Desired sampling rate + /// Lowpass anti-aliasing filter + /// Order public DiscreteSignal Resample(DiscreteSignal signal, int newSamplingRate, FirFilter filter = null, @@ -116,7 +112,7 @@ public DiscreteSignal Resample(DiscreteSignal signal, var input = signal.Samples; var output = new float[(int)(input.Length * g)]; - if (g < 1 && filter == null) + if (g < 1 && filter is null) { filter = new FirFilter(DesignFilter.FirWinLp(MinResamplingFilterOrder, g / 2)); @@ -149,13 +145,12 @@ public DiscreteSignal Resample(DiscreteSignal signal, } /// - /// Simple resampling as the combination of interpolation and decimation. + /// Does simple resampling of (as the combination of interpolation and decimation). /// - /// - /// - /// - /// - /// + /// Input signal + /// Interpolation factor + /// Decimation factor + /// Lowpass anti-aliasing filter public DiscreteSignal ResampleUpDown(DiscreteSignal signal, int up, int down, FirFilter filter = null) { if (up == down) @@ -181,7 +176,7 @@ public DiscreteSignal ResampleUpDown(DiscreteSignal signal, int up, int down, Fi var lpFilter = filter; - if (filter == null) + if (filter is null) { var factor = Math.Max(up, down); var filterSize = factor > MinResamplingFilterOrder / 2 ? diff --git a/NWaves/Operations/SpectralSubtractor.cs b/NWaves/Operations/SpectralSubtractor.cs index bca42c6..5e4c4da 100644 --- a/NWaves/Operations/SpectralSubtractor.cs +++ b/NWaves/Operations/SpectralSubtractor.cs @@ -5,25 +5,44 @@ namespace NWaves.Operations { + // Spectral subtraction algorithm: + // + // [1979] M. Berouti, R. Schwartz, J. Makhoul + // "Enhancement of Speech Corrupted by Acoustic Noise". + // + /// - /// Class that implements Spectral subtraction algorithm according to - /// - /// [1979] M. Berouti, R. Schwartz, J. Makhoul - /// "Enhancement of Speech Corrupted by Acoustic Noise". - /// + /// Represents spectral subtraction filter. /// public class SpectralSubtractor : OverlapAddFilter { - // Algorithm parameters - + /// + /// Gets or sets spectral floor (beta coefficient). + /// public float Beta { get; set; } = 0.009f; + + /// + /// Gets or sets min threshold for subtraction factor (alpha). + /// public float AlphaMin { get; set; } = 2f; + + /// + /// Gets or sets max threshold for subtraction factor (alpha). + /// public float AlphaMax { get; set; } = 5f; + + /// + /// Gets or sets min SNR value (in dB). + /// public float SnrMin { get; set; } = -5f; + + /// + /// Gets or sets max SNR value (in dB). + /// public float SnrMax { get; set; } = 20f; /// - /// Noise estimate + /// Noise estimate. /// private readonly float[] _noiseEstimate; @@ -34,11 +53,11 @@ public class SpectralSubtractor : OverlapAddFilter private readonly float[] _noiseAcc; /// - /// Constructor from float[] noise + /// Constructs . /// - /// - /// - /// + /// Array of noise samples + /// FFT size + /// Hop length (number of samples) public SpectralSubtractor(float[] noise, int fftSize = 1024, int hopSize = 128) : base(hopSize, fftSize) { _noiseEstimate = new float[_fftSize / 2 + 1]; @@ -50,18 +69,18 @@ public SpectralSubtractor(float[] noise, int fftSize = 1024, int hopSize = 128) } /// - /// Constructor from DiscreteSignal noise + /// Constructs . /// - /// - /// - /// + /// Noise signal + /// FFT size + /// Hop length (number of samples) public SpectralSubtractor(DiscreteSignal noise, int fftSize = 1024, int hopSize = 128) : this(noise.Samples, fftSize, hopSize) { } /// - /// Process one spectrum at each STFT step + /// Processes one spectrum at each STFT step. /// /// Real parts of input spectrum /// Imaginary parts of input spectrum @@ -95,11 +114,11 @@ protected override void ProcessSpectrum(float[] re, } /// - /// Estimate noise power spectrum + /// Estimates power spectrum of . /// - /// - /// - /// + /// Array of noise samples + /// Index of the first sample in array for processing + /// Index of the last sample in array for processing public void EstimateNoise(float[] noise, int startPos = 0, int endPos = -1) { if (endPos < 0) @@ -130,11 +149,11 @@ public void EstimateNoise(float[] noise, int startPos = 0, int endPos = -1) } /// - /// Estimate noise power spectrum + /// Estimates power spectrum of signal. /// - /// - /// - /// + /// Noise signal + /// Index of the first sample in signal + /// Index of the last sample in signal public void EstimateNoise(DiscreteSignal noise, int startPos = 0, int endPos = -1) { EstimateNoise(noise.Samples, startPos, endPos); diff --git a/NWaves/Operations/Tsm/PaulStretch.cs b/NWaves/Operations/Tsm/PaulStretch.cs index 674ed6e..76deb59 100644 --- a/NWaves/Operations/Tsm/PaulStretch.cs +++ b/NWaves/Operations/Tsm/PaulStretch.cs @@ -3,30 +3,29 @@ namespace NWaves.Operations.Tsm { /// - /// TSM processor based on Paul stretch algorithm + /// Represents TSM processor based on Paul stretch algorithm. /// class PaulStretch : PhaseVocoder { /// - /// Randomizer for phases + /// Randomizer for phases. /// private readonly Random _rand = new Random(); /// - /// Constructor + /// Constructs . /// - /// - /// - /// - public PaulStretch(double stretch, int hopAnalysis, int fftSize = 0) - : base(stretch, hopAnalysis, fftSize) + /// Stretch ratio + /// Hop length at analysis stage + /// FFT size + public PaulStretch(double stretch, int hopAnalysis, int fftSize = 0) : base(stretch, hopAnalysis, fftSize) { } /// - /// Process spectrum at each STFT step: simply randomize phases + /// Processes spectrum at each STFT step: simply randomizes phases. /// - public override void ProcessSpectrum() + protected override void ProcessSpectrum() { for (var j = 1; j <= _fftSize / 2; j++) { @@ -39,7 +38,7 @@ public override void ProcessSpectrum() } /// - /// Reset (nothing to do here) + /// Resets TSM processor. /// public override void Reset() { diff --git a/NWaves/Operations/Tsm/PhaseLockingVocoder.cs b/NWaves/Operations/Tsm/PhaseLockingVocoder.cs index a239041..dccabc2 100644 --- a/NWaves/Operations/Tsm/PhaseLockingVocoder.cs +++ b/NWaves/Operations/Tsm/PhaseLockingVocoder.cs @@ -4,39 +4,37 @@ namespace NWaves.Operations.Tsm { /// - /// Phase vocoder with identity phase locking [Puckette]. + /// Represents Phase Vocoder with identity phase locking [Puckette]. /// public class PhaseLockingVocoder : PhaseVocoder { /// - /// Array of spectrum magnitudes (at current step) + /// Array of spectrum magnitudes (at current step). /// private readonly double[] _mag; /// - /// Array of spectrum phases (at current step) + /// Array of spectrum phases (at current step). /// private readonly double[] _phase; /// - /// Array of phase deltas + /// Array of phase deltas. /// private readonly double[] _delta; /// - /// Array of peak positions (indices) + /// Array of peak positions (indices). /// private readonly int[] _peaks; /// - /// Constructor + /// Constructs . /// - /// - /// - /// - /// - public PhaseLockingVocoder(double stretch, int hopAnalysis, int fftSize = 0) - : base(stretch, hopAnalysis, fftSize) + /// Stretch ratio + /// Hop length at analysis stage + /// FFT size + public PhaseLockingVocoder(double stretch, int hopAnalysis, int fftSize = 0) : base(stretch, hopAnalysis, fftSize) { _mag = new double[_fftSize / 2 + 1]; _phase = new double[_fftSize / 2 + 1]; @@ -45,9 +43,9 @@ public PhaseLockingVocoder(double stretch, int hopAnalysis, int fftSize = 0) } /// - /// Process spectrum with phase-locking at each STFT step + /// Processes spectrum with phase-locking at each STFT step. /// - public override void ProcessSpectrum() + protected override void ProcessSpectrum() { for (var j = 0; j < _mag.Length; j++) { diff --git a/NWaves/Operations/Tsm/PhaseVocoder.cs b/NWaves/Operations/Tsm/PhaseVocoder.cs index c1ebf5d..5a78ed2 100644 --- a/NWaves/Operations/Tsm/PhaseVocoder.cs +++ b/NWaves/Operations/Tsm/PhaseVocoder.cs @@ -9,37 +9,37 @@ namespace NWaves.Operations.Tsm { /// - /// Conventional Phase Vocoder + /// Represents Phase Vocoder. /// public class PhaseVocoder : IFilter { /// - /// Hop size at analysis stage (STFT decomposition) + /// Hop size at analysis stage (STFT decomposition). /// protected readonly int _hopAnalysis; /// - /// Hop size at synthesis stage (STFT merging) + /// Hop size at synthesis stage (STFT merging). /// protected readonly int _hopSynthesis; /// - /// Size of FFT for analysis and synthesis + /// Size of FFT for analysis and synthesis. /// protected readonly int _fftSize; /// - /// Stretch ratio + /// Stretch ratio. /// protected readonly double _stretch; /// - /// Internal FFT transformer + /// Internal FFT transformer. /// protected readonly RealFft _fft; /// - /// Window coefficients + /// Window coefficients. /// protected readonly float[] _window; @@ -49,36 +49,36 @@ public class PhaseVocoder : IFilter protected readonly float _gain; /// - /// Linearly spaced frequencies + /// Linearly spaced frequencies. /// protected readonly double[] _omega; /// - /// Internal buffer for real parts of analyzed block + /// Internal buffer for real parts of analyzed block. /// protected readonly float[] _re; /// - /// Internal buffer for imaginary parts of analyzed block + /// Internal buffer for imaginary parts of analyzed block. /// protected readonly float[] _im; /// - /// Array of phases computed at previous step + /// Array of phases computed at previous step. /// protected readonly double[] _prevPhase; /// - /// Array of new synthesized phases + /// Array of new synthesized phases. /// protected readonly double[] _phaseTotal; /// - /// Constructor + /// Constructs . /// - /// - /// - /// + /// Stretch ratio + /// Hop length at analysis stage + /// FFT size public PhaseVocoder(double stretch, int hopAnalysis, int fftSize = 0) { _stretch = stretch; @@ -104,13 +104,9 @@ public PhaseVocoder(double stretch, int hopAnalysis, int fftSize = 0) } /// - /// Phase Vocoder algorithm + /// Processes entire and returns new time-stretched signal. /// - /// - /// - /// - public DiscreteSignal ApplyTo(DiscreteSignal signal, - FilteringMethod method = FilteringMethod.Auto) + public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { var input = signal.Samples; var output = new float[(int)(input.Length * _stretch) + _fftSize]; @@ -155,10 +151,10 @@ public DiscreteSignal ApplyTo(DiscreteSignal signal, } /// - /// Process one spectrum at each STFT step. + /// Processes one spectrum at each STFT step. /// This routine is different for different PV-based techniques. /// - public virtual void ProcessSpectrum() + protected virtual void ProcessSpectrum() { for (var j = 1; j <= _fftSize / 2; j++) { @@ -181,7 +177,7 @@ public virtual void ProcessSpectrum() } /// - /// Reset phase vocoder + /// Resets phase vocoder. /// public virtual void Reset() { diff --git a/NWaves/Operations/Tsm/TsmAlgorithm.cs b/NWaves/Operations/Tsm/TsmAlgorithm.cs index c3c78f2..f301b89 100644 --- a/NWaves/Operations/Tsm/TsmAlgorithm.cs +++ b/NWaves/Operations/Tsm/TsmAlgorithm.cs @@ -1,27 +1,27 @@ namespace NWaves.Operations.Tsm { /// - /// Algorithm for time scale modification + /// Time scale modification algorithms. /// public enum TsmAlgorithm { /// - /// Phase vocoder + /// Phase vocoder. /// PhaseVocoder = 0, /// - /// Phase vocoder with phase-locking + /// Phase vocoder with phase-locking. /// PhaseVocoderPhaseLocking = 1, /// - /// Waveform similarity-based Synchrnoized Overlap-Add + /// Waveform similarity-based Synchrnoized Overlap-Add. /// Wsola = 2, /// - /// Paul stretch + /// Paul stretch. /// PaulStretch = 3 } diff --git a/NWaves/Operations/Tsm/Wsola.cs b/NWaves/Operations/Tsm/Wsola.cs index 8cedbb9..9a5d8c2 100644 --- a/NWaves/Operations/Tsm/Wsola.cs +++ b/NWaves/Operations/Tsm/Wsola.cs @@ -9,57 +9,58 @@ namespace NWaves.Operations.Tsm { /// - /// Waveform-Synchronized Overlap-Add + /// Represents TSM processor based on Waveform-Synchronized Overlap-Add (WSOLA) technique. /// public class Wsola : IFilter { /// - /// Stretch ratio + /// Stretch ratio. /// protected readonly double _stretch; /// - /// Window size + /// Window size. /// private int _windowSize; /// - /// Hop size at analysis stage (STFT decomposition) + /// Hop size at analysis stage (STFT decomposition). /// private int _hopAnalysis; /// - /// Hop size at synthesis stage (STFT merging) + /// Hop size at synthesis stage (STFT merging). /// private int _hopSynthesis; /// - /// Maximum length of the fragment for search of the most similar waveform + /// Maximum length of the fragment for search of the most similar waveform. /// private int _maxDelta; /// - /// True if parameters were set by user (not by default) + /// True if parameters were set by user (not by default). /// private readonly bool _userParameters; /// /// Internal convolver - /// (will be used for evaluating auto-correlation if the window size is too big) + /// (will be used for evaluating auto-correlation if the window size is too big). /// private Convolver _convolver; /// - /// Cross-correlation signal + /// Cross-correlation signal. /// private float[] _cc; - /// - /// Constructor with detailed WSOLA settings + /// Constructs TSM processor. /// /// Stretch ratio - /// + /// Window size + /// Hop size at analysis stage + /// Max delta in WSOLA algorithm public Wsola(double stretch, int windowSize, int hopAnalysis, int maxDelta = 0) { _stretch = stretch; @@ -74,9 +75,9 @@ public Wsola(double stretch, int windowSize, int hopAnalysis, int maxDelta = 0) } /// - /// Constructor with smart parameter autoderivation + /// Constructs TSM processor and auto-derives WSOLA parameters for given ratio. /// - /// + /// Stretch ratio public Wsola(double stretch) { _stretch = stretch; @@ -111,7 +112,7 @@ public Wsola(double stretch) } /// - /// For large window sizes prepare the internal convolver + /// Prepares the internal convolver (for large window sizes). /// private void PrepareConvolver() { @@ -125,13 +126,9 @@ private void PrepareConvolver() } /// - /// WSOLA algorithm + /// Processes entire and returns new time-stretched signal. /// - /// - /// - /// - public DiscreteSignal ApplyTo(DiscreteSignal signal, - FilteringMethod method = FilteringMethod.Auto) + public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) { // adjust default parameters for a new sampling rate @@ -197,20 +194,19 @@ public DiscreteSignal ApplyTo(DiscreteSignal signal, } /// - /// Position of the best found waveform similarity + /// Finds position of the best waveform similarity. /// - /// - /// - /// - /// - public int WaveformSimilarityPos(float[] current, float[] prev, int maxDelta) + /// Current window + /// Previous window + /// Max delta + protected int WaveformSimilarityPos(float[] current, float[] prev, int maxDelta) { var optimalShift = 0; var maxCorrelation = 0.0f; // for small window sizes cross-correlate directly: - if (_convolver == null) + if (_convolver is null) { for (var i = 0; i < maxDelta; i++) { diff --git a/NWaves/Operations/WaveShaper.cs b/NWaves/Operations/WaveShaper.cs index b1a2fb1..bffa5b0 100644 --- a/NWaves/Operations/WaveShaper.cs +++ b/NWaves/Operations/WaveShaper.cs @@ -4,21 +4,44 @@ namespace NWaves.Operations { + /// + /// Represents wave shaper. + /// + /// Wave shaper is a filter that maps an input signal to the output signal + /// by applying arbitrary mathematical function (shaping function) to the input signal. + /// + /// public class WaveShaper : IFilter, IOnlineFilter { - private readonly Func _waveShaperFunction; + private readonly Func _waveShapingFunction; - public WaveShaper(Func waveShaperFunction) + /// + /// Constructs using . + /// + /// Wave shaping function + public WaveShaper(Func waveShapingFunction) { - _waveShaperFunction = waveShaperFunction; + _waveShapingFunction = waveShapingFunction; } - public float Process(float input) => _waveShaperFunction(input); + /// + /// Processes one sample. + /// + /// Input sample + public float Process(float sample) => _waveShapingFunction(sample); + /// + /// Resets wave shaper. + /// public void Reset() { } + /// + /// Processes entire and returns new wave-shaped signal. + /// + /// Input signal + /// Filtering method public DiscreteSignal ApplyTo(DiscreteSignal signal, FilteringMethod method = FilteringMethod.Auto) => this.FilterOnline(signal); } } diff --git a/NWaves/Transforms/HilbertTransform.cs b/NWaves/Transforms/HilbertTransform.cs index 5e7382d..dd16bf7 100644 --- a/NWaves/Transforms/HilbertTransform.cs +++ b/NWaves/Transforms/HilbertTransform.cs @@ -1,11 +1,12 @@ -using NWaves.Transforms.Base; +using NWaves.Signals; +using NWaves.Transforms.Base; using NWaves.Utils; using System; namespace NWaves.Transforms { /// - /// Class representing Fast Hilbert Transform. + /// Represents Fast Hilbert Transform. /// public class HilbertTransform : ITransform { @@ -30,9 +31,8 @@ public class HilbertTransform : ITransform private readonly float[] _im; /// - /// Construct Hilbert transformer. Transform must be a power of 2. + /// Constructs Hilbert transformer. Transform must be a power of 2. /// - /// Size of Hilbert Transform public HilbertTransform(int size = 512) { Size = size; @@ -42,10 +42,10 @@ public HilbertTransform(int size = 512) } /// - /// Compute complex analytic signal (real and imaginary parts) from . + /// Computes complex analytic signal (real and imaginary parts) from . /// /// Input data - public (float[], float[]) AnalyticSignal(float[] input) + public ComplexDiscreteSignal AnalyticSignal(float[] input) { Direct(input, _im); @@ -54,12 +54,12 @@ public HilbertTransform(int size = 512) _re[i] /= Size; _im[i] /= Size; } - - return (_re.FastCopy(), _im.FastCopy()); + + return new ComplexDiscreteSignal(1, _re.ToDoubles(), _im.ToDoubles(), allocateNew: true); } /// - /// Do Fast Hilbert Transform. + /// Does Fast Hilbert Transform. /// /// Input data /// Output data @@ -91,7 +91,7 @@ public void Direct(float[] input, float[] output) } /// - /// Do normalized Fast Hilbert Transform. + /// Does normalized Fast Hilbert Transform. /// /// Input data /// Output data @@ -106,7 +106,7 @@ public void DirectNorm(float[] input, float[] output) } /// - /// Do Inverse Fast Hilbert Transform. + /// Does Inverse Fast Hilbert Transform. /// /// Input data /// Output data @@ -121,7 +121,7 @@ public void Inverse(float[] input, float[] output) } /// - /// Do normalized Inverse Fast Hilbert Transform. + /// Does normalized Inverse Fast Hilbert Transform. /// /// Input data /// Output data diff --git a/NWaves/Transforms/HilbertTransform64.cs b/NWaves/Transforms/HilbertTransform64.cs index 731e50b..e6ca7bb 100644 --- a/NWaves/Transforms/HilbertTransform64.cs +++ b/NWaves/Transforms/HilbertTransform64.cs @@ -5,7 +5,7 @@ namespace NWaves.Transforms { /// - /// Class representing Fast Hilbert Transform (for 64-bit data). + /// Represents Fast Hilbert Transform (for 64-bit data). /// public class HilbertTransform64 { @@ -30,9 +30,8 @@ public class HilbertTransform64 private readonly double[] _im; /// - /// Construct Hilbert transformer. Transform must be a power of 2. + /// Constructs Hilbert transformer. Transform must be a power of 2. /// - /// Size of Hilbert Transform public HilbertTransform64(int size = 512) { Size = size; @@ -42,7 +41,7 @@ public HilbertTransform64(int size = 512) } /// - /// Compute complex analytic signal (real and imaginary parts) from . + /// Computes complex analytic signal (real and imaginary parts) from . /// /// Input data public ComplexDiscreteSignal AnalyticSignal(double[] input) @@ -59,7 +58,7 @@ public ComplexDiscreteSignal AnalyticSignal(double[] input) } /// - /// Do Fast Hilbert Transform. + /// Does Fast Hilbert Transform. /// /// Input data /// Output data @@ -91,7 +90,7 @@ public void Direct(double[] input, double[] output) } /// - /// Do normalized Fast Hilbert Transform. + /// Does normalized Fast Hilbert Transform. /// /// Input data /// Output data @@ -106,7 +105,7 @@ public void DirectNorm(double[] input, double[] output) } /// - /// Do Inverse Fast Hilbert Transform. + /// Does Inverse Fast Hilbert Transform. /// /// Input data /// Output data @@ -121,7 +120,7 @@ public void Inverse(double[] input, double[] output) } /// - /// Do normalized Inverse Fast Hilbert Transform. + /// Does normalized Inverse Fast Hilbert Transform. /// /// Input data /// Output data diff --git a/NWaves/Utils/FractionalDelayLine.cs b/NWaves/Utils/FractionalDelayLine.cs index 13bb43e..6abc56d 100644 --- a/NWaves/Utils/FractionalDelayLine.cs +++ b/NWaves/Utils/FractionalDelayLine.cs @@ -3,44 +3,44 @@ namespace NWaves.Utils { /// - /// Fractional delay line + /// Represents fractional delay line. /// public partial class FractionalDelayLine { /// - /// Interpolation mode + /// Gets or sets interpolation mode. /// public InterpolationMode InterpolationMode { get; set; } /// - /// Delay line + /// Gets the size of delay line (number of samples). /// - private float[] _delayLine; + public int Size => _delayLineSize; + private int _delayLineSize; /// - /// Delay line size + /// Delay line. /// - private int _delayLineSize; - public int Size => _delayLineSize; + private float[] _delayLine; /// - /// Current write position + /// Current write position. /// private int _n; /// - /// Used in InterpolationMode.Thiran + /// Previously interpolated sample (used with InterpolationMode.Thiran). /// private float _prevInterpolated; /// - /// Constructor + /// Constructs and reserves given for its samples. /// - /// Max delay in samples + /// Delay line size (number of samples) /// Interpolation mode - public FractionalDelayLine(int maxDelayInSamples, InterpolationMode interpolationMode = InterpolationMode.Linear) + public FractionalDelayLine(int size, InterpolationMode interpolationMode = InterpolationMode.Linear) { - _delayLineSize = Math.Max(4, maxDelayInSamples); + _delayLineSize = Math.Max(4, size); _delayLine = new float[_delayLineSize]; _n = 0; @@ -48,10 +48,11 @@ public FractionalDelayLine(int maxDelayInSamples, InterpolationMode interpolatio } /// - /// Constructor + /// Constructs and reserves the size + /// corresponding to seconds. /// /// Sampling rate - /// Max delay in seconds + /// Max delay (in seconds) /// Interpolation mode public FractionalDelayLine(int samplingRate, double maxDelay, @@ -61,9 +62,8 @@ public FractionalDelayLine(int samplingRate, } /// - /// Write (put) sample in the delay line + /// Writes (puts) to the delay line. /// - /// public void Write(float sample) { _delayLine[_n] = sample; @@ -75,10 +75,8 @@ public void Write(float sample) } /// - /// Read (get) sample from the delay line corresponding to given time delay (in seconds) + /// Reads (gets) sample from the delay line corresponding to given time (in seconds). /// - /// - /// public float Read(double delay) { var precisePosition = (float)(_n - delay + _delayLineSize) % _delayLineSize; @@ -153,7 +151,7 @@ public float Read(double delay) } /// - /// Reset delay line + /// Resets delay line. /// public void Reset() { @@ -163,23 +161,27 @@ public void Reset() } /// - /// Resize delay line to ensure new size + /// Resizes delay line to ensure new . + /// If does not exceed current size of the delay line then nothing happens. /// - public void Ensure(int maxDelayInSamples) + public void Ensure(int size) { - if (maxDelayInSamples <= _delayLineSize) + if (size <= _delayLineSize) { return; } - Array.Resize(ref _delayLine, maxDelayInSamples); + Array.Resize(ref _delayLine, size); - _delayLineSize = maxDelayInSamples; + _delayLineSize = size; } /// - /// Resize delay line to ensure new size + /// Resizes delay line to ensure new size corresponding to seconds. + /// If the new size does not exceed current size of the delay line then nothing happens. /// + /// Sampling rate + /// Max delay (in seconds) public void Ensure(int samplingRate, double maxDelay) { Ensure((int)(samplingRate * maxDelay) + 1); diff --git a/NWaves/Utils/Guard.cs b/NWaves/Utils/Guard.cs index 35c2f72..c112d56 100644 --- a/NWaves/Utils/Guard.cs +++ b/NWaves/Utils/Guard.cs @@ -4,13 +4,13 @@ namespace NWaves.Utils { /// - /// Static class containing the most widely used contracts / guard clauses + /// Contains the most widely used contracts / guard clauses. /// [DebuggerStepThrough] public static class Guard { /// - /// Guard against negative number or zero + /// Guards against negative number or zero. /// /// Argument (number) /// Argument name @@ -23,7 +23,7 @@ public static void AgainstNonPositive(double arg, string argName = "argument") } /// - /// Guard against inequality of two arguments + /// Guards against inequality of two arguments. /// /// The first argument /// The second argument @@ -38,7 +38,7 @@ public static void AgainstInequality(double arg1, double arg2, string arg1Name = } /// - /// Guard against the number being not in the given range + /// Guards against the number being not in the given range. /// /// Argument (number) /// Lower boundary of the range @@ -53,7 +53,7 @@ public static void AgainstInvalidRange(double value, double low, double high, st } /// - /// Guard against the case when the first and the second arguments are not valid boundaries of a range + /// Guards against the case when the first and the second arguments are not valid boundaries of a range. /// /// The first argument /// The second argument @@ -68,7 +68,7 @@ public static void AgainstInvalidRange(double low, double high, string lowName = } /// - /// Guard against the first argument exceeding the second argument + /// Guards against the first argument exceeding the second argument. /// /// The first argument /// The second argument @@ -83,7 +83,7 @@ public static void AgainstExceedance(double low, double high, string lowName = " } /// - /// Guard against integer number being not power of 2 (e.g. 8, 16, 128, etc.) + /// Guards against integer number being not power of 2 (e.g. 8, 16, 128, etc.) /// /// Argument (number) /// Argument name @@ -98,7 +98,7 @@ public static void AgainstNotPowerOfTwo(int n, string argName = "Parameter") } /// - /// Guard against even integer number + /// Guards against even integer number. /// /// Argument (number) /// Argument name @@ -111,7 +111,7 @@ public static void AgainstEvenNumber(int n, string argName = "Parameter") } /// - /// Guard against not ordered and not unique array + /// Guards against not ordered and not unique array. /// /// Argument (array of values) /// Argument name @@ -127,7 +127,7 @@ public static void AgainstNotOrdered(double[] values, string argName = "Values") } /// - /// Guard against incorrect parameters for (equiripple) filter design + /// Guards against incorrect parameters for (equiripple) filter design. /// /// Frequencies /// Desired magnitude response (gains) diff --git a/NWaves/Utils/Lpc.cs b/NWaves/Utils/Lpc.cs index 5c8de18..cda14bd 100644 --- a/NWaves/Utils/Lpc.cs +++ b/NWaves/Utils/Lpc.cs @@ -8,17 +8,17 @@ namespace NWaves.Utils { /// - /// Functions related to Linear Predictive Coding + /// Provides functions related to Linear Predictive Coding (LPC). /// public static class Lpc { /// - /// Levinson-Durbin algorithm for solving main LPC task + /// Evaluates LP coefficients using Levinson-Durbin algorithm and returns prediction error. /// /// Auto-correlation vector /// LP coefficients /// Order of LPC - /// Prediction error + /// Optional offset in auto-correlation vector public static float LevinsonDurbin(float[] input, float[] a, int order, int offset = 0) { var err = input[offset]; @@ -49,11 +49,11 @@ public static float LevinsonDurbin(float[] input, float[] a, int order, int offs } /// - /// Convert LPC coefficients to cepstrum (LPCC) + /// Converts LPC coefficients to LPC cepstrum (LPCC). /// - /// - /// - /// + /// LPC vector + /// Gain + /// LPC cepstrum public static void ToCepstrum(float[] lpc, float gain, float[] lpcc) { var n = lpcc.Length; @@ -83,17 +83,14 @@ public static void ToCepstrum(float[] lpc, float gain, float[] lpcc) } /// - /// Convert LPCC coefficients to LPC and gain - /// - /// Formulae: https://www.mathworks.com/help/dsp/ref/lpctofromcepstralcoefficients.html - /// + /// Converts LPC cepstrum to LPC coefficients and returns gain. /// - /// - /// - /// + /// LPC cepstrum + /// LPC vector public static float FromCepstrum(float[] lpcc, float[] lpc) { - var n = lpcc.Length; + // Formulae: https://www.mathworks.com/help/dsp/ref/lpctofromcepstralcoefficients.html + var p = lpc.Length; // must be lpcOrder + 1 (!) lpc[0] = 1; @@ -112,21 +109,20 @@ public static float FromCepstrum(float[] lpcc, float[] lpc) } /// - /// Method returns LPC order for a given sampling rate - /// according to the best practices. + /// Estimates LPC order for a given according to the best practices. /// /// Sampling rate - /// LPC order public static int EstimateOrder(int samplingRate) { return 2 + samplingRate / 1000; } /// - /// Convert LPC coefficients to Line Spectral Frequencies + /// Converts LPC coefficients to Line Spectral Frequencies . + /// The length of must be equal to length. Last element will be PI. /// - /// - /// The length must be equal to lpc length. Last element will be PI + /// LPC vector + /// Line spectral frequencies public static void ToLsf(float[] lpc, float[] lsf) { var first = lpc[0]; @@ -170,10 +166,11 @@ public static void ToLsf(float[] lpc, float[] lsf) } /// - /// Convert Line Spectral Frequencies to LPC coefficients + /// Converts Line Spectral Frequencies to LPC coefficients. + /// The length of must be equal to length. Last element must be PI. /// - /// The length must be equal to lpc length. Last element must be PI - /// + /// Line spectral frequencies + /// LPC vector public static void FromLsf(float[] lsf, float[] lpc) { var n = lsf.Length - 1; diff --git a/NWaves/Utils/MathUtils.cs b/NWaves/Utils/MathUtils.cs index 2415dd3..b9c2da9 100644 --- a/NWaves/Utils/MathUtils.cs +++ b/NWaves/Utils/MathUtils.cs @@ -4,32 +4,28 @@ namespace NWaves.Utils { /// - /// Static class providing some helpful math functions + /// Provides helpful math functions. /// public static class MathUtils { /// - /// Sinc-function + /// Returns Sinc of . /// - /// Argument - /// sinc(x) public static double Sinc(double x) { return Math.Abs(x) > 1e-20 ? Math.Sin(Math.PI * x) / (Math.PI * x) : 1.0; } /// - /// Method for computing next power of 2 (closest to the given number) + /// Returns next power of 2 closest to the given number . /// - /// Number - /// Next power of 2 closest to the number public static int NextPowerOfTwo(int n) { return (int)Math.Pow(2, Math.Ceiling(Math.Log(n, 2))); } /// - /// Greatest Common Divisor + /// Finds Greatest Common Divisor. /// public static int Gcd(int n, int m) { @@ -41,31 +37,24 @@ public static int Gcd(int n, int m) } /// - /// Modulo function that works correctly with negative numbers (as np.mod) + /// Modulo function that works correctly with negative numbers (as np.mod). /// - /// - /// - /// public static double Mod(double a, double b) { return ((a % b) + b) % b; } /// - /// Inverse sinh + /// Computes Inverse Sinh of . /// - /// - /// public static double Asinh(double x) { return Math.Log(x + Math.Sqrt(x * x + 1)); } /// - /// Factorial + /// Computes factorial !. /// - /// - /// public static double Factorial(int n) { var f = 1.0; @@ -76,21 +65,16 @@ public static double Factorial(int n) } /// - /// Binomial coefficient + /// Evaluates Binomial coefficient. /// - /// - /// - /// public static double BinomialCoefficient(int k, int n) { return Factorial(n) / (Factorial(k) * Factorial(n - k)); } /// - /// Diff signal (1st order derivative) + /// Evaluate discrete difference of (array of the 1st order derivatives). /// - /// - /// public static void Diff(float[] samples, float[] diff) { diff[0] = samples[0]; @@ -102,13 +86,8 @@ public static void Diff(float[] samples, float[] diff) } /// - /// Linear interpolation (as numpy.interp) + /// Does linear interpolation (as numpy.interp). /// - /// - /// - /// - /// - /// public static void InterpolateLinear(float[] x, float[] y, float[] arg, float[] interp) { var left = 0; @@ -127,10 +106,10 @@ public static void InterpolateLinear(float[] x, float[] y, float[] arg, float[] } /// - /// Bilinear transform (in-place) + /// Does bilinear transform (in-place). /// - /// - /// + /// Real parts of complex values + /// Imaginary parts of complex values public static void BilinearTransform(double[] re, double[] im) { for (var k = 0; k < re.Length; k++) @@ -154,11 +133,10 @@ public static void BilinearTransform(double[] re, double[] im) } /// - /// Unwrap (phase) + /// Unwraps phase. /// - /// + /// Phase array /// Jump size - /// public static double[] Unwrap(double[] phase, double tolerance = Math.PI) { var unwrapped = phase.FastCopy(); @@ -185,11 +163,10 @@ public static double[] Unwrap(double[] phase, double tolerance = Math.PI) } /// - /// Wrap (phase) + /// Wraps phase. /// - /// + /// Phase array /// Jump size - /// public static double[] Wrap(double[] phase, double tolerance = Math.PI) { var wrapped = phase.FastCopy(); @@ -214,13 +191,8 @@ public static double[] Wrap(double[] phase, double tolerance = Math.PI) } /// - /// Nth order statistics + /// Finds -th order statistics (n-th smallest value in array ). /// - /// - /// - /// - /// - /// public static float FindNth(float[] a, int n, int start, int end) { while (true) @@ -260,21 +232,19 @@ public static float FindNth(float[] a, int n, int start, int end) } /// - /// Modified Bessel function of the 1st kind (Taylor series, not very precise method) + /// Modified Bessel function I0() of the 1st kind + /// (using Taylor series, not very precise method). /// - /// x - /// I0(x) public static double I0(double x) { - double y = 1.0; - double prev = 1.0; - double summand = 0; + var y = 1.0; + var prev = 1.0; var i = 1; while (Math.Abs(prev) > 1e-20) { - summand = prev * x * x / (4 * i * i); + var summand = prev * x * x / (4 * i * i); y += summand; prev = summand; i++; @@ -286,14 +256,17 @@ public static double I0(double x) #region polynomials + /// + /// Number of iterations in Durand-Kerner algorithm for evaluating polynomial roots. + /// public const int PolyRootsIterations = 25000; /// - /// Method implementing Durand-Kerner algorithm for finding complex roots of polynomials. - /// Works for polynomials of order up to approx. 50. + /// Evaluates complex roots of polynomials using Durand-Kerner algorithm. + /// Works for polynomials of order up to approx. 50. /// /// Polynomial coefficients - /// + /// Max number of iterations public static Complex[] PolynomialRoots(double[] a, int maxIterations = PolyRootsIterations) { var n = a.Length; @@ -345,12 +318,8 @@ public static Complex[] PolynomialRoots(double[] a, int maxIterations = PolyRoot } /// - /// Method checks if two arrays of complex numbers are essentially identical + /// Checks if two arrays of complex numbers are essentially identical. /// - /// First array - /// Second array - /// Tolerance level - /// true if arrays are equal private static bool ArraysAreEqual(Complex[] a, Complex[] b, double tolerance = 1e-16) { for (var i = 0; i < a.Length; i++) @@ -365,11 +334,10 @@ private static bool ArraysAreEqual(Complex[] a, Complex[] b, double tolerance = } /// - /// Evaluate polynomial according to Horner scheme + /// Evaluates polynomial according to Horner scheme. /// /// Polynomial coefficients - /// x - /// The value of polynomial + /// Argument public static Complex EvaluatePolynomial(double[] a, Complex x) { var res = new Complex(a[0], 0); @@ -384,11 +352,8 @@ public static Complex EvaluatePolynomial(double[] a, Complex x) } /// - /// Multiply polynomials + /// Multiplies polynomials. /// - /// - /// - /// public static Complex[] MultiplyPolynomials(Complex[] poly1, Complex[] poly2) { var length = poly1.Length + poly2.Length - 1; @@ -406,11 +371,8 @@ public static Complex[] MultiplyPolynomials(Complex[] poly1, Complex[] poly2) } /// - /// Divide polynomials + /// Divides polynomials. /// - /// Dividend - /// Divisor - /// public static Complex[][] DividePolynomial(Complex[] dividend, Complex[] divisor) { var output = (Complex[])dividend.Clone(); diff --git a/NWaves/Utils/Matrix.cs b/NWaves/Utils/Matrix.cs index d3f204f..aae91ab 100644 --- a/NWaves/Utils/Matrix.cs +++ b/NWaves/Utils/Matrix.cs @@ -3,20 +3,25 @@ namespace NWaves.Utils { /// - /// Class representing 2d matrix + /// Represents 2D matrix. /// public class Matrix { private readonly double[][] _matrix; + /// + /// Gets or sets number of rows. + /// public int Rows { get; set; } + + /// + /// Gets or sets number of columns. + /// public int Columns { get; set; } /// - /// Constructor + /// Constructs with given number of and . /// - /// - /// public Matrix(int rows, int columns = 0) { if (columns == 0) columns = rows; @@ -36,13 +41,12 @@ public Matrix(int rows, int columns = 0) } /// - /// Get 2d array reference + /// Gets reference to underlying 2D array. /// - /// public double[][] As2dArray() => _matrix; /// - /// Transposed matrix + /// Gets transposed matrix. /// public Matrix T { @@ -63,10 +67,9 @@ public Matrix T } /// - /// Companion matrix + /// Returns companion matrix. /// /// Input array - /// Companion matrix public static Matrix Companion(double[] a) { if (a.Length < 2) @@ -97,10 +100,8 @@ public static Matrix Companion(double[] a) } /// - /// Identity matrix + /// Returns identity matrix of given . /// - /// - /// public static Matrix Eye(int size) { var eye = new Matrix(size); @@ -113,6 +114,9 @@ public static Matrix Eye(int size) return eye; } + /// + /// Returns sum of matrices and . + /// public static Matrix operator +(Matrix m1, Matrix m2) { Guard.AgainstInequality(m1.Rows, m2.Rows, "Number of rows in first matrix", "number of rows in second matrix"); @@ -131,6 +135,9 @@ public static Matrix Eye(int size) return result; } + /// + /// Subtracts matrix from matrix . + /// public static Matrix operator -(Matrix m1, Matrix m2) { Guard.AgainstInequality(m1.Rows, m2.Rows, "Number of rows in first matrix", "number of rows in second matrix"); @@ -149,6 +156,10 @@ public static Matrix Eye(int size) return result; } + /// + /// Gets row by its index. + /// + /// Row index public double[] this[int i] => _matrix[i]; } } diff --git a/NWaves/Utils/MemoryOperationExtensions.cs b/NWaves/Utils/MemoryOperationExtensions.cs index 2ac441f..f564d7c 100644 --- a/NWaves/Utils/MemoryOperationExtensions.cs +++ b/NWaves/Utils/MemoryOperationExtensions.cs @@ -4,23 +4,22 @@ namespace NWaves.Utils { + /// + /// Provides extension methods implementing fast operations with memory buffers. + /// public static class MemoryOperationExtensions { /// - /// Convert array of doubles to array of floats + /// Creates array of single-precision values from enumerable of double-precision values. /// - /// - /// public static float[] ToFloats(this IEnumerable values) { return values.Select(v => (float)v).ToArray(); } /// - /// Convert array of floats to array of doubles + /// Creates array of double-precision values from enumerable of single-precision values. /// - /// - /// public static double[] ToDoubles(this IEnumerable values) { return values.Select(v => (double)v).ToArray(); @@ -31,10 +30,8 @@ public static double[] ToDoubles(this IEnumerable values) private const byte _32Bits = sizeof(float); /// - /// Method simply copies source array to desination + /// Creates fast copy of array. /// - /// Source array - /// Source array copy public static float[] FastCopy(this float[] source) { var destination = new float[source.Length]; @@ -43,26 +40,25 @@ public static float[] FastCopy(this float[] source) } /// - /// Method copies an array (or its fragment) to existing array (or its part) + /// Makes fast copy of array (or its part) to existing array (or its part). /// - /// - /// - /// - /// - /// + /// Source array + /// Destination array + /// Number of elements to copy + /// Offset in source array + /// Offset in destination array public static void FastCopyTo(this float[] source, float[] destination, int size, int sourceOffset = 0, int destinationOffset = 0) { Buffer.BlockCopy(source, sourceOffset * _32Bits, destination, destinationOffset * _32Bits, size * _32Bits); } /// - /// Method copies some fragment of the source array starting at specified offset + /// Makes fast copy of array fragment starting at specified offset. /// - /// - /// - /// - /// - /// The copy of source array part + /// Source array + /// Number of elements to copy + /// Offset in source array + /// Offset in destination array public static float[] FastCopyFragment(this float[] source, int size, int sourceOffset = 0, int destinationOffset = 0) { var totalSize = size + destinationOffset; @@ -72,31 +68,25 @@ public static float[] FastCopyFragment(this float[] source, int size, int source } /// - /// Method does fast in-memory merge of two arrays + /// Performs fast merging of array with array. /// - /// The first array for merging - /// The second array for merging - /// Merged array - public static float[] MergeWithArray(this float[] source1, float[] source2) + public static float[] MergeWithArray(this float[] source, float[] another) { - var merged = new float[source1.Length + source2.Length]; - Buffer.BlockCopy(source1, 0, merged, 0, source1.Length * _32Bits); - Buffer.BlockCopy(source2, 0, merged, source1.Length * _32Bits, source2.Length * _32Bits); + var merged = new float[source.Length + another.Length]; + Buffer.BlockCopy(source, 0, merged, 0, source.Length * _32Bits); + Buffer.BlockCopy(another, 0, merged, source.Length * _32Bits, another.Length * _32Bits); return merged; } /// - /// Method repeats given array N times + /// Creates new array containing given array repeated times. /// - /// Source array - /// Number of times to repeat array - /// Array repeated N times - public static float[] RepeatArray(this float[] source, int times) + public static float[] RepeatArray(this float[] source, int n) { - var repeated = new float[source.Length * times]; + var repeated = new float[source.Length * n]; var offset = 0; - for (var i = 0; i < times; i++) + for (var i = 0; i < n; i++) { Buffer.BlockCopy(source, 0, repeated, offset * _32Bits, source.Length * _32Bits); offset += source.Length; @@ -106,12 +96,9 @@ public static float[] RepeatArray(this float[] source, int times) } /// - /// Method creates new zero-padded array from source array. + /// Creates new zero-padded array of given from given array. /// - /// Source array - /// The size of a zero-padded array - /// Zero-padded array - public static float[] PadZeros(this float[] source, int size = 0) + public static float[] PadZeros(this float[] source, int size) { var zeroPadded = new float[size]; Buffer.BlockCopy(source, 0, zeroPadded, 0, source.Length * _32Bits); @@ -123,40 +110,37 @@ public static float[] PadZeros(this float[] source, int size = 0) #region double precision private const byte _64Bits = sizeof(double); - + /// - /// Method simply copies source array to desination + /// Creates fast copy of array. /// - /// Source array - /// Source array copy public static double[] FastCopy(this double[] source) { var destination = new double[source.Length]; Buffer.BlockCopy(source, 0, destination, 0, source.Length * _64Bits); return destination; } - + /// - /// Method copies an array (or its fragment) to existing array (or its part) + /// Makes fast copy of array (or its part) to existing array (or its part). /// - /// - /// - /// - /// - /// + /// Source array + /// Destination array + /// Number of elements to copy + /// Offset in source array + /// Offset in destination array public static void FastCopyTo(this double[] source, double[] destination, int size, int sourceOffset = 0, int destinationOffset = 0) { Buffer.BlockCopy(source, sourceOffset * _64Bits, destination, destinationOffset * _64Bits, size * _64Bits); } - + /// - /// Method copies some fragment of the source array starting at specified offset + /// Makes fast copy of array fragment starting at specified offset. /// - /// - /// - /// - /// - /// The copy of source array part + /// Source array + /// Number of elements to copy + /// Offset in source array + /// Offset in destination array public static double[] FastCopyFragment(this double[] source, int size, int sourceOffset = 0, int destinationOffset = 0) { var totalSize = size + destinationOffset; @@ -164,33 +148,27 @@ public static double[] FastCopyFragment(this double[] source, int size, int sour Buffer.BlockCopy(source, sourceOffset * _64Bits, destination, destinationOffset * _64Bits, size * _64Bits); return destination; } - + /// - /// Method does fast in-memory merge of two arrays + /// Performs fast merging of array with array. /// - /// The first array for merging - /// The second array for merging - /// Merged array - public static double[] MergeWithArray(this double[] source1, double[] source2) + public static double[] MergeWithArray(this double[] source, double[] another) { - var merged = new double[source1.Length + source2.Length]; - Buffer.BlockCopy(source1, 0, merged, 0, source1.Length * _64Bits); - Buffer.BlockCopy(source2, 0, merged, source1.Length * _64Bits, source2.Length * _64Bits); + var merged = new double[source.Length + another.Length]; + Buffer.BlockCopy(source, 0, merged, 0, source.Length * _64Bits); + Buffer.BlockCopy(another, 0, merged, source.Length * _64Bits, another.Length * _64Bits); return merged; } - + /// - /// Method repeats given array N times + /// Creates new array containing given array repeated times. /// - /// Source array - /// Number of times to repeat array - /// Array repeated N times - public static double[] RepeatArray(this double[] source, int times) + public static double[] RepeatArray(this double[] source, int n) { - var repeated = new double[source.Length * times]; + var repeated = new double[source.Length * n]; var offset = 0; - for (var i = 0; i < times; i++) + for (var i = 0; i < n; i++) { Buffer.BlockCopy(source, 0, repeated, offset * _64Bits, source.Length * _64Bits); offset += source.Length; @@ -198,14 +176,11 @@ public static double[] RepeatArray(this double[] source, int times) return repeated; } - + /// - /// Method creates new zero-padded array from source array. + /// Creates new zero-padded array of given from given array. /// - /// Source array - /// The size of a zero-padded array - /// Zero-padded array - public static double[] PadZeros(this double[] source, int size = 0) + public static double[] PadZeros(this double[] source, int size) { var zeroPadded = new double[size]; Buffer.BlockCopy(source, 0, zeroPadded, 0, source.Length * _64Bits); @@ -214,4 +189,4 @@ public static double[] PadZeros(this double[] source, int size = 0) #endregion } -} \ No newline at end of file +} diff --git a/NWaves/Utils/Scale.cs b/NWaves/Utils/Scale.cs index d852c9e..4a0ec51 100644 --- a/NWaves/Utils/Scale.cs +++ b/NWaves/Utils/Scale.cs @@ -3,120 +3,116 @@ namespace NWaves.Utils { /// - /// Static class providing methods for - /// + /// Provides methods for + /// /// 1) converting between different scales: - /// - decibel - /// - MIDI pitch - /// - mel (HTK) - /// - mel (Slaney) - /// - bark1 (Traunmueller) - /// - bark2 (Wang) - /// - ERB - /// + /// + /// decibel + /// MIDI pitch + /// mel (HTK) + /// mel (Slaney) + /// bark1 (Traunmueller) + /// bark2 (Wang) + /// ERB + /// + /// + /// /// 2) loudness weighting: - /// - A-weighting - /// - B-weighting - /// - C-weighting - /// + /// + /// A-weighting + /// B-weighting + /// C-weighting + /// + /// /// public static class Scale { /// - /// Method converts magnitude value to dB level + /// Converts magnitude value to dB level. /// /// Magnitude /// Reference magnitude - /// Decibel level public static double ToDecibel(double value, double valueReference) { return 20 * Math.Log10(value / valueReference + double.Epsilon); } /// - /// Method converts magnitude value to dB level (simplified version for intermediate calculations) + /// Converts magnitude value to dB level (simplified version). /// /// Magnitude - /// Decibel level public static double ToDecibel(double value) { return 20 * Math.Log10(value); } /// - /// Method converts power to dB level + /// Converts power to dB level. /// /// Power /// Reference power - /// Decibel level public static double ToDecibelPower(double value, double valueReference = 1.0) { return 10 * Math.Log10(value / valueReference + double.Epsilon); } /// - /// Method converts dB level to magnitude value + /// Converts dB level to magnitude value. /// - /// dB level + /// Decibel level /// Reference magnitude - /// Magnitude value public static double FromDecibel(double level, double valueReference) { return valueReference * Math.Pow(10, level / 20); } /// - /// Method converts dB level to magnitude value (simplified version for intermediate calculations) + /// Converts dB level to magnitude value (simplified version). /// - /// dB level - /// Magnitude value + /// Decibel level public static double FromDecibel(double level) { return Math.Pow(10, level / 20); } /// - /// Method converts dB level to power + /// Converts dB level to power. /// - /// dB level + /// Decibel level /// Reference power - /// Power public static double FromDecibelPower(double level, double valueReference = 1.0) { return valueReference * Math.Pow(10, level / 10); } /// - /// Method converts MIDI pitch to frequency + /// Converts MIDI pitch to frequency (in Hz). /// - /// - /// + /// Pitch public static double PitchToFreq(int pitch) { return 440 * Math.Pow(2, (pitch - 69) / 12.0); } /// - /// Method converts frequency to MIDI pitch + /// Converts frequency to MIDI pitch. /// - /// - /// + /// Frequency (in Hz) public static int FreqToPitch(double freq) { return (int)Math.Round(69 + 12 * Math.Log(freq / 440, 2), MidpointRounding.AwayFromZero); } /// - /// Array of notes + /// Array of musical notes. /// public static string[] Notes = new[] { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; /// - /// Method converts note (in format ("G", 3), ("E", 5), etc.) to frequency in Hz + /// Converts musical note (in format ("G", 3), ("E", 5), etc.) to frequency in Hz. /// /// Note (A-G#) /// Octave (0-8) - /// Frequency in Hz public static double NoteToFreq(string note, int octave) { var noteIndex = Array.IndexOf(Notes, note); @@ -135,10 +131,9 @@ public static double NoteToFreq(string note, int octave) } /// - /// Method converts frequency in Hz to note (in format ("G", 3), ("E", 5), etc.) + /// Converts frequency in Hz to note (in tuple format ("G", 3), ("E", 5), etc.). /// /// Frequency in Hz - /// Tuple (note, octave) public static (string, int) FreqToNote(double freq) { var pitch = FreqToPitch(freq); @@ -150,30 +145,24 @@ public static (string, int) FreqToNote(double freq) } /// - /// Method converts herz frequency to corresponding mel frequency + /// Converts herz frequency to corresponding mel frequency. /// - /// Herz frequency - /// Mel frequency public static double HerzToMel(double herz) { return 1127 * Math.Log(herz / 700 + 1); // actually, should be 1127.01048, but HTK and Kaldi seem to use 1127 } /// - /// Method converts mel frequency to corresponding herz frequency + /// Converts mel frequency to corresponding herz frequency. /// - /// Mel frequency - /// Herz frequency public static double MelToHerz(double mel) { return (Math.Exp(mel / 1127) - 1) * 700; } /// - /// Method converts herz frequency to mel frequency (suggested by M.Slaney) + /// Converts herz frequency to mel frequency (suggested by M.Slaney). /// - /// Herz frequency - /// Mel frequency public static double HerzToMelSlaney(double herz) { const double minHerz = 0.0; @@ -187,10 +176,8 @@ public static double HerzToMelSlaney(double herz) } /// - /// Method converts mel frequency to herz frequency (suggested by M.Slaney) + /// Converts mel frequency to herz frequency (suggested by M.Slaney). /// - /// Mel frequency - /// Herz frequency public static double MelToHerzSlaney(double mel) { const double minHerz = 0.0; @@ -204,76 +191,58 @@ public static double MelToHerzSlaney(double mel) } /// - /// Method #1 converts herz frequency to corresponding bark frequency - /// (according to Traunmüller (1990)) + /// Converts herz frequency to corresponding bark frequency (according to Traunmüller (1990)). /// - /// Herz frequency - /// Bark frequency public static double HerzToBark(double herz) { return (26.81 * herz) / (1960 + herz) - 0.53; } /// - /// Method #1 converts bark frequency to corresponding herz frequency - /// (according to Traunmüller (1990)) + /// Converts bark frequency to corresponding herz frequency (according to Traunmüller (1990)). /// - /// Bark frequency - /// Herz frequency public static double BarkToHerz(double bark) { return 1960 / (26.81 / (bark + 0.53) - 1); } /// - /// Method #2 converts herz frequency to corresponding bark frequency - /// (according to Wang (1992)); used in M.Slaney's auditory toolbox + /// Converts herz frequency to corresponding bark frequency (according to Wang (1992)); + /// used in M.Slaney's auditory toolbox. /// - /// Herz frequency - /// Bark frequency public static double HerzToBarkSlaney(double herz) { return 6 * MathUtils.Asinh(herz / 600); } /// - /// Method #2 converts bark frequency to corresponding herz frequency - /// (according to Wang (1992)); used in M.Slaney's auditory toolbox + /// Converts bark frequency to corresponding herz frequency (according to Wang (1992)); + /// used in M.Slaney's auditory toolbox. /// - /// Bark frequency - /// Herz frequency public static double BarkToHerzSlaney(double bark) { return 600 * Math.Sinh(bark / 6); } /// - /// Method converts herz frequency to corresponding ERB frequency + /// Converts herz frequency to corresponding ERB frequency. /// - /// Herz frequency - /// ERB frequency public static double HerzToErb(double herz) { return 9.26449 * Math.Log(1.0 + herz) / (24.7 * 9.26449); } /// - /// Method converts ERB frequency to corresponding herz frequency + /// Converts ERB frequency to corresponding herz frequency. /// - /// ERB frequency - /// Herz frequency public static double ErbToHerz(double erb) { return (Math.Exp(erb / 9.26449) - 1.0) * (24.7 * 9.26449); } /// - /// Method converts Hz frequency to octave (used for constructing librosa-like Chroma filterbanks) + /// Converts Hz frequency to octave (used for constructing librosa-like Chroma filterbanks). /// - /// - /// - /// - /// public static double HerzToOctave(double herz, double tuning = 0, int binsPerOctave = 12) { var a440 = 440.0 * Math.Pow(2.0, tuning / binsPerOctave); @@ -282,20 +251,19 @@ public static double HerzToOctave(double herz, double tuning = 0, int binsPerOct } /// - /// Method for obtaining a perceptual loudness weight + /// Returns perceptual loudness weight (in dB). /// - /// Frequency + /// Frequency /// Weighting type (A, B, C) - /// Weight value in dB - public static double LoudnessWeighting(double freq, string weightingType = "A") + public static double LoudnessWeighting(double frequency, string weightingType = "A") { - var level2 = freq * freq; + var level2 = frequency * frequency; switch (weightingType.ToUpper()) { case "B": { - var r = (level2 * freq * 148693636) / + var r = (level2 * frequency * 148693636) / ( (level2 + 424.36) * Math.Sqrt(level2 + 25122.25) *