Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.media.sound;
   27   
   28   import java.util.Vector;
   29   import java.io.File;
   30   import java.io.InputStream;
   31   import java.io.OutputStream;
   32   import java.io.IOException;
   33   import java.io.EOFException;
   34   import java.net.URL;
   35   import java.net.MalformedURLException;
   36   
   37   import java.io.BufferedInputStream;
   38   import java.io.BufferedOutputStream;
   39   import java.io.DataInputStream;
   40   import java.io.FileInputStream;
   41   import java.io.DataOutputStream;
   42   import java.io.FileOutputStream;
   43   import java.io.ByteArrayInputStream;
   44   import java.io.ByteArrayOutputStream;
   45   import java.io.SequenceInputStream;
   46   
   47   import javax.sound.sampled.AudioFileFormat;
   48   import javax.sound.sampled.AudioInputStream;
   49   import javax.sound.sampled.AudioFormat;
   50   import javax.sound.sampled.AudioSystem;
   51   import javax.sound.sampled.UnsupportedAudioFileException;
   52   
   53   
   54   /**
   55    * AIFF file reader and writer.
   56    *
   57    * @author Kara Kytle
   58    * @author Jan Borgersen
   59    * @author Florian Bomers
   60    */
   61   public class AiffFileReader extends SunFileReader  {
   62   
   63       private static final int MAX_READ_LENGTH = 8;
   64   
   65   
   66       /**
   67        * AIFF parser type
   68        */
   69       public static final AudioFileFormat.Type types[] = {
   70           AudioFileFormat.Type.AIFF
   71       };
   72   
   73   
   74       /**
   75        * Constructs a new AiffParser object.
   76        */
   77       public AiffFileReader() {
   78       }
   79   
   80   
   81   
   82   
   83       // METHODS TO IMPLEMENT AudioFileReader
   84   
   85       /**
   86        * Obtains the audio file format of the input stream provided.  The stream must
   87        * point to valid audio file data.  In general, audio file providers may
   88        * need to read some data from the stream before determining whether they
   89        * support it.  These parsers must
   90        * be able to mark the stream, read enough data to determine whether they
   91        * support the stream, and, if not, reset the stream's read pointer to its original
   92        * position.  If the input stream does not support this, this method may fail
   93        * with an IOException.
   94        * @param stream the input stream from which file format information should be
   95        * extracted
   96        * @return an <code>AudioFileFormat</code> object describing the audio file format
   97        * @throws UnsupportedAudioFileException if the stream does not point to valid audio
   98        * file data recognized by the system
   99        * @throws IOException if an I/O exception occurs
  100        * @see InputStream#markSupported
  101        * @see InputStream#mark
  102        */
  103       public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException {
  104           // fix for 4489272: AudioSystem.getAudioFileFormat() fails for InputStream, but works for URL
  105           AudioFileFormat aff = getCOMM(stream, true);
  106           // the following is not strictly necessary - but was implemented like that in 1.3.0 - 1.4.1
  107           // so I leave it as it was. May remove this for 1.5.0
  108           stream.reset();
  109           return aff;
  110       }
  111   
  112   
  113       /**
  114        * Obtains the audio file format of the URL provided.  The URL must
  115        * point to valid audio file data.
  116        * @param url the URL from which file format information should be
  117        * extracted
  118        * @return an <code>AudioFileFormat</code> object describing the audio file format
  119        * @throws UnsupportedAudioFileException if the URL does not point to valid audio
  120        * file data recognized by the system
  121        * @throws IOException if an I/O exception occurs
  122        */
  123       public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
  124           AudioFileFormat fileFormat = null;
  125           InputStream urlStream = url.openStream();       // throws IOException
  126           try {
  127               fileFormat = getCOMM(urlStream, false);
  128           } finally {
  129               urlStream.close();
  130           }
  131           return fileFormat;
  132       }
  133   
  134   
  135       /**
  136        * Obtains the audio file format of the File provided.  The File must
  137        * point to valid audio file data.
  138        * @param file the File from which file format information should be
  139        * extracted
  140        * @return an <code>AudioFileFormat</code> object describing the audio file format
  141        * @throws UnsupportedAudioFileException if the File does not point to valid audio
  142        * file data recognized by the system
  143        * @throws IOException if an I/O exception occurs
  144        */
  145       public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
  146           AudioFileFormat fileFormat = null;
  147           FileInputStream fis = new FileInputStream(file);       // throws IOException
  148           // part of fix for 4325421
  149           try {
  150               fileFormat = getCOMM(fis, false);
  151           } finally {
  152               fis.close();
  153           }
  154   
  155           return fileFormat;
  156       }
  157   
  158   
  159   
  160   
  161       /**
  162        * Obtains an audio stream from the input stream provided.  The stream must
  163        * point to valid audio file data.  In general, audio file providers may
  164        * need to read some data from the stream before determining whether they
  165        * support it.  These parsers must
  166        * be able to mark the stream, read enough data to determine whether they
  167        * support the stream, and, if not, reset the stream's read pointer to its original
  168        * position.  If the input stream does not support this, this method may fail
  169        * with an IOException.
  170        * @param stream the input stream from which the <code>AudioInputStream</code> should be
  171        * constructed
  172        * @return an <code>AudioInputStream</code> object based on the audio file data contained
  173        * in the input stream.
  174        * @throws UnsupportedAudioFileException if the stream does not point to valid audio
  175        * file data recognized by the system
  176        * @throws IOException if an I/O exception occurs
  177        * @see InputStream#markSupported
  178        * @see InputStream#mark
  179        */
  180       public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException {
  181           // getCOMM leaves the input stream at the beginning of the audio data
  182           AudioFileFormat fileFormat = getCOMM(stream, true);     // throws UnsupportedAudioFileException, IOException
  183   
  184           // we've got everything, and the stream is at the
  185           // beginning of the audio data, so return an AudioInputStream.
  186           return new AudioInputStream(stream, fileFormat.getFormat(), fileFormat.getFrameLength());
  187       }
  188   
  189   
  190       /**
  191        * Obtains an audio stream from the URL provided.  The URL must
  192        * point to valid audio file data.
  193        * @param url the URL for which the <code>AudioInputStream</code> should be
  194        * constructed
  195        * @return an <code>AudioInputStream</code> object based on the audio file data pointed
  196        * to by the URL
  197        * @throws UnsupportedAudioFileException if the URL does not point to valid audio
  198        * file data recognized by the system
  199        * @throws IOException if an I/O exception occurs
  200        */
  201       public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
  202           InputStream urlStream = url.openStream();  // throws IOException
  203           AudioFileFormat fileFormat = null;
  204           try {
  205               fileFormat = getCOMM(urlStream, false);
  206           } finally {
  207               if (fileFormat == null) {
  208                   urlStream.close();
  209               }
  210           }
  211           return new AudioInputStream(urlStream, fileFormat.getFormat(), fileFormat.getFrameLength());
  212       }
  213   
  214   
  215       /**
  216        * Obtains an audio stream from the File provided.  The File must
  217        * point to valid audio file data.
  218        * @param file the File for which the <code>AudioInputStream</code> should be
  219        * constructed
  220        * @return an <code>AudioInputStream</code> object based on the audio file data pointed
  221        * to by the File
  222        * @throws UnsupportedAudioFileException if the File does not point to valid audio
  223        * file data recognized by the system
  224        * @throws IOException if an I/O exception occurs
  225        */
  226       public AudioInputStream getAudioInputStream(File file)
  227           throws UnsupportedAudioFileException, IOException {
  228   
  229           FileInputStream fis = new FileInputStream(file); // throws IOException
  230           AudioFileFormat fileFormat = null;
  231           // part of fix for 4325421
  232           try {
  233               fileFormat = getCOMM(fis, false);
  234           } finally {
  235               if (fileFormat == null) {
  236                   fis.close();
  237               }
  238           }
  239           return new AudioInputStream(fis, fileFormat.getFormat(), fileFormat.getFrameLength());
  240       }
  241   
  242       //--------------------------------------------------------------------
  243   
  244       private AudioFileFormat getCOMM(InputStream is, boolean doReset)
  245           throws UnsupportedAudioFileException, IOException {
  246   
  247           DataInputStream dis = new DataInputStream(is);
  248   
  249           if (doReset) {
  250               dis.mark(MAX_READ_LENGTH);
  251           }
  252   
  253           // assumes a stream at the beginning of the file which has already
  254           // passed the magic number test...
  255           // leaves the input stream at the beginning of the audio data
  256           int fileRead = 0;
  257           int dataLength = 0;
  258           AudioFormat format = null;
  259   
  260           // Read the magic number
  261           int magic = dis.readInt();
  262   
  263           // $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037
  264           if (magic != AiffFileFormat.AIFF_MAGIC) {
  265               // not AIFF, throw exception
  266               if (doReset) {
  267                   dis.reset();
  268               }
  269               throw new UnsupportedAudioFileException("not an AIFF file");
  270           }
  271   
  272           int length = dis.readInt();
  273           int iffType = dis.readInt();
  274           fileRead += 12;
  275   
  276           int totallength;
  277           if(length <= 0 ) {
  278               length = AudioSystem.NOT_SPECIFIED;
  279               totallength = AudioSystem.NOT_SPECIFIED;
  280           } else {
  281               totallength = length + 8;
  282           }
  283   
  284           // Is this an AIFC or just plain AIFF file.
  285           boolean aifc = false;
  286           // $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037
  287           if (iffType ==  AiffFileFormat.AIFC_MAGIC) {
  288               aifc = true;
  289           }
  290   
  291           // Loop through the AIFF chunks until
  292           // we get to the SSND chunk.
  293           boolean ssndFound = false;
  294           while (!ssndFound) {
  295               // Read the chunk name
  296               int chunkName = dis.readInt();
  297               int chunkLen = dis.readInt();
  298               fileRead += 8;
  299   
  300               int chunkRead = 0;
  301   
  302               // Switch on the chunk name.
  303               switch (chunkName) {
  304               case AiffFileFormat.FVER_MAGIC:
  305                   // Ignore format version for now.
  306                   break;
  307   
  308               case AiffFileFormat.COMM_MAGIC:
  309                   // AIFF vs. AIFC
  310                   // $$fb: fix for 4399551: Repost of bug candidate: cannot replay aif file (Review ID: 108108)
  311                   if ((!aifc && chunkLen < 18) || (aifc && chunkLen < 22)) {
  312                       throw new UnsupportedAudioFileException("Invalid AIFF/COMM chunksize");
  313                   }
  314                   // Read header info.
  315                   int channels = dis.readShort();
  316                   dis.readInt();
  317                   int sampleSizeInBits = dis.readShort();
  318                   float sampleRate = (float) read_ieee_extended(dis);
  319                   chunkRead += (2 + 4 + 2 + 10);
  320   
  321                   // If this is not AIFC then we assume it's
  322                   // a linearly encoded file.
  323                   AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
  324   
  325                   if (aifc) {
  326                       int enc = dis.readInt(); chunkRead += 4;
  327                       switch (enc) {
  328                       case AiffFileFormat.AIFC_PCM:
  329                           encoding = AudioFormat.Encoding.PCM_SIGNED;
  330                           break;
  331                       case AiffFileFormat.AIFC_ULAW:
  332                           encoding = AudioFormat.Encoding.ULAW;
  333                           sampleSizeInBits = 8; // Java Sound convention
  334                           break;
  335                       default:
  336                           throw new UnsupportedAudioFileException("Invalid AIFF encoding");
  337                       }
  338                   }
  339                   int frameSize = calculatePCMFrameSize(sampleSizeInBits, channels);
  340                   //$fb what's that ??
  341                   //if (sampleSizeInBits == 8) {
  342                   //    encoding = AudioFormat.Encoding.PCM_SIGNED;
  343                   //}
  344                   format =  new AudioFormat(encoding, sampleRate,
  345                                             sampleSizeInBits, channels,
  346                                             frameSize, sampleRate, true);
  347                   break;
  348               case AiffFileFormat.SSND_MAGIC:
  349                   // Data chunk.
  350                   // we are getting *weird* numbers for chunkLen sometimes;
  351                   // this really should be the size of the data chunk....
  352                   int dataOffset = dis.readInt();
  353                   int blocksize = dis.readInt();
  354                   chunkRead += 8;
  355   
  356                   // okay, now we are done reading the header.  we need to set the size
  357                   // of the data segment.  we know that sometimes the value we get for
  358                   // the chunksize is absurd.  this is the best i can think of:if the
  359                   // value seems okay, use it.  otherwise, we get our value of
  360                   // length by assuming that everything left is the data segment;
  361                   // its length should be our original length (for all AIFF data chunks)
  362                   // minus what we've read so far.
  363                   // $$kk: we should be able to get length for the data chunk right after
  364                   // we find "SSND."  however, some aiff files give *weird* numbers.  what
  365                   // is going on??
  366   
  367                   if (chunkLen < length) {
  368                       dataLength = chunkLen - chunkRead;
  369                   } else {
  370                       // $$kk: 11.03.98: this seems dangerous!
  371                       dataLength = length - (fileRead + chunkRead);
  372                   }
  373                   ssndFound = true;
  374                   break;
  375               } // switch
  376               fileRead += chunkRead;
  377               // skip the remainder of this chunk
  378               if (!ssndFound) {
  379                   int toSkip = chunkLen - chunkRead;
  380                   if (toSkip > 0) {
  381                       fileRead += dis.skipBytes(toSkip);
  382                   }
  383               }
  384           } // while
  385   
  386           if (format == null) {
  387               throw new UnsupportedAudioFileException("missing COMM chunk");
  388           }
  389           AudioFileFormat.Type type = aifc?AudioFileFormat.Type.AIFC:AudioFileFormat.Type.AIFF;
  390   
  391           return new AiffFileFormat(type, totallength, format, dataLength / format.getFrameSize());
  392       }
  393   
  394       // HELPER METHODS
  395       /** write_ieee_extended(DataOutputStream dos, double f) throws IOException {
  396        * Extended precision IEEE floating-point conversion routine.
  397        * @argument DataOutputStream
  398        * @argument double
  399        * @return void
  400        * @exception IOException
  401        */
  402       private void write_ieee_extended(DataOutputStream dos, double f) throws IOException {
  403   
  404           int exponent = 16398;
  405           double highMantissa = f;
  406   
  407           // For now write the integer portion of f
  408           // $$jb: 03.30.99: stay in synch with JMF on this!!!!
  409           while (highMantissa < 44000) {
  410               highMantissa *= 2;
  411               exponent--;
  412           }
  413           dos.writeShort(exponent);
  414           dos.writeInt( ((int) highMantissa) << 16);
  415           dos.writeInt(0); // low Mantissa
  416       }
  417   
  418   
  419       /**
  420        * read_ieee_extended
  421        * Extended precision IEEE floating-point conversion routine.
  422        * @argument DataInputStream
  423        * @return double
  424        * @exception IOException
  425        */
  426       private double read_ieee_extended(DataInputStream dis) throws IOException {
  427   
  428           double f = 0;
  429           int expon = 0;
  430           long hiMant = 0, loMant = 0;
  431           long t1, t2;
  432           double HUGE = ((double)3.40282346638528860e+38);
  433   
  434   
  435           expon = dis.readUnsignedShort();
  436   
  437           t1 = (long)dis.readUnsignedShort();
  438           t2 = (long)dis.readUnsignedShort();
  439           hiMant = t1 << 16 | t2;
  440   
  441           t1 = (long)dis.readUnsignedShort();
  442           t2 = (long)dis.readUnsignedShort();
  443           loMant = t1 << 16 | t2;
  444   
  445           if (expon == 0 && hiMant == 0 && loMant == 0) {
  446               f = 0;
  447           } else {
  448               if (expon == 0x7FFF)
  449                   f = HUGE;
  450               else {
  451                   expon -= 16383;
  452                   expon -= 31;
  453                   f = (hiMant * Math.pow(2, expon));
  454                   expon -= 32;
  455                   f += (loMant * Math.pow(2, expon));
  456               }
  457           }
  458   
  459           return f;
  460       }
  461   
  462   
  463   
  464   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]