package com.towel.sound; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.SourceDataLine; import com.towel.sound.filter.LoopFilter; /** * Manages the game sounds. All noise in game must be in the same format. <br> * TODO Adicionar um mecanismo de listeners para os sons.<br> * TODO Adicionar um tempo m�ximo para que o som seja tocado. * * @author Vin�cius */ public class SoundManager { private AudioFormat format; private ExecutorService soundPool; /** * Create a new SoundManager for the specified audio format. All future * sounds in this manager should match this format or will not be played. * * @param format The format that will be managed. */ public SoundManager(AudioFormat format) { if (format == null) throw new IllegalArgumentException("Invalid audio format!"); this.format = format; this.soundPool = createThreadPool(format, new SoundManagerThreadFactory()); } /** * Returns the format supported by this SoundManager. * * @return the format supported by this SoundManager. */ public AudioFormat getFormat() { return format; } /** * Retrieve the ExecutorService more adequate for this system using the * given AudioFormat. * * @param format The format to test * @return The more adequate ExecutorService. */ private ExecutorService createThreadPool(AudioFormat format, ThreadFactory threadFactory) { int max = getMaxSimultaneousSounds(format); if (max == AudioSystem.NOT_SPECIFIED || max == 0) return Executors.newCachedThreadPool(threadFactory); if (max == 1) return Executors.newSingleThreadExecutor(threadFactory); return Executors.newFixedThreadPool(max, threadFactory); } /** * Return the maximum number of simultaneous sounds in this format supported * by this audio format in the default mixer. * * @param format The format to be tested. * @return The maximum number of simultaneous sounds supported, or * AudioSystem.NOT_SPECIFIED if there's no known upper limit. */ private int getMaxSimultaneousSounds(AudioFormat format) { return AudioSystem.getMixer(null).getMaxLines( new DataLine.Info(SourceDataLine.class, format)); } /** * Play this Streamed. Return a PlayingStreamed object that represent the * noise being played. The noise starts almost immediatelly, as long as * there are available threads in the pool. * * @param streamed The noise to play. * @return A PlayingStreamed that represents the noise being played. * @throws IllegalArgumentException If the format of the given noise does * not match the noise manager supported format. */ public PlayingStreamed play(Streamed streamed) { return play(streamed, false); } /** * Play this Streamed. Return a PlayingStreamed object that represent the * noise being played. The noise starts almost immediatelly, as long as * there are available threads in the pool. * * @param streamed The noise to play. * @param loop If true, automatically adds a loop filter to the stream and * so, play the sound endlessly. * @return A PlayingStreamed that represents the noise being played. * @throws IllegalArgumentException If the format of the given noise does * not match the noise manager supported format. * @throws IllegalStateException If the manager was already closed. */ public PlayingStreamed play(Streamed streamed, boolean loop) { if (soundPool.isShutdown()) throw new IllegalStateException("Manager already closed!"); if (!format.matches(streamed.getFormat())) throw new IllegalArgumentException("The streamed noise is a \n" + streamed.getFormat() + " but it should be a \n" + format); PlayingStreamed playing; playing = new PlayingStreamed(loop ? new LoopFilter(streamed) : streamed); soundPool.execute(playing); return playing; } /** * Closes this manager. The manager will interrupt all sound threads and * will no longer accept any more sounds. */ public void close() { soundPool.shutdownNow(); } /** * Creates sound threads for the manager. * * @author Vin�cius */ private static class SoundManagerThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setName("Sound Thread - " + Long.toString(t.getId())); t.setDaemon(true); return t; } } }