1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* $Id$ */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "outputblock.h"
26 #include "sound.h"
27 #include "soundstream.h"
28 #include "character.h"
29 #include "method.h"
30 #include "input.h"
31 #include "libming.h"
32 #include "mp3.h"
33
34 struct SWFSound_s
35 {
36 struct SWFCharacter_s character;
37
38 byte flags;
39 int seekSamples;
40 byte freeInput;
41
42 SWFInput input;
43 struct SWFSoundStream_s *soundStream;
44 };
45
46
47 void
48 writeSWFSoundWithSoundStreamToMethod(SWFSoundStream stream,
49 SWFByteOutputMethod method, void *data);
50
51 static int
soundDataSize(SWFSound sound)52 soundDataSize(SWFSound sound)
53 {
54 if ((sound->flags&SWF_SOUND_COMPRESSION) == SWF_SOUND_NOT_COMPRESSED ||
55 (sound->flags&SWF_SOUND_COMPRESSION) == SWF_SOUND_NOT_COMPRESSED_LE)
56 {
57 int sampleCount = SWFInput_length(sound->input);
58
59 if ((sound->flags & SWF_SOUND_BITS) == SWF_SOUND_16BITS)
60 sampleCount /= 2;
61
62 if ((sound->flags & SWF_SOUND_CHANNELS) == SWF_SOUND_STEREO)
63 sampleCount /= 2;
64
65 return sampleCount;
66 }
67 else if ((sound->flags&SWF_SOUND_COMPRESSION) == SWF_SOUND_ADPCM_COMPRESSED)
68 {
69 int filesize, channels, nbits;
70 int bitsize, blocksize, n, res, m;
71
72 SWF_assert((sound->flags & SWF_SOUND_BITS) == SWF_SOUND_16BITS);
73
74 filesize = SWFInput_length(sound->input);
75
76 if ((sound->flags&SWF_SOUND_CHANNELS) == SWF_SOUND_MONO)
77 channels = 1;
78 else if ((sound->flags & SWF_SOUND_CHANNELS) == SWF_SOUND_STEREO)
79 channels = 2;
80 else
81 channels = 1; /* ? */
82
83 nbits = 4; /* XXX - testing.. */
84
85 /*
86 * Estimation of the sample count in ADPCM data from file size of the data.
87 * This is an approximate calculation.
88 */
89 bitsize = 8 * filesize - (2 + (8 - 1));
90 /* 2: header, (8 - 1): possible padding */
91 blocksize = ((16 + 6) + nbits * 4095) * channels;
92 n = bitsize / blocksize;
93 res = bitsize % blocksize;
94 m = (res - (16 + 6) * channels) / (nbits * channels);
95 return 4096 * n + m;
96 }
97 else if ((sound->flags&SWF_SOUND_COMPRESSION) == SWF_SOUND_MP3_COMPRESSED)
98 {
99 int pos = SWFInput_tell(sound->input);
100 int samples = -1;
101 getMP3Samples(sound->input, sound->flags, &samples);
102 SWFInput_seek(sound->input, pos, SEEK_SET);
103 return samples;
104 }
105 else
106 {
107 SWF_warn("SWFSound: can't determine sampleCount\n");
108 return 0;
109 }
110 }
111
112
113 void
writeSWFSoundToStream(SWFBlock block,SWFByteOutputMethod method,void * data)114 writeSWFSoundToStream(SWFBlock block, SWFByteOutputMethod method, void *data)
115 {
116 int l, i;
117 SWFSound sound = (SWFSound)block;
118
119 methodWriteUInt16(CHARACTERID(sound), method, data);
120 method(sound->flags, data);
121
122 l = SWFInput_length(sound->input);
123
124 methodWriteUInt32(soundDataSize(sound), method, data);
125
126 if ( (sound->flags & SWF_SOUND_COMPRESSION) == SWF_SOUND_MP3_COMPRESSED )
127 methodWriteUInt16(sound->seekSamples, method, data);
128
129 /* write samples */
130 for ( i=0; i<l; ++i )
131 method((unsigned char)SWFInput_getChar(sound->input), data);
132 }
133
134
135 int
completeDefineSWFSoundBlock(SWFBlock block)136 completeDefineSWFSoundBlock(SWFBlock block)
137 {
138 SWFSound sound = (SWFSound)block;
139
140 if ((sound->flags&SWF_SOUND_COMPRESSION) == SWF_SOUND_MP3_COMPRESSED)
141 return 7 + 2 + SWFInput_length(sound->input);
142 else
143 return 7 + SWFInput_length(sound->input);
144 }
145
146
147 void
writeSWFSoundWithSoundStreamToStream(SWFBlock block,SWFByteOutputMethod method,void * data)148 writeSWFSoundWithSoundStreamToStream(SWFBlock block, SWFByteOutputMethod method, void *data)
149 {
150 SWFSound sound = (SWFSound)block;
151
152 methodWriteUInt16(CHARACTERID(sound), method, data);
153 method(sound->flags, data);
154
155 writeSWFSoundWithSoundStreamToMethod(sound->soundStream, method, data);
156 }
157
158
159 int
completeDefineSWFSoundWithSoundStreamBlock(SWFBlock block)160 completeDefineSWFSoundWithSoundStreamBlock(SWFBlock block)
161 {
162 SWFSound sound = (SWFSound)block;
163 int len = SWFSoundStream_getLength(sound->soundStream, 0) + 9;
164 SWFSoundStream_rewind(sound->soundStream);
165 return len;
166 }
167
168 /*
169 * Set number of samples to seek forward or delay (works with MP3 only)
170 *
171 * If this value is positive, the player seeks this
172 * number of samples into the sound block before the
173 * sound is played.
174 * If this value is negative the player plays this
175 * number of silent samples before playing the sound block
176 */
177 void
SWFSound_setInitialMp3Delay(SWFSound sound,int delaySeek)178 SWFSound_setInitialMp3Delay(SWFSound sound, int delaySeek)
179 {
180 sound->seekSamples = delaySeek;
181 }
182
183
184 void
destroySWFSound(SWFSound sound)185 destroySWFSound(SWFSound sound)
186 {
187 if (sound->freeInput)
188 destroySWFInput(sound->input);
189 destroySWFCharacter((SWFCharacter) sound);
190 }
191
192 /*
193 * Creates a new EventSound object.
194 *
195 * The sound to be played is contained in a file and specified with flags.
196 *
197 * Flags must contain a sound format, sampling rate, size (in bits) and channels.
198 * If the file contains mp3 data it is not necessary to specify sampling rate,
199 * sound size and channels.
200 *
201 * Possible sound formats are:
202 * - SWF_SOUND_NOT_COMPRESSED
203 * - SWF_SOUND_ADPCM_COMPRESSED
204 * - SWF_SOUND_MP3_COMPRESSED
205 * - SWF_SOUND_NOT_COMPRESSED_LE
206 * - SWF_SOUND_NELLY_COMPRESSED
207 *
208 * Sampling rate must be one of the following values:
209 * - SWF_SOUND_5KHZ
210 * - SWF_SOUND_11KHZ
211 * - SWF_SOUND_22KHZ
212 * - SWF_SOUND_44KHZ
213 *
214 * Sound size is either SWF_SOUND_8BITS or SWF_SOUND_16BITS
215 * Channels are either SWF_SOUND_MONO or SWF_SOUND_STEREO
216 */
217 SWFSound
newSWFSound(FILE * f,byte flags)218 newSWFSound(FILE *f, byte flags)
219 {
220 SWFSound s = newSWFSound_fromInput(newSWFInput_file(f), flags);
221 s->freeInput = TRUE;
222 return s;
223 }
224
225 /* added by David McNab <david@rebirthing.co.nz> */
226 /* required so that python can pass in file descriptors instead of FILE* streams */
227 SWFSound
newSWFSoundFromFileno(int fd,byte flags)228 newSWFSoundFromFileno(int fd, byte flags)
229 {
230 FILE *fp = fdopen(fd, "r");
231 return newSWFSound(fp, flags);
232 }
233
234
235 SWFSound
newSWFSound_fromInput(SWFInput input,byte flags)236 newSWFSound_fromInput(SWFInput input, byte flags)
237 {
238 SWFSound sound = (SWFSound)malloc(sizeof(struct SWFSound_s));
239 SWFBlock block = (SWFBlock)sound;
240
241 SWFCharacterInit((SWFCharacter)sound);
242
243 CHARACTERID(sound) = ++SWF_gNumCharacters;
244
245 block->type = SWF_DEFINESOUND;
246
247 block->writeBlock = writeSWFSoundToStream;
248 block->complete = completeDefineSWFSoundBlock;
249 block->dtor = (destroySWFBlockMethod) destroySWFSound;
250
251 sound->input = input;
252 sound->flags = flags;
253 if((sound->flags&SWF_SOUND_COMPRESSION) == SWF_SOUND_MP3_COMPRESSED)
254 {
255 if(getMP3Flags(input, &sound->flags) < 0)
256 {
257 free(sound);
258 return NULL;
259 }
260 }
261 sound->soundStream = 0;
262 sound->seekSamples = SWFSOUND_INITIAL_DELAY;
263 sound->freeInput = FALSE;
264 return sound;
265 }
266
267 /*
268 * Creates an Event Sound object from a given SoundStream object
269 *
270 * see also newSWFSoundStream()
271 */
272 SWFSound
newSWFSound_fromSoundStream(SWFSoundStream stream)273 newSWFSound_fromSoundStream(SWFSoundStream stream)
274 {
275 SWFSound sound = (SWFSound)malloc(sizeof(struct SWFSound_s));
276 SWFBlock block = (SWFBlock)sound;
277
278 SWFCharacterInit((SWFCharacter)sound);
279
280 CHARACTERID(sound) = ++SWF_gNumCharacters;
281
282 block->type = SWF_DEFINESOUND;
283
284 block->writeBlock = writeSWFSoundWithSoundStreamToStream;
285 block->complete = completeDefineSWFSoundWithSoundStreamBlock;
286 block->dtor = (destroySWFBlockMethod) destroySWFSound;
287
288 sound->freeInput = FALSE;
289 sound->input = 0;
290 sound->flags = SWFSoundStream_getFlags(stream);
291 sound->soundStream = stream;
292
293 return sound;
294 }
295
296 /*
297 * Local variables:
298 * tab-width: 2
299 * c-basic-offset: 2
300 * End:
301 */
302