FileDocCategorySizeDatePackage
AIFFMux.javaAPI DocJMF 2.1.1e7666Mon May 12 12:20:58 BST 2003com.sun.media.multiplexer.audio

AIFFMux

public class AIFFMux extends BasicMux

Fields Summary
private Format
format
private AudioFormat
audioFormat
private int
sampleSizeInBits
private double
sampleRate
private int
channels
private int
blockAlign
private int
dataSizeOffset
private int
maxFrames
private int
maxFramesOffset
private String
formType
private String
aiffEncoding
private int
headerSize
private int
dataSize
private static int
AIFCVersion1
private static final String
FormID
private static final String
FormatVersionID
private static final String
CommonID
private static final String
SoundDataID
private static final int
CommonIDSize
Format
bigEndian
Constructors Summary
public AIFFMux()

   // ID for Common Chunk for AIFF

      
	supportedInputs = new Format[1];
	supportedInputs[0] = new AudioFormat(null);
	//				     8000.0,
	//				     33 * 8,
	//				     1);
	supportedOutputs = new ContentDescriptor[1];
	supportedOutputs[0] = new FileTypeDescriptor(FileTypeDescriptor.AIFF);
    
Methods Summary
public java.lang.StringgetName()

	return "AIFF Audio Multiplexer";
    
public javax.media.FormatsetInputFormat(javax.media.Format format, int trackID)


          

	String reason = null;
	
	if (!(format instanceof AudioFormat))
	    return null;
	
	audioFormat = (AudioFormat) format;

	String encodingString = audioFormat.getEncoding();
	sampleSizeInBits = audioFormat.getSampleSizeInBits();
	sampleRate = audioFormat.getSampleRate();
	channels = audioFormat.getChannels();

	blockAlign = channels * sampleSizeInBits / 8;

	if (encodingString.equalsIgnoreCase(AudioFormat.LINEAR)) {

	    if (sampleSizeInBits > 8 &&
		audioFormat.getEndian() == AudioFormat.LITTLE_ENDIAN)
		return null;

	    if (audioFormat.getSigned() == AudioFormat.UNSIGNED)
		return null;

	    if (audioFormat.getEndian() == AudioFormat.NOT_SPECIFIED ||
		audioFormat.getSigned() == AudioFormat.NOT_SPECIFIED)
		format = audioFormat.intersects(bigEndian);

	    // No compression: formType is AIFF
	    formType = "AIFF";
	    aiffEncoding = "NONE";

	} else {
	    // Some compression: formType is AIFC
	    formType = "AIFC";
	    if (encodingString.equalsIgnoreCase(AudioFormat.ULAW))
		aiffEncoding = "ulaw";
	    else if (encodingString.equalsIgnoreCase(AudioFormat.ALAW))
		aiffEncoding = "alaw";
	    else if (encodingString.equalsIgnoreCase(AudioFormat.IMA4)) {
		aiffEncoding = "ima4";
		/**
		 * Each packet contains 64 samples. Each sample is 4 bits/channel.
		 * So 64 samples is 32 bytes/channel.
		 * The 2 in the equation refers two bytes that the Apple's
		 * IMA compressor puts at the front of each packet, which 
		 * are referred to as predictor bytes
		 */
		blockAlign = (32 + 2) * channels;
	    } else if (encodingString.equalsIgnoreCase(AudioFormat.MAC3)) {
		aiffEncoding = encodingString;
		// 2 bytes represent 6 samples
		blockAlign = 2;
	    } else if (encodingString.equalsIgnoreCase(AudioFormat.MAC6)) {
		aiffEncoding = encodingString;
		// 1 byte represent 6 samples
		blockAlign = 1;
		// TODO: gsm
		// 	    } else if (encodingString.equalsIgnoreCase(AudioFormat.GSM)) {
		// 		aiffEncoding = "???";
		// 		/**
		// 		 * Each frame that consists of 160 speech samples
		// 		 * requires 33 bytes
		// 		 */
		// 		blockAlign = 33;
	    } else {
		reason = "Cannot handle encoding " + encodingString;
	    }
	}
	if (reason == null) {
	    inputs[0] = format;
	    return format;
	} else
	    return null;
    
public intsetNumTracks(int nTracks)

	if (nTracks != 1)
	    return 1;
	else
	    return super.setNumTracks(nTracks);
    
protected voidwriteFooter()

	byte [] dummy = new byte[] { 0 };
	
	dataSize = filePointer - headerSize;
	
	if ((filePointer & 1) != 0) {
	    // add a padding byte
	    write(dummy, 0, 1);
	}

	bufClear();
	seek(4);
	bufWriteInt(fileSize);
	bufFlush();

	bufClear();
	seek(maxFramesOffset);
	maxFrames = dataSize / blockAlign;
	//	System.out.println("maxFrames is " + maxFrames);
	bufWriteInt(maxFrames);
	bufFlush();
	
	bufClear();
	seek(dataSizeOffset);
	bufWriteInt(dataSize + 8); // 8 is for offset and blockSize
	bufFlush();
    
protected voidwriteHeader()

	bufClear();
	bufWriteBytes(FormID);
	bufWriteInt(0); // This is filled in later when filesize is known
	bufWriteBytes(formType);

	if (formType.equals("AIFC")) {
	    bufWriteBytes(FormatVersionID);
	    bufWriteInt(4);
	    bufWriteInt(AIFCVersion1);
	}

	bufWriteBytes(CommonID);
	int commonIDSize = CommonIDSize;
	if (formType.equals("AIFC")) {
	    commonIDSize += 8; // for 2 4cc strings representing
	                       // Compression type and name.
	}

	bufWriteInt(commonIDSize);

	bufWriteShort((short) channels);
	maxFramesOffset = (int) filePointer;
	bufWriteInt(maxFrames);   // To be filled in later
	bufWriteShort((short) sampleSizeInBits);

	// Write sample rate as IEEE extended.
	// For now write the integer portion of sampleRate
        // TODO: Verify this calculation

	int exponent = 16398;
        double highMantissa;

	highMantissa = sampleRate;
	while (highMantissa < 44000) {
	    highMantissa *= 2;
	    exponent--;
	}
 	bufWriteShort((short) exponent);  // Exponent
	bufWriteInt( ((int) highMantissa) << 16);
 	bufWriteInt(0); // low Mantissa

	// Note: Since we use 4cc codes, Compression Type
	// and Compression Name take up 8 bytes
	if (formType.equals("AIFC")) {
	    bufWriteBytes(aiffEncoding); // Compression Type
	    bufWriteBytes(aiffEncoding); // Compression Name
	}

	bufWriteBytes(SoundDataID);
	dataSizeOffset = filePointer;
	bufWriteInt(0); // This is filled in later when datasize is known
	// Both offset and blocksize set to 0 upon recommendation in
	// "Sound Manager" Chapter in "Inside Macintosh Sound:, page 2-87
	bufWriteInt(0); // offset
	bufWriteInt(0); // blocksize
	bufFlush();
	headerSize = filePointer;
	//	fileSize = 
	//System.out.println("fileSize size after header is done: " + fileSize);