GithubHelp home page GithubHelp logo

ar1st0crat / nwaves Goto Github PK

View Code? Open in Web Editor NEW
448.0 31.0 70.0 7.46 MB

.NET DSP library with a lot of audio processing functions

License: MIT License

C# 100.00%
audio dsp filtering sound-effects feature-extraction psychoacoustics sound-synthesis wav mfcc lpc

nwaves's Introduction

NWaves

License: MIT Version NuGet Gitter

logo

NWaves is a .NET DSP library with a lot of audio processing functions.

Releases

NWaves is available on NuGet:

PM> Install-Package NWaves

Read wiki documentation

New version 0.9.6 is out! Faster, smarter, more features. Read about changes here

Notes for non-experts in DSP

NWaves for MATLAB/sciPy users

Watch survey video | Playlist | Samples | Benchmarks | Playground (code)

Main features

  • major DSP transforms (FFT, DCT, MDCT, STFT, FWT, Hilbert, Hartley, Mellin, cepstral, Goertzel)
  • signal builders (sine, white/pink/red/Perlin noise, awgn, triangle, sawtooth, square, pulse, ramp, ADSR, wavetable)
  • basic LTI digital filters (moving average, comb, Savitzky-Golay, pre/de-emphasis, DC removal, RASTA)
  • FIR/IIR filtering (offline and online), zero-phase filtering
  • BiQuad filters (low-pass, high-pass, band-pass, notch, all-pass, peaking, shelving)
  • 1-pole filters (low-pass, high-pass)
  • IIR filters (Bessel, Butterworth, Chebyshev I & II, Elliptic, Thiran)
  • basic operations (convolution, cross-correlation, rectification, amplification, fade / crossfade)
  • block convolution (overlap-add / overlap-save offline and online)
  • basic filter design & analysis (group delay, zeros/poles, BP, BR, HP from/to LP, SOS, combining filters)
  • state space representation of LTI filters
  • FIR filter design: frequency sampling, window-sinc, equiripple (Remez / Parks-McClellan)
  • IIR filter design: IirNotch / IirPeak / IirCombNotch / IirCombPeak
  • non-linear filters (median filter, distortion effects, bit crusher)
  • windowing functions (Hamming, Blackman, Hann, Gaussian, Kaiser, KBD, triangular, Lanczos, flat-top, Bartlett)
  • periodograms (Welch / Lomb-Scargle)
  • psychoacoustic filter banks (Mel, Bark, Critical Bands, ERB, octaves) and VTLN warping
  • customizable feature extraction (time-domain, spectral, MFCC, PNCC/SPNCC, LPC, LPCC, PLP, AMS)
  • preconfigured MFCC extractors: HTK (MFCC-FB24), Slaney (MFCC-FB40)
  • LPC conversions: LPC<->cepstrum, LPC<->LSF
  • feature post-processing (mean and variance normalization, adding deltas) and CSV serialization
  • spectral features (centroid, spread, flatness, entropy, rolloff, contrast, crest, decrease, noiseness, MPEG7)
  • harmonic features (harmonic centroid and spread, inharmonicity, tristimulus, odd-to-even ratio)
  • time-domain characteristics (rms, energy, zero-crossing rate, entropy)
  • pitch tracking (autocorrelation, YIN, ZCR + Schmitt trigger, HSS/HPS, cepstrum)
  • chromagram (chroma feature extractor)
  • time scale modification (phase vocoder, PV with identity phase locking, WSOLA, PaulStretch)
  • simple resampling, interpolation, decimation
  • bandlimited resampling
  • wavelets: haar, db, symlet, coiflet
  • polyphase filters
  • noise reduction (spectral subtraction, sciPy-style Wiener filtering)
  • sound effects (echo, tremolo, wahwah, phaser, chorus, vibrato, flanger, pitch shift, morphing, robotize, whisperize)
  • 3D/Stereo audio (stereo panning, stereo and ping-pong delay, ITD-ILD, binaural panning)
  • envelope following
  • dynamics processing (limiter / compressor / expander / noise gate)
  • harmonic/percussive separation
  • Griffin-Lim algorithm
  • Karplus-Strong synthesis
  • PADSynth synthesis
  • adaptive filtering (LMS, NLMS, LMF, SignLMS, RLS)
  • simple modulation/demodulation (AM, ring, FM, PM)
  • simple audio playback and recording

Philosophy of NWaves

NWaves was initially intended for research, visualizing and teaching basics of DSP and sound programming.

Usually, DSP code is quite complicated and difficult to read, because it's full of optimizations (which is actually a very good thing). NWaves project aims in particular at achieving a tradeoff between good understandable code/design and satisfactory performance. Yet, the main purpose of this lib is to offer the DSP codebase that would be:

  • easy to read and understand
  • easy to incorporate into existing projects
  • easy to port to other programming languages and frameworks
  • even possibly treated as the DSP/audio textbook.

According to NWaves architecture, there are following general reusable building blocks for all kinds of DSP tasks:

Transforms | Filters | Signal builders | Feature extractors

Quickstart

Working with 1D signals

// Create signal from samples repeated 100 times

float[] samples = new [] { 0.5f, 0.2f, -0.3f, 1.2f, 1.6f, -1.8f, 0.3f, -0.2f };

var s = new DiscreteSignal(8000, samples).Repeat(100);

var length = s.Length;
var duration = s.Duration;

var echoSignal = s + s.Delay(50);

var marginSignal = s.First(64).Concatenate(s.Last(64));

var repeatMiddle = s[400, 500].Repeat(10);

var mean = s.Samples.Average();
var sigma = s.Samples.Average(x => (x - mean) * (x - mean));

var normSignal = s - mean;
normSignal.Attenuate(sigma);

Signal builders

DiscreteSignal sinusoid = 
    new SineBuilder()
        .SetParameter("frequency", 500.0/*Hz*/)
        .SetParameter("phase", Math.PI / 6)
        .OfLength(1000)
        .SampledAt(44100/*Hz*/)
        .Build();

DiscreteSignal noise = 
    new RedNoiseBuilder()
        .SetParameter("min", -2.5)
        .SetParameter("max", 2.5)
        .OfLength(800)
        .SampledAt(44100)
        .DelayedBy(200)
        .Build();

DiscreteSignal noisy = 
    new SineBuilder()
        .SetParameter("min", -10.0)
        .SetParameter("max", 10.0)
        .SetParameter("freq", 1200.0/*Hz*/)
        .OfLength(1000)
        .SampledAt(44100)
        .SuperimposedWith(noise)
        .Build();

Signal builders can also act as real-time generators of samples:

SignalBuilder lfo = 
    new TriangleWaveBuilder()
            .SetParameter("min", 100)
            .SetParameter("max", 1500)
            .SetParameter("frequency", 2.0/*Hz*/)
            .SampledAt(16000/*Hz*/);

//while (...)
{
    var sample = lfo.NextSample();
    //...
}

Signals and wave files:

WaveFile waveContainer;

// load

using (var stream = new FileStream("sample.wav", FileMode.Open))
{
    waveContainer = new WaveFile(stream);
}

DiscreteSignal left = waveContainer[Channels.Left];
DiscreteSignal right = waveContainer[Channels.Right];


// save

var waveFileOut = new WaveFile(left);

using (var stream = new FileStream("saved_mono.wav", FileMode.Create))
{
    waveFileOut.SaveTo(stream);
}

var waveFileStereo = new WaveFile(new [] { left, right });

using (var stream = new FileStream("saved_stereo.wav", FileMode.Create))
{
    waveFileStereo.SaveTo(stream);
}

Transforms

For each transform there's a corresponding transformer object. Each transformer object has Direct() and Inverse() methods.

FFT

// Complex FFT transformer:

var fft = new Fft(1024);

// Real FFT transformer (faster):

var rfft = new RealFft(1024);


float[] real = signal.First(1024).Samples;
float[] imag = new float [1024];

// in-place complex FFT
fft.Direct(real, imag);

// ...do something with real and imaginary parts of the spectrum...

// in-place complex IFFT
fft.Inverse(real, imag);

// post-processed FFT:

var magnitudeSpectrum = 
    fft.MagnitudeSpectrum(signal[1000, 2024]);

var powerSpectrum = 
    fft.PowerSpectrum(signal.First(1024), normalize: false);

var logPowerSpectrum = 
    fft.PowerSpectrum(signal.Last(1024))
       .Samples
       .Select(s => Scale.ToDecibel(s))
       .ToArray();


// real FFT transforms real-valued signal to complex-valued spectrum:

rfft.Direct(real, real, imag);   // real -> (real, imag)
rfft.Inverse(real, imag, real);  // (real, imag) -> real

var magnitudeSpectrum = 
    rfft.MagnitudeSpectrum(signal[1000, 2024]);

var powerSpectrum = 
    rfft.PowerSpectrum(signal.First(1024), normalize: false);

// ...

Lot of methods in NWaves have overloaded versions with output buffers as parameters. So reuse memory whenever possible:

float[] spectrum = new float[1024];

for (var i = start; i < end; i += step)
{
    rfft.MagnitudeSpectrum(signal[i, i + 1024], spectrum);
    // ...
    // do something with spectrum
}

STFT

// Short-Time Fourier Transform:

var stft = new Stft(1024, 256, WindowTypes.Hamming);
var timefreq = stft.Direct(signal);
var reconstructed = stft.Inverse(timefreq);

var spectrogram = stft.Spectrogram(signal);

Cepstral transform

// Cepstral transformer:

var ct = new CepstralTransform(24, fftSize: 512);

// complex cepstrum
ct.Direct(input, output);
// or
var delay = ct.ComplexCepstrum(input, output);

// real cepstrum
ct.RealCepstrum(input, output);

// inverse complex cepstrum
ct.InverseComplexCepstrum(output, input, delay: delay);

Wavelets

var fwt = new Fwt(192, new Wavelet("db5"));

// or
//var fwt = new Fwt(192, new Wavelet(WaveletFamily.Daubechies, 5));

var output = new float[192];
var reconstructed = new float[192];

fwt.Direct(input, output);
fwt.Inverse(output, reconstructed);

Operations:

// convolution

var conv = Operation.Convolve(signal, kernel);
var xcorr = Operation.CrossCorrelate(signal1, signal2);

// block convolution

var filtered = Operation.BlockConvolve(signal, kernel, 4096, FilteringMethod.OverlapAdd);

// periodogram evaluation

var periodogram = Operation.Welch(signal, 2048, 1024);
var pgram = Operation.LombScargle(x, y, freqs);

// resampling

var resampled = Operation.Resample(signal, 22050);
var interpolated = Operation.Interpolate(signal, 3);
var decimated = Operation.Decimate(signal, 2);
var updown = Operation.ResampleUpDown(signal, 3, 2);

// time scale modification

var stretch = Operation.TimeStretch(signal, 0.7, TsmAlgorithm.Wsola);
var cool = Operation.TimeStretch(signal, 16, TsmAlgorithm.PaulStretch);

// envelope following

var envelope = Operation.Envelope(signal);

// peak / rms normalization

var peakNorm = Operation.NormalizePeak(signal, -3/*dB*/);
var rmsNorm = Operation.NormalizeRms(signal, -3/*dB*/);
var rmsChanged = Operation.ChangeRms(signal, -6/*dB*/);

// rectification

var halfRect = Operation.HalfRectify(signal);
var fullRect = Operation.FullRectify(signal);

// spectral subtraction

var clean = Operation.SpectralSubtract(signal, noise);

// crossfade

var crossfaded = song1.Crossfade(song2, 0.05/*sec*/);

Filters and effects:

var maFilter = new MovingAverageFilter(7);
var smoothedSignal = maFilter.ApplyTo(signal);

var frequency = 800.0/*Hz*/;
var notchFilter = new BiQuad.NotchFilter(frequency / signal.SamplingRate);
var notchedSignal = notchFilter.ApplyTo(signal);


// filter analysis:

var transferFunction = new TransferFunction(new [] { 1, 0.5, 0.2 }, new [] { 1, -0.8, 0.3 });

var filter = new IirFilter(transferFunction);

// we can also write this:

// var filter = new IirFilter(new [] { 1, 0.5, 0.2 }, new [] { 1, -0.8, 0.3 });
// var transferFunction = filter.Tf;
// ...

// if we simply want to apply filter and don't care much about FDA precision:
// read more in tutorial


var impulseResponse = transferFunction.ImpulseResponse();
var magnitudeResponse = transferFunction.FrequencyResponse().Magnitude;
var phaseResponse = transferFunction.FrequencyResponse().Phase;

var b = transferFunction.Numerator;
var a = transferFunction.Denominator;
var zeros = transferFunction.Zeros;
var poles = transferFunction.Poles;

var gd = transferFunction.GroupDelay();
var pd = transferFunction.PhaseDelay();


// some examples of FIR filter design:

var kernel = DesignFilter.FirWinLp(345, 0.15);
var lpFilter = new FirFilter(kernel);

// HP filter can be obtained from LP with the same cutoff frequency:
var hpFilter = DesignFilter.FirLpToHp(lpFilter);

// design BP filter
var bpFilter = DesignFilter.FirWinBp(123, 0.05, 0.15);

// design equiripple HP filter
var bpFilter = DesignFilter.FirEquirippleHp(123, 0.34, 0.355, 0.05, 0.95);


// sequence of filters:

var cascade = filter * firFilter * notchFilter;
var filtered = cascade.ApplyTo(signal);

// filtering is conceptually equivalent to:

var filtered = filter.ApplyTo(signal);
filtered = firFilter.ApplyTo(filtered);
filtered = notchFilter.ApplyTo(filtered);

// same but with double precision:
var cascadeTf = filter.Tf * firFilter.Tf * notchFilter.Tf;
var cascadeFilter = new IirFilter(cascadeTf);
var filtered = cascadeFilter.ApplyTo(signal);

// parallel combination of filters:

var parallel = filter1 + filter2;
filtered = parallel.ApplyTo(signal);

// same but with double precision:
var parallelTf = filter1.Tf + filter2.Tf;
var parallelFilter = new IirFilter(parallelTf);
var filtered = parallelFilter.ApplyTo(signal);

// audio effects:

var flanger = new FlangerEffect(signal.SamplingRate);
var wahwah = new WahwahEffect(signal.SamplingRate, lfoFrequency: 2/*Hz*/);

var processed = wahwah.ApplyTo(flanger.ApplyTo(signal));
// this will create intermediate copy of the signal


// FilterChain is memory-efficient:

var filters = new FilterChain();
filters.Add(flanger);
filters.Add(wahwah);

processed = filters.ApplyTo(signal);


// Second-Order Sections:

var tf = new Butterworth.BandPassFilter(0.1, 0.16, 7).Tf;

// get array of SOS from TF:
TransferFunction[] sos = DesignFilter.TfToSos(tf);

var sosFilter = new FilterChain(sos);

var y = sosFilter.ApplyTo(x);

// or process samples online:
//    ... outSample = sosFilter.Process(sample);

Online processing

Online processing is supported by all classes that implement the IOnlineFilter interface. Currently, all LTI filters, FilterChain class, block convolvers (OlaBlockConvolver, OlsBlockConvolver) and audio effects contain the Process(sample) and Process(bufferIn, bufferOut) methods responsible for online processing.

Simply process data sample after sample:

var outputSample = filter.Process(sample);

Or prepare necessary buffers (or just use them if they come from another part of your system):

float[] output;

...

void NewChunkAvailable(float[] chunk)
{
    filter.Process(chunk, output);
}


// if input chunk shouldn't necessarily be preserved, it can be overwritten:

void NewChunkAvailable(float[] chunk)
{
    filter.Process(chunk, chunk);
}

Block convolvers:

// Overlap-Add / Overlap-Save

FirFilter filter = new FirFilter(kernel);

var blockConvolver = OlaBlockConvolver.FromFilter(filter, 4096);

// processing loop:
// while new input sample is available
{
    var outputSample = blockConvolver.Process(sample);
}

// or:
// while new input buffer is available
{
    blockConvolver.Process(input, output);
}

See also OnlineDemoForm code.

onlinedemo

Feature extractors

Highly customizable feature extractors are available for offline and online processing (MFCC family, LPC, pitch and lot of others).

var mfccOptions = new MfccOptions
{
    SamplingRate = signal.SamplingRate,
    FeatureCount = 13,
    FrameDuration = 0.032/*sec*/,
    HopDuration = 0.015/*sec*/,
    FilterBankSize = 26,
    PreEmphasis = 0.97,
    //...unspecified parameters will have default values 
};

var mfccExtractor = new MfccExtractor(mfccOptions);
var mfccVectors = mfccExtractor.ComputeFrom(signal);


// serialize current config to JSON file:

using (var config = new FileStream("file.json", FileMode.Create))
{
    config.SaveOptions(mfccOptions);
}


var lpcOptions = new LpcOptions
{
    SamplingRate = signal.SamplingRate,
    LpcOrder = 15
};

var lpcExtractor = new LpcExtractor(lpcOptions);
var lpcVectors = lpcExtractor.ParallelComputeFrom(signal);



var opts = new MultiFeatureOptions
{
    SamplingRate = signal.SamplingRate,
    FeatureList = "centroid, flatness, c1+c2+c3"
};

var spectralExtractor = new SpectralFeaturesExtractor(opts);

opts.FeatureList = "all";
var tdExtractor = new TimeDomainFeaturesExtractor(opts);

var vectors = FeaturePostProcessing.Join(
                  tdExtractor.ParallelComputeFrom(signal), 
                  spectralExtractor.ParallelComputeFrom(signal));

// each vector will contain 1) all time-domain features (energy, rms, entropy, zcr)
//                          2) specified spectral features


// open config from JSON file:

PnccOptions options;
using (var config = new FileStream("file.json", FileMode.Open))
{
    options = config.LoadOptions<PnccOptions>();
}

var pnccExtractor = new PnccExtractor(pnccOptions);
var pnccVectors = pnccExtractor.ComputeFrom(signal, /*from*/1000, /*to*/60000 /*sample*/);
FeaturePostProcessing.NormalizeMean(pnccVectors);


// serialization

using (var csvFile = new FileStream("mfccs.csv", FileMode.Create))
{
    var serializer = new CsvFeatureSerializer(mfccVectors);
    await serializer.SerializeAsync(csvFile);
}

Pre-processing

// There are 3 options to perform pre-emphasis filtering:

// 1) Set pre-emphasis coefficient in constructor of a feature extractor
// 2) Apply filter before processing and process filtered signal
// 3) Filter signal in-place and process it

// (...read more in docs...)

// option 1:

var opts = new MfccOptions
{
    SamplingRate = signal.SamplingRate,
    FeatureCount = 13,
    PreEmphasis = 0.95
};
var mfccExtractor = new MfccExtractor(opts);
var mfccVectors = mfccExtractor.ComputeFrom(signal);

// option 2:
// ApplyTo() will create new signal (allocate new memory)

opts.PreEmphasis = 0;
mfccExtractor = new MfccExtractor(opts);
var pre = new PreEmphasisFilter(0.95);
var filtered = pre.ApplyTo(signal);
mfccVectors = mfccExtractor.ComputeFrom(filtered);

// option 3:
// process array or DiscreteSignal samples in-place:

for (var i = 0; i < signal.Length; i++)
{
    signal[i] = pre.Process(signal[i]);
}
// or simply:
// pre.Process(signal.Samples, signal.Samples);

mfccVectors = mfccExtractor.ComputeFrom(signal);

Playing and recording

MciAudioPlayer and MciAudioRecorder work only at Windows-side, since they use winmm.dll and MCI commands.

IAudioPlayer player = new MciAudioPlayer();

// play entire file
await player.PlayAsync("temp.wav");

// play file from 16000th sample to 32000th sample
await player.PlayAsync("temp.wav", 16000, 32000);


// ...in some event handler
player.Pause();

// ...in some event handler
player.Resume();

// ...in some event handler
player.Stop();


// recording

IAudioRecorder recorder = new MciAudioRecorder();

// ...in some event handler
recorder.StartRecording(16000);

// ...in some event handler
recorder.StopRecording("temp.wav");

Samples

filters

pitch

lpc

mfcc

spectral

effects

wavelets

adaptive

nwaves's People

Contributors

ar1st0crat avatar bobasaurus avatar luthfiampas avatar notheisz57 avatar rachamimyaakobov avatar yaroslavingvarsson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nwaves's Issues

Resampling 250kHz signal to 192kHz

Hi,
I am not an expert in DSP. I use libraries like this one. Unfortunately the library I use does not have a resample capability.
This is the first one I can understand. It looks like it would work perfect for my usage.
So my first question is that can the FIR filter handle 1025 taps?
Second, what would be the performance like with 16384 samples in on a continuous basis?
Thanks. Tom

TF zeros, poles and gain from Butterworth are different to scipy z, p, k

I am comparing NWaves results with matlab and scipy results. TF zeros, poles and gain from Butterworth are different to scipy z, p, k

var bw = new Filters.Butterworth.BandPassFilter(lower / fs, upper / fs, 6);
var (z, p, k) = (bw.Tf.Zeros, bw.Tf.Poles, bw.Tf.Gain);

z, p, k = butter( N=6, Wn=np.array([lower, upper]) / (fs / 2), btype='bandpass', analog=False, output='zpk')

The results from z and p are reverse and so gain is different. Is it okay anyway?

How to get NWaves MFCC data similar to librosa

Hello!

I'm trying to get the same array of data in NWaves as in Librosa, I read and tried a lot of settings from wiki but results are not close to desired.

Initial line using librosa was:
mfcc = librosa.feature.mfcc(y = audio, sr = sr, n_fft = int(2048/2), hop_length = int(np.floor(len(audio)/20)), n_mfcc = 13)

With just these settings I got array of different length:
273 items in librosa from shape (13, 21)
1685 * 13 in NWaves

Audio length is 371499 in librosa (len(audio)), 134784 in NWaves. File is mono.

var waveFile = new WaveFile(stream);
var left = waveFile[Channels.Left];
// check left.Length

Then I tried to underestand which default parameters were used in librosa.
My results stayed the same with these list. By the way if fmax set to any value like sr/2 results are changing.
But anyway I didn't find all these parameters in NWaves.


mfcc = librosa.feature.mfcc(y = audio, sr = 8000, n_mfcc=13, n_fft=1024, hop_length=int(np.floor(len(audio)/20)),
                                    dct_type=2, norm='ortho', htk=False, fmin=0, center=True, n_mels=128, window='hanning')

Could you please advise how to achieve getting data in the same as librosa format?

Butterworth, Chebyshev and Bessel Filter

Hi. I use your Tool to learn some Signal Processing techniques. I like it and the code is very clean. There is already implemented the IIR Butterworth low pass filter. What about all other band forms (high pass, bandpass, stopband/notch)? What about Chebyshev and Bessel filter families? Hop you can implement this filters too!

LPC exctractor System.IndexOutOfRangeException

Pre-emphasis filter in LPCExtractor prepares initial sample for the next iteration. If it's the last iteration because of the end of the sample, it throws an exception. Same thing with LPCCExtractor.

RealFft Inverse wrong amplitude

Compared to FFTW.PlanDftComplexToReal1D the real inverse amplitude from NWaves is factor 2 smaller. So the Unit-Test TestFft.TestInverseRealFft should be
Assert.Multiple(() => { Assert.That(output, Is.EqualTo(array.Select(a => a * 8)).Within(1e-5)); Assert.That(outputNorm, Is.EqualTo(array).Within(1e-5)); });

and the RealFft.Inverse methode must be fixed.

Am I wrong?

Maximum size of FFT depending on the sampling rate

I use NWaves on a Raspberry Pi that has an external A/D to calculate FFTs. As I tested different sampling rates and FFT sizes I got IndexOutOfRangeExceptions with certain settings.

To reproduce the problem, you can use a DiscreteSignal with RealFft's MagnitudeSpectrum method. It normally works just fine, but if I increase the FFT size or lower my sampling rate, there is always a point where I got an exception.

I don't know enough about FFT to know if it's a theoretical limit or an intentional limit, but either way it would be great to have a more detailed Exception to explain the reason.

The sampling rate, and FFT size settings that I used and got the exception:
200kHz sampling rate, 1024k or higher
250kHz - 400kHz sampling rate, 2048k or higher
500kHz sampling rate, 4096k or higher

I had 5 seconds of data in my DiscreteSignal in all cases.

The exact stack trace of the IndexOutOfRangeException exception is:

   at NWaves.Transforms.RealFft.Direct(Single[] input, Single[] re, Single[] im)
   at NWaves.Transforms.RealFft.MagnitudeSpectrum(Single[] samples, Single[] spectrum, Boolean normalize)
   at NWaves.Transforms.RealFft.MagnitudeSpectrum(DiscreteSignal signal, Boolean normalize)
   at SleepLogger.Program.<>c__DisplayClass10_1.<Main>b__3() in C:\Work\BioBalanceDetector\Measurements\WaveForms\Experiments\SleepLogging\csharp\SleepLogger\Program.cs:line 256

Could you have a look?

Realtime filtering EEG signal (Bandpass Butterworth filter)

Hi,

My issue is related to already existing ones:
30
27
I was trying to use approach suggested there but with no success

I want to apply Butterworth bandpass filter to realtime EEG signal. It consists of several wave bands, for example:
-Theta (4-8Hz)
-Alpha (8-12Hz)
And others ranging from 2 to 50 Hz. The raw EEG signal ranges from -100microVolts to 100microVolts. My sampling rate is 250hz

First I tried to just create an filter and process incoming signal sample by sample:

            var filterDef = new BandPassFilter(4f/250f, 8f/ 250f, 6);

but the Process method always returns NaN. Then I switched to approach suggested in 27

            var filterDef = new BandPassFilter(4f/250f, 8f/ 250f, 6);
            var sosFilter = DesignFilter.TfToSos(filterDef.Tf);
            var chain = new FilterChain(sosFilter);

and using that I am getting results but while it should be something in range [-50,50] microVolts I am getting the values of billions.

I know it is possible to filter these bands because I am using already existing software which does it. Unfortunately the only information I can take from this software is filter definition, nothing more is provided. Below you can find images showing filter definition and realtime fitlering, where the output is delayed not more than 400ms
image
image

I know I am not providing much information but maybe you have some idea what else could be done to accomplish it?
The work you do with this library is amazing - I havent found anything comparable, which could be easily used in C#

Best regards,
Michal

Wrong elliptic filter ripple configuration

The elliptic filter ripple configuration in FiltersForm.AnalyzeEllipticFilter is converted to magnitude Db. But in PrototypeElliptic.Poles and PrototypeElliptic.Zeros it is converted as power Db. So my suggestion is not to use Db here. Or I am wrong?

Stft output frequency bin count doesn't match Stft constructor parameters?

Hi!

I'm currently using the Stft feature, when i provide these parameters

Stft stft = new Stft( windowSize: 1024, hopSize: 256, window: NWaves.Windows.WindowTypes.Hann, fftSize: 256);

The output spectrums result in a length 513 not 256?

See the image below that displays the number of bins in a single spectrum of the Stft spectrogram

Screenshot 2020-09-14 at 09 24 38

Additionally:
Q1) What is the resulting Y Axis graph representing, is it power?
Q2) The Y values output from the Stft are normalized, how are they normalized? e.g:
Screenshot 2020-09-14 at 09 32 29

MFCC returns -Infinity

Hello, I am getting -Infinity values when I try to run MFCC on my audio file. Any info on where this could occur? All of the values in the input file are normal (i.e. not NaN or Infinity).

Why are the default lower frequency from FilterBanks.OctaveBands is 62.5?

Why is the default lower frequency of FilterBanks.OctaveBands 62.5? Should it be 11, 22, 44 as specified in ISO 266?
Lower Frequencies: 11, 22, 44, 88, 177, 355, 710, 1420, 2840, 5680, 11360
Middle Frequencies: 16, 31.5, 63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000
Upper Frequencies: 22, 44, 88, 177, 355, 710, 1420, 2840, 5680, 11360, 22720

Can't read output of AudioRecorder Xamarin forms

I'm using Audio Recorder to record audio in Xamarin Forms.

but as I asked here I had a problem with playing the output of Audio Recorder with my Xiaomi Device.
and when I installed it on a Samsung Device and it works on it.
but when I tried to read and edit it with NWaves. I got this error :

System.IO.EndOfStreamException
Unable to read beyond the end of the stream.

How I can make this output readable for Xiaomi devices and also NWaves?

How to set coef of wavelet?

i write my code in matlab;
x is signal;
how to implement matlab code to nwave in c#?
I try to use wiki example to implement a wavelet filter in C#, But I get confused where in example I can put the coefficient I get via MATLAB.

For example I get the d1:d9 and a9 from MATLAB as below

[C, L] = wavedec (x,9,'db5'); % Decomposition
a9 = wrcoef ('a', C, L,'db5',9); % Approximate Component
d9 = wrcoef ('d', C, L,'db5',9); % Detailed components
d8 = wrcoef ('d', C, L,'db5',8);
d7 = wrcoef ('d', C, L,'db5',7);
d6 = wrcoef ('d', C, L,'db5',6);
d5 = wrcoef ('d', C, L,'db5',5);
d4 = wrcoef ('d', C, L,'db5',4);
d3 = wrcoef ('d', C, L,'db5',3);
d2 = wrcoef ('d', C, L,'db5',2);
d1 = wrcoef ('d', C, L,'db5',1);
y= d9+d8+d7+d6+d5+d4+d3+d2+d1;

MFCC similar to NWaves in librosa

I'm trying to replicate what NWaves does in python librosa lib. I've seen comments around the code so I guess there have been comparisons previously. Do you have any hints on how to generate similar looking mfc in librosa as in NWaves? Any points on what to look out for?

Thanks

HartleyTransform.Direct has wrong results

The spectrum from HartleyTransform.Direct has wrong results. Results containing not the frequencies from a generated signal (e.g. sine + sine + sine). The result from FHT should be comparable with the FFT result. Right?

Stft.Spectrogram with overlapping window plot

How can Stft.Spectrogram with overlapping windows be plotted in the SpectrogramPlot?

In general: should the overlapping part of the spectral chunks plot together (by overlap-add or something like that) or should the X time axis non continuously?

preemphasis filter in LPCExtractor doesn't work

If the preemphasis coefficient is not 0, LPCExtractor returns incorrect results, because the signal is copied to 2 different arrays for autocorrelation function, but preemphasis function is applied to only one array. Same thing with LPCCExtractor.

Redesign feature vectors

At earlier development stages I focused more on offline processing and I thought FeatureVector class was good design choice for storing both feature vectors (as float[]) and time positions (as double). But now I think the time position is kind of redundant here. The vector of time positions can easily be computed in a separate method if necessary. Hence, in ver.0.9.3 I'm planning to remove the class FeatureVector and simply use float[] arrays for features instead.

If there any ideas or objections you can write them in comments here.

MFCC extractor returns NaNs

I keep getting NaNs when I try to compute MFCC on my .wav audio file. I can email the audio file if needed as GitHub doesn't support uploading .wav files.

Code:

private static readonly MfccExtractor MfccExtractor = new MfccExtractor(
            16000,
            64,
            0.025,
            0.01,
            64,
            fftSize: 512,
            preEmphasis: 0.97,
            includeEnergy: true,
            dctType: "4",
            nonLinearity: NonLinearityType.LogE);
var samples = new WaveFile(new FileStream("./file.wav", FileMode.Open))[Channels.Left].Samples;
var mfccSamples  = MfccExtractor.ComputeFrom(samples);

Error when running Operation.TimeStretch

Hi @ar1st0crat thank you for wonderful library.
when I run the program , I got a error.

qb010005.zip

using (var stream = new FileStream("qb010005.wav", FileMode.Open))
{
orgwav = new WaveFile(stream)[0];
newwav = Operation.TimeStretch(orgwav,1.2);
using (var wst = new FileStream("mynew.wav", FileMode.Create))
{
newwavFile = new WaveFile(newwav);
newwavFile.SaveTo(wst);
}
}

But when I change 1.2 to 0.8 it's ok.

FIR Bandpass Resampling becomes unstable after a long duration

First of all, thanks for the great library.

I'm having an issue with resampling using a bandpass FIR filter, here is my Resample configuration:

public static float[] ResampleSignalBandpass(float[] data, int oldSr, int newSr)
{
	var lowCutoff = 0.5 / newSr;   // high pass to remove baseline wander
	var highCutoff = 0.5;   // cutoff at nyquist
	var filterOrder = 11;

	var resampler = new Resampler();
	var lpFilter = new FirFilter(DesignFilter.FirWinBp(filterOrder, lowCutoff, highCutoff)); 
	var resampled = resampler.Resample(new NWaves.Signals.DiscreteSignal(oldSr, data), newSr, lpFilter);
	return resampled.Samples;
}

The original sample rate is 128 Hz
The new sample rate is 192 Hz

After about 36 hours, I see a sudden change in the resample output:
image

Then at 72 hours, I see another abrupt degradation in signal quality
image

Is this a bug in the code, or something I can expect from resampling for a long duration?

Playing saved audio

Hi, when I save a wave file as the output like this
waveFile.SaveTo(stream);
it will save successfully.
but it can't Play it with Media Player in some devices like Xiaomi devices. but it works on Samsung device
Can do something to make the output playable on all android devices?

FFT Inverse return not normalized samples

FFT Inverse return not normalized samples. Is there any reason? Other libraries return normalized samples. Why some normalize and some not?
Normalization influence other calculations like cepstrum. The result of an cepstrum is totaly different if the inverse FFT is normalized or not...

FeatureExtractor ComputeFrom FastCopy bug

When trying to use MfccExtractor to compute the mfcc from a DiscreteSignal I am getting an out of bounds exception. I've traced this exception to be in the ComputeFrom(float[] samples, int startSample, int endSample, IList<float[]> vectors) function within FeatureExtractor.cs.

In this for loop on line 171:
for (int sample = startSample; sample <= lastSample; sample += hopSize, i++)

The copy is run on every iteration (line 175):
samples.FastCopyTo(block, frameSize, sample);

My case throws an exception when trying to copy a samples vector of size 704556 to a block of size 2048, with a frameSize of 1103, and sample with a value of 175077.

Looking at the implementation of FastCopyTo in MemoryOperationExtensions.cs:
Buffer.BlockCopy(source, sourceOffset * _32Bits, destination, destinationOffset * _32Bits, size * _32Bits);
source = samples, sourceOffset = sample = 175077, destionation = block, destinationOffset = 0, and size = 1103.

This makes it so that the BlockCopy is copying from offset 175077 * 4 = 700308 to offset 700308 + (1103 * 4) = 700308 + 4412 = 704720, which is greater than 704556.

Is there something I'm doing wrong here? I pass in a DIscreteSignal made from a float[] into the ComputeFrom function, and it seems that this function should be able to handle an array that does not have dimensions that are an exact multiple of frame size.

Low pass filter returning 0

Hi, first of all great work! The code is very clean and understandable.

I'm testing a low pass filter (I tried with BiQuad and Bessel for now), but the output is always 0. I'm trying with frequencies between 1000 and 22000, but no luck. I've changed also q=1 to q=1/sqrt(2), but still the same.

@ar1st0crat could you shed some light on what is happening?

Thanks!

Update: With OnePole, it is the high pass filter the one that always return 0 (frequencies between 0 and 1000).

NAudio AudioFileReader get left and right channel

            var audioFile = new AudioFileReader(path);
            var waveFile = new WaveFile(audioFile);

            left = waveFile[Channels.Left];
            right = waveFile[Channels.Right];

            var leftCool = Operation.TimeStretch(left, 16, TsmAlgorithm.PaulStretch);
            var rightCool = Operation.TimeStretch(right, 16, TsmAlgorithm.PaulStretch);

            using (var stream = new FileStream("saved_stereo.wav", FileMode.Create))
            {
                var waveFileSt = new WaveFile(new[] { leftCool, rightCool });
                waveFileSt.SaveTo(stream);
            }

throws System.FormatException: NOT RIFF!

Nuget installation issues targeting .NetFramework 4.5

Hi,
I tried to add NWaves to my project and i get the following error:
"Install-Package : Could not install package 'NWaves 0.9.3'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5', but the package does not contain any assembly references or content files that are compatible with that
framework. For more information, contact the package author."

thank you for your help.

Best Regards,
Fakhri

creating new wavefile does not normalize data.

When you read a 16 bit .wav file using as a new FileStream and then create a waveFile from that stream using the command
var waveFile = new NWaves.Audio.WaveFile(stream) or new NWaves.Audio.WaveFile(stream,true)

and then extract the signal using
signal = waveFile[Channels.Left];

The signal values (.samples) ARE NOT normalized between -1 and 1.

Mike

Xamarin Android not play wav file

            try
            {
                using (var stream = new FileStream(fistBank, FileMode.Open))
                {
                    var waveFile = new WaveFile(stream);
                    signal = waveFile[Channels.Left];
                }
            }
            catch(Exception ex)
            {
                Toast.MakeText(Application.Context, ex.ToString(), ToastLength.Short).Show();
            }

Added to the project, added permissions for reading files, I get the path to the file. I press the button and silence ... The file does not play ... It does not even generate signals from examples

MFCC extractor: Index was outside the bounds of the array

I am getting the following exception when I try to compute MFCC on my .wav file.

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at NWaves.Transforms.Dct4.Direct(Single[] input, Single[] output)
   at NWaves.FeatureExtractors.MfccExtractor.ProcessFrame(Single[] block)
   at NWaves.FeatureExtractors.Base.FeatureExtractor.ComputeFrom(Single[] samples, Int32 startSample, Int32 endSample)
   at MFCC.Example.Main(String[] args) in /home/stefan/Documents/work/ls_records/mfcc/WavMFCC/Program.cs:line 58

Here's my code where I construct the extractor.

        private static readonly MfccExtractor MfccExtractor = new MfccExtractor(
            16000,
            32,
            0.025,
            0.01,
            fftSize: 1024,
            preEmphasis: 0.97,
            includeEnergy:true,
            dctType: "4",
            nonLinearity:NonLinearityType.LogE);

Changing the feature count from 32 to a smaller number, say 13 passes and doesn't throw the exception.

how to implement a Notch filter

i write my code in matlab;
y is signal;
how to implement matlab code to nwave in c#?

Fs=1000;
w=50/(Fs/2);
bw=w;
[num,den]=iirnotch(w,bw); % notch filter implementation
y2=filter(num,den,y);

Bandpass frequencies

Hi, I am trying to use Butterworth BandPass filter. I have a signal with sampling rate of 250Hz and I want to filter for frequencies 22-32. I Dont understand what exactly should I put in BandPassFilter constructor. The constructor takes f1 and f2 but that seems no to be frequency. I tried with:

myFilter = new BandPassFilter(22, 32, 6);

and then simply for online processing:

myFilter.Process(mySample)

but it returns NaN all the time. I believe it is because f1 and f2 should be float in range 0-1 but how can I tranform it into particular frequencies ?

WaveFile class closes the underlying audio stream

Hello!

I don't know if that behavior is intentional but to me it does not seem completely logical. When I read an audio stream using the WaveFile class, the stream gets closed automatically afterwards by the underlying BinaryReader. Thus, when I instantiate another WaveFile object using the same Stream instance, I get this exception: "Cannot access a closed stream".

As a hint: the BinaryReader class supports leaving the stream open (see https://docs.microsoft.com/en-us/dotnet/api/system.io.binaryreader.-ctor?view=netcore-3.1#System_IO_BinaryReader__ctor_System_IO_Stream_System_Text_Encoding_System_Boolean_).

King regards from Austria!
Clemens

P.S.: I am a big fan of your work! I really like your coding style as it makes it very easy to debug.

How to avoid clipping during Concatenate ?

Hi, thanks for this wonderful code !
I'm trying to make some music with it, but when i concatenate two signal, for example two sins, i got a terrible clipping effect between every sound.
What can i do to avoid that ?

XML documentation and IntelliSense

Hi @ar1st0crat
If we install NWaves from Nuget, XML documentation/comments are not available with IntelliSense. I think adding <GenerateDocumentationFile>true</GenerateDocumentationFile> tag in the .csproj file would be really helpful :)

python_speech_features mfcc vs NWaves mfcc

Hello.

I've build a Keras model via python and want to use this model in C#. I need to be able to re-create the same MFCC's between the python library verses MWaves version. I've tried lots of options but can't seem to get it.

Below is the options used when training the model. I've also added a comment next to each line indicating what I think the matching field in MWave should be.

mfccs = python_speech_features.base.mfcc(signal,
         samplerate=8000,    
         winlen=0.256,      # Frame Duration, fft/sr
         winstep=0.050,     # Hop Duration, hop_length / sr
         numcep=16,   # Feature Count?
         nfilt=26,          # FilterBankSize
         nfft=2048,         # FFftSize
         preemph=0.0,       # PreEmphasis
         ceplifter=0,       # LifterSize
         appendEnergy=False, # IncludeEnergy
         winfunc=np.hanning) # Window = NWaves.Windows.WindowType.Hann)

The python version returns array[16][16]

But my MWaves equivalent returns array[15][16]. Here's my options

var mfccOptions = new MfccOptions
            {
                SamplingRate = sampleRate,
                FeatureCount = 16,
                FrameDuration = (double)fftSize / sampleRate, 
                HopDuration = 0.05, 
                FftSize = 2048,
                Window = NWaves.Windows.WindowType.Hann,
                IncludeEnergy=false,
                FilterBankSize = 26,
                LifterSize = 0,
                PreEmphasis = 0
            };

Any thoughts on where I might be going wrong?

Thanks

exception on Convolver.convolve function

Hello
I need to call convolution function using Convolver, but always fall in exception.
I have input and kernel arrays with different sizes. I tried to use fft_size with various values, but none of them worked

input array length: 7992
kernel array length: 30
fft_size values: 1024, 16, ...
exception Message:
"Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection."

exception callstack:
at System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count)
at NWaves.Utils.MemoryOperationExtensions.FastCopyTo(Single[] source, Single[] destination, Int32 size, Int32 sourceOffset, Int32 destinationOffset)
at NWaves.Operations.Convolution.Convolver.Convolve(Single[] input, Single[] kernel, Single[] output)

Could you please check this issue and tell me what is proper fft_size?
Thanks

Nuget package

How do you feel about putting this on Nuget? Would you be willing to accept a PR that includes:

  • Updating the project file format to 2017 style?
  • Changing the project target to netstandard2.0?
  • Creating an appveyor account for this in order to introduce CI and to build the nuget package?

I'd be happy to contribute to this as I think .NET is in need of a decent signal processing library.

Does Savitzky-Golay filter calculate correct results?

I am testing the Savitzky-Golay filter. The filter implementation looks very simplified. Or how were the coefficients calculated?
Does the filter calculate correct results? In the example below, the filter is supposed to remove the noise. However, more is removed:

var signal = Enumerable.Range(0, 100).Select(x => (float)System.Math.Sin(x * 0.1)); var random = new Random(); var noise = Enumerable.Range(0, 100).Select(_ => (float)random.NextDouble() * 0.01f); var noisySignal = signal.Zip(noise, (x, y) => x + y).ToArray(); var filteredSignal = new SavitzkyGolayFilter(5, 1).ApplyFilterDirectly(new DiscreteSignal(1, noisySignal));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.