1 /* 2 * Copyright (c) 1999, 2016, 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.io.DataInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 32 import javax.sound.sampled.AudioFileFormat; 33 import javax.sound.sampled.AudioFileFormat.Type; 34 import javax.sound.sampled.AudioFormat; 35 import javax.sound.sampled.AudioSystem; 36 import javax.sound.sampled.UnsupportedAudioFileException; 37 38 /** 39 * AIFF file reader and writer. 40 * 41 * @author Kara Kytle 42 * @author Jan Borgersen 43 * @author Florian Bomers 44 */ 45 public final class AiffFileReader extends SunFileReader { 46 47 @Override 48 StandardFileFormat getAudioFileFormatImpl(final InputStream stream) 49 throws UnsupportedAudioFileException, IOException { 50 DataInputStream dis = new DataInputStream(stream); 51 52 AudioFormat format = null; 53 54 // Read the magic number 55 int magic = dis.readInt(); 56 57 // $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037 58 if (magic != AiffFileFormat.AIFF_MAGIC) { 59 // not AIFF, throw exception 60 throw new UnsupportedAudioFileException("not an AIFF file"); 61 } 62 63 long /* unsigned 32bit */ frameLength = 0; 64 int length = dis.readInt(); 65 int iffType = dis.readInt(); 66 67 final long totallength; 68 if(length <= 0 ) { 69 length = AudioSystem.NOT_SPECIFIED; 70 totallength = AudioSystem.NOT_SPECIFIED; 71 } else { 72 totallength = length + 8; 73 } 74 75 // Is this an AIFC or just plain AIFF file. 76 boolean aifc = false; 77 // $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037 78 if (iffType == AiffFileFormat.AIFC_MAGIC) { 79 aifc = true; 80 } 81 82 // Loop through the AIFF chunks until 83 // we get to the SSND chunk. 84 boolean ssndFound = false; 85 while (!ssndFound) { 86 // Read the chunk name 87 int chunkName = dis.readInt(); 88 int chunkLen = dis.readInt(); 89 90 int chunkRead = 0; 91 92 // Switch on the chunk name. 93 switch (chunkName) { 94 case AiffFileFormat.FVER_MAGIC: 95 // Ignore format version for now. 96 break; 97 98 case AiffFileFormat.COMM_MAGIC: 99 // AIFF vs. AIFC 100 // $$fb: fix for 4399551: Repost of bug candidate: cannot replay aif file (Review ID: 108108) 101 if ((!aifc && chunkLen < 18) || (aifc && chunkLen < 22)) { 102 throw new UnsupportedAudioFileException("Invalid AIFF/COMM chunksize"); 103 } 104 // Read header info. 105 int channels = dis.readUnsignedShort(); 106 if (channels <= 0) { 107 throw new UnsupportedAudioFileException("Invalid number of channels"); 108 } 109 frameLength = dis.readInt() & 0xffffffffL; // numSampleFrames 110 111 int sampleSizeInBits = dis.readUnsignedShort(); 112 if (sampleSizeInBits < 1 || sampleSizeInBits > 32) { 113 throw new UnsupportedAudioFileException("Invalid AIFF/COMM sampleSize"); 114 } 115 float sampleRate = (float) read_ieee_extended(dis); 116 chunkRead += (2 + 4 + 2 + 10); 117 118 // If this is not AIFC then we assume it's 119 // a linearly encoded file. 120 AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED; 121 122 if (aifc) { 123 int enc = dis.readInt(); chunkRead += 4; 124 switch (enc) { 125 case AiffFileFormat.AIFC_PCM: 126 encoding = AudioFormat.Encoding.PCM_SIGNED; 127 break; 128 case AiffFileFormat.AIFC_ULAW: 129 encoding = AudioFormat.Encoding.ULAW; 130 sampleSizeInBits = 8; // Java Sound convention 131 break; 132 default: 133 throw new UnsupportedAudioFileException("Invalid AIFF encoding"); 134 } 135 } 136 int frameSize = calculatePCMFrameSize(sampleSizeInBits, channels); 137 //$fb what's that ?? 138 //if (sampleSizeInBits == 8) { 139 // encoding = AudioFormat.Encoding.PCM_SIGNED; 140 //} 141 format = new AudioFormat(encoding, sampleRate, 142 sampleSizeInBits, channels, 143 frameSize, sampleRate, true); 144 break; 145 case AiffFileFormat.SSND_MAGIC: 146 // Data chunk. 147 int dataOffset = dis.readInt(); // for now unused in javasound 148 int blocksize = dis.readInt(); // for now unused in javasound 149 chunkRead += 8; 150 ssndFound = true; 151 break; 152 } // switch 153 // skip the remainder of this chunk 154 if (!ssndFound) { 155 int toSkip = chunkLen - chunkRead; 156 if (toSkip > 0) { 157 dis.skipBytes(toSkip); 158 } 159 } 160 } // while 161 162 if (format == null) { 163 throw new UnsupportedAudioFileException("missing COMM chunk"); 164 } 165 Type type = aifc ? Type.AIFC : Type.AIFF; 166 167 return new AiffFileFormat(type, totallength, format, frameLength); 168 } 169 170 // HELPER METHODS 171 /** 172 * read_ieee_extended 173 * Extended precision IEEE floating-point conversion routine. 174 * @argument DataInputStream 175 * @return double 176 * @exception IOException 177 */ 178 private double read_ieee_extended(DataInputStream dis) throws IOException { 179 180 double f = 0; 181 int expon = 0; 182 long hiMant = 0, loMant = 0; 183 long t1, t2; 184 double HUGE = 3.40282346638528860e+38; 185 186 187 expon = dis.readUnsignedShort(); 188 189 t1 = (long)dis.readUnsignedShort(); 190 t2 = (long)dis.readUnsignedShort(); 191 hiMant = t1 << 16 | t2; 192 193 t1 = (long)dis.readUnsignedShort(); 194 t2 = (long)dis.readUnsignedShort(); 195 loMant = t1 << 16 | t2; 196 197 if (expon == 0 && hiMant == 0 && loMant == 0) { 198 f = 0; 199 } else { 200 if (expon == 0x7FFF) 201 f = HUGE; 202 else { 203 expon -= 16383; 204 expon -= 31; 205 f = (hiMant * Math.pow(2, expon)); 206 expon -= 32; 207 f += (loMant * Math.pow(2, expon)); 208 } 209 } 210 211 return f; 212 } 213 }