added chapter seperation.
[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 = malloc(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     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 "../lame/lame.h"
91
92 static lame_global_flags*lame_flags;
93
94 static void initlame()
95 {
96     unsigned char buf[4096];
97     int bufsize = 1152*2;
98
99     lame_flags = lame_init();
100
101     lame_set_in_samplerate(lame_flags, swf_mp3_in_samplerate);
102     lame_set_num_channels(lame_flags, swf_mp3_channels);
103     lame_set_scale(lame_flags, 0);
104
105     // MPEG1    32, 44.1,   48khz
106     // MPEG2    16, 22.05,  24
107     // MPEG2.5   8, 11.025, 12
108     lame_set_out_samplerate(lame_flags, swf_mp3_out_samplerate);
109
110     lame_set_quality(lame_flags, 0);
111     lame_set_mode(lame_flags, MONO/*3*/);
112     lame_set_brate(lame_flags, swf_mp3_bitrate);
113     //lame_set_compression_ratio(lame_flags, 11.025);
114     lame_set_bWriteVbrTag(lame_flags, 0);
115
116     lame_init_params(lame_flags);
117     lame_init_bitstream(lame_flags);
118
119     /* The first two flush calls to lame always fail, for
120        some reason. Do them here where they cause no damage. */
121     lame_encode_flush_nogap(lame_flags, buf, bufsize);
122     //printf("init:flush_nogap():%d\n", len);
123     lame_encode_flush(lame_flags, buf, bufsize);
124     //printf("init:flush():%d\n", len);
125 }
126
127 void swf_SetSoundStreamHead(TAG*tag, int avgnumsamples)
128 {
129     int len;
130
131     U8 playbackrate = 1; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
132     U8 playbacksize = 1; // 0 = 8 bit, 1 = 16 bit
133     U8 playbacktype = 0; // 0 = mono, 1 = stereo
134     U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
135     U8 rate = 1; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
136     U8 size = 1; // 0 = 8 bit, 1 = 16 bit
137     U8 type = 0; // 0 = mono, 1 = stereo
138
139     if(swf_mp3_out_samplerate == 5512) playbackrate = rate = 0; // lame doesn't support this
140     else if(swf_mp3_out_samplerate == 11025) playbackrate = rate = 1;
141     else if(swf_mp3_out_samplerate == 22050) playbackrate = rate = 2;
142     else if(swf_mp3_out_samplerate == 44100) playbackrate = rate = 3;
143     else fprintf(stderr, "Invalid samplerate: %d\n", swf_mp3_out_samplerate);
144     
145     initlame();
146
147     swf_SetU8(tag,(playbackrate<<2)|(playbacksize<<1)|playbacktype);
148     swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
149     swf_SetU16(tag,avgnumsamples);
150 }
151
152 void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int seek, char first)
153 {
154     char*buf;
155     int len = 0;
156     int bufsize = 16384;
157     int numsamples = (int)(((swf_mp3_out_samplerate > 22050) ? 1152 : 576) * ((double)swf_mp3_in_samplerate/swf_mp3_out_samplerate));
158     int fs = 0;
159
160     buf = malloc(bufsize);
161     if(!buf)
162         return;
163
164     if(first) {
165         fs = lame_get_framesize(lame_flags);
166         swf_SetU16(tag, fs * first); // samples per mp3 frame
167         swf_SetU16(tag, seek); // seek
168     }
169
170     len += lame_encode_buffer(lame_flags, samples, samples, numsamples, &buf[len], bufsize-len);
171     len += lame_encode_flush_nogap(lame_flags, &buf[len], bufsize-len);
172     swf_SetBlock(tag, buf, len);
173     if(len == 0) {
174         fprintf(stderr, "error: mp3 empty block, %d samples, first:%d, framesize:%d\n",
175                 numsamples, first, fs);
176     }/* else {
177         fprintf(stderr, "ok: mp3 nonempty block, %d samples, first:%d, framesize:%d\n",
178                 numsamples, first, fs);
179     }*/
180     free(buf);
181 }
182
183 void swf_SetSoundStreamEnd(TAG*tag)
184 {
185     lame_close (lame_flags);
186 }
187
188 void swf_SetSoundDefineRaw(TAG*tag, S16*samples, int num, int samplerate)
189 {
190     //swf_SetU8(tag,(/*compression*/0<<4)|(/*rate*/3<<2)|(/*size*/1<<1)|/*mono*/0);
191     //swf_SetU32(tag, numsamples); // 44100 -> 11025
192     //swf_SetBlock(tag, wav2.data, numsamples*2);
193 }
194 void swf_SetSoundDefine(TAG*tag, S16*samples, int num)
195 {
196     char*buf;
197     int oldlen=0,len = 0;
198     int bufsize = 16384;
199     int blocksize = (int)(((swf_mp3_out_samplerate > 22050) ? 1152 : 576) * ((double)swf_mp3_in_samplerate/swf_mp3_out_samplerate));
200     int t;
201     int blocks;
202
203     U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 = nellymoser
204     U8 rate = 1; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
205     U8 size = 1; // 0 = 8 bit, 1 = 16 bit
206     U8 type = 0; // 0 = mono, 1 = stereo
207     
208     if(swf_mp3_out_samplerate == 5512) rate = 0;
209     else if(swf_mp3_out_samplerate == 11025) rate = 1;
210     else if(swf_mp3_out_samplerate == 22050) rate = 2;
211     else if(swf_mp3_out_samplerate == 44100) rate = 3;
212     else fprintf(stderr, "Invalid samplerate: %d\n", swf_mp3_out_samplerate);
213
214     blocks = num / (blocksize);
215
216     swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
217
218     swf_SetU32(tag, (int)(tag,blocks*blocksize / 
219             ((double)swf_mp3_in_samplerate/swf_mp3_out_samplerate)) // account for resampling
220             );
221
222     buf = malloc(bufsize);
223     if(!buf)
224         return;
225
226     initlame();
227
228     swf_SetU16(tag, 0); //delayseek
229     for(t=0;t<blocks;t++) {
230         int s;
231         U16*pos;
232         pos= &samples[t*blocksize];
233         len += lame_encode_buffer(lame_flags, pos, pos, blocksize, &buf[len], bufsize-len);
234         len += lame_encode_flush_nogap(lame_flags, &buf[len], bufsize-len);
235         swf_SetBlock(tag, buf, len);
236         len = 0;
237     }
238
239     free(buf);
240 }
241
242 #endif
243
244 #endif
245
246 #ifndef HAVE_SOUND
247
248 // supply stubs
249
250 void swf_SetSoundStreamHead(TAG*tag, int avgnumsamples)
251 {
252     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
253 }
254 void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int seek, char first)
255 {
256     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
257 }
258 void swf_SetSoundStreamEnd(TAG*tag)
259 {
260     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
261 }
262 void swf_SetSoundDefineRaw(TAG*tag, S16*samples, int num, int samplerate)
263 {
264     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
265 }
266 void swf_SetSoundDefine(TAG*tag, S16*samples, int num)
267 {
268     fprintf(stderr, "Error: no sound support compiled in.\n");exit(1);
269 }
270
271 #endif
272
273 #define SOUNDINFO_STOP 32
274 #define SOUNDINFO_NOMULTIPLE 16
275 #define SOUNDINFO_HASENVELOPE 8
276 #define SOUNDINFO_HASLOOPS 4
277 #define SOUNDINFO_HASOUTPOINT 2
278 #define SOUNDINFO_HASINPOINT 1
279
280
281 void swf_SetSoundInfo(TAG*tag, SOUNDINFO*info)
282 {
283     U8 flags = (info->stop?SOUNDINFO_STOP:0)
284               |(info->nomultiple?SOUNDINFO_NOMULTIPLE:0)
285               |(info->envelopes?SOUNDINFO_HASENVELOPE:0)
286               |(info->loops?SOUNDINFO_HASLOOPS:0)
287               |(info->outpoint?SOUNDINFO_HASOUTPOINT:0)
288               |(info->inpoint?SOUNDINFO_HASINPOINT:0);
289     swf_SetU8(tag, flags);
290     if(flags&SOUNDINFO_HASINPOINT)
291         swf_SetU32(tag, info->inpoint);
292     if(flags&SOUNDINFO_HASOUTPOINT)
293         swf_SetU32(tag, info->outpoint);
294     if(flags&SOUNDINFO_HASLOOPS)
295         swf_SetU16(tag, info->loops);
296     if(flags&SOUNDINFO_HASENVELOPE) {
297         int t;
298         swf_SetU8(tag, info->envelopes);
299         for(t=0;t<info->envelopes;t++) {
300             swf_SetU32(tag, info->pos[t]);
301             swf_SetU16(tag, info->left[t]);
302             swf_SetU16(tag, info->right[t]);
303         }
304     }
305 }
306
307