
musicg.extension.Spectrogram Maven / Gradle / Ivy
/*
*
* *
* * * Copyright 2015 Skymind,Inc.
* * *
* * * Licensed under the Apache License, Version 2.0 (the "License");
* * * you may not use this file except in compliance with the License.
* * * You may obtain a copy of the License at
* * *
* * * http://www.apache.org/licenses/LICENSE-2.0
* * *
* * * Unless required by applicable law or agreed to in writing, software
* * * distributed under the License is distributed on an "AS IS" BASIS,
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * * See the License for the specific language governing permissions and
* * * limitations under the License.
* *
*
*/
package musicg.extension;
import musicg.Wave;
import musicg.dsp.FastFourierTransform;
import musicg.dsp.WindowFunction;
/**
* Handles the wave data in frequency-time domain.
*
* @author Jacquet Wong
*/
public class Spectrogram{
public static final int SPECTROGRAM_DEFAULT_FFT_SAMPLE_SIZE = 1024;
public static final int SPECTROGRAM_DEFAULT_OVERLAP_FACTOR = 0; // 0 for no overlapping
private Wave wave;
private double[][] spectrogram; // relative spectrogram
private double[][] absoluteSpectrogram; // absolute spectrogram
private int fftSampleSize; // number of sample in fft, the value needed to be a number to power of 2
private int overlapFactor; // 1/overlapFactor overlapping, e.g. 1/4=25% overlapping
private int numFrames; // number of frames of the spectrogram
private int framesPerSecond; // frame per second of the spectrogram
private int numFrequencyUnit; // number of y-axis unit
private double unitFrequency; // frequency per y-axis unit
/**
* Constructor
*
* @param wave
*/
public Spectrogram(Wave wave) {
this.wave=wave;
// default
this.fftSampleSize=SPECTROGRAM_DEFAULT_FFT_SAMPLE_SIZE;
this.overlapFactor=SPECTROGRAM_DEFAULT_OVERLAP_FACTOR;
buildSpectrogram();
}
/**
* Constructor
*
* @param wave
* @param fftSampleSize number of sample in fft, the value needed to be a number to power of 2
* @param overlapFactor 1/overlapFactor overlapping, e.g. 1/4=25% overlapping, 0 for no overlapping
*/
public Spectrogram(Wave wave, int fftSampleSize, int overlapFactor) {
this.wave=wave;
if (Integer.bitCount(fftSampleSize)==1){
this.fftSampleSize=fftSampleSize;
}
else{
System.err.print("The input number must be a power of 2");
this.fftSampleSize=SPECTROGRAM_DEFAULT_FFT_SAMPLE_SIZE;
}
this.overlapFactor=overlapFactor;
buildSpectrogram();
}
/**
* Build spectrogram
*/
private void buildSpectrogram(){
short[] amplitudes=wave.getSampleAmplitudes();
int numSamples = amplitudes.length;
int pointer=0;
// overlapping
if (overlapFactor>1){
int numOverlappedSamples=numSamples*overlapFactor;
int backSamples=fftSampleSize*(overlapFactor-1)/overlapFactor;
int fftSampleSize_1=fftSampleSize-1;
short[] overlapAmp= new short[numOverlappedSamples];
pointer=0;
for (int i=0; i0){
numFrequencyUnit=absoluteSpectrogram[0].length;
unitFrequency=(double)wave.getWaveHeader().getSampleRate()/2/numFrequencyUnit; // frequency could be caught within the half of nSamples according to Nyquist theory
// normalization of absoultSpectrogram
spectrogram=new double[numFrames][numFrequencyUnit];
// set max and min amplitudes
double maxAmp=Double.MIN_VALUE;
double minAmp=Double.MAX_VALUE;
for (int i=0; imaxAmp){
maxAmp=absoluteSpectrogram[i][j];
}
else if(absoluteSpectrogram[i][j]
© 2015 - 2025 Weber Informatics LLC | Privacy Policy