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.util; 034 035import java.util.ArrayList; 036import java.util.List; 037 038import org.openimaj.audio.AudioStream; 039import org.openimaj.audio.SampleChunk; 040 041/** 042 * Provides a buffered audio source such that the audio can be reset 043 * and re-read as many times as needed without the need for redecoding. 044 * You should pass your audio stream through this method if you need 045 * to do certain complete-source calculations on the data (such as 046 * finding peak or means) prior to some other processing. Clearly, 047 * the limitation to how long an audio source you can store with this 048 * class is the memory of your machine, and remember that the audio 049 * samples are stored uncompressed, so they take up a lot of room! If 050 * you're planning on performing complete-source calculations on large 051 * audio data, it is recommended to stream the data multiple times. 052 * 053 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 054 * @created 4 Mar 2013 055 * @version $Author$, $Revision$, $Date$ 056 */ 057public class MemoryAudioSource extends AudioStream 058{ 059 /** The original audio stream */ 060 private AudioStream stream = null; 061 062 /** The buffered sample list */ 063 private final List<SampleChunk> buffer = new ArrayList<SampleChunk>(); 064 065 /** The current index in the buffer being read */ 066 private int currentIndex = -1; 067 068 /** The number of milliseconds of data in the buffer */ 069 private long bufferLength = 0; 070 071 /** 072 * Constructor that takes the audio stream to buffer. 073 * @param as The audio stream 074 */ 075 public MemoryAudioSource( final AudioStream as ) 076 { 077 this.stream = as; 078 } 079 080 /** 081 * {@inheritDoc} 082 * @see org.openimaj.audio.AudioStream#nextSampleChunk() 083 */ 084 @Override 085 public SampleChunk nextSampleChunk() 086 { 087 // See if we're reading from the buffer and if so, return 088 // the current sample chunk in the buffer (and move to the next index) 089 if( !this.buffer.isEmpty() && this.currentIndex < this.buffer.size() ) 090 return this.buffer.get( this.currentIndex++ -1 ); 091 else 092 { 093 // If we're outside of the buffer, we'll try to get the next 094 // sample chunk from the original stream... 095 final SampleChunk sc = this.stream.nextSampleChunk(); 096 097 // If we get one, we'll add it to the buffer then return it... 098 if( sc != null ) 099 { 100 this.buffer.add( sc ); 101 this.currentIndex++; 102 this.bufferLength += (long)(sc.getNumberOfSamples() 103 / sc.getFormat().getSampleRateKHz() ); 104 return sc; 105 } 106 // Otherwise we're at the end of the buffer and the original 107 // stream, so we'll just return null (end of stream). 108 else 109 return null; 110 } 111 } 112 113 /** 114 * {@inheritDoc} 115 * @see org.openimaj.audio.AudioStream#reset() 116 */ 117 @Override 118 public void reset() 119 { 120 this.currentIndex = 0; 121 } 122 123 /** 124 * For live streams, returns the length of the buffered audio, 125 * otherwise returns the length of the original stream. 126 * 127 * @see org.openimaj.audio.AudioStream#getLength() 128 */ 129 @Override 130 public long getLength() 131 { 132 if( this.stream.getLength() == -1 ) 133 return this.bufferLength; 134 else return this.stream.getLength(); 135 } 136}