Source code: com/anotherbigidea/flash/sound/MP3Helper.java
1 /****************************************************************
2 * Copyright (c) 2001, David N. Main, All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the
6 * following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * 3. The name of the author may not be used to endorse or
18 * promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ****************************************************************/
34 package com.anotherbigidea.flash.sound;
35
36 import java.io.*;
37 import java.util.*;
38 import com.anotherbigidea.io.*;
39 import com.anotherbigidea.flash.*;
40 import com.anotherbigidea.flash.structs.*;
41 import com.anotherbigidea.flash.interfaces.*;
42 import com.anotherbigidea.flash.writers.*;
43 import com.anotherbigidea.flash.movie.*;
44
45 /**
46 * MP3 Utilities
47 */
48 public class MP3Helper
49 {
50 public static Sound getSoundDefinition( InputStream mp3 ) throws IOException
51 {
52 MP3Frame frame = MP3Frame.readFrame( mp3 );
53
54 int samplesPerFrame = frame.getSamplesPerFrame();
55 int sampleRate = frame.getSampleRate();
56
57 boolean isStereo = frame.isStereo();
58
59 int rate = SWFConstants.SOUND_FREQ_5_5KHZ;
60 if ( sampleRate >= 44000 ) rate = SWFConstants.SOUND_FREQ_44KHZ;
61 else if( sampleRate >= 22000 ) rate = SWFConstants.SOUND_FREQ_22KHZ;
62 else if( sampleRate >= 11000 ) rate = SWFConstants.SOUND_FREQ_11KHZ;
63
64 int sampleCount = 0;
65 ByteArrayOutputStream bout = new ByteArrayOutputStream();
66
67 while( true && frame != null )
68 {
69 //--Write DelaySeek of zero
70 bout.write(0);
71 bout.write(0);
72
73 while( frame != null )
74 {
75 sampleCount += frame.getSamplesPerFrame();
76 frame.write( bout );
77 frame = MP3Frame.readFrame( mp3 );
78 }
79
80 bout.flush();
81 }
82
83 mp3.close();
84
85 byte[] data = bout.toByteArray();
86
87 return new Sound( SWFConstants.SOUND_FORMAT_MP3, rate, true, isStereo, sampleCount, data );
88 }
89
90 /**
91 * Read an MP3 input file.
92 * Write the Sound Stream Header to the SWFTagTypes interface.
93 * Return a list of byte[] - one for each Streaming Sound Block
94 */
95 public static SoundStreamHead streamingBlocks( InputStream mp3, int framesPerSecond, ArrayList blocks )
96 throws IOException
97 {
98 MP3Frame frame = MP3Frame.readFrame( mp3 );
99
100 int samplesPerFrame = frame.getSamplesPerFrame();
101 int sampleRate = frame.getSampleRate();
102 int totalSamples = 0;
103
104 int samplesPerSWFFrame = sampleRate / framesPerSecond;
105
106 boolean isStereo = frame.isStereo();
107
108 int rate = SWFConstants.SOUND_FREQ_5_5KHZ;
109 if ( sampleRate >= 44000 ) rate = SWFConstants.SOUND_FREQ_44KHZ;
110 else if( sampleRate >= 22000 ) rate = SWFConstants.SOUND_FREQ_22KHZ;
111 else if( sampleRate >= 11000 ) rate = SWFConstants.SOUND_FREQ_11KHZ;
112
113 SoundStreamHead head = new SoundStreamHead( rate, true, isStereo, SWFConstants.SOUND_FORMAT_MP3,
114 rate, true, isStereo, samplesPerSWFFrame );
115
116 ByteArrayOutputStream bout = new ByteArrayOutputStream();
117
118 while( frame != null )
119 {
120 //--Write dummy sample count
121 bout.write(0);
122 bout.write(0);
123
124 //--Write DelaySeek of zero
125 bout.write(0);
126 bout.write(0);
127
128 int sampleCount = 0;
129 int targetSampleCount = samplesPerSWFFrame * (blocks.size() + 1);
130
131 while( frame != null && ( totalSamples + sampleCount < targetSampleCount ) )
132 {
133 sampleCount += frame.getSamplesPerFrame();
134 frame.write( bout );
135 frame = MP3Frame.readFrame( mp3 );
136 }
137
138 bout.flush();
139 byte[] bytes = bout.toByteArray();
140 bytes[0] = (byte)(sampleCount & 0xFF);
141 bytes[1] = (byte)(sampleCount >> 8);
142
143 totalSamples += sampleCount;
144
145 blocks.add( bytes );
146 bout.reset();
147 }
148
149 mp3.close();
150
151 double soundLength = ((double)totalSamples) / ((double)sampleRate);
152 int requiredFrames = (int)(soundLength * framesPerSecond);
153
154 System.out.println( "Required=" + requiredFrames + " actual=" + blocks.size() );
155
156 //--Add null blocks to the end to make up the correct number of SWF frames
157 while( blocks.size() < requiredFrames ) blocks.add( null );
158
159 return head;
160 }
161
162 /**
163 * Makes a streaming SWF from an MP3.
164 * args[0] = MP3 in filename
165 * args[1] = SWF out filename
166 */
167 public static void main( String[] args ) throws IOException
168 {
169 FileInputStream mp3 = new FileInputStream( args[0] );
170
171 ArrayList blocks = new ArrayList();
172 SoundStreamHead head = MP3Helper.streamingBlocks( mp3, 30, blocks );
173
174 Movie movie = new Movie();
175 movie.setFrameRate( 30 );
176
177 Frame f = movie.appendFrame();
178 f.setSoundHeader( head );
179
180 for( Iterator i = blocks.iterator(); i.hasNext(); )
181 {
182 byte[] data = (byte[])i.next();
183 f.setSoundData( data );
184 f = movie.appendFrame();
185 }
186
187 movie.write( args[1] );
188 }
189 }