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 javax.sound.sampled.AudioSystem;
039import javax.sound.sampled.DataLine;
040import javax.sound.sampled.LineUnavailableException;
041import javax.sound.sampled.Mixer;
042import javax.sound.sampled.SourceDataLine;
043
044import org.openimaj.audio.AudioDevice;
045import org.openimaj.audio.AudioFormat;
046
047/**
048 *      Various static methods for dealing with audio information and data.     
049 *
050 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
051 *      
052 *      @created 26 Nov 2011
053 */
054public class AudioUtils
055{
056        /** When looking for devices, these are the sample rates we'll try */
057        static final double[] freqsToTry = new double[] 
058                        {11.025, 22.05, 44.1, 48, 96.1, 192};
059        
060        /** When looking for devices, these are the bits per sample we'll try */
061        static final int[] bitsToTry = new int[] {8,16,24,32};
062        
063        /** When looking for devices, these are the number of channels we'll try */
064        static final int[] chansToTry = new int[] {1,2,4,5,7,8};
065        
066        /**
067         *      Returns a list of devices that are available on this system.
068         *      @return The list of devices available on this system.
069         */
070        static public List<AudioDevice> getDevices()
071        {
072                final List<AudioDevice> l = new ArrayList<AudioDevice>();
073                final Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
074                 
075                for(int i = 0; i < mixerInfo.length; i++)
076                {
077                        l.add( new AudioDevice( mixerInfo[i].getName(),
078                                        mixerInfo[i].getDescription() ) );
079                }
080                
081                return l;
082        }
083        
084        /**
085         *      Returns a Java sound line for the given device name. Use 
086         *      {@link AudioDevice#deviceName} as input to this method. Use
087         *      {@link AudioUtils#getDevices()} to get an {@link AudioDevice} object.
088         * 
089         *      @param deviceName The device name.
090         *  @param af The format 
091         *      @return A Java sound line.
092         *      @throws LineUnavailableException 
093         */
094        static public SourceDataLine getJavaOutputLine( final String deviceName, 
095                        final AudioFormat af ) 
096                throws LineUnavailableException
097        {
098                final Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
099                for( final Mixer.Info info: mixerInfo )
100                {
101                        if( info.getName().equals( deviceName ) )
102                        {
103                                final Mixer m = AudioSystem.getMixer(info);
104                                if( m.getSourceLineInfo().length > 0 )
105                                        return (SourceDataLine)AudioSystem.getLine( 
106                                                        m.getSourceLineInfo()[0] );
107                        }
108                }
109                
110                return null;
111        }
112        
113        /**
114         *      Gets a Java output line (SourceDataLine) that can play something with
115         *      the given audio format.
116         * 
117         *      @param af The audio format.
118         *      @return A SourceDataLine
119         *      @throws LineUnavailableException
120         */
121        static public SourceDataLine getAnyJavaOutputLine( final AudioFormat af ) 
122                throws LineUnavailableException
123        {
124                // Convert the OpenIMAJ audio format to a Java Sound audio format object
125                final javax.sound.sampled.AudioFormat audioFormat = af.getJavaAudioFormat();
126                
127                // Create info to create an output data line
128                final DataLine.Info info = new DataLine.Info(   
129                                SourceDataLine.class, audioFormat );
130                
131                // Get the output line to write to using the given
132                // sample format we just created.
133                return (SourceDataLine) AudioSystem.getLine( info );
134        }
135        
136        /**
137         *      Converts a frequency to an approximation of a Mel frequency.
138         *      This formula gives a close approximation for frequencies less than
139         *      1000Hz.
140         *  
141         *      @param freq The frequency to convert
142         *      @return The Mel frequency
143         */
144        static public double frequencyToMelFrequency( final double freq )
145        {
146                return (1127d * Math.log( 1 + freq/700d ) );
147//              return (2595d * Math.log10(1 + freq/700d) );
148        }
149        
150        /**
151         *      Converts a Mel frequency back into an approximation of a frequency.
152         * 
153         *      @param melFreq The Mel frequency to convert
154         *      @return The frequency
155         */
156        static public double melFrequencyToFrequency( final double melFreq )
157        {
158                return (700d * Math.exp( melFreq/1127d ) -700d );
159//               return (700d * (Math.pow(10, melFreq/2595d) - 1) );
160        }
161        
162        /**
163         *      Converts a frequency to a Bark frequency
164         * 
165         *      @param freq The frequency to convert
166         *      @return The Bark frequency
167         */
168        static public double frequencyToBarkFrequency( final double freq )
169        {
170                return 6*Math.log( (freq/600d) + Math.sqrt(Math.pow(freq/600d,2) + 1 ) );
171        }
172
173        /**
174         * 
175         *      @param args
176         */
177        public static void main( final String[] args )
178        {
179                try
180                {
181                        System.out.println( AudioUtils.getDevices() );
182                        System.out.println( AudioUtils.getJavaOutputLine( "Line 1/2 (M-Audio Delta 44)", 
183                                        new AudioFormat( 16, 44.1, 2 ) ) );
184                }
185                catch( final LineUnavailableException e )
186                {
187                        e.printStackTrace();
188                }
189        }
190}