I got tired of waiting for some else to commit it. I made some small mods to Nick original proposal. Submitted by: Nick Pellow <nick@cortexebusiness.com.au> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268381 13f79535-47bb-0310-9956-ffa450edef68master
@@ -79,6 +79,7 @@ | |||||
<available property="stylebook.present" classname="org.apache.stylebook.Engine" /> | <available property="stylebook.present" classname="org.apache.stylebook.Engine" /> | ||||
<available property="jakarta.regexp.present" classname="org.apache.regexp.RE" /> | <available property="jakarta.regexp.present" classname="org.apache.regexp.RE" /> | ||||
<available property="jakarta.oro.present" classname="org.apache.oro.text.regex.Perl5Matcher" /> | <available property="jakarta.oro.present" classname="org.apache.oro.text.regex.Perl5Matcher" /> | ||||
<available property="jmf.present" classname="javax.sound.sampled.Clip" /> | |||||
</target> | </target> | ||||
<!-- =================================================================== --> | <!-- =================================================================== --> | ||||
@@ -158,6 +159,8 @@ | |||||
<exclude name="**/ANTLR.java" unless="antlr.present" /> | <exclude name="**/ANTLR.java" unless="antlr.present" /> | ||||
<exclude name="**/ide/VAJ*.java" unless="vaj.present" /> | <exclude name="**/ide/VAJ*.java" unless="vaj.present" /> | ||||
<exclude name="**/perforce/*.java" unless="jakarta.oro.present" /> | <exclude name="**/perforce/*.java" unless="jakarta.oro.present" /> | ||||
<exclude name="org/apache/tools/ant/taskdefs/optional/sound/*.java" | |||||
unless="jmf.present" /> | |||||
</javac> | </javac> | ||||
</target> | </target> | ||||
@@ -86,6 +86,7 @@ ccupdate=org.apache.tools.ant.taskdefs.optional.clearcase.CCUpdate | |||||
cccheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckout | cccheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckout | ||||
cccheckin=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckin | cccheckin=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckin | ||||
ccuncheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnCheckout | 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) | # deprecated ant tasks (kept for back compatibility) | ||||
javadoc2=org.apache.tools.ant.taskdefs.Javadoc | javadoc2=org.apache.tools.ant.taskdefs.Javadoc | ||||
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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){ | |||||
} | |||||
} | |||||
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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: | |||||
* | |||||
* <code>source</code>: the location of the audio file to be played | |||||
* <code>duration</code>: play the sound file continuously until "duration" milliseconds has expired | |||||
* <code>loops</code>: 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; | |||||
} | |||||
} | |||||
} | |||||