📄 fssoundconstructor.java
字号:
/*
* FSSoundConstructor.java
* Transform Utilities
*
* Copyright (c) 2001-2006 Flagstone Software Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Flagstone Software Ltd. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.flagstone.transform.util;
import java.io.*;
import java.util.zip.*;
import com.flagstone.transform.*;
/**
* The FSSoundConstructor class is used to generate the objects used to define and
* control the sounds that are played in a Flash movie. The FSSoundConstructor can
* be used to generate definitions for:
*
* <ul>
* <li>Event sounds that are played in response to a particular event such as a button
* being clicked.</li>
* <li>Streaming sound that is played as movie is being displayed.</li>
* </ul>
*
* The FSSoundConstructor contains constructors and methods that allow sound data to
* be loaded from an external file simplifying the process of adding sound to a movie.
* The FSSoundConstructor currently supports uncompressed PCM format (with either
* big-endian or little-endian byte ordering) and MP3 format files.
*
* Once loaded, the PCM sound data should be compressed to ADPCM format as the relatively
* large sizes make PCM coded sounds generally unsuitable for inclusion in a Flash movie.
* ADPCM is a compressed format and Flash supports a modified ADPCM algorithm with
* compressed samples taking 2, 3, 4 or 5 bits. This results in much smaller file sizes
* when a movie is encoded. Code, developed at Centre for Mathematics and Computer Science,
* Amsterdam, The Netherlands, is available on Flagstone's web site to perform the
* ADPCM compression.
*
* For sounds containing more than one channel, the sound levels for each channel are
* interleaved for each sample. For example a stereo sound the order of the samples and
* channels levels are:
*
*<pre>
* Sample 0 1 2
* +---+---+ +---+---+ +---+---+
* | 1 | 2 | | 1 | 2 | | 1 | 2 | ....
* +---+---+ +---+---+ +---+---+
*</pre>
*
* NOTE: The byte order for the PCM data in WAVE sound files may vary according to the
* platform on which the sound file was created. The FSSoundConstructor currently only
* supports WAVE files with little-endian byte order.
*
* <b>Examples</b>
*
* The following code samples illustrate how to use the FSSoundConstructor class to add
* sounds to a Flash file.
*
* 1. Playing an uncompressed WAVE file.\n
*
*<pre>
* int soundId = movie.newIdentifier();
*
* // Generate an FSDefineSound object using the attributes defined in the wave file.
* // An FSSound object is used to instruct the Flash Player to start playing a sound.
*
* FSSoundConstructor soundGenerator = new FSSoundGenerator("sound.wav");
*
* movie.add(soundGenerator.defineSound(soundId));
* movie.add(new FSSound(soundId, FSSound.Start));
*</pre>
*
* 2. Streaming Sounds.\n
*
* Larger sound files may be streamed to the Flash Player - splitting the sound data into a
* sequence of blocks which is synchronised with the frames as they are displayed. Typically
* block of sound data is generated for each frame displayed.
*
*<pre>
* int framesPerSecond = 12;
*
* FSSoundConstructor soundGenerator = new FSSoundGenerator("soundTrack.wav");
*
* // Calculate the number of decoded sound samples played for each frame
*
* int samplesPerBlock = soundGenerator.getSampleRate() / framesPerSecond;
* int numberOfBlocks = soundGenerator.getSamplesPerChannel() / samplesPerBlock;
*
* // An FSSoundStreamHeader2 object defines the attributes of the streaming sound.
*
* movie.add(soundGenerator.streamHeader(samplesPerBlock));
*
* // Add a streaming block for each frame so the sound is played as each frame is displayed.
*
* for (int i=0; i<numberOfBlocks; i++)
* {
* movie.add(soundGenerator.streamBlock(i, samplesPerBlock));
* movie.add(new FSShowFrame());
* }
* </pre>
*
*/
public class FSSoundConstructor
{
private static final int[] riffSignature = { 82, 73, 70, 70 };
private static final int[] wavSignature = { 87, 65, 86, 69 };
private static final int FMT = 0x20746d66;
private static final int DATA = 0x61746164;
private static final int MPEG1 = 3;
private static final int frameSizeMP3[] = { 576, 576, 576, 1152 };
private static final int channelCount[] = { 2, 2, 2, 1 };
private static final int bitRates[][] =
{
{ -1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, // MPEG 2.5
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Reserved
{ -1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, // MPEG 2.0
{ -1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, // MPEG 1.0
};
private static final int samplingRates[][] =
{
{ 11025, -1, -1, -1 },
{ -1, -1, -1, -1 },
{ 22050, -1, -1, -1 },
{ 44100, -1, -1, -1 }
};
private int format = FSSound.PCM;
private int numberOfChannels = 0;
private int samplesPerChannel = 0;
private int sampleRate = 0;
private int sampleSize = 0;
private byte[] sound = null;
private int[][] frameTable = null;
private int samplesPerFrame = 0;
/**
* Creates a new uninitialized FSSoundConstructor object. Use setSound to
* provide the content.
*/
public FSSoundConstructor()
{
}
/**
* Creates a new FSSoundConstructor object initialised with the contents of
* the specified sound file.
*
* @param fileName the name of the file containing the sound.
*
* @throws FileNotFoundException - if the file does not exist, is a
* directory rather than a regular file, or for some other reason cannot be
* opened for reading.
*
* @throws IOException - if an I/O error occurs while reading the file.
*
* @throws DataFormatException if the file contains a sound format not
* supported by the FSSoundConstructor.
*/
public FSSoundConstructor(String fileName) throws IOException, DataFormatException
{
setSound(fileName);
}
/**
* Accessor method returning the format for the encoded sound data.
*
* @return the format of the encoded sound, either FSSound.NATIVE_PCM (platform
* dependent byte-order), FSSound.PCM (PCM little-endian byte-order), FSSound.ADPCM or
* FSSound.MP3.
*/
public int getFormat()
{
return format;
}
/**
* Accessor method returning the number of channels in the sound.
*
* @return the number of sound channels, typically this will be 1 (mono) or 2 (stereo).
*/
public int getNumberOfChannels()
{
return numberOfChannels;
}
/**
* Accessor method returning the number of samples in each channel.
*
* @return the number of samples in each channel.
*/
public int getSamplesPerChannel()
{
return samplesPerChannel;
}
/**
* Accessor method returning the rate at which the sound will be played. The playback
* rate should be a value supported by the Flash Player 5512, 11025, 22050 or 44100
* Hertz. Although the sound rate may be changed using the changeSampleRate method
* the FSSoundConstructor class does not support the filtering required to change
* the sample rate from an arbitrary value to one of the rates supported by the Flash
* Player.
*
* MP3 formatted sounds have playback rates of 11025, 22050 or 44100.
*
* @return the playback rate for the sound, either 5512, 11025, 22050 or 44100 Hertz.
*/
public int getSampleRate()
{
return sampleRate;
}
/**
* Accessor method returning the number of bytes for each decoded sound sample.
*
* @return the number of bytes in each sample.
*/
public int getSampleSize()
{
return sampleSize;
}
/**
* Accessor method returning a copy of the encoded sound data.
*
* @return encoded sound data.
*/
public byte[] getSound()
{
byte[] bytes = new byte[sound.length];
System.arraycopy(sound, 0, bytes, 0, sound.length);
return bytes;
}
/**
* Initialises the FSSoundConstructor with the contents of the specified file.
*
* @param filename the name of a file containing encoded sound data.
*
* @throws FileNotFoundException - if the file does not exist, is a directory
* rather than a regular file, or for some other reason cannot be opened for
* reading.
*
* @throws IOException - if an I/O error occurs while reading the file.
*
* @throws DataFormatException if the file contains a sound format not
* supported by the FSSoundConstructor.
*/
public void setSound(String filename) throws IOException, DataFormatException
{
if (filename.toLowerCase().endsWith(".mp3"))
decodeMP3(dataFromFile(filename));
else if (filename.toLowerCase().endsWith(".wav"))
decodeWAV(filename);
}
/**
* Initialises the FSSoundConstructor with the sound data and set of
* parameters. This method can be used to update the sound following
* processing for example to convert a stereo sound to mono to reduce the
* size of the encoded data.
*
* @param format the format of the encoded sound either FSSound.PCM,
* FSSound.ADPCM or FSSound.MP3.
*
* @param channelCount the number of sound channels, 1 = mono, 2 = stereo.
* @param sampleCount the number of samples in each channel.
*
* @param sampleRate the rate at which the sound is played in kiloHertz.
* Flash supports 5512, 11025, 22050 or 44100.
*
* @param sampleSize the number of bytes for each uncompressed sound sample,
* either 1 or 2.
*
* @param bytes an array of sound samples encoding in the specified format.
*/
public void setSound(int format, int channelCount, int sampleCount, int sampleRate, int sampleSize, byte[] bytes)
{
this.format = format;
this.numberOfChannels = channelCount;
this.samplesPerChannel = sampleCount;
this.sampleRate = sampleRate;
this.sampleSize = sampleSize;
sound = new byte[bytes.length];
System.arraycopy(bytes, 0, sound, 0, bytes.length);
if (format == FSSound.MP3)
initFrameTable(bytes);
}
/**
* Generates an FSDefineSound object from the sound data. The FSDefineSound object is
* created using the encoded sound data so if the sound was decoded in order to change
* the number of channels, sample rate or sample size it must be re-encoded.
*
* @param anIdentifier a unique identifier for the FSDefineSound object.
*
* @return an FSDefineSound object initialised with the encoded sound data.
*/
public FSDefineSound defineSound(int anIdentifier)
{
byte[] bytes = null;
switch (format)
{
case FSSound.PCM:
case FSSound.ADPCM:
bytes = new byte[sound.length];
System.arraycopy(sound, 0, bytes, 0, sound.length);
break;
case FSSound.MP3:
bytes = new byte[2+sound.length];
bytes[0] = 0;
bytes[1] = 0;
System.arraycopy(sound, 0, bytes, 2, sound.length);
break;
}
return new FSDefineSound(anIdentifier, format, sampleRate, numberOfChannels, sampleSize, samplesPerChannel, bytes);
}
/**
* Generates an FSSoundStreamHead2 object to stream the sound data to the Flash Player.
*
* @param samplesPerBlock the number of samples in each subsequent FSSoundStreamBlock
* object.
*
* @return an FSDefineSound object initialised with the encoded sound data.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -