Java tutorial
/* * LumaQQ - Java QQ Client * * Copyright (C) 2004 luma <stubma@163.com> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.tsinghua.lumaqq; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.util.LinkedList; import java.util.Queue; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MetaEventListener; import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiSystem; import javax.sound.midi.Sequence; import javax.sound.midi.Sequencer; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import javax.sound.sampled.DataLine; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * ? * * @author luma */ public class Sounder extends Thread implements MetaEventListener { // Log private static Log log = LogFactory.getLog(Sounder.class); // ? private volatile boolean stop; // ? private Object currentSound; // ??? private boolean enable; // ???? private Queue<String> playQueue; // ? private Sequencer sequencer; // midi??? private boolean midiEOM; /** * */ public Sounder() { stop = false; enable = true; playQueue = new LinkedList<String>(); setName("Sound"); setDaemon(true); } /** * ??? * @param filename ?? */ public synchronized void play(String filename) { // playQueue.offer(filename); this.notify(); } /** * @return ??? */ public synchronized String getNext() { return playQueue.poll(); } /** * ? * @param b */ public synchronized void setStop(boolean b) { stop = b; this.notify(); } /** * @return true??? */ public synchronized boolean isStop() { return stop; } /** * */ public synchronized void clear() { playQueue.clear(); } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { log.debug("???"); while (!isStop()) { // ????? synchronized (this) { try { if (stop) break; if (playQueue.size() == 0) this.wait(); } catch (InterruptedException e) { // ?? } } // while (enable && !isStop()) { // ?? String filename = getNext(); // ??null if (filename == null) break; // ? if (loadSound(filename)) playSound(); } clear(); } log.debug("?"); } /** * */ private void playSound() { // midi? midiEOM = false; if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { /* ?Sequence? */ if (sequencer == null) openSequencer(); sequencer.start(); while (!midiEOM) { try { sleep(99); } catch (Exception e) { break; } } sequencer.stop(); sequencer.close(); } else if (currentSound instanceof Clip) { /* Clip */ Clip clip = (Clip) currentSound; clip.start(); try { sleep(99); } catch (Exception e) { log.error(e.getMessage()); } while (clip.isActive()) { try { sleep(99); } catch (Exception e) { break; } } clip.stop(); clip.close(); } currentSound = null; } /** * * @param filename * @return */ private boolean loadSound(String filename) { // ?? File file = new File(filename); try { currentSound = AudioSystem.getAudioInputStream(file); } catch (Exception e) { try { FileInputStream is = new FileInputStream(file); currentSound = new BufferedInputStream(is, 1024); } catch (Exception ex) { log.error(ex.getMessage()); currentSound = null; return false; } } // ?????? if (currentSound instanceof AudioInputStream) { try { AudioInputStream stream = (AudioInputStream) currentSound; AudioFormat format = stream.getFormat(); // ?? ALAW/ULAW ? ALAW/ULAW ?? PCM if ((format.getEncoding() == AudioFormat.Encoding.ULAW) || (format.getEncoding() == AudioFormat.Encoding.ALAW)) { AudioFormat tmp = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), format.getSampleSizeInBits() * 2, format.getChannels(), format.getFrameSize() * 2, format.getFrameRate(), true); stream = AudioSystem.getAudioInputStream(tmp, stream); format = tmp; } DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(), ((int) stream.getFrameLength() * format.getFrameSize())); Clip clip = (Clip) AudioSystem.getLine(info); clip.open(stream); currentSound = clip; } catch (Exception ex) { log.error(ex.getMessage()); currentSound = null; return false; } } else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { try { sequencer.open(); if (currentSound instanceof Sequence) { sequencer.setSequence((Sequence) currentSound); } else { sequencer.setSequence((BufferedInputStream) currentSound); } log.trace("Sequence Created"); } catch (InvalidMidiDataException imde) { log.error("???"); currentSound = null; return false; } catch (Exception ex) { log.error(ex.getMessage()); currentSound = null; return false; } } return true; } /** * @return Returns the enable. */ public boolean isEnable() { return enable; } /** * @param enable The enable to set. */ public void setEnable(boolean enable) { this.enable = enable; } /** * ? */ public void openSequencer() { try { sequencer = MidiSystem.getSequencer(); sequencer.addMetaEventListener(this); } catch (Exception ex) { log.error("Midi Sequencer?"); sequencer = null; return; } } /* (non-Javadoc) * @see javax.sound.midi.MetaEventListener#meta(javax.sound.midi.MetaMessage) */ public void meta(MetaMessage meta) { if (meta.getType() == 47) { // 47? midiEOM = true; } } }