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.analysis.benchmarking; 034 035import java.util.List; 036import java.util.ListIterator; 037 038import org.openimaj.audio.AudioFormat; 039import org.openimaj.audio.AudioStream; 040import org.openimaj.audio.SampleChunk; 041import org.openimaj.audio.samples.SampleBuffer; 042import org.openimaj.data.dataset.ListDataset; 043 044/** 045 * A class for helping to deal with datasets of audio information. 046 * 047 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 048 * @created 14 May 2013 049 * @version $Author$, $Revision$, $Date$ 050 */ 051public class AudioDatasetHelper 052{ 053 /** 054 * From a dataset that contains sample buffers, this method will return an 055 * {@link AudioStream} which will return each of the sample buffers in turn. 056 * The returned stream will have an undefined length (-1). If you need to know 057 * the length of the stream, use {@link #calculateStreamLength(ListDataset)}. 058 * 059 * @param samples The samples 060 * @return The audio stream 061 */ 062 static public AudioStream getAudioStream( final ListDataset<List<SampleBuffer>> samples ) 063 { 064 final long streamLength = -1; 065 return new AudioStream() 066 { 067 private int index = 0; 068 private List<SampleBuffer> l = null; 069 private int listIndex = 0; 070 private long timecodeOffset = 0; 071 private long currentTimecode = 0; 072 073 @Override 074 public void reset() 075 { 076 this.listIndex = 0; 077 this.l = null; 078 this.index = 0; 079 this.timecodeOffset = 0; 080 this.currentTimecode = 0; 081 } 082 083 @Override 084 public SampleChunk nextSampleChunk() 085 { 086 if( this.listIndex >= samples.size() ) 087 return null; 088 089 if( this.l == null || this.index >= this.l.size() ) 090 { 091 this.l = samples.get(this.listIndex); 092 this.index = 0; 093 this.listIndex++; 094 this.timecodeOffset += this.currentTimecode; 095 } 096 097 // Get the current sample chunk 098 final SampleChunk sc = this.l.get(this.index).getSampleChunk(); 099 100 // Work out the timecode at the end of the sample chunk 101 this.currentTimecode = (long)(sc.getStartTimecode().getTimecodeInMilliseconds() + 102 sc.getNumberOfSamples() / sc.getFormat().getSampleRateKHz()); 103 104 // Add the offset into the current timecode. 105 sc.getStartTimecode().setTimecodeInMilliseconds( 106 sc.getStartTimecode().getTimecodeInMilliseconds() + this.timecodeOffset ); 107 108 this.index++; 109 110 return sc; 111 } 112 113 @Override 114 public long getLength() 115 { 116 return streamLength; 117 } 118 119 @Override 120 public AudioFormat getFormat() 121 { 122 final SampleChunk sc = this.nextSampleChunk(); 123 this.reset(); 124 return sc.getFormat(); 125 } 126 }; 127 } 128 129 /** 130 * Calculate the length of the stream of samples that will come from the dataset. 131 * 132 * @param samples The sample list 133 * @return The length of the stream in milliseconds 134 */ 135 public static long calculateStreamLength( final ListDataset<List<SampleBuffer>> samples ) 136 { 137 final ListIterator<List<SampleBuffer>> i = samples.listIterator(); 138 long length = 0; 139 while( i.hasNext() ) 140 { 141 final List<SampleBuffer> l = i.next(); 142 for( final SampleBuffer sb : l ) 143 { 144 length += sb.size() / sb.getFormat().getNumChannels() * sb.getFormat().getSampleRateKHz(); 145 } 146 } 147 148 return length; 149 } 150}