/*
* 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.DynamicMixer;
import com.frinika.audio.io.AudioReaderFactory;
import com.frinika.audio.analysis.gui.*;
import com.frinika.audio.io.LimitedAudioReader;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
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.JPanel;
import com.frinika.audio.analysis.Mapper;
import com.frinika.audio.analysis.SpectrumDataBuilder;
import com.frinika.audio.analysis.StaticSpectrogramSynth;
import uk.org.toot.audio.core.AudioBuffer;
import uk.org.toot.audio.core.AudioProcess;
import uk.org.toot.audio.server.AudioClient;
import uk.org.toot.audio.server.IOAudioProcess;
import com.frinika.project.FrinikaAudioSystem;
@SuppressWarnings("serial")
public class AudioAnalysisTimePanel extends JPanel implements Observer {
Vector<CursorObserver> cursorObservers = new Vector<CursorObserver>();
AudioReaderFactory part;
LimitedAudioReader input;
WaveImage wavePanel;
SpectrogramImage spectroImage;
//SpectrumDataBuilder spectroData;
boolean isPlaying;
private Dimension size = new Dimension(400, 100);
private int chunkCursor;
private long framePtr = 0;
AudioProcess myProcess;
DynamicMixer mixer;
private boolean staticSynthMode = false;
StaticSpectrogramSynth synthPlayer;
private KeyboardFocusManager kbd;
static int count=0;
String tag;
private KeyEventDispatcher keyDispatcher;
float curBin;
public AudioAnalysisTimePanel(AudioReaderFactory part, DynamicMixer mixer,Mapper mapper,
SpectrumDataBuilder spectroData,KeyboardFocusManager kbd) {
// synthPlayer = spectroData.getSynth(); //new StaticSpectrogramSynth(spectroData);
if (synthPlayer != null) addCursorObserver(synthPlayer);
this.part = part;
this.kbd=kbd;
// this.client = new MyClient();
this.mixer=mixer;
myProcess=new MyAudioProcess();
mixer.addMixerInput(myProcess, tag="XYZ"+count++);
// FrinikaAudioSystem.stealAudioServer(this, this.client);
try {
this.spectroImage = new SpectrogramImage(spectroData, mapper);
this.wavePanel = new WaveImage(part.createAudioReader());
spectroData.addSizeObserver(this.wavePanel);
spectroData.addSizeObserver(this.spectroImage);
// spectroData.addObserver(spectroImage);
this.spectroImage.addObserver(this);
this.wavePanel.addObserver(this);
addMouseListener(new MyMouseListener());
addMouseMotionListener(new MouseMotionListener() {
public void mouseMoved(MouseEvent e) {
if (isPlaying) return;
int curY=e.getY();
curBin=spectroImage.pixToBin(curY);
chunkCursor=e.getX();
notifyCursorObservers();
repaint();
// System.out.println(" MOUSE MOVED");
}
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setFocusable(true);
overrideKeys();
}
StaticSpectrogramSynth getSynth() {
return synthPlayer;
}
// public Vector<Tweakable> getTweaks() {
// return spectroImage.getTweaks();
// }
//
public void dispose() {
// TODO remove other types of observers
this.wavePanel.deleteObservers();
this.spectroImage.deleteObservers();
mixer.removeStrip(tag);
kbd.removeKeyEventDispatcher(keyDispatcher);
keyDispatcher=null;
// FrinikaAudioSystem.returnAudioServer(this);
}
@Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
// System.out.println(" AnalysisPanel PAINT");
Graphics2D g = (Graphics2D) gg;
this.spectroImage.drawImage(g, 0, 0);
this.wavePanel.drawImage(g, 0, this.spectroImage.getHeight());
g.setColor(Color.RED);
g.drawLine(this.chunkCursor, 0, this.chunkCursor, this.size.height);
}
public void update(Observable o, Object arg) {
this.size = new Dimension(this.wavePanel.getWidth(), this.spectroImage.getHeight()
+ this.wavePanel.getHeight());
revalidate();
// getParent().validate();
repaint();
}
@Override
public Dimension getPreferredSize() {
return this.size;
}
@Override
public Dimension getMinimumSize() {
return this.size;
}
@Override
public Dimension getMaximumSize() {
return this.size;
}
public void addCursorObserver(CursorObserver o) {
this.cursorObservers.add(o);
}
private void notifyCursorObservers() {
for (CursorObserver o : this.cursorObservers) {
o.notifyCursorChange(this.chunkCursor,this.curBin);
}
}
public void startStop() {
//System.out.println(" START-STOP");
this.isPlaying = !this.isPlaying;
}
public void nudge(int pixs) {
this.chunkCursor += pixs;
this.framePtr = this.wavePanel.screenToFrame(this.chunkCursor);
try {
this.input.seekFrameInEnvelope(this.framePtr,false);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
notifyCursorObservers();
repaint();
}
public int cursorChunkPos() {
return this.chunkCursor;
}
void overrideKeys() {
kbd.addKeyEventDispatcher(keyDispatcher=new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
// System.out.println(" KEY HIT " + e);
switch (e.getKeyCode()) {
case KeyEvent.VK_SPACE:
if ((e.getID() == KeyEvent.KEY_PRESSED)) {
startStop();
}
return true;
case KeyEvent.VK_LEFT:
if ((e.getID() == KeyEvent.KEY_PRESSED)) {
nudge(-1);
}
return true;
case KeyEvent.VK_RIGHT:
if ((e.getID() == KeyEvent.KEY_PRESSED)) {
nudge(1);
}
return true;
//
// case KeyEvent.VK_HOME:
// if ((e.getID() == KeyEvent.KEY_PRESSED)) {
// rewind.actionPerformed(null);
// }
// return true;
//
// case KeyEvent.VK_MULTIPLY:
// if ((e.getID() == KeyEvent.KEY_PRESSED)) {
// record.actionPerformed(null);
// }
// return true;
//
// case KeyEvent.VK_NUMPAD1:
// if ((e.getID() == KeyEvent.KEY_PRESSED)) {
// warpToLeft.actionPerformed(null);
// }
// return true;
//
// case KeyEvent.VK_NUMPAD2:
// if ((e.getID() == KeyEvent.KEY_PRESSED)) {
// warpToRight.actionPerformed(null);
// }
// return true;
//
// case KeyEvent.VK_A:
//
// if ((e.getID() == KeyEvent.KEY_PRESSED)) {
//
// if (e.isControlDown()) {
// return selectAllAction.selectAll(e);
// }
// }
default:
return false;
}
}
});
}
class MyClient implements AudioClient {
IOAudioProcess output;
AudioBuffer buffer;
private boolean enabled;
MyClient() {
this.buffer = FrinikaAudioSystem.getAudioServer().createAudioBuffer(
"TiemAnalysis");
this.output = FrinikaAudioSystem.getDefaultOutput(null);
try {
input = part.createAudioReader(); // TODO CachedAudio stuff
input.seekFrameInEnvelope(framePtr,false);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void work(int size) {
buffer.makeSilence();
if (staticSynthMode) {
synthPlayer.processAudio(this.buffer);
} else if (isPlaying) {
input.processAudio(this.buffer);
framePtr += buffer.getSampleCount();
updateCursorFromFramePos();
} else {
buffer.makeSilence();
}
output.processAudio(buffer);
}
private void updateCursorFromFramePos() {
int newCursor = wavePanel.frameToScreen(framePtr);
if (newCursor != chunkCursor) {
chunkCursor = newCursor;
notifyCursorObservers();
repaint();
}
}
public void setEnabled(boolean b) {
this.enabled = b;
}
}
class MyAudioProcess implements AudioProcess {
private boolean enabled;
MyAudioProcess() {
// this.buffer = FrinikaAudioSystem.getAudioServer().createAudioBuffer(
// "TiemAnalysis");
// this.output = FrinikaAudioSystem.getDefaultOutput(null);
try {
input = part.createAudioReader(); // TODO CachedAudio stuff
input.seekFrameInEnvelope(framePtr,false);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int processAudio(AudioBuffer buffer) {
buffer.makeSilence();
if (staticSynthMode) {
synthPlayer.processAudio(buffer);
} else if (isPlaying) {
input.processAudio(buffer);
framePtr += buffer.getSampleCount();
updateCursorFromFramePos();
} else {
buffer.makeSilence();
}
return AUDIO_OK;
}
private void updateCursorFromFramePos() {
int newCursor = wavePanel.frameToScreen(framePtr);
if (newCursor != chunkCursor) {
chunkCursor = newCursor;
notifyCursorObservers();
repaint();
}
}
public void setEnabled(boolean b) {
this.enabled = b;
}
public void close() throws Exception {
// TODO Auto-generated method stub
}
public void open() throws Exception {
// TODO Auto-generated method stub
}
}
class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
// if (chunkCursor == e.getX()) {
// return;
// }
chunkCursor = e.getX();
framePtr = wavePanel.screenToFrame(chunkCursor);
try {
input.seekFrameInEnvelope(framePtr,false);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
notifyCursorObservers();
repaint();
}
@Override
public void mouseEntered(MouseEvent arg0) {
requestFocusInWindow();
}
}
public void setSynthMode(boolean b) {
this.staticSynthMode=b;
}
}