+ All Categories
Home > Documents > Code Audio Analyzer

Code Audio Analyzer

Date post: 03-Jun-2018
Category:
Upload: thao-le-minh
View: 237 times
Download: 0 times
Share this document with a friend

of 52

Transcript
  • 8/12/2019 Code Audio Analyzer

    1/52

    1. DFT.java

    /** Copyright (c) 2007 - 2008 by Damien Di Fede

    ** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU Library General Public License aspublished* by the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU Library General Public License for more details.** You should have received a copy of the GNU Library General Public* License along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/

    package com.badlogic.audio.analysis;

    /*** DFT stands for Discrete Fourier Transform and is the most widely usedFourier* Transform. You will never want to use this class due to the fact that itis a* brute force implementation of the DFT and as such is quite slow. Use anFFT

    * instead. This exists primarily as a way to ensure that otherimplementations* of the DFT are working properly. This implementation expects an even* timeSize and will throw and IllegalArgumentException if this* is not the case.** @author Damien Di Fede** @see FourierTransform* @see FFT* @see The Discrete FourierTransform**/public class DFT extends FourierTransform{/*** Constructs a DFT that expects audio buffers of length

    timeSize that* have been recorded with a sample rate of sampleRate. Will

    throw an* IllegalArgumentException if timeSize is not even.*

  • 8/12/2019 Code Audio Analyzer

    2/52

    * @param timeSize the length of the audio buffers you plan to analyze* @param sampleRate the sample rate of the audio samples you plan to

    analyze*/public DFT(int timeSize, float sampleRate){super(timeSize, sampleRate);if (timeSize % 2 != 0)throw new IllegalArgumentException("DFT: timeSize must be even.");

    buildTrigTables();}

    protected void allocateArrays(){spectrum = new float[timeSize / 2 + 1];real = new float[timeSize / 2 + 1];imag = new float[timeSize / 2 + 1];

    }

    /**

    * Not currently implemented.*/public void scaleBand(int i, float s){}

    /*** Not currently implemented.*/public void setBand(int i, float a){}

    public void forward(float[] samples){if (samples.length != timeSize){

    throw new IllegalArgumentException("DFT.forward: The length of thepassed sample buffer must be equal to DFT.timeSize().");

    }doWindow(samples);int N = samples.length;for (int f = 0; f

  • 8/12/2019 Code Audio Analyzer

    3/52

    int N = buffer.length;real[0] /= N;imag[0] = -imag[0] / (N / 2);real[N / 2] /= N;imag[N / 2] = -imag[0] / (N / 2);for (int i = 0; i < N / 2; i++){real[i] /= (N / 2);imag[i] = -imag[i] / (N / 2);

    }for (int t = 0; t < N; t++){buffer[t] = 0.0f;for (int f = 0; f < N / 2; f++){buffer[t] += real[f] * cos(t * f) + imag[f] * sin(t * f);

    }}

    }

    // lookup table data and functions

    private float[] sinlookup;private float[] coslookup;

    private void buildTrigTables(){int N = spectrum.length * timeSize;sinlookup = new float[N];coslookup = new float[N];for (int i = 0; i < N; i++){sinlookup[i] = (float) Math.sin(i * TWO_PI / timeSize);coslookup[i] = (float) Math.cos(i * TWO_PI / timeSize);

    }}

    private float sin(int i){return sinlookup[i];

    }

    private float cos(int i){return coslookup[i];

    }}

  • 8/12/2019 Code Audio Analyzer

    4/52

    2.FFT.java

    /** Copyright (c) 2007 - 2008 by Damien Di Fede ** This program is free software; you can redistribute it and/or modify

    * it under the terms of the GNU Library General Public License aspublished* by the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU Library General Public License for more details.** You should have received a copy of the GNU Library General Public* License along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/

    package com.badlogic.audio.analysis;

    /*** FFT stands for Fast Fourier Transform. It is an efficient way to calculatethe Complex* Discrete Fourier Transform. There is not much to say about this classother than the fact* that when you want to analyze the spectrum of an audio buffer you willalmost always use* this class. One restriction of this class is that the audio buffers youwant to analyze

    * must have a length that is a power of two. If you try to construct an FFTwith a* timeSize that is not a power of two, anIllegalArgumentException will be* thrown.** @see FourierTransform* @see The Fast FourierTransform** @author Damien Di Fede**/public class FFT extends FourierTransform

    {/*** Constructs an FFT that will accept sample buffers that are* timeSize long and have been recorded with a sample rate of* sampleRate. timeSize must be a* power of two. This will throw an exception if it is not.** @param timeSize* the length of the sample buffers you will be analyzing

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FFT.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FFT.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FFT.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FFT.java?r=11
  • 8/12/2019 Code Audio Analyzer

    5/52

    * @param sampleRate* the sample rate of the audio you will be analyzing*/public FFT(int timeSize, float sampleRate){super(timeSize, sampleRate);if ((timeSize & (timeSize - 1)) != 0)throw new IllegalArgumentException(

    "FFT: timeSize must be a power of two.");buildReverseTable();buildTrigTables();

    }

    protected void allocateArrays(){spectrum = new float[timeSize / 2 + 1];real = new float[timeSize];imag = new float[timeSize];

    }

    public void scaleBand(int i, float s){if (s < 0){throw new IllegalArgumentException("Can't scale a frequency band by a

    negative value.");}if (spectrum[i] != 0){real[i] /= spectrum[i];imag[i] /= spectrum[i];spectrum[i] *= s;real[i] *= spectrum[i];imag[i] *= spectrum[i];

    }if (i != 0 && i != timeSize / 2){real[timeSize - i] = real[i];imag[timeSize - i] = -imag[i];

    }}

    public void setBand(int i, float a){if (a < 0){throw new IllegalArgumentException("Can't set a frequency band to a

    negative value.");}if (real[i] == 0 && imag[i] == 0){real[i] = a;spectrum[i] = a;

    }else{real[i] /= spectrum[i];

  • 8/12/2019 Code Audio Analyzer

    6/52

    imag[i] /= spectrum[i];spectrum[i] = a;real[i] *= spectrum[i];imag[i] *= spectrum[i];

    }if (i != 0 && i != timeSize / 2){real[timeSize - i] = real[i];imag[timeSize - i] = -imag[i];

    }}

    // performs an in-place fft on the data in the real and imag arrays// bit reversing is not necessary as the data will already be bit reversedprivate void fft(){for (int halfSize = 1; halfSize < real.length; halfSize *= 2){// float k = -(float)Math.PI/halfSize;// phase shift step

    // float phaseShiftStepR = (float)Math.cos(k);// float phaseShiftStepI = (float)Math.sin(k);// using lookup tablefloat phaseShiftStepR = cos(halfSize);float phaseShiftStepI = sin(halfSize);// current phase shiftfloat currentPhaseShiftR = 1.0f;float currentPhaseShiftI = 0.0f;for (int fftStep = 0; fftStep < halfSize; fftStep++){for (int i = fftStep; i < real.length; i += 2 * halfSize){int off = i + halfSize;float tr = (currentPhaseShiftR * real[off]) - (currentPhaseShiftI *

    imag[off]);float ti = (currentPhaseShiftR * imag[off]) + (currentPhaseShiftI *

    real[off]);real[off] = real[i] - tr;imag[off] = imag[i] - ti;real[i] += tr;imag[i] += ti;

    }float tmpR = currentPhaseShiftR;currentPhaseShiftR = (tmpR * phaseShiftStepR) - (currentPhaseShiftI *

    phaseShiftStepI);currentPhaseShiftI = (tmpR * phaseShiftStepI) + (currentPhaseShiftI *

    phaseShiftStepR);

    }}

    }

    public void forward(float[] buffer){if (buffer.length != timeSize){

    throw new IllegalArgumentException("FFT.forward: The length of thepassed sample buffer must be equal to timeSize().");

  • 8/12/2019 Code Audio Analyzer

    7/52

    }doWindow(buffer);// copy samples to real/imag in bit-reversed orderbitReverseSamples(buffer);// perform the fftfft();// fill the spectrum buffer with amplitudesfillSpectrum();

    }

    /*** Performs a forward transform on the passed buffers.** @param buffReal the real part of the time domain signal to transform* @param buffImag the imaginary part of the time domain signal to

    transform*/public void forward(float[] buffReal, float[] buffImag){if (buffReal.length != timeSize || buffImag.length != timeSize)

    {throw new IllegalArgumentException("FFT.forward: The length of the

    passed buffers must be equal to timeSize().");}setComplex(buffReal, buffImag);bitReverseComplex();fft();fillSpectrum();

    }

    public void inverse(float[] buffer){if (buffer.length > real.length){

    throw new IllegalArgumentException("FFT.inverse: the passed array'slength must equal FFT.timeSize().");

    }// conjugatefor (int i = 0; i < timeSize; i++){imag[i] *= -1;

    }bitReverseComplex();fft();// copy the result in real into buffer, scaling as we dofor (int i = 0; i < buffer.length; i++){

    buffer[i] = real[i] / real.length;}

    }

    private int[] reverse;

    private void buildReverseTable(){int N = timeSize;reverse = new int[N];

  • 8/12/2019 Code Audio Analyzer

    8/52

  • 8/12/2019 Code Audio Analyzer

    9/52

    }}

    }

  • 8/12/2019 Code Audio Analyzer

    10/52

    3.FourierTransform.java

    /*

    * Copyright (c) 2007 - 2008 by Damien Di Fede

    *

    * This program is free software; you can redistribute it and/or modify

    * it under the terms of the GNU Library General Public License as published

    * by the Free Software Foundation; either version 2 of the License, or

    * (at your option) any later version.

    *

    * This program is distributed in the hope that it will be useful,

    * but WITHOUT ANY WARRANTY; without even the implied warranty of

    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    * GNU Library General Public License for more details.

    *

    * You should have received a copy of the GNU Library General Public

    * License along with this program; if not, write to the Free Software

    * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    */

    package com.badlogic.audio.analysis;

    /**

    * A Fourier Transform is an algorithm that transforms a signal in the time

    * domain, such as a sample buffer, into a signal in the frequency domain, often* called the spectrum. The spectrum does not represent individual frequencies,

    * but actually represents frequency bands centered on particular frequencies.

    * The center frequency of each band is usually expressed as a fraction of the

    * sampling rate of the time domain signal and is equal to the index of the

    * frequency band divided by the total number of bands. The total number of

    * frequency bands is usually equal to the length of the time domain signal, but

    * access is only provided to frequency bands with indices less than half the

    * length, because they correspond to frequencies below the Nyquist frequency.

    * In other words, given a signal of length N, there will be

    * N/2 frequency bands in the spectrum.

    *

    * As an example, if you construct a FourierTransform with a

    * timeSize of 1024 and and a sampleRate of 44100

    * Hz, then the spectrum will contain values for frequencies below 22010 Hz,

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FourierTransform.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FourierTransform.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FourierTransform.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/analysis/FourierTransform.java?r=11
  • 8/12/2019 Code Audio Analyzer

    11/52

    * which is the Nyquist frequency (half the sample rate). If you ask for the

    * value of band number 5, this will correspond to a frequency band centered on

    * 5/1024 * 44100 = 0.0048828125 * 44100 = 215 Hz. The width of

    * that frequency band is equal to 2/1024, expressed as a

    * fraction of the total bandwidth of the spectrum. The total bandwith of the* spectrum is equal to the Nyquist frequency, which in this case is 22100, so

    * the bandwidth is equal to about 50 Hz. It is not necessary for you to

    * remember all of these relationships, though it is good to be aware of them.

    * The function getFreq() allows you to query the spectrum with a

    * frequency in Hz and the function getBandWidth() will return

    * the bandwidth in Hz of each frequency band in the spectrum.

    *

    * Usage

    *

    * A typical usage of a FourierTransform is to analyze a signal so that the

    * frequency spectrum may be represented in some way, typically with vertical

    * lines. You could do this in Processing with the following code, where

    * audio is an AudioSource and fft is an FFT (one

    * of the derived classes of FourierTransform).

    *

    *

    * fft.forward(audio.left);

    * for (int i = 0; i < fft.specSize(); i++)

    * {

    * // draw the line for frequency band i, scaling it by 4 so we can see it a bit better

    * line(i, height, i, height - fft.getBand(i) * 4);

    * }

    *

    *

    * Windowing

    *

    * Windowing is the process of shaping the audio samples before transforming them

    * to the frequency domain. If you call the window() function

    * with an appropriate constant, such as FourierTransform.HAMMING, the sample

    * buffers passed to the object for analysis will be shaped by the current

    * window before being transformed. The result of using a window is to reduce

    * the noise in the spectrum somewhat.

    *

  • 8/12/2019 Code Audio Analyzer

    12/52

    * Averages

    *

    * FourierTransform also has functions that allow you to request the creation of

    * an average spectrum. An average spectrum is simply a spectrum with fewer

    * bands than the full spectrum where each average band is the average of the* amplitudes of some number of contiguous frequency bands in the full spectrum.

    *

    * linAverages() allows you to specify the number of averages

    * that you want and will group frequency bands into groups of equal number. So

    * if you have a spectrum with 512 frequency bands and you ask for 64 averages,

    * each average will span 8 bands of the full spectrum.

    *

    * logAverages() will group frequency bands by octave and allows

    * you to specify the size of the smallest octave to use (in Hz) and also how

    * many bands to split each octave into. So you might ask for the smallest

    * octave to be 60 Hz and to split each octave into two bands. The result is

    * that the bandwidth of each average is different. One frequency is an octave

    * above another when it's frequency is twice that of the lower frequency. So,

    * 120 Hz is an octave above 60 Hz, 240 Hz is an octave above 120 Hz, and so on.

    * When octaves are split, they are split based on Hz, so if you split the

    * octave 60-120 Hz in half, you will get 60-90Hz and 90-120Hz. You can see how

    * these bandwidths increase as your octave sizes grow. For instance, the last

    * octave will always span sampleRate/4 - sampleRate/2, which in

    * the case of audio sampled at 44100 Hz is 11025-22010 Hz. These

    * logarithmically spaced averages are usually much more useful than the full

    * spectrum or the linearly spaced averages because they map more directly to

    * how humans perceive sound.

    *

    * calcAvg() allows you to specify the frequency band you want an

    * average calculated for. You might ask for 60-500Hz and this function will

    * group together the bands from the full spectrum that fall into that range and

    * average their amplitudes for you.

    *

    * If you don't want any averages calculated, then you can call

    * noAverages(). This will not impact your ability to use

    * calcAvg(), it will merely prevent the object from calculating

    * an average array every time you use forward().

    *

  • 8/12/2019 Code Audio Analyzer

    13/52

  • 8/12/2019 Code Audio Analyzer

    14/52

    *

    * @param ts

    * the length of the buffers that will be analyzed

    * @param sr

    * the sample rate of the samples that will be analyzed*/

    FourierTransform(int ts, float sr)

    {

    timeSize = ts;

    sampleRate = (int)sr;

    bandWidth = (2f / timeSize) * ((float)sampleRate / 2f);

    noAverages();

    allocateArrays();

    whichWindow = NONE;

    }

    // allocating real, imag, and spectrum are the responsibility of derived

    // classes

    // because the size of the arrays will depend on the implementation being used

    // this enforces that responsibility

    protected abstract void allocateArrays();

    protected void setComplex(float[] r, float[] i)

    {

    if (real.length != r.length && imag.length != i.length){

    throw new IllegalArgumentException( "This won't work" );

    }

    else

    {

    System.arraycopy(r, 0, real, 0, r.length);

    System.arraycopy(i, 0, imag, 0, i.length);

    }

    }// fill the spectrum array with the amps of the data in real and imag

    // used so that this class can handle creating the average array

    // and also do spectrum shaping if necessary

    protected void fillSpectrum()

    {

    for (int i = 0; i < spectrum.length; i++)

  • 8/12/2019 Code Audio Analyzer

    15/52

    {

    spectrum[i] = (float) Math.sqrt(real[i] * real[i] + imag[i] * imag[i]);

    }

    if (whichAverage == LINAVG)

    {int avgWidth = (int) spectrum.length / averages.length;

    for (int i = 0; i < averages.length; i++)

    {

    float avg = 0;

    int j;

    for (j = 0; j < avgWidth; j++)

    {

    int offset = j + i * avgWidth;

    if (offset < spectrum.length){

    avg += spectrum[offset];

    }

    else

    {

    break;

    }

    }

    avg /= j + 1;averages[i] = avg;

    }

    }

    else if (whichAverage == LOGAVG)

    {

    for (int i = 0; i < octaves; i++)

    {

    float lowFreq, hiFreq, freqStep;

    if (i == 0)

    {

    lowFreq = 0;

    }

    else

    {

    lowFreq = (sampleRate / 2) / (float) Math.pow(2, octaves - i);

  • 8/12/2019 Code Audio Analyzer

    16/52

    }

    hiFreq = (sampleRate / 2) / (float) Math.pow(2, octaves - i - 1);

    freqStep = (hiFreq - lowFreq) / avgPerOctave;

    float f = lowFreq;

    for (int j = 0; j < avgPerOctave; j++){

    int offset = j + i * avgPerOctave;

    averages[offset] = calcAvg(f, f + freqStep);

    f += freqStep;

    }

    }

    }

    }

    /*** Sets the object to not compute averages.

    *

    */

    public void noAverages()

    {

    averages = new float[0];

    whichAverage = NOAVG;

    }

    /*** Sets the number of averages used when computing the spectrum and spaces the

    * averages in a linear manner. In other words, each average band will be

    * specSize() / numAvg bands wide.

    *

    * @param numAvg

    * how many averages to compute

    */

    public void linAverages(int numAvg)

    {if (numAvg > spectrum.length / 2)

    {

    throw new IllegalArgumentException("The number of averages for this transform can be at

    most " + spectrum.length / 2 + ".");

    }

    else

  • 8/12/2019 Code Audio Analyzer

    17/52

    {

    averages = new float[numAvg];

    }

    whichAverage = LINAVG;

    }/**

    * Sets the number of averages used when computing the spectrum based on the

    * minimum bandwidth for an octave and the number of bands per octave. For

    * example, with audio that has a sample rate of 44100 Hz,

    * logAverages(11, 1) will result in 12 averages, each

    * corresponding to an octave, the first spanning 0 to 11 Hz. To ensure that

    * each octave band is a full octave, the number of octaves is computed by

    * dividing the Nyquist frequency by two, and then the result of that by two,

    * and so on. This means that the actual bandwidth of the lowest octave may* not be exactly the value specified.

    *

    * @param minBandwidth

    * the minimum bandwidth used for an octave

    * @param bandsPerOctave

    * how many bands to split each octave into

    */

    public void logAverages(int minBandwidth, int bandsPerOctave)

    {float nyq = (float) sampleRate / 2f;

    octaves = 1;

    while ((nyq /= 2) > minBandwidth)

    {

    octaves++;

    }

    avgPerOctave = bandsPerOctave;

    averages = new float[octaves * bandsPerOctave];

    whichAverage = LOGAVG;

    }

    /**

    * Sets the window to use on the samples before taking the forward transform.

    * If an invalid window is asked for, an error will be reported and the

    * current window will not be changed.

    *

  • 8/12/2019 Code Audio Analyzer

    18/52

    * @param which

    * FourierTransform.HAMMING or FourierTransform.NONE

    */

    public void window(int which)

    {if (which < 0 || which > 1)

    {

    throw new IllegalArgumentException("Invalid window type.");

    }

    else

    {

    whichWindow = which;

    }

    }

    protected void doWindow(float[] samples)

    {

    switch (whichWindow)

    {

    case HAMMING:

    hamming(samples);

    break;

    }

    }// windows the data in samples with a Hamming window

    protected void hamming(float[] samples)

    {

    for (int i = 0; i < samples.length; i++)

    {

    samples[i] *= (0.54f - 0.46f * Math.cos(TWO_PI * i / (samples.length - 1)));

    }

    }

    /*** Returns the length of the time domain signal expected by this transform.

    *

    * @return the length of the time domain signal expected by this transform

    */

    public int timeSize()

    {

  • 8/12/2019 Code Audio Analyzer

    19/52

    return timeSize;

    }

    /**

    * Returns the size of the spectrum created by this transform. In other words,

    * the number of frequency bands produced by this transform. This is typically* equal to timeSize()/2 + 1, see above for an explanation.

    *

    * @return the size of the spectrum

    */

    public int specSize()

    {

    return spectrum.length;

    }

    /*** Returns the amplitude of the requested frequency band.

    *

    * @param i

    * the index of a frequency band

    * @return the amplitude of the requested frequency band

    */

    public float getBand(int i)

    {

    if (i < 0) i = 0;if (i > spectrum.length - 1) i = spectrum.length - 1;

    return spectrum[i];

    }

    /**

    * Returns the width of each frequency band in the spectrum (in Hz). It should

    * be noted that the bandwidth of the first and last frequency bands is half

    * as large as the value returned by this function.

    *

    * @return the width of each frequency band in Hz.*/

    public float getBandWidth()

    {

    return bandWidth;

    }

  • 8/12/2019 Code Audio Analyzer

    20/52

    /**

    * Sets the amplitude of the ith frequency band to

    * a. You can use this to shape the spectrum before using

    * inverse().

    ** @param i

    * the frequency band to modify

    * @param a

    * the new amplitude

    */

    public abstract void setBand(int i, float a);

    /**

    * Scales the amplitude of the ith frequency band

    * by s. You can use this to shape the spectrum before using* inverse().

    *

    * @param i

    * the frequency band to modify

    * @param s

    * the scaling factor

    */

    public abstract void scaleBand(int i, float s);

    /*** Returns the index of the frequency band that contains the requested

    * frequency.

    *

    * @param freq

    * the frequency you want the index for (in Hz)

    * @return the index of the frequency band that contains freq

    */

    public int freqToIndex(float freq)

    {// special case: freq is lower than the bandwidth of spectrum[0]

    if (freq < getBandWidth() / 2) return 0;

    // special case: freq is within the bandwidth of spectrum[spectrum.length - 1]

    if (freq > sampleRate / 2 - getBandWidth() / 2) return spectrum.length - 1;

    // all other cases

    float fraction = freq / (float) sampleRate;

  • 8/12/2019 Code Audio Analyzer

    21/52

    int i = Math.round(timeSize * fraction);

    return i;

    }

    /*** Returns the middle frequency of the ith band.

    * @param i

    * the index of the band you want to middle frequency of

    */

    public float indexToFreq(int i)

    {

    float bw = getBandWidth();

    // special case: the width of the first bin is half that of the others.

    // so the center frequency is a quarter of the way.

    if ( i == 0 ) return bw * 0.25f;

    // special case: the width of the last bin is half that of the others.

    if ( i == spectrum.length - 1 )

    {

    float lastBinBeginFreq = (sampleRate / 2) - (bw / 2);

    float binHalfWidth = bw * 0.25f;

    return lastBinBeginFreq + binHalfWidth;

    }

    // the center frequency of the ith band is simply i*bw

    // because the first band is half the width of all others.

    // treating it as if it wasn't offsets us to the middle

    // of the band.

    return i*bw;

    }

    /**

    * Returns the center frequency of the ith average band.

    *

    * @param i

    * which average band you want the center frequency of.

    */

    public float getAverageCenterFrequency(int i)

    {

    if ( whichAverage == LINAVG )

  • 8/12/2019 Code Audio Analyzer

    22/52

    {

    // an average represents a certain number of bands in the spectrum

    int avgWidth = (int) spectrum.length / averages.length;

    // the "center" bin of the average, this is fudgy.

    int centerBinIndex = i*avgWidth + avgWidth/2;return indexToFreq(centerBinIndex);

    }

    else if ( whichAverage == LOGAVG )

    {

    // which "octave" is this index in?

    int octave = i / avgPerOctave;

    // which band within that octave is this?

    int offset = i % avgPerOctave;

    float lowFreq, hiFreq, freqStep;

    // figure out the low frequency for this octave

    if (octave == 0)

    {

    lowFreq = 0;

    }

    else

    {

    lowFreq = (sampleRate / 2) / (float) Math.pow(2, octaves - octave);

    }

    // and the high frequency for this octave

    hiFreq = (sampleRate / 2) / (float) Math.pow(2, octaves - octave - 1);

    // each average band within the octave will be this big

    freqStep = (hiFreq - lowFreq) / avgPerOctave;

    // figure out the low frequency of the band we care about

    float f = lowFreq + offset*freqStep;

    // the center of the band will be the low plus half the width

    return f + freqStep/2;

    }

    return 0;

    }

    /**

  • 8/12/2019 Code Audio Analyzer

    23/52

    * Gets the amplitude of the requested frequency in the spectrum.

    *

    * @param freq

    * the frequency in Hz

    * @return the amplitude of the frequency in the spectrum*/

    public float getFreq(float freq)

    {

    return getBand(freqToIndex(freq));

    }

    /**

    * Sets the amplitude of the requested frequency in the spectrum to

    * a.

    ** @param freq

    * the frequency in Hz

    * @param a

    * the new amplitude

    */

    public void setFreq(float freq, float a)

    {

    setBand(freqToIndex(freq), a);

    }/**

    * Scales the amplitude of the requested frequency by a.

    *

    * @param freq

    * the frequency in Hz

    * @param s

    * the scaling factor

    */

    public void scaleFreq(float freq, float s){

    scaleBand(freqToIndex(freq), s);

    }

    /**

    * Returns the number of averages currently being calculated.

    *

  • 8/12/2019 Code Audio Analyzer

    24/52

    * @return the length of the averages array

    */

    public int avgSize()

    {

    return averages.length;}

    /**

    * Gets the value of the ith average.

    *

    * @param i

    * the average you want the value of

    * @return the value of the requested average band

    */

    public float getAvg(int i){

    float ret;

    if (averages.length > 0)

    ret = averages[i];

    else

    ret = 0;

    return ret;

    }

    /*** Calculate the average amplitude of the frequency band bounded by

    * lowFreq and hiFreq, inclusive.

    *

    * @param lowFreq

    * the lower bound of the band

    * @param hiFreq

    * the upper bound of the band

    * @return the average of all spectrum values within the bounds

    */public float calcAvg(float lowFreq, float hiFreq)

    {

    int lowBound = freqToIndex(lowFreq);

    int hiBound = freqToIndex(hiFreq);

    float avg = 0;

    for (int i = lowBound; i

  • 8/12/2019 Code Audio Analyzer

    25/52

    {

    avg += spectrum[i];

    }

    avg /= (hiBound - lowBound + 1);

    return avg;}

    /**

    * Performs a forward transform on buffer.

    *

    * @param buffer

    * the buffer to analyze

    */

    public abstract void forward(float[] buffer);

    /**

    * Performs a forward transform on values in buffer.

    *

    * @param buffer

    * the buffer of samples

    * @param startAt

    * the index to start at in the buffer. there must be at least timeSize() samples

    * between the starting index and the end of the buffer. If there aren't, an

    * error will be issued and the operation will not be performed.*

    */

    public void forward(float[] buffer, int startAt)

    {

    if ( buffer.length - startAt < timeSize )

    {

    throw new IllegalArgumentException( "FourierTransform.forward: not enough samples inthe buffer between " + startAt + " and " + buffer.length + " to perform a transform." );

    }

    // copy the section of samples we want to analyze

    float[] section = new float[timeSize];

    System.arraycopy(buffer, startAt, section, 0, section.length);

    forward(section);

    }

  • 8/12/2019 Code Audio Analyzer

    26/52

    /**

    * Performs an inverse transform of the frequency spectrum and places the

    * result in buffer.

    ** @param buffer

    * the buffer to place the result of the inverse transform in

    */

    public abstract void inverse(float[] buffer);

    /**

    * Performs an inverse transform of the frequency spectrum represented by

    * freqReal and freqImag and places the result in buffer.

    *

    * @param freqReal* the real part of the frequency spectrum

    * @param freqImag

    * the imaginary part the frequency spectrum

    * @param buffer

    * the buffer to place the inverse transform in

    */

    public void inverse(float[] freqReal, float[] freqImag, float[] buffer)

    {

    setComplex(freqReal, freqImag);inverse(buffer);

    }

    /**

    * @return the spectrum of the last FourierTransform.forward() call.

    */

    public float[] getSpectrum( )

    {

    return spectrum;

    }

    /**

    * @return the real part of the last FourierTransform.forward() call.

    */

    public float[] getRealPart( )

  • 8/12/2019 Code Audio Analyzer

    27/52

    {

    return real;

    }

    /*** @return the imaginary part of the last FourierTransform.forward() call.

    */

    public float[] getImaginaryPart( )

    {

    return imag;

    }

    }

  • 8/12/2019 Code Audio Analyzer

    28/52

    4.AudioDevice.java

    package com.badlogic.audio.io;

    import java.io.FileInputStream;

    import javax.sound.sampled.AudioFormat;import javax.sound.sampled.AudioSystem;

    import javax.sound.sampled.SourceDataLine;

    import javax.sound.sampled.AudioFormat.Encoding;

    /**

    * Class that allows directly passing PCM float mono

    * data to the sound card for playback. The sampling

    * rate of the PCM data must be 44100Hz.

    *

    * @author mzechner*

    */

    public class AudioDevice

    {

    /** the buffer size in samples **/

    private final static int BUFFER_SIZE = 1024;

    /** the java sound line we write our samples to **/

    private final SourceDataLine out;

    /** buffer for BUFFER_SIZE 16-bit samples **/

    private byte[] buffer = new byte[BUFFER_SIZE*2];

    /**

    * Constructor, initializes the audio system for

    * 44100Hz 16-bit signed mono output.

    *

    * @throws Exception in case the audio system could not be initialized*/

    public AudioDevice( ) throws Exception

    {

    AudioFormat format = new AudioFormat( Encoding.PCM_SIGNED, 44100, 16, 1, 2,44100, false );

    out = AudioSystem.getSourceDataLine( format );

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/AudioDevice.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/AudioDevice.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/AudioDevice.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/AudioDevice.java?r=11
  • 8/12/2019 Code Audio Analyzer

    29/52

    out.open(format);

    out.start();

    }

    /*** Writes the given samples to the audio device. The samples

    * have to be sampled at 44100Hz, mono and have to be in

    * the range [-1,1].

    *

    * @param samples The samples.

    */

    public void writeSamples( float[] samples )

    {

    fillBuffer( samples );

    out.write( buffer, 0, buffer.length );

    }

    private void fillBuffer( float[] samples )

    {

    for( int i = 0, j = 0; i < samples.length; i++, j+=2 )

    {

    short value = (short)(samples[i] * Short.MAX_VALUE);

    buffer[j] = (byte)(value | 0xff);

    buffer[j+1] = (byte)(value >> 8 );

    }

    }

    public static void main( String[] argv ) throws Exception

    {

    float[] samples = new float[1024];

    WaveDecoder reader = new WaveDecoder( new FileInputStream(

    "samples/sample.wav" ) );

    AudioDevice device = new AudioDevice( );

    while( reader.readSamples( samples ) > 0 )

    {

    device.writeSamples( samples );

    }

  • 8/12/2019 Code Audio Analyzer

    30/52

    Thread.sleep( 10000 );

    }

    }

  • 8/12/2019 Code Audio Analyzer

    31/52

    5.EndianDataInputStream.java

    package com.badlogic.audio.io;

    import java.io.DataInputStream;

    import java.io.InputStream;

    public class EndianDataInputStream extends DataInputStream

    {

    public EndianDataInputStream(InputStream in)

    {

    super(in);

    }

    public String read4ByteString( ) throws Exception

    {

    byte[] bytes = new byte[4];readFully(bytes);

    return new String( bytes, "US-ASCII" );

    }

    public short readShortLittleEndian( ) throws Exception

    {

    int result = readUnsignedByte();

    result |= readUnsignedByte()

  • 8/12/2019 Code Audio Analyzer

    32/52

  • 8/12/2019 Code Audio Analyzer

    33/52

    6/MP3Decoder.java

    package com.badlogic.audio.io;

    import java.io.BufferedInputStream;

    import java.io.InputStream;

    import javazoom.jl.decoder.Bitstream;

    import javazoom.jl.decoder.Decoder;

    import javazoom.jl.decoder.Header;

    import javazoom.jl.decoder.SampleBuffer;

    /**

    * A simple MP3 decoder based on JLayer

    * @author mzechner

    *

    */public class MP3Decoder

    {

    /** inverse max short value as float **/

    private final float MAX_VALUE = 1.0f / Short.MAX_VALUE;

    /** the bit stream **/

    private final Bitstream bitStream;

    /** the decoder **/private final Decoder decoder;

    /** samples left over **/

    private float[] leftOverSamples = new float[1024];

    /** how many samples are left over **/

    private int leftOver = 0;

    /*** Constructor, sets the input stream to read the mp3 from

    * @param stream The input stream.

    * @throws Exception in case something baaaaad happened.

    */

    public MP3Decoder( InputStream stream ) throws Exception

    {

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/MP3Decoder.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/MP3Decoder.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/MP3Decoder.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/MP3Decoder.java?r=11
  • 8/12/2019 Code Audio Analyzer

    34/52

    bitStream = new Bitstream( new BufferedInputStream( stream, 1024*1024) );

    decoder = new Decoder( );

    }

    /**

    * Tries to read in samples.length samples, merging stereo to a mono

    * channel by averaging and converting non float formats to float 32-bit.

    * Returns the number of samples actually read. Guarantees that samples.length

    * samples are read in if there was enough data in the stream.

    *

    * @param samples The samples array to write the samples to

    * @return The number of samples actually read.

    */

    public int readSamples( float[] samples )

    {

    int readSamples = 0;

    if( leftOver > 0 )

    {

    int maxSamples = Math.min( leftOver, samples.length );

    for( int i = 0; i < maxSamples; i++, readSamples++ )

    samples[i] = leftOverSamples[i];

    if( leftOver > samples.length )

    {

    leftOver = leftOver - samples.length;

    System.arraycopy( leftOverSamples, leftOverSamples.length - leftOver,leftOverSamples, 0, leftOver );

    return samples.length;

    }

    else

    leftOver = 0;

    }

    try

    {

    Header header = bitStream.readFrame();

    if( header == null )

  • 8/12/2019 Code Audio Analyzer

    35/52

    return 0;

    float frequency = header.frequency();

    if( frequency != 44100 )

    {bitStream.closeFrame();

    return 0;

    }

    SampleBuffer frame = (SampleBuffer)decoder.decodeFrame( header, bitStream);

    if( frame.getBufferLength() > leftOverSamples.length )

    leftOverSamples = new float[frame.getBufferLength()];

    int channels = frame.getChannelCount();if( channels > 2 )

    {

    bitStream.closeFrame();

    return 0;

    }

    for( int i = 0; i < frame.getBufferLength(); )

    {

    float value = frame.getBuffer()[i++] * MAX_VALUE;if( channels == 2 )

    {

    value += frame.getBuffer()[i++] * MAX_VALUE;

    value /= 2;

    }

    if( readSamples >= samples.length )

    leftOverSamples[leftOver++] = value;

    else

    samples[readSamples++] = value;

    }

    bitStream.closeFrame();

    return readSamples;

    } catch (Exception e)

  • 8/12/2019 Code Audio Analyzer

    36/52

    {

    return 0;

    }

    }

    }

  • 8/12/2019 Code Audio Analyzer

    37/52

    7.WaveDecoder.java

    package com.badlogic.audio.io;

    import java.io.BufferedInputStream;

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.io.InputStream;

    /**

    * A simple class that can read in the PCM data from a

    * Wav file, converting the data to signed 32-bit floats

    * in the range [-1,1], merging stereo channels to a mono

    * channel for processing. This only supports 16-bit signed

    * stereo and mono Wav files with a sampling rate of 44100.

    *

    * @author mzechner

    *

    */

    public class WaveDecoder

    {

    /** inverse max short value as float **/

    private final float MAX_VALUE = 1.0f / Short.MAX_VALUE;

    /** the input stream we read from **/

    private final EndianDataInputStream in;

    /** number of channels **/

    private final int channels;

    /** sample rate in Herz**/

    private final float sampleRate;

    /** **/

    /**

    * Constructor, sets the input stream to read

    * the Wav file from.

    *

    * @param stream The input stream.

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/WaveDecoder.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/WaveDecoder.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/WaveDecoder.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/WaveDecoder.java?r=11
  • 8/12/2019 Code Audio Analyzer

    38/52

    * @throws Exception in case the input stream couldn't be read properly

    */

    public WaveDecoder( InputStream stream ) throws Exception

    {

    if( stream == null )throw new IllegalArgumentException( "Input stream must not be null" );

    in = new EndianDataInputStream( new BufferedInputStream( stream, 1024*1024) );

    if( !in.read4ByteString().equals( "RIFF" ) )

    throw new IllegalArgumentException( "not a wav" );

    in.readIntLittleEndian();

    if( !in.read4ByteString().equals( "WAVE" ) )

    throw new IllegalArgumentException( "expected WAVE tag" );

    if( !in.read4ByteString().equals( "fmt " ) )

    throw new IllegalArgumentException( "expected fmt tag" );

    if( in.readIntLittleEndian() != 16 )

    throw new IllegalArgumentException( "expected wave chunk size to be 16" );

    if( in.readShortLittleEndian() != 1 )

    throw new IllegalArgumentException( "expected format to be 1" );

    channels = in.readShortLittleEndian();

    sampleRate = in.readIntLittleEndian();

    if( sampleRate != 44100 )

    throw new IllegalArgumentException( "Not 44100 sampling rate" );

    in.readIntLittleEndian();

    in.readShortLittleEndian();

    int fmt = in.readShortLittleEndian();

    if( fmt != 16 )

    throw new IllegalArgumentException( "Only 16-bit signed format supported" );

    if( !in.read4ByteString().equals( "data" ) )

    throw new RuntimeException( "expected data tag" );

  • 8/12/2019 Code Audio Analyzer

    39/52

    in.readIntLittleEndian();

    }

    /*** Tries to read in samples.length samples, merging stereo to a mono

    * channel by averaging and converting non float formats to float 32-bit.

    * Returns the number of samples actually read. Guarantees that samples.length

    * samples are read in if there was enough data in the stream.

    *

    * @param samples The samples array to write the samples to

    * @return The number of samples actually read.

    */

    public int readSamples( float[] samples )

    {

    int readSamples = 0;

    for( int i = 0; i < samples.length; i++ )

    {

    float sample = 0;

    try

    {

    for( int j = 0; j < channels; j++ )

    {

    int shortValue = in.readShortLittleEndian( );

    sample += (shortValue * MAX_VALUE);

    }

    sample /= channels;

    samples[i] = sample;

    readSamples++;

    }

    catch( Exception ex )

    {

    break;

    }

    }

    return readSamples;

    }

  • 8/12/2019 Code Audio Analyzer

    40/52

    public static void main( String[] args ) throws FileNotFoundException, Exception

    {

    WaveDecoder decoder = new WaveDecoder( new FileInputStream(

    "samples/sample.wav" ) );

    float[] samples = new float[1024];

    int readSamples = 0;

    while( ( readSamples = decoder.readSamples( samples ) ) > 0 )

    System.out.println( "read " + readSamples + " samples" );

    }

    }

  • 8/12/2019 Code Audio Analyzer

    41/52

    8.FourierTransformPlot.java

    package com.badlogic.audio.samples;

    import java.awt.Color;

    import com.badlogic.audio.analysis.FFT;import com.badlogic.audio.io.AudioDevice;

    import com.badlogic.audio.visualization.Plot;

    /**

    * Simple example that generates a 1024 samples sine wave at 440Hz

    * and plots the resulting spectrum.

    *

    * @author mzechner

    *

    */public class FourierTransformPlot

    {

    public static void main( String[] argv )

    {

    final float frequencyA = 440; // Note A

    final float frequencyAOctave = 880; // Note A in the next octave

    float incrementA = (float)(2*Math.PI) * frequencyA / 44100;

    float incrementAOctave = (float)(2*Math.PI)*frequencyAOctave / 44100;

    float angleA = 0;float angleAOctave = 0;

    float samples[] = new float[1024];

    FFT fft = new FFT( 1024, 44100 );

    for( int i = 0; i < samples.length; i++ )

    {

    samples[i] = ((float)Math.sin( angleA ) + (float)Math.sin( angleAOctave) ) / 2;

    angleA += incrementA;

    angleAOctave += incrementAOctave;}

    fft.forward( samples );

    Plot plot = new Plot( "Note A Spectrum", 512, 512);

    plot.plot(fft.getSpectrum(), 1, Color.red );

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11
  • 8/12/2019 Code Audio Analyzer

    42/52

    }

  • 8/12/2019 Code Audio Analyzer

    43/52

    9.FourierTransformPlot.java

    package com.badlogic.audio.samples;

    import java.io.FileInputStream;

    import com.badlogic.audio.analysis.FFT;import com.badlogic.audio.io.AudioDevice;

    import com.badlogic.audio.io.WaveDecoder;

    /**

    * A simple example that shows that transforming samples to

    * the frequency domain and back to the time domain preserves

    * the original signal nearly perfectly.

    * @author mzechner

    *

    */public class FourierTransformReconstruction

    {

    public static void main( String[] argv ) throws Exception

    {

    AudioDevice device = new AudioDevice( );

    WaveDecoder decoder = new WaveDecoder( new FileInputStream("samples/sample.wav" ) );

    float[] samples = new float[1024];

    FFT fft = new FFT( 1024, 44100 );

    while( decoder.readSamples( samples ) > 0 )

    {

    fft.forward( samples );

    fft.inverse( samples );

    device.writeSamples( samples );

    }

    }

    }

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/FourierTransformPlot.java?r=11
  • 8/12/2019 Code Audio Analyzer

    44/52

    10.MP3Output.java

    package com.badlogic.audio.samples;

    import java.io.FileInputStream;import java.io.FileNotFoundException;

    import com.badlogic.audio.io.AudioDevice;import com.badlogic.audio.io.MP3Decoder;

    /*** Simple example that shows how to decode an mp3 file.** @author mzechner**/public class MP3Output{

    public static void main( String[] argv ) throwsFileNotFoundException, Exception

    {AudioDevice device = new AudioDevice( );MP3Decoder decoder = new MP3Decoder( new FileInputStream(

    "samples/sample.mp3" ) );float[] samples = new float[1024];

    while( decoder.readSamples( samples ) > 0 ){

    device.writeSamples( samples );// System.out.println( "samples" );

    }

    }}

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/MP3Output.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/MP3Output.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/MP3Output.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/MP3Output.java?r=11
  • 8/12/2019 Code Audio Analyzer

    45/52

    11.NoteGenerator.java

    package com.badlogic.audio.samples;

    import com.badlogic.audio.io.AudioDevice;

    /*** A simple generator that outputs a sinewave at some* frequency (here 440Hz = Note A) in mono to an {@link AudioDevice}.** @author mzechner**/public class NoteGenerator{

    public static void main( String[] argv ) throws Exception{

    final float frequency = 880; // 440Hz for note Afloat increment = (float)(2*Math.PI) * frequency / 44100; //

    angular increment for each sample

    float angle = 0;AudioDevice device = new AudioDevice( );float samples[] = new float[1024];

    while( true ){

    for( int i = 0; i < samples.length; i++ ){

    samples[i] = (float)Math.sin( angle );angle += increment;

    }

    device.writeSamples( samples );

    }}}

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/NoteGenerator.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/NoteGenerator.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/NoteGenerator.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/NoteGenerator.java?r=11
  • 8/12/2019 Code Audio Analyzer

    46/52

    14.PlotExample.java

    package com.badlogic.audio.samples;

    import java.awt.Color;

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.util.ArrayList;

    import com.badlogic.audio.io.WaveDecoder;

    import com.badlogic.audio.visualization.Plot;

    /**

    * A simple example that shows how to use the {@link Plot} class.

    * Note that the plots will not be entirely synchronous to the

    * music playback. This is just an example, you should not do

    * real-time plotting with the Plot class it is just not made for* this.

    *

    * @author mzechner

    *

    */

    public class PlotExample

    {

    public static void main( String[] argv ) throws FileNotFoundException, Exception

    {WaveDecoder decoder = new WaveDecoder( new FileInputStream(

    "samples/sample.wav" ) );

    ArrayList allSamples = new ArrayList( );

    float[] samples = new float[1024];

    while( decoder.readSamples( samples ) > 0 )

    {

    for( int i = 0; i < samples.length; i++ )

    allSamples.add( samples[i] );

    }

    samples = new float[allSamples.size()];

    for( int i = 0; i < samples.length; i++ )

    samples[i] = allSamples.get(i);

    Plot plot = new Plot( "Wave Plot", 512, 512 );

    plot.plot( samples, 44100 / 100, Color.red );

    }

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/PlotExample.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/PlotExample.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/PlotExample.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/PlotExample.java?r=11
  • 8/12/2019 Code Audio Analyzer

    47/52

    }

  • 8/12/2019 Code Audio Analyzer

    48/52

    15.WaveOutput.java

    package com.badlogic.audio.samples;

    import java.io.FileInputStream;

    import com.badlogic.audio.io.AudioDevice;import com.badlogic.audio.io.WaveDecoder;

    /*** A simple example how to read in a Wave file via* a {@link WaveDecoder} and output its contents to* an {@link AudioDevice}.* @author mzechner**/public class WaveOutput{

    public static void main( String[] argv ) throws Exception{

    AudioDevice device = new AudioDevice( );WaveDecoder decoder = new WaveDecoder( new FileInputStream(

    "samples/sample.wav" ) );float[] samples = new float[1024];

    while( decoder.readSamples( samples ) > 0 ){

    device.writeSamples( samples );}

    }}

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/WaveOutput.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/WaveOutput.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/WaveOutput.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/samples/WaveOutput.java?r=11
  • 8/12/2019 Code Audio Analyzer

    49/52

    16.Plot.java

    package com.badlogic.audio.visualization;

    import java.awt.Color;

    import java.awt.Dimension;

    import java.awt.Graphics2D;

    import java.awt.image.BufferedImage;

    import java.lang.reflect.InvocationTargetException;

    import javax.swing.ImageIcon;

    import javax.swing.JFrame;

    import javax.swing.JLabel;

    import javax.swing.JScrollPane;

    import javax.swing.SwingUtilities;

    /*** A simple class that allows to plot float[] arrays

    * to a swing window. The first function to plot that

    * is given to this class will set the minimum and

    * maximum height values. I'm not that good with Swing

    * so i might have done a couple of stupid things in here :)

    *

    * @author mzechner

    *

    */public class Plot

    {

    /** the frame **/

    private JFrame frame;

    /** the scroll pane **/

    private JScrollPane scrollPane;

    /** the image gui component **/

    private JLabel panel;

    /** the image **/

    private BufferedImage image;

    /** current samples to draw **/

    http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/visualization/Plot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/visualization/Plot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/visualization/Plot.java?r=11http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/visualization/Plot.java?r=11
  • 8/12/2019 Code Audio Analyzer

    50/52

    private float[] currentSamples;

    /** the last scaling factor to normalize samples **/

    private float scalingFactor = 1;

    /** wheter the plot was cleared, if true we have to recalculate the scaling factor **/

    private boolean cleared = true;

    /**

    * Creates a new Plot with the given title and dimensions.

    *

    * @param title The title.

    * @param width The width of the plot in pixels.

    * @param height The height of the plot in pixels.

    */

    public Plot( final String title, final int width, final int height )

    {

    SwingUtilities.invokeLater( new Runnable() {

    @Override

    public void run()

    {

    frame = new JFrame( title );

    frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );

    frame.setPreferredSize( new Dimension( width, height ) );

    BufferedImage img = new BufferedImage( width, height,

    BufferedImage.TYPE_4BYTE_ABGR );

    Graphics2D g = (Graphics2D)img.getGraphics();

    g.setColor( Color.black );

    g.fillRect( 0, 0, width, height );

    g.dispose();

    image = img;

    panel = new JLabel( new ImageIcon( img ) );

    scrollPane = new JScrollPane( panel );

    frame.getContentPane().add(scrollPane);

    frame.pack();

    frame.setVisible( true );

    }

  • 8/12/2019 Code Audio Analyzer

    51/52

    });

    }

    public void clear( )

    {SwingUtilities.invokeLater( new Runnable( ) {

    @Override

    public void run() {

    Graphics2D g = image.createGraphics();

    g.setColor( Color.black );

    g.fillRect( 0, 0, image.getWidth(), image.getHeight() );

    g.dispose();

    cleared = true;

    }});

    }

    public void plot( float[] samples, final float samplesPerPixel, final Color color )

    {

    final float[] smps = new float[samples.length];

    System.arraycopy( samples, 0, smps, 0, samples.length );

    SwingUtilities.invokeLater( new Runnable( )

    {@Override

    public void run()

    {

    if( image.getWidth() < smps.length / samplesPerPixel )

    {

    image = new BufferedImage( (int)(smps.length / samplesPerPixel),frame.getHeight(), BufferedImage.TYPE_4BYTE_ABGR );

    Graphics2D g = image.createGraphics();

    g.setColor( Color.black );

    g.fillRect( 0, 0, image.getWidth(), image.getHeight() );

    g.dispose();

    }

    if( cleared )

    {

  • 8/12/2019 Code Audio Analyzer

    52/52

    float min = 0;

    float max = 0;

    for( int i = 0; i < smps.length; i++ )

    {

    min = Math.min( smps[i], min );max = Math.max( smps[i], max );

    }

    scalingFactor = max - min;

    cleared = false;

    }

    Graphics2D g = image.createGraphics();

    g.setColor( color );

    float lastValue = (smps[0] / scalingFactor) * image.getHeight() / 3 +

    image.getHeight() / 2;

    for( int i = 1; i < smps.length; i++ )

    {

    float value = (smps[i] / scalingFactor) * image.getHeight() / 3 +image.getHeight() / 2;

    g.drawLine( (int)((i-1) / samplesPerPixel), image.getHeight() -

    (int)lastValue, (int)(i / samplesPerPixel), image.getHeight() - (int)value );

    lastValue = value;

    }

    g.dispose();

    panel.setIcon( new ImageIcon( image ) );

    }

    });

    }

    }


Recommended