001: /*
002: * $Id: SoundStreamBuilder.java,v 1.2 2002/02/15 23:44:28 skavish Exp $
003: *
004: * ===========================================================================
005: *
006: */
007:
008: package org.openlaszlo.iv.flash.api.sound;
009:
010: import org.openlaszlo.iv.flash.parser.*;
011: import org.openlaszlo.iv.flash.util.*;
012: import org.openlaszlo.iv.flash.api.*;
013: import org.openlaszlo.iv.flash.url.*;
014:
015: import java.io.*;
016:
017: public class SoundStreamBuilder {
018: /** Holds the MP3 samples are read from */
019:
020: private MP3Helper mp3;
021:
022: /** Calculated ideal samples per block: sampleRate / frameRate */
023:
024: private int idealSamplesPerBlock = 0;
025:
026: /** Frame rate of containing file */
027:
028: private int frameRate = 0;
029:
030: /** Total samples completed so far */
031:
032: private int samplesCompleted = 0;
033:
034: /** Total sound blocks completed so far */
035:
036: private int blocksCompleted = 0;
037:
038: /** Saves us the trouble of mark and reset */
039:
040: private byte[] firstFrameCache = null;
041:
042: /** Data size (skavish 05/03/2001) */
043: private int dataSize = 0;
044:
045: /** Create SoundStreamBuilder from url and frame rate */
046:
047: public static SoundStreamBuilder newSoundStreamBuilder(IVUrl url,
048: int rate) throws IOException, IVException {
049: return newSoundStreamBuilder(Util.readUrl(url), rate);
050: }
051:
052: /** Create a SoundStreamBuilder for the provided buffer and frame rate */
053:
054: public static SoundStreamBuilder newSoundStreamBuilder(
055: FlashBuffer fob, int rate) throws IOException, IVException {
056: SoundStreamBuilder o = new SoundStreamBuilder();
057:
058: o.mp3 = new MP3Helper(fob);
059: o.frameRate = rate >> 8;
060: o.dataSize = fob.getSize();
061:
062: return o;
063: }
064:
065: /** Get the SoundStreamHead object for this sound */
066:
067: public SoundStreamHead getSoundStreamHead() throws IOException,
068: IVException {
069: SoundStreamHead o = new SoundStreamHead();
070:
071: firstFrameCache = mp3.nextFrame();
072:
073: o.streamCompression = Sound.COMPRESS_MP3;
074:
075: // Set the rate from the MP3's frequency
076:
077: switch (mp3.getFrequency()) {
078: case 11025:
079: o.playbackRate = o.streamRate = Sound.RATE_11;
080: break;
081: case 22050:
082: o.playbackRate = o.streamRate = Sound.RATE_22;
083: break;
084: case 44100:
085: o.playbackRate = o.streamRate = Sound.RATE_44;
086: break;
087: }
088:
089: o.isPlayback16bit = o.isStream16bit = true;
090:
091: o.isPlaybackStereo = o.isStreamStereo = mp3.getStereo();
092:
093: // This can only be set once a block has been read
094:
095: o.streamSampleCount = idealSamplesPerBlock = (mp3
096: .getFrequency() / frameRate);
097:
098: return o;
099: }
100:
101: /** Get the next StreamSoundBlock for this sound */
102:
103: public SoundStreamBlock getNextSoundStreamBlock()
104: throws IOException, IVException {
105: byte[] buffer;
106: int sampleCount = 0;
107:
108: ByteArrayOutputStream out = new ByteArrayOutputStream();
109:
110: // Increment the blocks completed upfront, so the division in the
111: // while loop works nicely.
112:
113: blocksCompleted++;
114:
115: // Add frames to the ouput buffer while the average samples per block
116: // completed does not exceed the ideal.
117:
118: while ((samplesCompleted / blocksCompleted) < idealSamplesPerBlock) {
119: // Get the next frame ( unless one is already cached )
120:
121: if (firstFrameCache == null) {
122: buffer = mp3.nextFrame();
123: } else {
124: buffer = firstFrameCache;
125:
126: firstFrameCache = null;
127: }
128:
129: // End loop prematurely if there are no more frames
130:
131: if (buffer == null) {
132: break;
133: }
134:
135: // Write the frame to the output buffer
136:
137: out.write(buffer, 0, buffer.length);
138:
139: samplesCompleted += mp3.getSamplesPerFrame();
140: sampleCount += mp3.getSamplesPerFrame();
141: }
142:
143: // If no samples are in the buffer at this point, there must be no more sound
144:
145: if (sampleCount == 0) {
146: return null;
147: }
148:
149: // If all has gone well, build the new block and return it
150:
151: MP3SoundStreamBlock o = new MP3SoundStreamBlock();
152:
153: o.sampleCount = sampleCount;
154: o.delaySeek = 0;
155:
156: o.data = new DataMarker(out.toByteArray(), 0, out.size());
157:
158: return o;
159: }
160:
161: /**
162: * Return data size
163: */
164: public int getSize() {
165: return dataSize;
166: }
167:
168: }
|