/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2011 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.create.tina.audio; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D; public class RecordedFFT implements Serializable { private static final long serialVersionUID = 1L; private final int samplesPerSecond; private final int recordedIntervalInMilliseconds; private final int movingAvgSize; private final int inputSamplePerFFTRowCount; private final int storedValuesPerFFTRow; private final int recordedChannels; private List<long[]> fftList = new ArrayList<long[]>(); public RecordedFFT(int pRecordedIntervalInMilliseconds, int pMovingAvgSize, int pInputSamplePerFFTRowCount, int pStoredValuesPerFFTRow, int pRecordedChannels, int pSamplesPerSecond) { recordedIntervalInMilliseconds = pRecordedIntervalInMilliseconds; movingAvgSize = pMovingAvgSize; inputSamplePerFFTRowCount = pInputSamplePerFFTRowCount; storedValuesPerFFTRow = pStoredValuesPerFFTRow; recordedChannels = pRecordedChannels; samplesPerSecond = pSamplesPerSecond; } public int getRecordedInterval() { return recordedIntervalInMilliseconds; } public int getMovingAvgSize() { return movingAvgSize; } public int getRecordedValueCount() { return inputSamplePerFFTRowCount; } public int getRecordedEachSampleCount() { return storedValuesPerFFTRow; } public void addData(short[] data) { { int length = inputSamplePerFFTRowCount / 2; float[] input = new float[length * 2]; for (int i = 0; i < 2 * length; i++) { input[i] = (float) data[i]; } FloatFFT_1D fftlib = new FloatFFT_1D(length); fftlib.complexForward(input); // int multiplier = (int) (BASE_FREQUENCY / ((float) SAMPLE_RATE / (float) FFT_SIZE)); float outputData[] = new float[(input.length + 1) / 2]; for (int i = 0; i < length / 2; i++) { outputData[i] = (float) Math.sqrt((Math.pow(input[2 * i], 2)) + (Math.pow(input[2 * i + 1], 2))); } for (int i = 0; i < length; i++) { data[i] = (short) (outputData[i] * 0.07 + 0.5f); } } { int avgCount = storedValuesPerFFTRow; int avgWidth = inputSamplePerFFTRowCount / avgCount; long[] avgArray = new long[avgCount]; int sidx = 0; for (int i = 0; i < avgCount; i++) { long v = 0; for (int j = 0; j < avgWidth; j++) { v += data[sidx++]; } avgArray[i] = (v / (long) avgWidth); } fftList.add(avgArray); } } public short[] getDataByTimeOffset(long pTimeOffsetInMS) { double intervals = (double) pTimeOffsetInMS / (double) recordedIntervalInMilliseconds; long position = (long) (inputSamplePerFFTRowCount * intervals / (double) recordedChannels + 0.5); return getData(position); } public long getRecordedTime() { return ((long) fftList.size() * (long) inputSamplePerFFTRowCount * (long) 1000) / (long) samplesPerSecond; } public short[] getData(long pPosition) { short[] res = new short[storedValuesPerFFTRow]; double fidx = (double) pPosition / (double) inputSamplePerFFTRowCount * (double) recordedChannels; int idx = (int) fidx; if (idx < 0 || idx >= fftList.size() - 1) { return res; } long data0[] = fftList.get(idx); long data1[] = fftList.get(idx + 1); for (int i = 0; i < storedValuesPerFFTRow; i++) { res[i] = (short) (0.5 + (double) data0[i] + ((double) (data1[i] - data0[i])) * (fidx - (double) idx)); } if (movingAvgSize > 1 && idx - movingAvgSize >= 0) { double avgDiv = movingAvgSize - 1.0 + (fidx - idx); for (int i = 0; i < storedValuesPerFFTRow; i++) { long val = res[i]; for (int j = 1; j <= movingAvgSize; j++) { val += fftList.get(idx - j)[i]; } res[i] = (short) ((double) val / avgDiv + 0.5); } } return res; } public int getSize() { return fftList.size(); } }