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}