Example #1
0
        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])));
                }
            }
        }
Example #2
0
        /*
         * 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);
        }
Example #3
0
 public bool GetFftData(float[] fftDataBuffer)
 {
     if (_fftProvider == null)
     {
         return(false);
     }
     return(_fftProvider.GetFftData(fftDataBuffer));
 }
Example #4
0
        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;
        }
Example #5
0
        public float[] GetFftData()
        {
            if (!_readStarted)
            {
                start();
                return(null);
            }
            var fftBuffer = new float[(int)fftSize];

            if (fftProvider.GetFftData(fftBuffer))
            {
                return(fftBuffer);
            }
            return(null);
        }
Example #6
0
    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;
    }
Example #7
0
        /// <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);
        }
Example #8
0
 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);
     }
 }
Example #9
0
        /*
         * 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);
        }
Example #10
0
        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);
        }
Example #11
0
 public void GetFFTData(float[] data)
 {
     _fft.GetFftData(data);
 }
Example #12
0
        /// <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);
        }
Example #13
0
 public override void GetFftData(float[] resultBuffer)
 {
     m_Fft.GetFftData(resultBuffer);
 }
Example #14
0
        /*
         * 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);
            }
        }