package uk.co.mmscomputing.sound; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.border.*; import javax.sound.sampled.*; import uk.co.mmscomputing.concurrent.TimeUnit; import uk.co.mmscomputing.concurrent.Semaphore; import uk.co.mmscomputing.util.JarImageIcon; public class SoundPlayer extends JComponent implements WindowListener{ static AudioFormat format = new AudioFormat(8000,16,1,true,false); // PCM 16 bit mono 8000Hz // static AudioFormat format = new AudioFormat(44100,16,2,true,false); protected AudioInputStream in; protected Clip clip=null; protected JButton playButton; protected JButton pauseButton; protected JButton stopButton; protected JButton rewindButton; private JSlider slider; private boolean mousedown=false; protected JTextPane text=new JTextPane(); private JPanel progress=new JPanel(); private TitledBorder tb=new TitledBorder("Progress"); private Semaphore blocker=new Semaphore(0,true); public SoundPlayer(AudioInputStream input)throws IOException, LineUnavailableException{ slider=new JSlider(JSlider.HORIZONTAL,0,100,0); slider.setBorder(new EmptyBorder(5,10,5,10)); MIA mia=new MIA(); slider.addMouseListener(mia); slider.addMouseMotionListener(mia); slider.setMinorTickSpacing(5); slider.setMajorTickSpacing(10); slider.setPaintTicks(true); slider.setPaintLabels(true); slider.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); progress.setLayout(new BorderLayout()); progress.setBorder(tb); progress.add(slider,BorderLayout.CENTER); text.setFont(new Font("Courier",Font.PLAIN,12)); JPanel buttons=new JPanel(); buttons.setLayout(new GridLayout(1,0)); addButtons(buttons); setLayout(new BorderLayout()); add(progress,BorderLayout.NORTH); add(new JScrollPane(text),BorderLayout.CENTER); add(buttons,BorderLayout.SOUTH); setClip(input); } protected void addButtons(JPanel buttons){ playButton=new JButton( new AbstractAction("",new JarImageIcon(getClass(),"32x32/play.png")){ public void actionPerformed(ActionEvent ev){ play();} } ); buttons.add(playButton); pauseButton=new JButton( new AbstractAction("",new JarImageIcon(getClass(),"32x32/pause.png")){ public void actionPerformed(ActionEvent ev){ pause();} } ); buttons.add(pauseButton); stopButton=new JButton( new AbstractAction("",new JarImageIcon(getClass(),"32x32/stop.png")){ public void actionPerformed(ActionEvent ev){ stop();} } ); buttons.add(stopButton); rewindButton=new JButton( new AbstractAction("",new JarImageIcon(getClass(),"32x32/rew.png")){ public void actionPerformed(ActionEvent ev){ rewind();} } ); buttons.add(rewindButton); } protected void setTimeText(double time){ tb.setTitle("Progress ["+time+" sec]"); progress.repaint(); } protected void setClip(AudioInputStream in)throws IOException,LineUnavailableException{ if(clip!=null){clip.close();} if( in.getFormat().getEncoding().equals(AudioFormat.Encoding.ALAW) || in.getFormat().getEncoding().equals(AudioFormat.Encoding.ULAW) ){ in=AudioSystem.getAudioInputStream(format,in); } DataLine.Info info=new DataLine.Info(Clip.class,in.getFormat()); clip=(Clip)AudioSystem.getLine(info); clip.open(in); setTimeText(clip.getMicrosecondLength()/1000000.0); new Thread(){ public void run(){ try{ while(clip.isOpen()){ if(!mousedown){ int value=(clip.getFramePosition()*100)/clip.getFrameLength(); slider.setValue(value); } blocker.tryAcquire(200,TimeUnit.MILLISECONDS); } }catch(Exception e){e.printStackTrace();} } }.start(); } protected AudioInputStream getAudioInputStream(){return in;} protected void play(){ if(!clip.isActive()){ clip.setFramePosition(clip.getFramePosition()); clip.start(); } } protected void pause(){ if(clip.isActive()){ clip.stop(); } } protected void stop(){ if(clip.isActive()){ clip.stop(); } clip.setFramePosition(0); } protected void rewind(){ if(clip.isActive()){ clip.stop(); clip.setFramePosition(0); clip.start(); }else{ clip.setFramePosition(0); } } public void setText(String txt){ text.setText(txt); } // start window listener methods public void windowOpened(WindowEvent e){play();} public void windowClosing(WindowEvent e){clip.stop();} public void windowClosed(WindowEvent e){clip.close();} public void windowIconified(WindowEvent e){pause();} public void windowDeiconified(WindowEvent e){play();} public void windowActivated(WindowEvent e){play();} public void windowDeactivated(WindowEvent e){pause();} // end window listener methods static public JFrame getDevice(String argv[]){ SoundPlayer player; JFrame frame=null; if((argv==null)||(argv.length!=3)){throw new IllegalArgumentException();} if(argv[0]==null){argv[0]="mmsc - SoundPlayer [2004-09-09]";} if(argv[1]==null){argv[1]="uk/co/mmscomputing/sounds/startmsg.wav";} if(argv[2]==null){argv[2]="Playing\n\t"+argv[1];} try{ player=new SoundPlayer(AudioSystem.getAudioInputStream(new File(argv[1]))); player.setText(argv[2]); frame=new JFrame(argv[0]); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.addWindowListener(player); frame.getContentPane().add(player); GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment(); Rectangle r=ge.getMaximumWindowBounds(); frame.setSize(400,200); frame.setLocationRelativeTo(null); frame.setVisible(true); }catch(Exception e){ JOptionPane.showMessageDialog(null,e.getMessage(),"Soundplayer Exception",JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } return frame; } public static void main(String[] argv){ try{ // System.err.println(new SoundMixerEnumerator().toString()); String[] arg=new String[3]; arg[0]="mmsc - Test SoundPlayer [2004-09-09]"; arg[1]="uk/co/mmscomputing/sounds/startmsg.wav"; // arg[1]="/home/mmsc/Documents/music/Grease/Track08-John Travolta-Greased Lightnin.wav"; JFrame frame=SoundPlayer.getDevice(arg); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); }catch(Exception e){ e.printStackTrace(); } } // MouseInputAdapter class MIA extends MouseInputAdapter{ public void mouseClicked(MouseEvent e){} public void mousePressed(MouseEvent e){ mousedown=true; pause(); } public void mouseReleased(MouseEvent e){ int value=slider.getValue()*clip.getFrameLength()/100; clip.setFramePosition(value); clip.start(); mousedown=false; } public void mouseMoved(MouseEvent e){} public void mouseDragged(MouseEvent e){} } }