// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.resource.sound;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.nio.ByteBuffer;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import org.infinity.NearInfinity;
import org.infinity.gui.ButtonPanel;
import org.infinity.gui.ButtonPopupMenu;
import org.infinity.icon.Icons;
import org.infinity.resource.Closeable;
import org.infinity.resource.Resource;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.ViewableContainer;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.WavReferenceSearcher;
import org.infinity.util.io.StreamUtils;
/**
* Handles all kinds of supported single track audio files.
*/
public class SoundResource implements Resource, ActionListener, ItemListener, Closeable, Runnable
{
private final ResourceEntry entry;
private final ButtonPanel buttonPanel = new ButtonPanel();
private AudioPlayer player;
private AudioBuffer audioBuffer = null;
private JButton bPlay, bStop;
private JMenuItem miExport, miConvert;
private JPanel panel;
private boolean isWAV, isReference, isClosed;
public SoundResource(ResourceEntry entry) throws Exception
{
this.entry = entry;
player = new AudioPlayer();
isWAV = false;
isReference = (entry.getExtension().equalsIgnoreCase("WAV"));
isClosed = false;
}
//--------------------- Begin Interface ActionListener ---------------------
@Override
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == bPlay) {
new Thread(this).start();
} else if (event.getSource() == bStop) {
bStop.setEnabled(false);
player.stopPlay();
bPlay.setEnabled(true);
} else if (buttonPanel.getControlByType(ButtonPanel.Control.FIND_REFERENCES) == event.getSource()) {
new WavReferenceSearcher(entry, panel.getTopLevelAncestor());
}
}
//--------------------- End Interface ActionListener ---------------------
//--------------------- Begin Interface ItemListener ---------------------
@Override
public void itemStateChanged(ItemEvent event)
{
if (buttonPanel.getControlByType(ButtonPanel.Control.EXPORT_MENU) == event.getSource()) {
ButtonPopupMenu bpmExport = (ButtonPopupMenu)event.getSource();
if (bpmExport.getSelectedItem() == miExport) {
ResourceFactory.exportResource(entry, panel.getTopLevelAncestor());
} else if (bpmExport.getSelectedItem() == miConvert) {
String fileName = entry.toString();
if (fileName.lastIndexOf('.') > 0) {
fileName = fileName.substring(0, fileName.lastIndexOf('.')) + ".WAV";
}
ByteBuffer buffer = StreamUtils.getByteBuffer(audioBuffer.getAudioData());
ResourceFactory.exportResource(entry, buffer, fileName, panel.getTopLevelAncestor());
}
}
}
//--------------------- End Interface ItemListener ---------------------
//--------------------- Begin Interface Closeable ---------------------
@Override
public void close() throws Exception
{
setClosed(true);
if (player != null) {
player.stopPlay();
player = null;
}
audioBuffer = null;
panel = null;
}
//--------------------- End Interface Closeable ---------------------
//--------------------- Begin Interface Resource ---------------------
@Override
public ResourceEntry getResourceEntry()
{
return entry;
}
//--------------------- End Interface Resource ---------------------
//--------------------- Begin Interface Runnable ---------------------
@Override
public void run()
{
bPlay.setEnabled(false);
bStop.setEnabled(true);
if (audioBuffer != null) {
try {
player.play(audioBuffer);
} catch (Exception e) {
JOptionPane.showMessageDialog(panel, "Error during playback", "Error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
player.stopPlay();
}
}
bStop.setEnabled(false);
bPlay.setEnabled(true);
}
//--------------------- End Interface Runnable ---------------------
//--------------------- Begin Interface Viewable ---------------------
@Override
public JComponent makeViewer(ViewableContainer container)
{
JPanel controlPanel = new JPanel();
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
controlPanel.setLayout(gbl);
gbc.insets = new Insets(3, 3, 3, 3);
gbc.fill = GridBagConstraints.HORIZONTAL;
bPlay = new JButton(Icons.getIcon(Icons.ICON_PLAY_16));
bPlay.addActionListener(this);
gbl.setConstraints(bPlay, gbc);
controlPanel.add(bPlay);
bStop = new JButton(Icons.getIcon(Icons.ICON_STOP_16));
bStop.addActionListener(this);
bStop.setEnabled(false);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbl.setConstraints(bStop, gbc);
controlPanel.add(bStop);
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.add(controlPanel, BorderLayout.CENTER);
if (isReference) {
// only available for WAV resource types
((JButton)buttonPanel.addControl(ButtonPanel.Control.FIND_REFERENCES)).addActionListener(this);
}
miExport = new JMenuItem("original");
miConvert = new JMenuItem("as WAV");
miConvert.setEnabled(!isWAV);
ButtonPopupMenu bpmExport = (ButtonPopupMenu)buttonPanel.addControl(ButtonPanel.Control.EXPORT_MENU);
bpmExport.setMenuItems(new JMenuItem[]{miExport, miConvert});
bpmExport.addItemListener(this);
panel = new JPanel(new BorderLayout());
panel.add(centerPanel, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.SOUTH);
centerPanel.setBorder(BorderFactory.createLoweredBevelBorder());
loadSoundResource();
return panel;
}
// Returns the top level container associated with this viewer
private Container getContainer()
{
if (panel != null) {
return panel.getTopLevelAncestor();
} else
return NearInfinity.getInstance();
}
private void loadSoundResource()
{
setLoaded(false);
(new SwingWorker<Boolean, Void>() {
@Override
public Boolean doInBackground()
{
return loadAudio();
}
}).execute();
}
private synchronized void setLoaded(boolean b)
{
if (bPlay != null) {
bPlay.setEnabled(b);
}
miConvert.setEnabled(b);
}
private synchronized void setClosed(boolean b)
{
if (b != isClosed) {
isClosed = b;
}
}
private synchronized boolean isClosed()
{
return isClosed;
}
private boolean loadAudio()
{
try {
AudioBuffer.AudioOverride override = null;
AudioBuffer buffer = null;
synchronized (entry) {
// ignore # channels in ACM headers
if (entry.getExtension().equalsIgnoreCase("ACM")) {
override = AudioBuffer.AudioOverride.overrideChannels(2);
}
buffer = AudioFactory.getAudioBuffer(entry, override);
}
if (buffer != null && !isClosed()) {
synchronized (this) {
audioBuffer = buffer;
isWAV = (audioBuffer instanceof WavBuffer);
isReference = (entry.getExtension().compareToIgnoreCase("WAV") == 0);
}
setLoaded(true);
return true;
}
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(getContainer(), e.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
return false;
}
//--------------------- End Interface Viewable ---------------------
}