Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/anotherbigidea/flash/sound/ADPCMHelper.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 javax.sound.sampled.*;
44  import com.anotherbigidea.flash.movie.*;
45  
46  /**
47   * ADPCM Utilities
48   */
49  public class ADPCMHelper
50  {
51      public class ADPCMPacket
52      {
53          public int initialLeftSample  = 0;
54          public int initialLeftIndex   = 0;
55          public int initialRightSample = 0;
56          public int initialRightIndex  = 0;
57          public int[] leftData;
58          public int[] rightData;
59          public int sampleCount;
60      }
61      
62      protected AudioInputStream audioIn;
63      protected boolean isStereo;
64      protected boolean is16Bit;
65      protected int sampleRate;
66      protected int rate;
67      protected int samplesPerFrame;
68      protected boolean isSigned;
69      
70      protected int sampleCount = 0;
71      
72      protected ADPCMEncodeStream leftEncoder;
73      protected ADPCMEncodeStream rightEncoder;
74      protected ADPCMPacket currentPacket;
75      
76      public ADPCMHelper( InputStream audioFile, int framesPerSecond )
77          throws IOException, UnsupportedAudioFileException
78      {
79          audioIn = AudioSystem.getAudioInputStream( new BufferedInputStream( audioFile ) );
80          
81          AudioFormat format = audioIn.getFormat();
82          int frameSize    = format.getFrameSize();
83          isStereo = format.getChannels() == 2;
84          is16Bit  = format.getSampleSizeInBits() > 8;
85          sampleRate = (int)format.getSampleRate();
86          
87          isSigned = format.getEncoding() == AudioFormat.Encoding.PCM_SIGNED;
88          
89          //System.out.println( format + " FrameSize=" + frameSize );
90          
91          if     ( sampleRate >= 44000 ) sampleRate = 44000;
92          else if( sampleRate >= 22000 ) sampleRate = 22000;
93          else if( sampleRate >= 11000 ) sampleRate = 11000;
94          else sampleRate = 5500;
95  
96          rate = SWFConstants.SOUND_FREQ_5_5KHZ;        
97          if     ( sampleRate == 44000 ) rate = SWFConstants.SOUND_FREQ_44KHZ;
98          else if( sampleRate == 22000 ) rate = SWFConstants.SOUND_FREQ_22KHZ;
99          else if( sampleRate == 11000 ) rate = SWFConstants.SOUND_FREQ_11KHZ;        
100         
101         samplesPerFrame = sampleRate / framesPerSecond;
102         
103         FramedInputStream frameIn = new FramedInputStream( audioIn, frameSize );
104         
105         leftEncoder = new ADPCMEncodeStream( frameIn, is16Bit, isSigned );
106         
107         if( isStereo )
108         {
109             rightEncoder = new ADPCMEncodeStream( frameIn, is16Bit, isSigned );
110         }
111     }
112     
113     public Sound getSoundDefinition() throws IOException
114     {
115         ByteArrayOutputStream bout = new ByteArrayOutputStream();
116         OutStream out = new OutStream( bout );
117         sampleCount = 0;
118         boolean first = true;
119         
120         for( ADPCMPacket packet = readPacket( ADPCMConstants.PACKET_SIZE );
121              packet != null;
122              packet = readPacket( ADPCMConstants.PACKET_SIZE ) )
123         {
124             sampleCount += packet.sampleCount + 1;
125             writePacket( packet, out, first );
126             first = false;
127             
128             //System.out.println( "Packet size = " + packet.leftData.length );
129         }
130         
131         out.flush();
132         byte[] soundData = bout.toByteArray();
133         return new Sound( SWFConstants.SOUND_FORMAT_ADPCM, rate, true, isStereo, sampleCount, soundData );
134     }
135     
136     /**
137      * @return null if no more packets are available
138      */
139     public ADPCMPacket readPacket( int packetSize ) throws IOException
140     {
141         ADPCMPacket packet = new ADPCMPacket();
142         packet.initialLeftSample = leftEncoder.getFirstPacketSample();
143         if( leftEncoder.isDone() ) return null;
144 
145         int count = 0;
146         
147         if( isStereo )
148         {
149             packet.initialRightSample = rightEncoder.getFirstPacketSample();
150         }
151         
152         packet.initialLeftIndex = leftEncoder.setIndex( packet.initialLeftSample );
153         
154         if( isStereo )
155         {
156             packet.initialRightIndex  = rightEncoder.setIndex( packet.initialRightSample );
157         }
158         
159         packet.leftData = new int[ packetSize-1 ];;
160         if( isStereo ) packet.rightData = new int[ packetSize-1 ];;
161         
162         for( int i = 0; i < packetSize-1; i++ )
163         {
164             packet.leftData[i] = leftEncoder.getDelta();
165 
166             if( ! leftEncoder.isDone() ) count++;
167             
168             if( isStereo ) packet.rightData[i] = rightEncoder.getDelta();
169         }
170         
171         packet.sampleCount = count;
172         return packet;
173     }
174     
175     /**
176      * Streaming block
177      * @return null if no more blocks
178      */
179     public byte[] getBlockData( boolean firstBlock ) throws IOException
180     {
181         ByteArrayOutputStream bout = new ByteArrayOutputStream();
182         OutStream os = new OutStream( bout );
183         
184         currentPacket = readPacket( samplesPerFrame );
185         if( currentPacket == null ) return null;
186         
187         writePacket( currentPacket, os, true );        
188         os.flushBits();
189         
190         return bout.toByteArray();
191     }
192 
193     public void writePacket( ADPCMPacket packet, OutStream out, boolean includeBitCount ) throws IOException 
194     {
195         if( packet == null ) return;
196 
197         int sample = packet.initialLeftSample;
198         
199         if( includeBitCount ) out.writeUBits( 2, 2 );
200         out.writeUBits( 16, sample );
201         out.writeUBits( 6, packet.initialLeftIndex );
202                
203         if( isStereo )
204         {
205             sample = packet.initialRightSample;
206         
207             out.writeUBits( 16, sample );
208             out.writeUBits( 6, packet.initialRightIndex );
209         }
210         
211         for( int i = 0; i < packet.sampleCount; i++ )
212         {
213             out.writeUBits( 4, packet.leftData[i] );
214             if( isStereo ) out.writeUBits( 4, packet.rightData[i] );            
215         }
216     }
217     
218     public SoundStreamHead getStreamHeader()
219     {
220         return new SoundStreamHead( rate, true, isStereo,
221                                     SWFConstants.SOUND_FORMAT_ADPCM,
222                                     rate, true, isStereo, 
223                                     samplesPerFrame );
224     }
225     
226     /**
227      * InputStream wrapper that ensures AudioInputStream is read on a frame-by-frame basis
228      */
229     public static class FramedInputStream extends InputStream 
230     {
231         protected InputStream in;
232         protected byte[] frameData;
233         protected int dataPtr;
234         protected int frameSize;
235         protected boolean done = false;
236         
237         public FramedInputStream( InputStream in, int frameSize )
238         {
239             this.in = in;
240             this.frameSize  = frameSize;
241             frameData = new byte[ frameSize ];
242             dataPtr = frameSize;
243         }
244         
245         public int read() throws IOException
246         {
247             if( dataPtr < frameData.length )
248             {
249                 int val = frameData[dataPtr++];
250                 if( val < 0 ) val = val + 0x100;
251                 return val;
252             }
253             
254             if( done ) return -1;
255             
256             dataPtr = 0;
257             int read = 0;
258             
259             while( dataPtr < frameSize && (read = in.read( frameData, dataPtr, frameSize-dataPtr)) >= 0 )
260             {
261                 dataPtr += read;
262             }
263             
264             if( dataPtr == 0 )
265             {
266                 done = true;
267                 return -1;
268             }
269             
270             while( dataPtr < frameData.length ) frameData[dataPtr++] = 0;
271             dataPtr = 0;
272             
273             return read();
274         }
275     }
276     
277  
278     /**
279      * Makes a non-streaming SWF from a Java Sound compatible audio file.
280      * args[0] = audio in filename
281      * args[1] = SWF out filename
282      */
283     public static void main( String[] args ) throws Exception
284     {
285         InputStream audioFile = new FileInputStream( args[0] );
286         
287         Movie movie = new Movie();
288         movie.setFrameRate(30);
289         ADPCMHelper helper = new ADPCMHelper( audioFile, 30 );
290                           
291         Frame frame = movie.appendFrame();
292         Sound sound = helper.getSoundDefinition();
293         int frames = frame.startSound( sound, 30 );
294         
295         while( frames-- > 0 ) frame = movie.appendFrame();
296         frame.stop();        
297         
298         audioFile.close();
299         
300         movie.write( args[1] );
301     }    
302     
303     
304     /**
305      * Makes a streaming SWF from a Java Sound compatible audio file.
306      * args[0] = audio in filename
307      * args[1] = SWF out filename
308      */
309     public static void main2( String[] args ) throws Exception
310     {
311         InputStream audioFile     = new FileInputStream( args[0] );
312         SWFWriter       swfwriter = new SWFWriter( args[1] );
313         
314         SWFTagTypes tags = new TagWriter( swfwriter );
315         
316         tags.header( 5, -1, 200, 200, 12, -1 );
317         tags.tagSetBackgroundColor( new Color(255,255,255));
318         
319         ADPCMHelper helper = new ADPCMHelper( audioFile, 12 );
320                           
321         SoundStreamHead header = helper.getStreamHeader();
322         
323         header.write( tags );
324 
325         byte[] block = helper.getBlockData( true );
326         
327         while( block != null )
328         {
329             tags.tagSoundStreamBlock( block );
330             tags.tagShowFrame();           
331             
332             block = helper.getBlockData( false );
333         }
334         
335         SWFActions acts = tags.tagDoAction();
336         acts.start(0);
337         acts.stop();
338         acts.end();
339         acts.done();
340         
341         tags.tagShowFrame();
342         tags.tagEnd();
343         
344         audioFile.close();
345     }
346 }