applied mp3 patch from Joel Yliluoma.
[swftools.git] / lib / modules / swfsound.c
1 /* swfaction.c
2
3    SWF Sound handling routines
4    
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2001, 2002 Matthias Kramm <kramm@quiss.org>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #ifndef NO_MP3
25
26 #include "../rfxswf.h"
27
28 #ifdef BLADEENC
29 #define HAVE_SOUND
30
31 CodecInitOut * init = 0;
32 void swf_SetSoundStreamHead(TAG*tag, U16 avgnumsamples)
33 {
34     U8 playbackrate = 3; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
35     U8 playbacksize = 1; // 0 = 8 bit, 1 = 16 bit
36     U8 playbacktype = 0; // 0 = mono, 1 = stereo
37     U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
38     U8 rate = 3; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
39     U8 size = 1; // 0 = 8 bit, 1 = 16 bit
40     U8 type = 0; // 0 = mono, 1 = stereo
41
42     CodecInitIn params;
43     memset(&params, 0, sizeof(params));
44     params.frequency = 44100;  //48000, 44100 or 32000
45     params.mode = 3;      //0 = Stereo, 2 = Dual Channel, 3 = Mono
46     params.emphasis = 0;  //0 = None, 1 = 50/15 microsec, 3 = CCITT J.17
47     params.bitrate = 128;         //default is 128 (64 for mono)
48     init = codecInit(&params);
49
50     swf_SetU8(tag,(playbackrate<<2)|(playbacksize<<1)|playbacktype);
51     swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
52     swf_SetU16(tag,avgnumsamples);
53
54     printf("numSamples:%d\n",init->nSamples);
55     printf("bufferSize:%d\n",init->bufferSize);
56 }
57
58 void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int numsamples, char first)
59 {
60     char*buf;
61     int len = 0;
62
63     buf = rfx_alloc(init->bufferSize);
64     if(!buf)
65         return;
66     
67     len = codecEncodeChunk (numsamples, samples, buf);
68     len += codecFlush (&buf[len]);
69     len += codecExit (&buf[len]);
70
71     if(first) {
72         swf_SetU16(tag, numsamples); // number of samples
73         swf_SetU16(tag, 0); // seek
74     }
75     swf_SetBlock(tag, buf, len);
76     rfx_free(buf);
77 }
78 #endif
79
80 /* TODO: find a better way to set these from the outside */
81
82 int swf_mp3_in_samplerate = 44100;
83 int swf_mp3_out_samplerate = 11025;
84 int swf_mp3_channels = 1;
85 int swf_mp3_bitrate = 32;
86
87 #ifdef HAVE_LAME
88 #define HAVE_SOUND
89
90 #include <stdarg.h>
91 #include <lame.h>
92
93 static lame_global_flags*lame_flags;
94
95 void null_errorf(const char *format, va_list ap)
96 {
97 }
98
99 static void initlame()
100 {
101     unsigned char buf[4096];
102     int bufsize = 1152*2;
103
104     lame_flags = lame_init();
105
106     lame_set_in_samplerate(lame_flags, swf_mp3_in_samplerate);
107     lame_set_num_channels(lame_flags, swf_mp3_channels);
108     lame_set_scale(lame_flags, 0);
109
110     // MPEG1    32, 44.1,   48khz
111     // MPEG2    16, 22.05,  24
112     // MPEG2.5   8, 11.025, 12
113     lame_set_out_samplerate(lame_flags, swf_mp3_out_samplerate);
114
115     lame_set_quality(lame_flags, 0);
116     lame_set_mode(lame_flags, MONO/*3*/);
117     lame_set_brate(lame_flags, swf_mp3_bitrate);
118     //lame_set_compression_ratio(lame_flags, 11.025);
119     lame_set_bWriteVbrTag(lame_flags, 0);
120
121     lame_init_params(lame_flags);
122     lame_init_bitstream(lame_flags);
123
124     lame_set_errorf(lame_flags, null_errorf);
125     /* The first two flush calls to lame always fail, for
126        some reason. Do them here where they cause no damage. */
127     lame_encode_flush_nogap(lame_flags, buf, bufsize);
128     //printf("init:flush_nogap():%d\n", len);
129     lame_encode_flush(lame_flags, buf, bufsize);
130     //printf("init:flush():%d\n", len);
131     lame_set_errorf(lame_flags, 0);
132 }
133
134 void swf_SetSoundStreamHead(TAG*tag, int avgnumsamples)
135 {
136     int len;
137
138     U8 playbackrate = 1; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
139     U8 playbacksize = 1; // 0 = 8 bit, 1 = 16 bit
140     U8 playbacktype = 0; // 0 = mono, 1 = stereo
141     U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
142     U8 rate = 1; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
143     U8 size = 1; // 0 = 8 bit, 1 = 16 bit
144     U8 type = 0; // 0 = mono, 1 = stereo
145
146     if(swf_mp3_out_samplerate == 5512) playbackrate = rate = 0; // lame doesn't support this
147     else if(swf_mp3_out_samplerate == 11025) playbackrate = rate = 1;
148     else if(swf_mp3_out_samplerate == 22050) playbackrate = rate = 2;
149     else if(swf_mp3_out_samplerate == 44100) playbackrate = rate = 3;
150     else fprintf(stderr, "Invalid samplerate: %d\n", swf_mp3_out_samplerate);
151     
152     initlame();
153
154     swf_SetU8(tag,(playbackrate<<2)|(playbacksize<<1)|playbacktype);
155     swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
156     swf_SetU16(tag,avgnumsamples);
157 }
158
159 void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int seek, char first)
160 {
161     char*buf;
162     int len = 0;
163     int bufsize = 16384;
164     int numsamples = (int)(((swf_mp3_out_samplerate > 22050) ? 1152 : 576) * ((double)swf_mp3_in_samplerate/swf_mp3_out_samplerate));
165     int fs = 0;
166
167     buf = rfx_alloc(bufsize);
168     if(!buf)
169         return;
170
171     if(first) {
172         fs = lame_get_framesize(lame_flags);
173         swf_SetU16(tag, fs * first); // samples per mp3 frame
174         swf_SetU16(tag, seek); // seek
175     }
176
177     len += lame_encode_buffer(lame_flags, samples, samples, numsamples, &buf[len], bufsize-len);
178     len += lame_encode_flush_nogap(lame_flags, &buf[len], bufsize-len);
179     swf_SetBlock(tag, buf, len);
180     if(len == 0) {
181         fprintf(stderr, "error: mp3 empty block, %d samples, first:%d, framesize:%d\n",
182                 numsamples, first, fs);
183     }/* else {
184         fprintf(stderr, "ok: mp3 nonempty block, %d samples, first:%d, framesize:%d\n",
185                 numsamples, first, fs);
186     }*/
187     rfx_free(buf);
188 }
189
190 void swf_SetSoundStreamEnd(TAG*tag)
191 {
192     lame_close (lame_flags);
193 }
194
195 void swf_SetSoundDefineRaw(TAG*tag, S16*samples, int num, int samplerate)
196 {
197     //swf_SetU8(tag,(/*compression*/0<<4)|(/*rate*/3<<2)|(/*size*/1<<1)|/*mono*/0);
198     //swf_SetU32(tag, numsamples); // 44100 -> 11025
199     //swf_SetBlock(tag, wav2.data, numsamples*2);
200 }
201 void swf_SetSoundDefine(TAG*tag, S16*samples, int num)
202 {
203     char*buf;
204     int oldlen=0,len = 0;
205     int bufsize = 16384;
206     int blocksize = (int)(((swf_mp3_out_samplerate > 22050) ? 1152 : 576) * ((double)swf_mp3_in_samplerate/swf_mp3_out_samplerate));
207     int t;
208     int blocks;
209
210     U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
211     U8 rate = 1; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
212     U8 size = 1; // 0 = 8 bit, 1 = 16 bit
213     U8 type = 0; // 0 = mono, 1 = stereo
214     
215     if(swf_mp3_out_samplerate == 5512) rate = 0;
216     else if(swf_mp3_out_samplerate == 11025) rate = 1;
217     else if(swf_mp3_out_samplerate == 22050) rate = 2;
218     else if(swf_mp3_out_samplerate == 44100) rate = 3;
219     else fprintf(stderr, "Invalid samplerate: %d\n", swf_mp3_out_samplerate);
220
221     blocks = num / (blocksize);
222
223     swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
224
225     swf_SetU32(tag, (int)(tag,blocks*blocksize / 
226             ((double)swf_mp3_in_samplerate/swf_mp3_out_samplerate)) // account for resampling
227             );
228
229     buf = rfx_alloc(bufsize);
230     if(!buf)
231         return;
232
233     initlame();
234
235     swf_SetU16(tag, 0); //delayseek
236     for(t=0;t<blocks;t++) {
237         int s;
238         U16*pos;
239         pos= &samples[t*blocksize];
240         len += lame_encode_buffer(lame_flags, pos, pos, blocksize, &buf[len], bufsize-len);
241         len += lame_encode_flush_nogap(lame_flags, &buf[len], bufsize-len);
242         swf_SetBlock(tag, buf, len);
243         len = 0;
244     }
245
246     rfx_free(buf);
247 }
248
249 #endif
250
251 #endif
252
253 #ifndef HAVE_SOUND
254
255 // supply stubs
256
257 void swf_SetSoundStreamHead(TAG*tag, int avgnumsamples)
258 {
259     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
260 }
261 void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int seek, char first)
262 {
263     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
264 }
265 void swf_SetSoundStreamEnd(TAG*tag)
266 {
267     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
268 }
269 void swf_SetSoundDefineRaw(TAG*tag, S16*samples, int num, int samplerate)
270 {
271     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
272 }
273 void swf_SetSoundDefine(TAG*tag, S16*samples, int num)
274 {
275     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
276 }
277
278 #endif
279
280 #define SOUNDINFO_STOP 32
281 #define SOUNDINFO_NOMULTIPLE 16
282 #define SOUNDINFO_HASENVELOPE 8
283 #define SOUNDINFO_HASLOOPS 4
284 #define SOUNDINFO_HASOUTPOINT 2
285 #define SOUNDINFO_HASINPOINT 1
286
287
288 void swf_SetSoundInfo(TAG*tag, SOUNDINFO*info)
289 {
290     U8 flags = (info->stop?SOUNDINFO_STOP:0)
291               |(info->nomultiple?SOUNDINFO_NOMULTIPLE:0)
292               |(info->envelopes?SOUNDINFO_HASENVELOPE:0)
293               |(info->loops?SOUNDINFO_HASLOOPS:0)
294               |(info->outpoint?SOUNDINFO_HASOUTPOINT:0)
295               |(info->inpoint?SOUNDINFO_HASINPOINT:0);
296     swf_SetU8(tag, flags);
297     if(flags&SOUNDINFO_HASINPOINT)
298         swf_SetU32(tag, info->inpoint);
299     if(flags&SOUNDINFO_HASOUTPOINT)
300         swf_SetU32(tag, info->outpoint);
301     if(flags&SOUNDINFO_HASLOOPS)
302         swf_SetU16(tag, info->loops);
303     if(flags&SOUNDINFO_HASENVELOPE) {
304         int t;
305         swf_SetU8(tag, info->envelopes);
306         for(t=0;t<info->envelopes;t++) {
307             swf_SetU32(tag, info->pos[t]);
308             swf_SetU16(tag, info->left[t]);
309             swf_SetU16(tag, info->right[t]);
310         }
311     }
312 }
313
314
315 void swf_SetSoundDefineMP3(TAG*tag, U8* data, unsigned length,
316                            unsigned SampRate,
317                            unsigned Channels,
318                            unsigned NumFrames)
319 {
320     U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
321     U8 rate;     // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
322     U8 size = 1; // 0 = 8 bit, 1 = 16 bit
323     U8 type = Channels==2; // 0=mono, 1=stereo
324     
325     rate = (SampRate >= 40000) ? 3
326          : (SampRate >= 19000) ? 2
327          : (SampRate >= 8000) ? 1
328          : 0;
329
330     swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
331
332     swf_SetU32(tag, NumFrames * 576);
333
334     swf_SetU16(tag, 0); //delayseek
335     swf_SetBlock(tag, data, length);
336 }