// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.gui; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.infinity.NearInfinity; import org.infinity.icon.Icons; import org.infinity.resource.Closeable; import org.infinity.resource.ResourceFactory; import org.infinity.resource.key.ResourceEntry; import org.infinity.resource.mus.Entry; import org.infinity.resource.sound.AudioBuffer; import org.infinity.resource.sound.AudioPlayer; import org.infinity.util.SimpleListModel; import org.infinity.util.io.StreamUtils; public final class InfinityAmp extends ChildFrame implements ActionListener, ListSelectionListener, Runnable, Closeable { private final SimpleListModel<ResourceEntry> allMusModel = new SimpleListModel<ResourceEntry>(); private final SimpleListModel<ResourceEntry> selectedMusModel = new SimpleListModel<ResourceEntry>(); private final JButton bPlay = new JButton(Icons.getIcon(Icons.ICON_PLAY_16)); private final JButton bStop = new JButton(Icons.getIcon(Icons.ICON_STOP_16)); private final JButton bAdd = new JButton(Icons.getIcon(Icons.ICON_FORWARD_16)); private final JButton bRemove = new JButton(Icons.getIcon(Icons.ICON_BACK_16)); private final JButton bUp = new JButton(Icons.getIcon(Icons.ICON_UP_16)); private final JButton bDown = new JButton(Icons.getIcon(Icons.ICON_DOWN_16)); private final JCheckBox cbLoop = new JCheckBox("Loop", true); private final JList<ResourceEntry> allMusList; private final JList<ResourceEntry> selectedMusList; private final JTextField tfNowPlaying = new JTextField(10); private final AudioPlayer player = new AudioPlayer(); private List<Entry> entryList = new ArrayList<Entry>(); private boolean keepPlaying = true; public InfinityAmp() { super("InfinityAmp"); setIconImage(Icons.getIcon(Icons.ICON_VOLUME_16).getImage()); List<ResourceEntry> files = ResourceFactory.getResources("MUS"); for (int i = 0; i < files.size(); i++) { allMusModel.addElement(files.get(i)); } allMusList = new JList<>(allMusModel); selectedMusList = new JList<>(selectedMusModel); bPlay.addActionListener(this); bStop.addActionListener(this); bAdd.addActionListener(this); bRemove.addActionListener(this); bUp.addActionListener(this); bDown.addActionListener(this); allMusList.addListSelectionListener(this); selectedMusList.addListSelectionListener(this); selectedMusList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); bAdd.setEnabled(false); bRemove.setEnabled(false); bUp.setEnabled(false); bDown.setEnabled(false); bPlay.setEnabled(false); bStop.setEnabled(false); tfNowPlaying.setEnabled(false); cbLoop.setMnemonic('l'); JPanel leftPanel = new JPanel(new BorderLayout()); leftPanel.add(new JLabel("Available music"), BorderLayout.NORTH); leftPanel.add(new JScrollPane(allMusList), BorderLayout.CENTER); JPanel rightPanel = new JPanel(new BorderLayout()); rightPanel.add(new JLabel("Playlist"), BorderLayout.NORTH); rightPanel.add(new JScrollPane(selectedMusList), BorderLayout.CENTER); JPanel buttonPanel = new JPanel(new GridLayout(4, 1, 0, 3)); buttonPanel.add(bAdd); buttonPanel.add(bRemove); buttonPanel.add(bUp); buttonPanel.add(bDown); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); JPanel playlistPanel = new JPanel(gbl); rightPanel.setPreferredSize(leftPanel.getPreferredSize()); rightPanel.setMaximumSize(leftPanel.getMaximumSize()); rightPanel.setMinimumSize(leftPanel.getMinimumSize()); gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.fill = GridBagConstraints.BOTH; gbc.anchor = GridBagConstraints.CENTER; gbc.insets = new Insets(3, 3, 3, 3); gbl.setConstraints(leftPanel, gbc); playlistPanel.add(leftPanel); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; gbl.setConstraints(buttonPanel, gbc); playlistPanel.add(buttonPanel); gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbl.setConstraints(rightPanel, gbc); playlistPanel.add(rightPanel); JPanel lowerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); lowerPanel.add(bPlay); lowerPanel.add(bStop); lowerPanel.add(cbLoop); lowerPanel.add(new JLabel("Now playing:")); lowerPanel.add(tfNowPlaying); JPanel pane = (JPanel)getContentPane(); pane.setLayout(new BorderLayout()); pane.add(playlistPanel, BorderLayout.CENTER); pane.add(lowerPanel, BorderLayout.SOUTH); pane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); setSize(450, 350); Center.center(this, NearInfinity.getInstance().getBounds()); } //--------------------- Begin Interface ActionListener --------------------- @Override public void actionPerformed(ActionEvent event) { if (event.getSource() == bPlay) { new Thread(this).start(); } else if (event.getSource() == bStop) { keepPlaying = false; player.stopPlay(); } else if (event.getSource() == bAdd) { int indices[] = allMusList.getSelectedIndices(); for (final int index : indices) selectedMusModel.addElement(allMusModel.get(index)); bPlay.setEnabled(true); } else if (event.getSource() == bRemove) { int index = selectedMusList.getSelectedIndex(); selectedMusModel.remove(index); index = Math.min(index, selectedMusModel.size() - 1); if (index >= 0) selectedMusList.addSelectionInterval(index, index); bPlay.setEnabled(selectedMusModel.size() > 0); } else if (event.getSource() == bUp) { int index = selectedMusList.getSelectedIndex(); ResourceEntry o = selectedMusModel.remove(index); selectedMusModel.add(index - 1, o); selectedMusList.addSelectionInterval(index - 1, index - 1); } else if (event.getSource() == bDown) { int index = selectedMusList.getSelectedIndex(); ResourceEntry o = selectedMusModel.remove(index); selectedMusModel.add(index + 1, o); selectedMusList.addSelectionInterval(index + 1, index + 1); } } //--------------------- End Interface ActionListener --------------------- //--------------------- Begin Interface Closeable --------------------- @Override public void close() { keepPlaying = false; player.stopPlay(); Entry.clearCache(); } //--------------------- End Interface Closeable --------------------- //--------------------- Begin Interface ListSelectionListener --------------------- @Override public void valueChanged(ListSelectionEvent event) { if (event.getSource() == allMusList) bAdd.setEnabled(allMusList.getSelectedIndices().length != 0); else if (event.getSource() == selectedMusList) { bRemove.setEnabled(selectedMusList.getSelectedIndices().length != 0); bUp.setEnabled(selectedMusList.getSelectedIndex() > 0); bDown.setEnabled(selectedMusList.getSelectedIndex() >= 0 && selectedMusList.getSelectedIndex() < selectedMusModel.size() - 1); } } //--------------------- End Interface ListSelectionListener --------------------- //--------------------- Begin Interface Runnable --------------------- @Override public void run() { keepPlaying = true; bPlay.setEnabled(false); bStop.setEnabled(true); bAdd.setEnabled(false); bRemove.setEnabled(false); bUp.setEnabled(false); bDown.setEnabled(false); allMusList.setEnabled(false); selectedMusList.setEnabled(false); int index = 0; if (selectedMusList.getSelectedIndex() != -1) index = selectedMusList.getSelectedIndex(); while (keepPlaying) { ResourceEntry musEntry = selectedMusModel.get(index++); playMus(musEntry); if (index == selectedMusModel.size()) { if (cbLoop.isSelected()) index = 0; else keepPlaying = false; } } tfNowPlaying.setText(""); bPlay.setEnabled(true); bStop.setEnabled(false); bAdd.setEnabled(allMusList.getSelectedIndices().length != 0); bRemove.setEnabled(selectedMusList.getSelectedIndices().length != 0); bUp.setEnabled(selectedMusList.getSelectedIndex() > 0); bDown.setEnabled(selectedMusList.getSelectedIndex() >= 0 && selectedMusList.getSelectedIndex() < selectedMusModel.size() - 1); allMusList.setEnabled(true); selectedMusList.setEnabled(true); } //--------------------- End Interface Runnable --------------------- private void playMus(ResourceEntry musEntry) { try { ByteBuffer bb = musEntry.getResourceBuffer(); String[] lines = StreamUtils.readString(bb, bb.limit()).split("\r?\n"); int idx = 0; String dir = lines[idx++].trim(); int count = Integer.parseInt(lines[idx++].trim()); entryList.clear(); for (int i = 0; i < count; i++) { entryList.add(new Entry(musEntry, dir, entryList, lines[idx++].trim(), i)); } for (final Entry entry : entryList) { entry.init(); } tfNowPlaying.setText(musEntry.toString()); setTitle("InfinityAmp: " + musEntry.toString()); int nextnr = 0; while (keepPlaying) { AudioBuffer audio = entryList.get(nextnr).getAudioBuffer(); player.play(audio); if (entryList.get(nextnr).getNextNr() <= nextnr || entryList.get(nextnr).getNextNr() >= entryList.size()) break; nextnr = entryList.get(nextnr).getNextNr(); } if (keepPlaying && entryList.get(nextnr).getEndBuffer() != null) player.play(entryList.get(nextnr).getEndBuffer()); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Error accessing " + musEntry + '\n' + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } }