/* * Created on Mar 20, 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.gui; import com.frinika.audio.io.AudioReaderFactory; import com.frinika.audio.DynamicMixer; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.io.IOException; import java.util.Observable; import java.util.Observer; import java.util.Vector; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JToggleButton; import com.frinika.util.tweaks.gui.TweakerPanel; import com.frinika.util.tweaks.Tweakable; import com.frinika.util.tweaks.TweakableDouble; import com.frinika.audio.analysis.Mapper; import com.frinika.audio.analysis.SpectrumController; import com.frinika.audio.analysis.SpectrumDataBuilder; import com.frinika.audio.analysis.constantq.ConstantQSpectrogramDataBuilder; import com.frinika.audio.analysis.constantq.ConstantQSpectrumController; //import com.frinika.sequencer.model.AudioPart; import com.frinika.audio.io.LimitedAudioReader; /** * * TOp level panel for the audioanalysis GUI * * @author pjl * */ public class AudioAnalysisPanel extends JPanel { Vector<Tweakable> tweaks = new Vector<Tweakable>(); TweakableDouble mindB = new TweakableDouble(tweaks, -400.0, 100.0, -70.0, 1.0, "minDb"); TweakableDouble maxdB = new TweakableDouble(tweaks, -400.0, 100.0, -30.0, 1.0, "maxDb"); JToggleButton linearBut; /** * */ private static final long serialVersionUID = 1L; AudioAnalysisTimePanel timePanel; SingleImagePanel spectroSlicePanel; LimitedAudioReader reader; private ValMapper valMapper; private Mapper freqMapper; SpectrumDataBuilder spectroData; SpectrumController spectroController; JPanel spectroPanel; private KeyboardFocusManager kbd; DynamicMixer mixer; public AudioAnalysisPanel(final AudioReaderFactory part,DynamicMixer mixer,JFrame frame,KeyboardFocusManager kbd) { this.mixer=mixer; this.kbd=kbd; setFocusable(true); setLayout(new BorderLayout()); try { reader = part.createAudioReader(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } valMapper = new ValMapper(); maxdB.addObserver(valMapper); mindB.addObserver(valMapper); JMenu menu= new JMenu("Spectral"); JMenuItem item=new JMenuItem("FFT"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { clear(); spectroData = new FFTSpectrogramDataBuilderWrapper(reader); spectroController= ((FFTSpectrogramDataBuilderWrapper)spectroData).getController(); // new FFTSpectrumController((FFTSpectrogramControlable) spectroData,reader); setSpectralView(part); } }); menu.add(item); item=new JMenuItem("constant Q"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { clear(); spectroData = new ConstantQSpectrogramDataBuilder(); spectroController=new ConstantQSpectrumController((ConstantQSpectrogramDataBuilder)spectroData,reader); setSpectralView(part); } }); menu.add(item); frame.getJMenuBar().add(menu); } void clear() { if (spectroData != null) spectroData.dispose(); if (timePanel != null) timePanel.dispose(); removeAll(); } void setSpectralView(AudioReaderFactory part) { freqMapper=spectroController.getFrequencyMapper(); timePanel = new AudioAnalysisTimePanel(part,mixer, valMapper, spectroData,kbd); SpectralSliceImage spectralSliceImage = new SpectralSliceImage( spectroData, valMapper, freqMapper , timePanel.getSynth()); // Make sure this is the last thing notified spectroData.addSizeObserver(spectralSliceImage); timePanel.addCursorObserver(spectralSliceImage); spectroSlicePanel = new SingleImagePanel(spectralSliceImage); add(spectroSlicePanel, BorderLayout.NORTH); JScrollPane scroll = new JScrollPane(timePanel); add(scroll, BorderLayout.CENTER); setPreferredSize(new Dimension(1000, 400)); JPanel buts = new JPanel(); buts.setLayout(new BoxLayout(buts, BoxLayout.Y_AXIS)); // Log linear switch linearBut = new JToggleButton("Log10"); // linearBut.setSelected(valMapper.linear); linearBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (!linearBut.isSelected()) { linearBut.setText("Log10"); } else { linearBut.setText("Linear"); } valMapper.update(null, null); } }); buts.add(linearBut); // Switch to static synth final JToggleButton synthBut = new JToggleButton("Synth Mode"); synthBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { timePanel.setSynthMode(synthBut.isSelected()); } }); buts.add(synthBut); TweakerPanel tpanel = new TweakerPanel(2, 4); for (Tweakable t : tweaks) { tpanel.addSpinTweaker(t); } JPanel control= new JPanel(); control.add(buts); control.add(tpanel); control.add(spectroController.getTweakPanel()); add(control, BorderLayout.SOUTH); valMapper.update(null, null); spectroController.update(); revalidate(); repaint(); } public void dispose() { timePanel.dispose(); } final class ValMapper implements Observer, Mapper { double maxdb; double mindb; double max; double min; boolean linear=true; private Thread thread; public final float eval(float val) { if (linear) { float vv = (float) ((val - min) / (max - min)); return (float)Math.max(0.0,vv); } else { double dB = 20 * Math.log10(val + 1e-15); float vv = (float) ((dB - mindb) / (maxdb - mindb)); return (float) Math.max(0.0, vv); } } public void update(Observable o, Object arg) { linear = ! linearBut.isSelected(); maxdb = maxdB.doubleValue(); max = Math.pow(10, maxdb / 20.0); mindb = mindB.doubleValue(); min = Math.pow(10, mindb / 20.0); if (thread != null) thread.interrupt(); thread = new Thread(new Runnable() { public void run() { spectroSlicePanel.repaint(); timePanel.spectroImage.update(null, null); thread = null; } }); thread.start(); } } }