001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.audio.processor; 034 035import org.openimaj.audio.AudioStream; 036import org.openimaj.audio.SampleChunk; 037 038/** 039 * An interface for objects that are able to process audio sample 040 * data. Due to the fact that audio processors provide processed 041 * audio, they are also able to implement the {@link AudioStream} interface 042 * thereby making processors chainable. 043 * 044 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 045 * @created 8 Jun 2011 046 * 047 */ 048public abstract class AudioProcessor extends AudioStream 049{ 050 /** The audio stream to process in a chain */ 051 private AudioStream stream = null; 052 053 /** 054 * A default constructor for processing sample chunks or files 055 * in an ad-hoc manner. 056 */ 057 public AudioProcessor() 058 { 059 } 060 061 /** 062 * Construct a new processor based on the given stream. This 063 * processor can then be used as a stream itself in a chain. 064 * 065 * @param a The audio stream to process. 066 */ 067 public AudioProcessor( final AudioStream a ) 068 { 069 this.stream = a; 070 if( a != null ) 071 this.format = a.getFormat().clone(); 072 } 073 074 /** 075 * Function to process a whole audio stream. If the process returns 076 * null, it will stop the processing of the audio stream. Note that the 077 * output of the audio stream processing is not stored (it may be a live 078 * stream and so would be too large to store), so the caller must interact 079 * with the audio processor themselves to retrieve any useful information 080 * from the processing. 081 * 082 * @param a The audio stream to process. 083 * @throws Exception If the processing failed 084 */ 085 public void process( final AudioStream a ) throws Exception 086 { 087 this.stream = a; 088 while( this.nextSampleChunk() != null ); 089 this.processingComplete( a ); 090 } 091 092 /** 093 * Function that takes a sample chunk and processes the chunk. 094 * It should also return a sample chunk containing the processed data. 095 * If wished, the chunk may be side-affected and the input chunk returned. 096 * It should not be assumed that the input chunk will be side-affected, 097 * but it must be noted that it is possible that it could be. This process 098 * function may also return null. If null is returned it means that the 099 * rest of the audio stream is not required to be processed by this 100 * processing function. Whether the rest of the sample chunks are copied or 101 * ignored is up to the caller. 102 * 103 * @param sample The sample chunk to process. 104 * @return A sample chunk containing processed data. 105 * @throws Exception If the processing could not take place 106 */ 107 public abstract SampleChunk process( SampleChunk sample ) throws Exception; 108 109 /** 110 * Called when the processing of a given audio stream 111 * has been completed. This can be used to alter the audio 112 * stream's properties. 113 * 114 * @param a The audio stream that has finished processing. 115 */ 116 public void processingComplete( final AudioStream a ) 117 { 118 // Default is no implementation. Override this if necessary. 119 } 120 121 /** 122 * {@inheritDoc} 123 * @see org.openimaj.audio.AudioStream#nextSampleChunk() 124 */ 125 @Override 126 public SampleChunk nextSampleChunk() 127 { 128 try 129 { 130 final SampleChunk s = this.stream.nextSampleChunk(); 131 return (s != null ? this.process( s ) : null ); 132 } 133 catch( final Exception e ) 134 { 135 e.printStackTrace(); 136 return null; 137 } 138 } 139 140 /** 141 * Get the underlying stream. Will return null for non-chained 142 * audio processors. 143 * 144 * @return The underlying stream on chained processors. 145 */ 146 public AudioStream getUnderlyingStream() 147 { 148 return this.stream; 149 } 150 151 /** 152 * Sets the underlying stream, allowing it to be changed. 153 * @param stream The stream 154 */ 155 public void setUnderlyingStream( final AudioStream stream ) 156 { 157 this.stream = stream; 158 if( stream != null ) 159 this.format = stream.getFormat().clone(); 160 } 161 162 /** 163 * {@inheritDoc} 164 * 165 * The implementation in this class does nothing, but removed other classes 166 * from having to implement an empty version. Override this if the stream 167 * can be reset. 168 * 169 * @see org.openimaj.audio.AudioStream#reset() 170 */ 171 @Override 172 public void reset() 173 { 174 } 175 176 /** 177 * {@inheritDoc} 178 * @see org.openimaj.audio.AudioStream#getLength() 179 */ 180 @Override 181 public long getLength() 182 { 183 return this.stream.getLength(); 184 } 185}