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 */
030package org.openimaj.vis.audio;
031
032import java.awt.BorderLayout;
033import java.awt.Dimension;
034import java.util.ArrayList;
035import java.util.List;
036
037import javax.swing.JFrame;
038
039import org.jfree.chart.ChartFactory;
040import org.jfree.chart.ChartPanel;
041import org.jfree.chart.JFreeChart;
042import org.jfree.chart.plot.PlotOrientation;
043import org.jfree.data.xy.DefaultXYDataset;
044import org.openimaj.audio.AudioStream;
045import org.openimaj.audio.SampleChunk;
046import org.openimaj.audio.samples.SampleBuffer;
047import org.openimaj.util.pair.IndependentPair;
048
049/**
050 *      Allows the drawing of frames of audio onto an interactive line chart (JFreeChart XY plot).
051 *
052 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
053 *  @created 13 Feb 2013
054 *      @version $Author$, $Revision$, $Date$
055 */
056public class AudioFramePlot
057{
058        /**
059         *      Draws the first 3 frames of the audio stream on to a chart.  If the number of streams
060         *      is 1, then the frames will be coloured, otherwise the streams will be coloured. The
061         *      streams will be named "Stream n" and a legend shown if there is more than one stream.
062         *
063         *      @param streams The audio stream
064         */
065        public static void drawChart( final AudioStream ... streams )
066        {
067                if( streams.length == 1 )
068                                AudioFramePlot.drawChart( 3, true, streams );
069                else    AudioFramePlot.drawChart( 3, false, streams );
070        }
071
072        /**
073         *      Draws the first n frames of the audio stream on to a chart. If the number of streams
074         *      is 1, then the frames will be coloured, otherwise the streams will be coloured. The
075         *      streams will be named "Stream n" and a legend shown if there is more than one stream.
076         *
077         *      @param numFrames The number of frames to draw
078         *      @param streams The audio streams
079         */
080        public static void drawChart( final int numFrames, final AudioStream ... streams )
081        {
082                if( streams.length == 1 )
083                                AudioFramePlot.drawChart( numFrames, true, streams );
084                else    AudioFramePlot.drawChart( numFrames, false, streams );
085        }
086
087        /**
088         *      Draws the first n frames of the audio stream on to a chart. Will label each of the streams
089         *      as "Stream n" and a legend will be shown on the chart if there is more than one stream.
090         *
091         *      @param numFrames The number of frames to draw
092         *      @param colouredFrames Whether to colour individual frames
093         *      @param streams The audio streams
094         */
095        public static void drawChart( final int numFrames, final boolean colouredFrames, final AudioStream ... streams )
096        {
097                final List<IndependentPair<AudioStream, String>> pairs =
098                                new ArrayList<IndependentPair<AudioStream,String>>();
099
100                for( int i = 0; i < streams.length; i++ )
101                        pairs.add( new IndependentPair<AudioStream, String>( streams[i], "Stream "+i ) );
102
103                AudioFramePlot.drawChart( numFrames, colouredFrames, pairs );
104        }
105
106        /**
107         *      Draws the first n frames of the audio streams on to a chart mapping the names given
108         *      to each stream into the legend. Note that the legend will only be shown if there is more
109         *      than one stream.
110         *
111         *      @param numFrames The number of frames to draw
112         *      @param colouredFrames Whether to colour individual frames
113         *      @param streams The audio streams and their labels
114         */
115        public static void drawChart( final int numFrames, final boolean colouredFrames,
116                        final List<IndependentPair<AudioStream,String>> streams )
117        {
118                final DefaultXYDataset ds = new DefaultXYDataset();
119
120                for( final IndependentPair<AudioStream, String> asl : streams )
121                {
122                        final AudioStream as = asl.firstObject();
123                        final String label = asl.secondObject();
124
125                        SampleChunk s = as.nextSampleChunk();
126                        SampleBuffer b = s.getSampleBuffer();
127
128                        int x = 0;
129                        int y = 0;
130                        double[][] data = new double[2][];
131                        if( !colouredFrames )
132                        {
133                                data[0] = new double[b.size()*numFrames]; // x
134                                data[1] = new double[b.size()*numFrames]; // y
135                        }
136
137                        for( int n = 0; n < numFrames; n++ )
138                        {
139                                s = as.nextSampleChunk();
140                                if( s == null ) break;
141
142                                // Convert sample to a XY data plot
143                                if( colouredFrames )
144                                {
145                                        data = new double[2][];
146                                        data[0] = new double[b.size()]; // x
147                                        data[1] = new double[b.size()]; // y
148                                        x = 0;
149                                }
150
151                                System.out.println( "Loop "+x+" to "+(x+b.size())+", y = "+y);
152                                // Copy the value into the data series
153                                for( int z = x; z < x+b.size(); z++ )
154                                {
155                                        data[0][z] = b.get(z-x);
156                                        data[1][z] = z+y;
157                                }
158
159                                // Add as a series if we're using coloured frames
160                                if( colouredFrames )
161                                {
162                                        y += b.size();
163                                        ds.addSeries( label+", Frame "+n, data );
164                                }
165                                else    x += b.size();
166
167                                // Get ready for next loop
168                                b = s.getSampleBuffer();
169                        }
170
171                        if( !colouredFrames )
172                                ds.addSeries( label, data );
173                }
174
175                final JFreeChart chart = ChartFactory.createXYLineChart( "Sample", "samples",
176                        "amplitude", ds, PlotOrientation.HORIZONTAL, streams.size() > 1, false,
177                        false );
178                final ChartPanel chartPanel = new ChartPanel( chart, false );
179                chartPanel.setPreferredSize( new Dimension( 1280, 480 ) );
180
181                final JFrame f = new JFrame();
182                f.add( chartPanel, BorderLayout.CENTER );
183                f.pack();
184                f.setVisible( true );
185        }
186}
187