From 736bd1b658a16317f90c94fea4e568867774fa48 Mon Sep 17 00:00:00 2001 From: Conor MacNeill Date: Fri, 22 Dec 2000 11:47:56 +0000 Subject: [PATCH] A fun little task to play a sound at the end of a build. I got tired of waiting for some else to commit it. I made some small mods to Nick original proposal. Submitted by: Nick Pellow git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268381 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 3 + .../tools/ant/taskdefs/defaults.properties | 1 + .../optional/sound/AntSoundPlayer.java | 268 ++++++++++++++++++ .../taskdefs/optional/sound/SoundTask.java | 176 ++++++++++++ 4 files changed, 448 insertions(+) create mode 100644 src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java create mode 100644 src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java diff --git a/build.xml b/build.xml index c74fb8f01..a6d985f41 100644 --- a/build.xml +++ b/build.xml @@ -79,6 +79,7 @@ + @@ -158,6 +159,8 @@ + diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index 258938e08..d0a56c7ef 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -86,6 +86,7 @@ ccupdate=org.apache.tools.ant.taskdefs.optional.clearcase.CCUpdate cccheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckout cccheckin=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckin ccuncheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnCheckout +sound=org.apache.tools.ant.taskdefs.optional.sound.SoundTask # deprecated ant tasks (kept for back compatibility) javadoc2=org.apache.tools.ant.taskdefs.Javadoc diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java b/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java new file mode 100644 index 000000000..bad922c26 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java @@ -0,0 +1,268 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs.optional.sound; + +// ant includes +import org.apache.tools.ant.*; + +// imports for all the sound classes required +// note: comes with jmf or jdk1.3 + +// these can be obtained from http://java.sun.com/products/java-media/sound/ +import javax.sound.sampled.*; + +import java.io.*; +import java.util.*; + + +/** + * This class is designed to be used by any AntTask that requires audio output. + * + * It implements the BuildListener interface to listen for BuildEvents and could + * be easily extended to provide audio output upon any specific build events occuring. + * + * I have only tested this with .WAV and .AIFF sound file formats. Both seem to work fine. + * + * @author Nick Pellow + * @version $Revision$, $Date$ + */ + +public class AntSoundPlayer implements LineListener, BuildListener { + + private File fileSuccess = null; + private int loopsSuccess = 1; + private Long durationSuccess = null; + + private File fileFail = null; + private int loopsFail = 1; + private Long durationFail = null; + + public AntSoundPlayer() { + + } + + /** + * @param fileName the location of the audio file to be played when the build is succesful + * @param loops the number of times the file should be played when the build is succesful + * @param duration the number of milliseconds the file should be played when the build is succesful + */ + public void addBuildSuccesfulSound(File file, int loops, Long duration) { + this.fileSuccess = file; + this.loopsSuccess = loops; + this.durationSuccess = duration; + } + + + /** + * @param fileName the location of the audio file to be played when the build fails + * @param loops the number of times the file should be played when the build is fails + * @param duration the number of milliseconds the file should be played when the build fails + */ + public void addBuildFailedSound(File fileFail, int loopsFail, Long durationFail) { + this.fileFail = fileFail; + this.loopsFail = loopsFail; + this.durationFail = durationFail; + } + + /** + * Plays the file for duration milliseconds or loops loops. + */ + private void play(Project project, File file, int loops, Long duration) { + + Clip audioClip = null; + + AudioInputStream audioInputStream = null; + + + try { + audioInputStream = AudioSystem.getAudioInputStream(file); + } + catch (UnsupportedAudioFileException uafe) { + project.log("Audio format is not yet supported: "+uafe.getMessage()); + } + catch (IOException ioe) { + ioe.printStackTrace(); + } + + if (audioInputStream != null) { + AudioFormat format = audioInputStream.getFormat(); + DataLine.Info info = new DataLine.Info(Clip.class, format, AudioSystem.NOT_SPECIFIED); + try { + audioClip = (Clip) AudioSystem.getLine(info); + audioClip.addLineListener(this); + audioClip.open(audioInputStream); + } + catch (LineUnavailableException e) { + project.log("The sound device is currently unavailable"); + return; + } + catch (IOException e) { + e.printStackTrace(); + } + + if (duration != null) { + playClip(audioClip, duration.longValue()); + } else { + playClip(audioClip, loops); + } + audioClip.drain(); + audioClip.close(); + } + else { + project.log("SoundTask: can't get data from file " + file.getName()); + } + } + + private void playClip(Clip clip, int loops) { + + clip.loop(loops); + while (clip.isRunning()) { + } + } + + private void playClip(Clip clip, long duration) { + + long currentTime = System.currentTimeMillis(); + clip.loop(Clip.LOOP_CONTINUOUSLY); + try { + Thread.sleep(duration); + } + catch (InterruptedException e) { + } + } + + /** + * This is implemented to listen for any line events and closes the clip if required. + */ + public void update(LineEvent event) { + if (event.getType().equals(LineEvent.Type.STOP)) { + Line line = event.getLine(); + line.close(); + } + else if (event.getType().equals(LineEvent.Type.CLOSE)) { + /* + * There is a bug in JavaSound 0.90 (jdk1.3beta). + * It prevents correct termination of the VM. + * So we have to exit ourselves. + */ + //System.exit(0); + } + } + + + /** + * Fired before any targets are started. + */ + public void buildStarted(BuildEvent event){ + } + + /** + * Fired after the last target has finished. This event + * will still be thrown if an error occured during the build. + * + * @see BuildEvent#getException() + */ + public void buildFinished(BuildEvent event){ + if (event.getException() == null && fileSuccess != null) { + // build successfull! + play(event.getProject(), fileSuccess, loopsSuccess, durationSuccess); + } else if (fileFail != null) { + play(event.getProject(), fileFail, loopsFail, durationFail); + } + } + + /** + * Fired when a target is started. + * + * @see BuildEvent#getTarget() + */ + public void targetStarted(BuildEvent event){ + } + + /** + * Fired when a target has finished. This event will + * still be thrown if an error occured during the build. + * + * @see BuildEvent#getException() + */ + public void targetFinished(BuildEvent event){ + } + + /** + * Fired when a task is started. + * + * @see BuildEvent#getTask() + */ + public void taskStarted(BuildEvent event){ + } + + /** + * Fired when a task has finished. This event will still + * be throw if an error occured during the build. + * + * @see BuildEvent#getException() + */ + public void taskFinished(BuildEvent event){ + } + + /** + * Fired whenever a message is logged. + * + * @see BuildEvent#getMessage() + * @see BuildEvent#getPriority() + */ + public void messageLogged(BuildEvent event){ + } +} + diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java new file mode 100644 index 000000000..f5f9650e6 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java @@ -0,0 +1,176 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs.optional.sound; + +import org.apache.tools.ant.*; + +import java.io.*; +import java.util.*; + +/** + * This is an example of an AntTask that makes of use of the AntSoundPlayer. + * + * There are four attributes to be set: + * + * source: the location of the audio file to be played + * duration: play the sound file continuously until "duration" milliseconds has expired + * loops: the number of times the sound file should be played until stopped + * + * I have only tested this with .WAV and .AIFF sound file formats. Both seem to work fine. + * + * plans for the future: + * - use the midi api to define sounds (or drum beat etc) in xml and have Ant play them back + * + * @author Nick Pellow + * @version $Revision$, $Date$ + */ + +public class SoundTask extends Task { + + private BuildAlert success = null; + private BuildAlert fail = null; + + public BuildAlert createSuccess() { + success = new BuildAlert(); + return success; + } + + public BuildAlert createFail() { + fail = new BuildAlert(); + return fail; + } + + public SoundTask() { + } + + public void init(){ + } + + public void execute() throws BuildException { + if ( success == null && fail == null) { + throw new BuildException("No nested elements provided."); + } + + AntSoundPlayer soundPlayer = new AntSoundPlayer(); + if (success != null) { + soundPlayer.addBuildSuccesfulSound(success.getSource(), success.getLoops(), success.getDuration()); + } + + if (fail != null) { + soundPlayer.addBuildFailedSound(fail.getSource(), fail.getLoops(), fail.getDuration()); + } + getProject().addBuildListener(soundPlayer); + } + + /** + * A static class to be extended by any BuildAlert's that require the output of sound. + */ + public static class BuildAlert { + private File file = null; + private int loops = 1; + private Long duration = null; + + /** + * Sets the duration in milliseconds the file should be played. + */ + public void setDuration(Long duration) { + this.duration = duration; + } + + /** + * Sets the location of the file to get the audio. + * + * @param fileName the location of the audio file + */ + public void setSource(File file) { + this.file = file; + } + + /** + * This attribute sets the number of times the source file should + * be played. + * + * @param loops the number of loops to play the source file + */ + public void setLoops(int loops) { + this.loops = loops; + } + + /** + * Gets the duration in milliseconds the file should be played. + */ + public Long getDuration() { + return this.duration; + } + + /** + * Gets the location of the file to get the audio. + */ + public File getSource() { + return this.file; + } + + /** + * This attribute sets the number of times the source file should + * be played. + * + * @return the number of loops to play the source file + */ + public int getLoops() { + return this.loops; + } + } +} +