public void DrawSpectrum(Graphics graphics, Pen pen, int width, int height) { _graphics.Clear(Color.Black); var fftBuffer = new float[(int)_fftProvider.FftSize]; var fftData = new List <double>(); int fftBand = 32; if (_fftProvider.GetFftData(fftBuffer)) { for (int i = 0; i < fftBand; i++) { double value = 0; for (int j = i * fftBand; j < (i * fftBand) + fftBand; j++) { value += (((20 * Math.Log10(fftBuffer[i])) - -60) / -60) * height; } fftData.Add(value / fftBand); } int barWidth = width / fftData.Count; for (int i = 0; i < fftData.Count; i++) { _graphics.DrawLine(Pens.Red, i * barWidth + (barWidth / 2), height, i * barWidth + (barWidth / 2), (float)(height - (fftData[i] < 0 ? 0 : fftData[i]))); } } }
/* * Get the current array of sample data by running the FFT and massaging the output. */ // *Decibel scaling method: // spectrumValues[i] = (((20 * Math.Log10(fftBuf[logFreqIdxs[i]])) - (-90)) / 90); // Sqrt scaling method: // spectrumValues[i] = Math.Sqrt(fftBuf[logFreqIdxs[i]]) * 2; public float[] GetSpectrumValues() { if (!fftProvider.IsNewDataAvailable) { Console.WriteLine("no new data available"); return(null); } // Do the FFT fftProvider.GetFftData(fftBuf); float[] spectrumValues = new float[NUM_COLS]; for (int i = 0; i < NUM_COLS; i++) { // Find the max within each frequency band, then apply Decibel scaling, // per-index scaling (to bring up the mid-high end), time smoothing, // and a minimum threshold int bandSize = logFreqIdxs[i + 1] - logFreqIdxs[i]; float max = new ArraySegment <float>(fftBuf, logFreqIdxs[i], bandSize).Max(); float dbScaled = Math.Max((float)((20 * Math.Log10(max) + 90) / 90), 0); float idxScaled = dbScaled + (float)Math.Sqrt((double)i / (double)NUM_COLS) * dbScaled; float smoothed = prevSpectrumValues[i] * SMOOTHING + idxScaled * (1 - SMOOTHING); spectrumValues[i] = smoothed < MIN_THRESHOLD ? 0 : smoothed; } return(prevSpectrumValues = spectrumValues); }
public bool GetFftData(float[] fftDataBuffer) { if (_fftProvider == null) { return(false); } return(_fftProvider.GetFftData(fftDataBuffer)); }
public void Update() { if (fft.IsNewDataAvailable) { fft.GetFftData(fftData); } bool outwardNormalized = Random.Range(0, 100) == 99; foreach (var particle in particleSet.GetEntities()) { var velocity = particle.Get <Velocity>(); var translation = particle.Get <Translation>().Value; var original = particle.Get <Anchor>().Value; // Drag velocity.Value *= (1 - Time.deltaTime * 10); const float yScaling = 1; // Outward force - stronger when further // if (Random.Range(0, 100) > 90) // { // var outwardForce = translation * (1 * Time.deltaTime); // outwardForce.y *= yScaling; // velocity.Value += outwardForce; // } //Outward force - stronger whe closer // if (Random.Range(0, 100) > 90) // { // var outwardForce = Mathf.Min(1 / translation.magnitude, 1) * Time.deltaTime; // velocity.Value += translation.normalized * (outwardForce * 10); // } // Outward force - normalized // if (outwardNormalized) // { // var outwardForce = translation.normalized * (100 * Time.deltaTime); // velocity.Value += outwardForce; // } // Force towards original position velocity.Value += (original - translation) * (Time.deltaTime * 40); // Random variation float x = Random.Range(-1f, 1f); float y = Random.Range(-1f, 1f) * yScaling; var randomForce = new Vector3(x, y) * (Time.deltaTime * 0.2f); velocity.Value += randomForce; } t += Time.deltaTime; }
public float[] GetFftData() { if (!_readStarted) { start(); return(null); } var fftBuffer = new float[(int)fftSize]; if (fftProvider.GetFftData(fftBuffer)) { return(fftBuffer); } return(null); }
private void UpdateSpectrumData(byte[] data) { for (int i = 0; i < (int)fftProvider.FftSize; i++) { float l = BitConverter.ToSingle(data, i * 8) * hamming[i]; float r = BitConverter.ToSingle(data, i * 8 + 4) * hamming[i]; fftProvider.Add(l, r); } lock (spectrumData) { fftProvider.GetFftData(spectrumData); } newDataRead = false; }
/// <summary> /// Sampling audio device and updating processor internal data. Returns 'at the momement' spectrum data. /// </summary> public List <byte> Sample(Settings settings) { if (!initialized) { return(null); } fftProvider.GetFftData(fftBuffer); rawSpectrum.Clear(); // Get frequencies distribution from FFT data. int b0 = 0; for (int x = 0; x < settings.SamplingResolution; x++) { float peak = 0; int b1 = (int)Math.Pow(2, (x * 10.0 / (settings.SamplingResolution))); if (b1 > 1023) { b1 = 1023; } if (b1 <= b0) { b1 = b0 + 1; } for (; b0 < b1; b0++) { if (peak < fftBuffer[1 + b0]) { peak = fftBuffer[1 + b0]; } } int y = (int)(Math.Sqrt(peak) * 3 * 255); if (y > 255) { y = 255; } if (y < 0) { y = 0; } rawSpectrum.Add((byte)y); } return(rawSpectrum); }
public float[] GetFftData(bool takeRightChannel = false) { if (!SeparateChannels || !takeRightChannel) { return(GetFftData()); } else { if (!_readStarted) { start(); return(null); } var fftBuffer = new float[(int)fftSize]; if (fftProvider2.GetFftData(fftBuffer)) { return(fftBuffer); } return(null); } }
/* * Get the current array of sample data by running the FFT and massaging the output. */ public double[] GetSpectrumValues() { // Check for no data coming through FFT and send nulls if true if (!fftProvider.IsNewDataAvailable) { // Real-time debug only // Console.WriteLine("no new data available"); return(null); } else { // Do the FFT fftProvider.GetFftData(fftBuf); } // Assign to frequency bands double[] spectrumValues = new double[columns]; // This assigns results kind of properly to 10-band octaves but still have ginormous leakage when presented // with a single frequency. Code taken from https://github.com/m4r1vs/Audioly { int spectrumColumn, peak; int indexTick = 0; int fftIdxs = 1023; for (spectrumColumn = 0; spectrumColumn < columns; spectrumColumn++) { double max = 0; int Idxs = (int)Math.Pow(2, spectrumColumn * 10.0 / (columns - 1)); if (Idxs > fftIdxs) { Idxs = fftIdxs; } if (Idxs <= indexTick) { Idxs = indexTick + 1; } for (; indexTick < Idxs; indexTick++) { if (max < fftBuf[1 + indexTick]) { max = fftBuf[1 + indexTick]; } } peak = (int)(Math.Sqrt(max) * 8); // Peak exceeding 0-100 handling. if (peak > 100) { peak = 100; } if (peak < 0) { peak = 0; } _spectrumData.Add(peak); } for (int i = 0; i < _spectrumData.ToArray().Length; i++) { try { double newSmoothed = prevSpectrumValues[i] * smoothing + _spectrumData[i] * (1 - smoothing); spectrumValues[i] = newSmoothed < minThreshold ? 0 : newSmoothed; } catch (Exception) { } } } // Real-time debug only // Console.WriteLine(string.Join("new ", spectrumValues)); // Clear the _spectrumData from any previous results for new FFT data. _spectrumData.Clear(); return(prevSpectrumValues = spectrumValues); }
public string GetLevelsFromAudioFX(string audioType, string audioFile) { string audioFilename = Path.Combine(Executor.Current.ExpanderSharedFiles, audioType, audioFile); string levelsFilename = Path.Combine(Executor.Current.ExpanderSharedFiles, audioType, audioFile + ".levels"); if (!File.Exists(levelsFilename)) { using (ISampleSource source = CodecFactory.Instance.GetCodec(audioFilename).ToSampleSource()) { var fftProvider = new FftProvider(source.WaveFormat.Channels, FftSize.Fft1024); int millisecondsPerFrame = 1000 / 40; long maxBufferLengthInSamples = source.GetRawElements(millisecondsPerFrame); long bufferLength = Math.Min(source.Length, maxBufferLengthInSamples); float[] buffer = new float[bufferLength]; int read = 0; int totalSamplesRead = 0; var fftData = new float[1024]; var list = new List <float>(); float highest = 0; do { //determine how many samples to read int samplesToRead = (int)Math.Min(source.Length - totalSamplesRead, buffer.Length); read = source.Read(buffer, 0, samplesToRead); if (read == 0) { break; } totalSamplesRead += read; //add read data to the fftProvider fftProvider.Add(buffer, read); fftProvider.GetFftData(fftData); float highestAmplitude = 0; for (int i = 0; i < fftData.Length / 2; i++) { if (fftData[i] > highestAmplitude) { highestAmplitude = fftData[i]; } } list.Add(highestAmplitude); if (highestAmplitude > highest) { highest = highestAmplitude; } } while (totalSamplesRead < source.Length); if (highest > 0) { // Adjust to equalize float adjustment = 1 / highest; for (int i = 0; i < list.Count; i++) { list[i] *= adjustment; } } using (var fs = File.Create(levelsFilename)) { fs.Write(list.Select(x => (byte)(x * 255)).ToArray(), 0, list.Count); } } } return(levelsFilename); }
public void GetFFTData(float[] data) { _fft.GetFftData(data); }
/// <summary> /// Entry point /// </summary> /// <param name="args"></param> static void Main(string[] args) { // Validate cmd line args if (args.Length != 1) { Console.WriteLine("Provide a valid music file location (mp3, wav, or m4a)"); return; } string filename = args[0]; if (!File.Exists(filename)) { Console.Error.WriteLine("Could not find file: '{0}'", filename); return; } // Read in audio file and initialize fft IWaveSource waveSource; ISampleSource sampleSource; try { waveSource = CodecFactory.Instance.GetCodec(filename); } catch (NotSupportedException ex) { Console.Error.WriteLine("No supporting decoder for given file: '{0}'\n", filename); Console.Error.WriteLine(ex.ToString()); return; } sampleSource = waveSource.ToSampleSource(); FftProvider fftProvider = new FftProvider(sampleSource.WaveFormat.Channels, FftSize.Fft1024); List <Tuple <int, Complex[]> > fftResults = new List <Tuple <int, Complex[]> >(); int i = 0; // Scrub through the audio 1024 samples at a time and perform fft on each chunk while (sampleSource.Position < sampleSource.Length) { float[] samples = new float[1024]; sampleSource.Read(samples, 0, 1024); fftProvider.Add(samples, samples.Count()); Complex[] result = new Complex[(int)fftProvider.FftSize]; if (fftProvider.GetFftData(result)) { fftResults.Add(new Tuple <int, Complex[]>(i, result)); ++i; } } Console.WriteLine("FFT done"); // Stores the fundamental frequency and amplitude at each frame (1024 samples) List <Tuple <double, double> > fundFreqs = new List <Tuple <double, double> >(); i = 0; // For each fft output foreach (var pair in fftResults) { // The output of the fft has a frequency domain and amplitude range. // In this case, the index of the value represents frequency: index * ((sampleRate / 2) / (vals.Length / 2)) // The value at an index is the amplitude as a complex number. To normalize, calculate: sqrt(real^2 + imaginary^2), this can then be // used to calculate dB level with dBspl equation (20 * log10(normal)) Complex[] vals = pair.Item2; // Frequency buckets produced by fft. Size of each bucket depends on sample rate. // 0 to N/2 of fft output is what we want, N/2 to N is garbage (negative frequencies) int nyquistLength = vals.Length / 2; // Nyquist rate is maximum possible reproducible sample frequency of a given sample rate int nyquistRate = sampleSource.WaveFormat.SampleRate / 2; // Normalize the amplitudes double[] normals = new double[nyquistLength]; for (int j = 0; j < nyquistLength; ++j) { normals[j] = Math.Sqrt(Math.Pow(vals[j].Real, 2) + Math.Pow(vals[j].Imaginary, 2)); } // Find the fundamental frequency and amplitude of that frequency double fundFreq = 0; double amplitude = double.NegativeInfinity; // in dB spl int freqBucket = MaxIndex(normals); if (freqBucket > 0) { fundFreq = freqBucket * (nyquistRate / nyquistLength); } if (fundFreq != 0) { amplitude = 20 * Math.Log10(normals[freqBucket]); // Convert to dB } fundFreqs.Add(new Tuple <double, double>(fundFreq, amplitude)); ++i; } Console.WriteLine("Fundamental frequency analysis of each frame done"); Console.WriteLine("Writing results to csv (timestamp,frequency,amplitude)..."); FileStream outFileStream = null; StreamWriter writer = null; try { outFileStream = File.Create("out.csv"); writer = new StreamWriter(outFileStream); for (int j = 0; j < fundFreqs.Count; ++j) { writer.WriteLine(string.Format("{0},{1},{2}", FrameIndexToTimestamp(j, sampleSource.WaveFormat.SampleRate, 1024), fundFreqs[j].Item1, fundFreqs[j].Item2)); } writer.Close(); outFileStream.Close(); } catch (Exception ex) { Console.Error.WriteLine("failed to write output:"); Console.Error.WriteLine(ex.ToString()); if (outFileStream != null) { outFileStream.Close(); } if (writer != null) { writer.Close(); } } Console.WriteLine("Done"); Console.ReadKey(true); }
public override void GetFftData(float[] resultBuffer) { m_Fft.GetFftData(resultBuffer); }
/* * Get the current array of sample data by running the FFT and massaging the output. */ public double[] GetSpectrumValues(double smoothing, double[] correctorColumns) { double preamp = correctorColumns[10]; // Check for no data coming through FFT and send null if true if (!fftProvider.IsNewDataAvailable) { return(prevSpectrumValues); } else { // Do the FFT fftProvider.GetFftData(fftBuf); } // Assign to frequency bands double[] spectrumValues = new double[columns]; // This assigns results kind of properly to 10-band octaves but still have ginormous leakage when presented // with a single frequency. Code taken from https://github.com/m4r1vs/Audioly { int spectrumColumn; float peak; int indexTick = 0; int fftIdxs = 1023; for (spectrumColumn = 0; spectrumColumn < columns; spectrumColumn++) { double max = 0; int Idxs = (int)Math.Pow(2, spectrumColumn * 10.0 / (columns - 1)); if (Idxs > fftIdxs) { Idxs = fftIdxs; } if (Idxs <= indexTick) { Idxs = indexTick + 1; } for (; indexTick < Idxs; indexTick++) { if (max < fftBuf[1 + indexTick]) { max = fftBuf[1 + indexTick]; } } peak = (float)max; // Peak exceeding 0-100 handling. Not that anything close to 100 happens since it's an // amplitude. if (peak > 100) { peak = 100; } if (peak < 0) { peak = 0; } _spectrumData.Add(peak); foreach (float data in _spectrumData) { firstData = _spectrumData.ToArray(); } if (Properties.Settings.Default.corrector) { /* * Do not apply the corrector when output is less than -100dB, will prevent constant * strip light up. The next part is rather stupid - convert output and corrector to dB, * add them then convert back to amplitude. I'm too bad at math to do it in a better way, * converting dB in corrector to amplitude then adding logarithms produce wrong values. */ if (_spectrumData[spectrumColumn] > 0.00001) { _spectrumData[spectrumColumn] = (float)(20 * Math.Log(_spectrumData[spectrumColumn], 10)); _spectrumData[spectrumColumn] = _spectrumData[spectrumColumn] + (float)correctorColumns[spectrumColumn] + (float)preamp; _spectrumData[spectrumColumn] = (float)(Math.Pow(10, (_spectrumData[spectrumColumn] / 20))); } } /* * Output is in amplitude, using a dB level for our purpose generates so little dB difference * between beats it's not even introducing a flicker. Also, values are so high, you can't even * use a positive corrector, else you're stuck with constant 100s. I'm including a dB method * as a comment, if you want to use it, but there's no practical reason to do so. * On a side note, you'd also want to edit (or delete, if you wanted to) the Normalize function * in Handler class and make the height multiplier of 0.00 to 1.00, so it'd steer the resulting * dB as a percentage value. You'll also want to apply a filter so it'd bring values over 100 * back to 100. An additional preapplied A corrector seems to be needed for that method too. */ for (int i = 0; i < _spectrumData.ToArray().Length; i++) { try { // +90 is to change a reference value to a 0dB point. // double dBscaled = (20*Math.Log(_spectrumData[i],10)+90); // double Smoothed = prevSpectrumValues[i] * smoothing + dBscaled * (1 - smoothing); double Smoothed = prevSpectrumValues[i] * smoothing + _spectrumData[i] * (1 - smoothing); spectrumValues[i] = Smoothed < minThreshold ? 0 : Smoothed; } catch (Exception) { } } } // Clear the _spectrumData from any previous results for new FFT data. _spectrumData.Clear(); return(prevSpectrumValues = spectrumValues); } }