import processing.net.*; import java.io.*; import javax.sound.sampled.*; public class JClipVolumePan extends PApplet implements LineListener { float _starttime; int _mouse = 0; Clip _clip; // Audio Clip FloatControl _gainCtl; // Mixer Control for GAIN CHANGE FloatControl _panCtl; // Mixer Control for PANNING boolean _isPan; // true if Pan control was avilable, false if Balance control was available float _gainR = 0; // Radius of clicked point. Propotional to the playback volume void setup(){ size(600, 400); smooth(); PFont font = loadFont("FFDIN-Light-12.vlw"); textAlign(CENTER); textFont(font); fill(255); ellipseMode(CENTER); /* Prepare for PLAYBACK */ String _filepath = getCodeBase() + "beep4.aif"; // String _filepath = dataPath("beep4.aif"); loadClip(_filepath); if (_clip == null) text("Cannot Load Sound", width/2, height/2); // Print available controls for this clip showControls(); // Get and Preapare Pan and Volume controls prepareControls(); } private void loadClip(String path){ try{ // 1. access the audio file as a stream AudioInputStream stream = AudioSystem.getAudioInputStream(getClass().getResource(path)); // AudioInputStream stream = AudioSystem.getAudioInputStream(new File(path)); // 2. Get the original audio format of the file and convert it to a suitable format (if necessary) AudioFormat format = stream.getFormat(); if ( (format.getEncoding() == AudioFormat.Encoding.ULAW) || (format.getEncoding() == AudioFormat.Encoding.ALAW)) { AudioFormat newFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), format.getSampleSizeInBits()*2, format.getChannels(), format.getFrameSize()*2, format.getFrameRate(), true); // big endian stream = AudioSystem.getAudioInputStream(newFormat, stream); println("Convert audio fomat: " + newFormat); format = newFormat; } // 3. Gather information for line creation DataLine.Info info = new DataLine.Info(Class.forName("javax.sound.sampled.Clip"), format); // 4. Check if the DataLine format is supported or not on this system if (!AudioSystem.isLineSupported(info)){ println("Unsupported Clip File: " + path); return; } // 5. Make Empty clip _clip = (Clip)AudioSystem.getLine(info); // 6. Start monitoring line event _clip.addLineListener(this); // 7. Open the InputStream _clip.open(stream); stream.close(); // done with input stream // Get clip duration double duration = _clip.getMicrosecondLength() / 1000000.0; // duration in sec println("Duration: " + duration); } catch (Exception e){ println("Cannot load sound file. Unknown error occurred."); } } private void prepareControls(){ if (_clip == null) return; // do nothing // Volume Control if (_clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) { _gainCtl = (FloatControl) _clip.getControl(FloatControl.Type.MASTER_GAIN); println("Gain control found."); } else { println("MASTER_GAIN Control is Not Avaliable"); } // J2SE 1.3 - 1.4 if (_clip.isControlSupported(FloatControl.Type.PAN)) { _panCtl = (FloatControl) _clip.getControl(FloatControl.Type.PAN); _isPan = true; println("Pan control found."); } // J2SE 1.5 has BALANCE Control else if (_clip.isControlSupported(FloatControl.Type.BALANCE)) { _panCtl = (FloatControl) _clip.getControl(FloatControl.Type.BALANCE); _isPan = false; println("BALANCE control found."); } else { println("Neither PAN nor BALANCE Control is Not Avaliable"); } } void update(LineEvent event){ if (event.getType() == LineEvent.Type.STOP){ println("stop"); _clip.stop(); } } void draw(){ background(0); if (mousePressed){ ellipse(mouseX,mouseY,_gainR,_gainR); } // Show Conrols' info textAlign(RIGHT); if (_gainCtl != null) text("MASTER_GAIN", width - 10, height - 40); else text("MASTER_GAIN Control is Not Avaliable", width - 10, height - 40); if (_panCtl != null && _isPan) text("PAN", width - 10, height - 20); else if (_panCtl != null && !_isPan) text("BALANCE", width - 10, height - 20); else text("Neither PAN nor BALANCE Control is Not Avaliable", width - 10, height - 20); // Show Java Version String javaVersion = System.getProperty("java.version"); textAlign(LEFT); text("Java Version: " + javaVersion, 10, height - 20); } void mousePressed(){ // set volume and pan float vol = (float)(height - mouseY) / height; // 0 - 1 float pan = 2.0 * (mouseX - width/2) / width; // -1 - 1 float range = _gainCtl.getMaximum() - _gainCtl.getMinimum(); float gain = (range * vol) + _gainCtl.getMinimum(); _gainCtl.setValue(gain); _panCtl.setValue(pan); // indicate where you clicked _gainR = 80 * vol * vol; // .. then Play it! play(); } void mouseReleased(){ } private void play(){ if (_clip != null){ _clip.start(); println("start"); } } public void stop(){ _clip.stop(); } /* Killer Game Programming in Java Andrew Davison O'Reilly, May 2005 ISBN: 0-596-00730-2 http://www.oreilly.com/catalog/killergame/*/ private void showControls(){ if (_clip != null) { Control cntls[] = _clip.getControls(); for(int i=0; i