Browse Source

Recast SoundTask in Myrmidon. i18n it and clean up some of its structures

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271320 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Donald 24 years ago
parent
commit
8821afcf82
4 changed files with 456 additions and 0 deletions
  1. +237
    -0
      proposal/myrmidon/src/java/org/apache/antlib/sound/AntSoundPlayer.java
  2. +81
    -0
      proposal/myrmidon/src/java/org/apache/antlib/sound/BuildAlert.java
  3. +4
    -0
      proposal/myrmidon/src/java/org/apache/antlib/sound/Resources.properties
  4. +134
    -0
      proposal/myrmidon/src/java/org/apache/antlib/sound/SoundTask.java

+ 237
- 0
proposal/myrmidon/src/java/org/apache/antlib/sound/AntSoundPlayer.java View File

@@ -0,0 +1,237 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.antlib.sound;

import java.io.File;
import java.io.IOException;
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 javax.sound.sampled.Line;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.myrmidon.listeners.AbstractProjectListener;
import org.apache.myrmidon.listeners.LogEvent;
import org.apache.myrmidon.listeners.ProjectEvent;

/**
* 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
extends AbstractProjectListener
implements LineListener, LogEnabled
{
private File m_fileSuccess;
private int m_loopsSuccess;
private Long m_durationSuccess;

private File m_fileFail;
private int m_loopsFail;
private Long m_durationFail;

private Logger m_logger;

/**
* Provide component with a logger.
*
* @param logger the logger
*/
public void enableLogging( final Logger logger )
{
m_logger = logger;
}

protected final Logger getLogger()
{
return m_logger;
}

/**
* Notify listener of projectFinished event.
*/
public void projectFinished( final ProjectEvent event )
{
success();
}

/**
* Notify listener of log message event.
*/
public void log( final LogEvent event )
{
if( event.getThrowable() != null )
{
failure();
}
}

/**
* @param fileFail The feature to be added to the BuildFailedSound attribute
* @param loopsFail The feature to be added to the BuildFailedSound
* attribute
* @param durationFail The feature to be added to the BuildFailedSound
* attribute
*/
public void addBuildFailedSound( File fileFail, int loopsFail, Long durationFail )
{
m_fileFail = fileFail;
m_loopsFail = loopsFail;
m_durationFail = durationFail;
}

/**
* @param loops the number of times the file should be played when the build
* is successful
* @param duration the number of milliseconds the file should be played when
* the build is successful
* @param file The feature to be added to the BuildSuccessfulSound attribute
*/
public void addBuildSuccessfulSound( File file, int loops, Long duration )
{
m_fileSuccess = file;
m_loopsSuccess = loops;
m_durationSuccess = duration;
}

/**
* 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);
}
}

protected void success()
{
if( null != m_fileSuccess )
{
// build successfull!
play( m_fileSuccess, m_loopsSuccess, m_durationSuccess );
}
}

protected void failure()
{
if( null != m_fileFail )
{
play( m_fileFail, m_loopsFail, m_durationFail );
}
}

/**
* Plays the file for duration milliseconds or loops.
*/
private void play( File file, int loops, Long duration )
{
Clip audioClip = null;

AudioInputStream audioInputStream = null;

try
{
audioInputStream = AudioSystem.getAudioInputStream( file );
}
catch( UnsupportedAudioFileException uafe )
{
final String message = "Audio format is not yet supported: " + uafe.getMessage();
getLogger().info( message );
}
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 )
{
final String message = "The sound device is currently unavailable";
getLogger().info( message );
return;
}
catch( IOException e )
{
e.printStackTrace();
}

if( duration != null )
{
playClip( audioClip, duration.longValue() );
}
else
{
playClip( audioClip, loops );
}
audioClip.drain();
audioClip.close();
}
else
{
final String message = "Can't get data from file " + file.getName();
getLogger().info( message );
}
}

private void playClip( Clip clip, int loops )
{

clip.loop( loops );
while( clip.isRunning() )
{
}
}

private void playClip( Clip clip, long duration )
{
clip.loop( Clip.LOOP_CONTINUOUSLY );
try
{
Thread.sleep( duration );
}
catch( InterruptedException e )
{
}
}
}


+ 81
- 0
proposal/myrmidon/src/java/org/apache/antlib/sound/BuildAlert.java View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.antlib.sound;

import java.io.File;

/**
* A class to be extended by any BuildAlert's that require the output of
* sound.
*/
public class BuildAlert
{
private File m_source;
private int m_loops;
private Long m_duration;

/**
* Sets the duration in milliseconds the file should be played.
*
* @param duration The new Duration value
*/
public void setDuration( Long duration )
{
m_duration = duration;
}

/**
* 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 )
{
m_loops = loops;
}

/**
* Sets the location of the file to get the audio.
*
* @param source the name of a sound-file directory or of the audio file
*/
public void setSource( final File source )
{
m_source = source;
}

/**
* Gets the duration in milliseconds the file should be played.
*
* @return The Duration value
*/
public Long getDuration()
{
return m_duration;
}

/**
* 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 m_loops;
}

/**
* Gets the location of the file to get the audio.
*
* @return The Source value
*/
public File getSource()
{
return m_source;
}
}

+ 4
- 0
proposal/myrmidon/src/java/org/apache/antlib/sound/Resources.properties View File

@@ -0,0 +1,4 @@
sound.missing-success.error=No nested success element found.
sound.missing-failure.error=No nested failure element found.
sound.empty.dir.error=No files found in directory {0}.
sound.invalid-path.error={0}: invalid path.

+ 134
- 0
proposal/myrmidon/src/java/org/apache/antlib/sound/SoundTask.java View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.antlib.sound;

import java.io.File;
import java.util.ArrayList;
import java.util.Random;
import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.interfaces.workspace.Workspace;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.excalibur.i18n.ResourceManager;

/**
* This is an example of an AntTask that makes of use of the AntSoundPlayer.
* There are three 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
*
* @ant:task name="sound-listener"
* @author Nick Pellow
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @version $Revision$, $Date$
*/
public class SoundTask
extends AbstractTask
{
private final static Resources REZ =
ResourceManager.getPackageResources( SoundTask.class );

private BuildAlert m_success;
private BuildAlert m_fail;

public void addFail( final BuildAlert fail )
{
m_fail = fail;
}

public void addSuccess( final BuildAlert success )
{
m_success = success;
}

public void execute()
throws TaskException
{
final AntSoundPlayer soundPlayer = new AntSoundPlayer();
if( null == m_success )
{
final String message = REZ.getString( "sound.missing-success.error" );
getLogger().warn( message );
}
else
{
final File source = getRandomSource( m_success );
soundPlayer.addBuildSuccessfulSound( source,
m_success.getLoops(),
m_success.getDuration() );
}

if( null == m_fail )
{
final String message = REZ.getString( "sound.missing-failure.error" );
getLogger().warn( message );
}
else
{
final File source = getRandomSource( m_fail );
soundPlayer.addBuildFailedSound( source,
m_fail.getLoops(),
m_fail.getDuration() );
}

final Workspace workspace = (Workspace)getContext().getService( Workspace.class );
workspace.addProjectListener( soundPlayer );
}

/**
* Gets the location of the file to get the audio.
*/
private File getRandomSource( final BuildAlert alert )
throws TaskException
{
final File source = alert.getSource();
// Check if source is a directory
if( source.exists() )
{
if( source.isDirectory() )
{
// get the list of files in the dir
final String[] entries = source.list();
final ArrayList files = new ArrayList();
for( int i = 0; i < entries.length; i++ )
{
final File file = new File( source, entries[ i ] );
if( file.isFile() )
{
files.add( file );
}
}
if( files.size() < 1 )
{
final String message = REZ.getString( "sound.empty.dir.error", source );
throw new TaskException( message );
}
final int numfiles = files.size();
// get a random number between 0 and the number of files
final Random random = new Random();
final int x = random.nextInt( numfiles );
// set the source to the file at that location
return (File)files.get( x );
}
else
{
return null;
}
}
else
{
final String message = REZ.getString( "sound.invalid-path.error", source );
getLogger().warn( message );
return null;
}
}
}

Loading…
Cancel
Save