/* * Created on Apr 11, 2007 * * Copyright (c) 2006-2007 P.J.Leonard * * http://www.frinika.com * * This file is part of Frinika. * * Frinika is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Frinika 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with Frinika; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.frinika.audio.analysis; import java.awt.Dimension; import java.util.Arrays; import com.frinika.audio.analysis.gui.CursorObserver; import uk.org.toot.audio.core.AudioBuffer; import uk.org.toot.audio.core.AudioProcess; /** * * An attempt at resynthesis from the spectral data. * * Use the AudioProcess interface to grab the sound. * * The CursorObserver selects the bin to resynthesize. * * Doesn't work that well !!!!! * * @author pjl */ public class StaticSpectrogramSynth implements AudioProcess, CursorObserver, SpectrogramDataListener { private SpectrumDataBuilder data; private int nBins; private MagFreq magFreq[]; int peaks[]; private OscillatorNode oscNext[]; OscillatorNode oscBank[]; // Array of osccillators. /** * Contruct a synth that will attempt to resynthesize using a set of oscillators. * * * @param data Spectral Data */ public StaticSpectrogramSynth(SpectrumDataBuilder data) { this.data = data; data.addSizeObserver(this); } /** * * * @return The current oscillators */ public OscillatorNode[] getOscillatorBank(){ return oscBank; } private final void activateOscillatorsAtChunk( long chunkPtr) { if (!data.validAt(chunkPtr)) { System.out.println(" Data not ready at " + chunkPtr); for (OscillatorNode osc:oscBank) { osc.active=false; } return; } float freqs[] = data.getFreqArray(); // TODO sort out newing float magn[] = data.getMagnitudeAt(chunkPtr); float pfreq[] = data.getPhaseFreqAt(chunkPtr); float phase[] = data.getPhaseFreqAt(chunkPtr); // long sampleTime = data.chunkStartInSamples(chunkPtr); int cnt = findPeaks(magn, peaks, 0.0f); for (int i = 0; i < cnt; i++) { magFreq[i].set(peaks[i], magn[peaks[i]]); } Arrays.sort(magFreq, 0, cnt); System.out.println(" Found " + cnt + " peaks "); Arrays.fill(oscNext, null); for (int i = 0; i < cnt; i++) { int ifreq = magFreq[i].ifreq; if (!isMasked(ifreq, magn[ifreq])) { int inear = findOscNear(ifreq); if (inear != ifreq) swap(inear, ifreq); oscBank[ifreq].setNext(pfreq[ifreq], magn[ifreq], phase[ifreq]); oscNext[ifreq]=oscBank[ifreq]; } } for (int i=0;i<nBins;i++) { if (oscNext[i] == null && oscBank[i].active) oscBank[i].silence(); } // final Vector<OscillatorNode> tmpNextOsc = activeOsc; // // synchronized(activeOsc) { // activeOsc=tmpOsc; // tmpOsc=tmpNextOsc; // } // OscillatorNode ttt[]=oscPrev; // oscPrev = oscNext; // oscNext = ttt; // for (int i=0;i<nBins;i++) { // if (oscBank[i].active()) tmpOsc.add(oscBank[i]); // } // return tmpOsc; } private void swap(int inear, int ifreq) { OscillatorNode nn=oscBank[inear]; oscBank[inear]=oscBank[ifreq]; oscBank[ifreq]=nn; } private int findOscNear(int ifreq) { OscillatorNode osc = oscBank[ifreq]; if (osc.active()) { return ifreq; } if (ifreq < nBins) { osc = oscBank[ifreq + 1]; if (osc.active()) { return ifreq + 1; } } if (ifreq > 0) { osc = oscBank[ifreq - 1]; if (osc != null) { return ifreq - 1; } } return ifreq; } final private boolean isMasked(int ifreq, float f) { int i1 = ifreq - 2; int i2 = ifreq + 2; if (i1 < 0) i1 = 0; if (i2 >= nBins) i2 = nBins - 1; for (int i = i1; i <= i2; i++) { if (oscNext[i] != null) return true; } return false; } private final int findPeaks(float a[], int peaks[], float threshold) { float max = 0.0f; int imax = -1; int cnt = 0; for (int i = 1; i < a.length - 1; i++) { if (a[i] < threshold) continue; if (a[i] >= a[i - 1] && a[i] > a[i + 1]) { peaks[cnt++] = i; } } return cnt; } // class AmpComparator implements Comparator<OscillatorNode> { // // public int compare(OscillatorNode arg0, OscillatorNode arg1) { // int i = Double.compare(arg0.amp, arg1.amp); // if (i != 0) // return i; // System.out.println(" magnitudes are the same "); // if (arg0.hashCode() > arg1.hashCode()) // return 1; // return -1; // } // // } public void close() { } public void open() { } /** * Probably best to call this when not running ? * * @param ptr */ void setChunkPtr(long ptr) { // System.out.println("OscPlayer set frame " + ptr ); activateOscillatorsAtChunk(ptr); System.out.println("OscPlayer set frame " + ptr); // for (Oscillator osc : tmpOsc) { // System.out.println(osc.toString()); // } } public int processAudio(AudioBuffer buffer) { // int size = buffer.getSampleCount(); buffer.makeSilence(); for (OscillatorNode osc : oscBank) { if (osc.active) osc.processAudio(buffer); } return AUDIO_OK; } public void notifyCursorChange(int pix,float dmy) { setChunkPtr(pix); } public void notifyMoreDataReady() { } /** * * @param d */ public void notifySizeChange(Dimension d) { System.out.println(" Synth SIZE SET "); nBins = d.height; oscNext = new OscillatorNode[nBins]; magFreq = new MagFreq[nBins]; oscBank = new OscillatorNode[nBins]; for (int i = 0; i < nBins; i++) { magFreq[i] = new MagFreq(i, 0.0f); oscBank[i] = new OscillatorNode(); } peaks = new int[nBins]; } final class MagFreq implements Comparable { int ifreq; float magn; public MagFreq(int i, float f) { ifreq = i; magn = f; } final public int compareTo(Object o) { return Float.compare(magn, ((MagFreq) o).magn); } final public void set(int i, float f) { ifreq = i; magn = f; } }; }