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}