Partially sync files.el from XEmacs 21.5 for wildcard support.
[sxemacs] / src / media / media-mad.c
1 /* media-mad.c - analyse audio files or streams
2
3    Copyright (C) 2006 Sebastian Freundt
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "lisp.h"
28
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <string.h>
34
35 #include "sysfile.h"
36
37 #include "media-mad.h"
38
39 #define MYSELF MDRIVER_MAD
40
41 Lisp_Object Qmad;
42
43 #define __MAD_DEBUG__(args...)          fprintf(stderr, "MAD " args)
44 #ifndef MAD_DEBUG_FLAG
45 #define MAD_DEBUG(args...)
46 #else
47 #define MAD_DEBUG(args...)              __MAD_DEBUG__(args)
48 #endif
49 #define MAD_DEBUG_S(args...)            MAD_DEBUG("[stream]: " args)
50 #define MAD_DEBUG_DEC(args...)          MAD_DEBUG("[decoder]: " args)
51 #define MAD_CRITICAL(args...)           __MAD_DEBUG__("CRITICAL: " args)
52
53 \f
54 DECLARE_MEDIA_DRIVER_OPEN_METH(media_mad);
55 DECLARE_MEDIA_DRIVER_CLOSE_METH(media_mad);
56 DECLARE_MEDIA_DRIVER_READ_METH(media_mad);
57 DECLARE_MEDIA_DRIVER_REWIND_METH(media_mad);
58
59 DEFINE_MEDIA_DRIVER_CUSTOM(media_mad,
60                            media_mad_open, media_mad_close,
61                            NULL, NULL,
62                            media_mad_read, NULL,
63                            media_mad_rewind, NULL);
64
65 DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_MAD);
66
67 \f
68 static void
69 media_mad_close(ms_driver_data_t data)
70 {
71         mad_decoder_t *madd = data;
72
73         MAD_DEBUG_DEC("closing decoder handle: 0x%x\n",
74                       (unsigned int)madd);
75         if (madd->synth)
76                 xfree(madd->synth);
77         madd->synth = NULL;
78
79         if (madd->stream)
80                 xfree(madd->stream);
81         madd->stream = NULL;
82
83         if (madd->frame)
84                 xfree(madd->frame);
85         madd->frame = NULL;
86
87         if (madd->fp)
88                 fclose(madd->fp);
89         madd->fp = NULL;
90
91         if (madd->sd)
92                 xfree(madd->sd);
93         madd->sd = NULL;
94
95         return;
96 }
97
98 static ms_driver_data_t
99 media_mad_open(Lisp_Media_Stream *ms)
100 {
101         media_substream *mss;
102         mtype_audio_properties *mtap;
103         /* libmad stuff */
104         mad_decoder_t *madd = NULL;
105         media_data *sd = NULL;
106
107         /* initialise */
108         sd = xnew_and_zero(media_data);
109         madd = xnew_and_zero(mad_decoder_t);
110
111         switch (media_stream_kind(ms)) {
112         case MKIND_FILE: {
113                 mkind_file_properties *mkfp = NULL;
114                 const char *file = NULL;
115                 /* file stuff */
116                 FILE *f = NULL;
117                 long file_len = 0;
118
119                 /* open the file */
120                 mkfp = media_stream_kind_properties(ms).fprops;
121                 TO_EXTERNAL_FORMAT(LISP_STRING, mkfp->filename,
122                                    ALLOCA, (file, file_len), Qnil);
123                 if ( file != NULL ) {
124                         /* read in the file */
125                         f = fopen(file, "rb");
126                 }
127                 if (!f) {
128                         media_stream_set_meths(ms, NULL);
129                         media_stream_driver(ms) = MDRIVER_UNKNOWN;
130                         xfree(sd);
131                         xfree(madd);
132                         return NULL;
133                 }
134                 fseek(f, 0, SEEK_END);
135                 file_len = ftell(f);
136                 if ( file_len < 0) {
137                         fclose(f);
138                         media_stream_set_meths(ms, NULL);
139                         media_stream_driver(ms) = MDRIVER_UNKNOWN;
140                         xfree(sd);
141                         xfree(madd);
142                         return NULL;
143                 }
144                 fseek(f, 0, SEEK_SET);
145
146                 /* now copy into media_data structure */
147                 sd->data = xmalloc_atomic(file_len+1);
148                 sd->seek = 0;
149                 sd->length = (size_t)file_len;
150
151                 /* THIS IS VEEEEEERY BAD! */
152                 if (fread(sd->data, sizeof(char), file_len, f) < file_len)
153                         MAD_DEBUG("could not read complete file\n");
154                 madd->fp = f;
155
156                 /* store the filesize */
157                 mkfp->filesize = file_len;
158                 break;
159         }
160         case MKIND_STRING: {
161                 mkind_string_properties *mksp = NULL;
162
163                 /* prepare our user_data */
164                 mksp = media_stream_kind_properties(ms).sprops;
165                 sd->length = mksp->size;
166                 sd->seek = 0;
167                 sd->data = mksp->stream_data;
168
169                 break;
170         }
171
172         case MKIND_UNKNOWN:
173         case MKIND_FIFO:
174         case MKIND_STREAM:
175         case NUMBER_OF_MEDIA_KINDS:
176         default:
177                 break;
178         }
179
180         /* now initialise our decoder struct */
181         madd->synth = xnew_and_zero(struct mad_synth);
182         madd->stream = xnew_and_zero(struct mad_stream);
183         madd->frame = xnew_and_zero(struct mad_frame);
184
185         mad_synth_init(madd->synth);
186         mad_stream_init(madd->stream);
187         mad_frame_init(madd->frame);
188
189         mad_stream_buffer(madd->stream, (unsigned char*)sd->data, sd->length);
190         madd->have_frame = (mad_frame_decode(madd->frame, madd->stream) == 0);
191         if (!madd->have_frame) {
192                 media_stream_set_meths(ms, NULL);
193                 media_stream_driver(ms) = MDRIVER_UNKNOWN;
194                 media_mad_close(madd);
195                 xfree(madd);
196                 xfree(sd);
197                 return NULL;
198         }
199         madd->sd = sd;
200
201         /* create a substream */
202         mss = make_media_substream_append(ms);
203
204         media_substream_type(mss) = MTYPE_AUDIO;
205         mtap = xnew_and_zero(mtype_audio_properties);
206
207         mtap->channels = (madd->frame->header.mode ==
208                           MAD_MODE_SINGLE_CHANNEL) ? 1 : 2;
209         mtap->samplerate = madd->frame->header.samplerate;
210         mtap->bitrate = madd->frame->header.bitrate;
211         mtap->samplewidth = 16;
212         mtap->framesize = mtap->channels * 2;
213         mtap->msf = sxe_msf_MAD;
214         mtap->endianness = 0;
215
216         /* now assign */
217         media_substream_type_properties(mss).aprops = mtap;
218         media_stream_set_meths(ms, media_mad);
219
220         /* keep the SNDFILE context */
221         media_stream_data(ms) = madd;
222         media_substream_data(mss) = madd;
223         /* set me as driver indicator */
224         media_stream_driver(ms) = MYSELF;
225
226         return madd;
227 }
228
229 \f
230 /* utility to scale and round samples to 16 bits */
231
232 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_MAD);
233
234 static void
235 sxe_msf_MAD_up(void *d, void *s, size_t len)
236 {
237         /* convert MAD samples to internal format (S24in32) */
238         int i;
239         int32_t *dst = d;
240         mad_fixed_t *src = s;
241
242         /* len is the number of samples (== #frame * #channels) */
243         MEDIA_DEBUG_FMT("upsampling MAD->internal: %u samples\n", len);
244
245         for (i = len-1; i >= 0; i--) {
246                 src[i] += (1L << (MAD_F_FRACBITS - 24));
247                 if (src[i] >= MAD_F_ONE)
248                         src[i] = MAD_F_ONE - 1;
249                 else if (src[i] < -MAD_F_ONE)
250                         src[i] = -MAD_F_ONE;
251
252                 dst[i] = (int32_t)(src[i] >> (MAD_F_FRACBITS + 1 - 24));
253         }
254
255         return;
256 }
257
258 static void
259 sxe_msf_MAD_down(void *d, void *s, size_t len)
260 {
261         /* len is the number of samples (== #frame * #channels) */
262         MEDIA_DEBUG_FMT("downsampling internal->MAD: %u samples\n", len);
263
264         MAD_CRITICAL(".oO{ Which Id10T called this?! }\n");
265
266         return;
267 }
268
269
270 static size_t
271 media_mad_read(media_substream *mss, void *outbuf, size_t length)
272 {
273 /* read at most `length' frames into `outbuf' */
274         /* stream stuff */
275         Lisp_Media_Stream *ms = mss->up;
276         mtype_audio_properties *mtap;
277         /* libsndfile stuff */
278         mad_decoder_t *madd = NULL;
279         struct mad_stream *mads = NULL;
280         struct mad_frame *madf = NULL;
281         struct mad_synth *mady = NULL;
282         /* buffering */
283         size_t size = 0;
284         size_t framesize;
285         mad_fixed_t *tmpbuf = (mad_fixed_t*)outbuf;
286
287         /* check the integrity of the media stream */
288         if (media_stream_driver(ms) != MYSELF)
289                 return 0;
290         if (media_substream_type(mss) != MTYPE_AUDIO)
291                 return 0;
292
293
294         /* fetch the decoder context and our audio props */
295         if (!(madd = media_stream_data(ms)))
296                 return 0;
297         if (!(mtap = media_substream_type_properties(mss).aprops))
298                 return 0;
299
300         /* fetch framesize */
301         framesize = mtap->framesize;
302
303         /* prepare mad */
304         mads = madd->stream;
305         mady = madd->synth;
306         madf = madd->frame;
307
308         MAD_DEBUG("req:%d\n", length);
309         while (size <= length) {
310                 unsigned int nchannels, nframes;
311                 mad_fixed_t const *left_ch, *right_ch;
312                 struct mad_pcm *pcm = &mady->pcm;
313
314                 if (!madd->have_frame) {
315                         MAD_DEBUG_DEC("no frames atm, fetching new ones\n");
316                         madd->have_frame = (mad_frame_decode(madf, mads) == 0);
317                 }
318                 if (!madd->have_frame) {
319                         MAD_DEBUG_DEC("no frames there :(\n");
320                         return size;
321                 }
322
323                 mad_synth_frame(mady, madf);
324
325                 nchannels = pcm->channels;
326                 nframes  = pcm->length;
327                 left_ch   = pcm->samples[0];
328                 right_ch  = pcm->samples[1];
329
330                 size += nframes;
331
332                 MAD_DEBUG_S("frames: %d, samples: %d, size:%d\n",
333                             nframes, nframes*nchannels, size);
334
335                 if (nchannels == 2) {
336                         while (nframes--) {
337                                 *tmpbuf++ = *left_ch++;
338                                 *tmpbuf++ = *right_ch++;
339                         }
340                 } else if (nchannels == 1) {
341                         while (nframes--)
342                                 *tmpbuf++ = *left_ch++;
343                 }
344
345                 madd->have_frame = 0;
346         }
347
348         /* upsample the thing */
349         MEDIA_SAMPLE_FORMAT_UPSAMPLE(sxe_msf_MAD)(
350                 outbuf, outbuf, size*mtap->channels);
351
352         return size;
353 }
354
355 static void
356 media_mad_rewind(media_substream *mss)
357 {
358 /* rewind the stream to the first frame */
359         /* libavformat */
360         mad_decoder_t *madd;
361         Lisp_Media_Stream *ms = mss->up;
362         unsigned char *sdd = NULL;
363         size_t sdl = 0;
364
365         /* check the integrity of the media stream */
366         if (media_stream_driver(ms) != MYSELF)
367                 return;
368
369         /* fetch the format context */
370         if (!(madd = media_stream_data(ms)))
371                 return;
372
373         sdd = (unsigned char*)madd->sd->data;
374         sdl = madd->sd->length;
375
376         /* ... and reset the stream */
377         madd->have_frame=0;
378         mad_synth_init(madd->synth);
379         mad_stream_init(madd->stream);
380         mad_frame_init(madd->frame);
381
382         mad_stream_buffer(madd->stream, sdd, sdl);
383
384         return;
385 }
386
387 #undef MYSELF