public static Matrix ShortTimeFourierTransform(Complex[] sig, Set filter, double vol = 0.01, int dbMin = -20, int dbMax = +20) { Console.Write($"\r\nBuilding a new Mel model...\r\n"); double norm = 0.0, cc = 0; var Model = new Matrix((int)Math.Ceiling(sig.Length / (double)2048)); foreach (var STFT in Complex.ShortTimeFourierTransform(sig)) { int i = Model.Count; if (i >= Model.Capacity) { throw new OutOfMemoryException(); } Vector it; Debug.Assert(Model[i] == null); Model[i] = it = MelFromFourier(STFT); for (var j = 0; j < it.Axis.Length; j++) { norm += it.Axis[j].Re; cc++; } } if (cc > 0) { norm = norm /= cc; if (norm > 0) { norm = 1d / norm; } } for (int i = 0; i < Model.Count; i++) { var it = Model[i]; if (it != null) { for (var j = 0; j < it.Axis.Length; j++) { it.Axis[j].Re = Math.Round(norm /* Note that this surface is really wierd... i.e. There are * positive and negative decibeles */ * it.Axis[j].Re / (it.Axis.Length * 0.1), 3); it.Axis[j].Re = it.Axis[j].Re; if (it.Axis[j].Re > 0) { RunSpeachFrequencyFilters(it, j, vol, dbMin, dbMax); } if (it.Axis[j].Re > 0 && filter != null) { /* Filter out the specified pitches */ var n = Envelopes.MIDI2NOTE(Envelopes.FREQ2MIDI(it.Axis[j].Im)); if (string.IsNullOrWhiteSpace(n) || filter.Has(n)) { it.Axis[j].Re = 0; } } double finalMag = Math.Round(it.Axis[j].Re, 2); it.Axis[j].Re = finalMag; } double dot = 0.0; for (var j = 0; j < it.Axis.Length; j++) { dot += it.Axis[j].Re * 1; } it.Score.Im = Math.Round( Tanh.f(dot), 2); } } return(Model); }