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; 034 035import java.util.ArrayList; 036import java.util.List; 037 038/** 039 * A class used to force a specific number of loops of an audio stream. 040 * The class can buffer the stream, if you consider that it will be small 041 * enough to fit within memory, otherwise it will reset the audio stream 042 * at each loop. 043 * 044 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 045 * 046 * @created 27 Nov 2011 047 */ 048public class AudioLooper extends AudioStream 049{ 050 /** The audio stream to loop */ 051 private AudioStream stream = null; 052 053 /** The number of times to loop */ 054 private int nLoops = 1; 055 056 /** The current loop being played */ 057 private int currentLoop = 0; 058 059 /** If we're caching the stream, it will be put in this list */ 060 private List<SampleChunk> streamCache = null; 061 062 /** The index into the cache if we're playing from the cache */ 063 private int currentCacheIndex = 0; 064 065 /** Whether we're caching the stream or not */ 066 private boolean cacheStream = false; 067 068 /** 069 * Create a new looper that will loop the given stream the given number 070 * of times. 071 * 072 * @param stream The stream to loop 073 * @param nLoops The number of times to loop the stream 074 */ 075 public AudioLooper( AudioStream stream, int nLoops ) 076 { 077 this( stream, nLoops, false ); 078 } 079 080 /** 081 * Create a new looper that will loop the given stream the given number 082 * of times. Whether the stream is cached or not is able to be specified. 083 * 084 * @param stream The stream to loop 085 * @param nLoops The number of loops to do 086 * @param cacheStream Whether to cache the stream or not 087 */ 088 public AudioLooper( AudioStream stream, int nLoops, boolean cacheStream ) 089 { 090 this.stream = stream; 091 this.nLoops = nLoops; 092 this.cacheStream = cacheStream; 093 this.format = stream.getFormat(); 094 095 if( cacheStream ) 096 streamCache = new ArrayList<SampleChunk>(); 097 } 098 099 /** 100 * {@inheritDoc} 101 * @see org.openimaj.audio.AudioStream#nextSampleChunk() 102 */ 103 @Override 104 public SampleChunk nextSampleChunk() 105 { 106 if( currentLoop == 0 || !cacheStream ) 107 { 108 SampleChunk sc = stream.nextSampleChunk(); 109 110 if( sc != null ) 111 { 112 // Cache the chunk if necessary 113 if( cacheStream && nLoops > 1 ) 114 streamCache.add( sc.clone() ); 115 116 // We're on the first loop, so simply return this chunk 117 return sc; 118 } 119 else 120 { 121 currentCacheIndex = 0; 122 currentLoop++; 123 124 // If we're not caching the stream, we need to reset the 125 // stream. 126 if( !cacheStream ) 127 { 128 stream.reset(); 129 return stream.nextSampleChunk(); 130 } 131 } 132 } 133 134 if( currentLoop < nLoops ) 135 { 136 SampleChunk sc = streamCache.get( currentCacheIndex ); 137 currentCacheIndex++; 138 139 if( currentCacheIndex == streamCache.size() ) 140 { 141 currentCacheIndex = 0; 142 currentLoop++; 143 } 144 145 return sc; 146 } 147 148 return null; 149 } 150 151 /** 152 * {@inheritDoc} 153 * @see org.openimaj.audio.AudioStream#reset() 154 */ 155 @Override 156 public void reset() 157 { 158 } 159 160 /** 161 * {@inheritDoc} 162 * @see org.openimaj.audio.AudioStream#getLength() 163 */ 164 @Override 165 public long getLength() 166 { 167 return this.stream.getLength() * nLoops; 168 } 169}