Initial git import
[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;
115                 /* file stuff */
116                 FILE *f;
117                 size_t 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                 /* read in the file */
124                 f = fopen(file, "rb");
125                 if (!f) {
126                         media_stream_set_meths(ms, NULL);
127                         media_stream_driver(ms) = MDRIVER_UNKNOWN;
128                         xfree(sd);
129                         xfree(madd);
130                         return NULL;
131                 }
132                 fseek(f, 0, SEEK_END);
133                 file_len = ftell(f);
134                 fseek(f, 0, SEEK_SET);
135
136                 /* now copy into media_data structure */
137                 sd->data = xmalloc_atomic(file_len+1);
138                 sd->seek = 0;
139                 sd->length = file_len;
140
141                 /* THIS IS VEEEEEERY BAD! */
142                 if (fread(sd->data, sizeof(char), file_len, f) < file_len)
143                         MAD_DEBUG("could not read complete file\n");
144                 madd->fp = f;
145
146                 /* store the filesize */
147                 mkfp->filesize = file_len;
148                 break;
149         }
150         case MKIND_STRING: {
151                 mkind_string_properties *mksp = NULL;
152
153                 /* prepare our user_data */
154                 mksp = media_stream_kind_properties(ms).sprops;
155                 sd->length = mksp->size;
156                 sd->seek = 0;
157                 sd->data = mksp->stream_data;
158
159                 break;
160         }
161
162         case MKIND_UNKNOWN:
163         case MKIND_FIFO:
164         case MKIND_STREAM:
165         case NUMBER_OF_MEDIA_KINDS:
166         default:
167                 break;
168         }
169
170         /* now initialise our decoder struct */
171         madd->synth = xnew_and_zero(struct mad_synth);
172         madd->stream = xnew_and_zero(struct mad_stream);
173         madd->frame = xnew_and_zero(struct mad_frame);
174
175         mad_synth_init(madd->synth);
176         mad_stream_init(madd->stream);
177         mad_frame_init(madd->frame);
178
179         mad_stream_buffer(madd->stream, (unsigned char*)sd->data, sd->length);
180         madd->have_frame = (mad_frame_decode(madd->frame, madd->stream) == 0);
181         if (!madd->have_frame) {
182                 media_stream_set_meths(ms, NULL);
183                 media_stream_driver(ms) = MDRIVER_UNKNOWN;
184                 media_mad_close(madd);
185                 xfree(madd);
186                 return NULL;
187         }
188         madd->sd = sd;
189
190         /* create a substream */
191         mss = make_media_substream_append(ms);
192         
193         media_substream_type(mss) = MTYPE_AUDIO;
194         mtap = xnew_and_zero(mtype_audio_properties);
195
196         mtap->channels = (madd->frame->header.mode ==
197                           MAD_MODE_SINGLE_CHANNEL) ? 1 : 2;
198         mtap->samplerate = madd->frame->header.samplerate;
199         mtap->bitrate = madd->frame->header.bitrate;
200         mtap->samplewidth = 16;
201         mtap->framesize = mtap->channels * 2;
202         mtap->msf = sxe_msf_MAD;
203         mtap->endianness = 0;
204
205         /* now assign */
206         media_substream_type_properties(mss).aprops = mtap;
207         media_stream_set_meths(ms, media_mad);
208
209         /* keep the SNDFILE context */
210         media_stream_data(ms) = madd;
211         media_substream_data(mss) = madd;
212         /* set me as driver indicator */
213         media_stream_driver(ms) = MYSELF;
214
215         return madd;
216 }
217
218 \f
219 /* utility to scale and round samples to 16 bits */
220
221 DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_MAD);
222
223 static void
224 sxe_msf_MAD_up(void *d, void *s, size_t len)
225 {
226         /* convert MAD samples to internal format (S24in32) */
227         int i;
228         int32_t *dst = d;
229         mad_fixed_t *src = s;
230
231         /* len is the number of samples (== #frame * #channels) */
232         MEDIA_DEBUG_FMT("upsampling MAD->internal: %u samples\n", len);
233
234         for (i = len-1; i >= 0; i--) {
235                 src[i] += (1L << (MAD_F_FRACBITS - 24));
236                 if (src[i] >= MAD_F_ONE)
237                         src[i] = MAD_F_ONE - 1;
238                 else if (src[i] < -MAD_F_ONE)
239                         src[i] = -MAD_F_ONE;
240
241                 dst[i] = (int32_t)(src[i] >> (MAD_F_FRACBITS + 1 - 24));
242         }
243
244         return;
245 }
246
247 static void
248 sxe_msf_MAD_down(void *d, void *s, size_t len)
249 {
250         /* len is the number of samples (== #frame * #channels) */
251         MEDIA_DEBUG_FMT("downsampling internal->MAD: %u samples\n", len);
252
253         MAD_CRITICAL(".oO{ Which Id10T called this?! }\n");
254
255         return;
256 }
257
258
259 static size_t
260 media_mad_read(media_substream *mss, void *outbuf, size_t length)
261 {
262 /* read at most `length' frames into `outbuf' */
263         /* stream stuff */
264         Lisp_Media_Stream *ms = mss->up;
265         mtype_audio_properties *mtap;
266         /* libsndfile stuff */
267         mad_decoder_t *madd = NULL;
268         struct mad_stream *mads = NULL;
269         struct mad_frame *madf = NULL;
270         struct mad_synth *mady = NULL;
271         /* buffering */
272         size_t size = 0;
273         size_t framesize;
274         mad_fixed_t *tmpbuf = (mad_fixed_t*)outbuf;
275
276         /* check the integrity of the media stream */
277         if (media_stream_driver(ms) != MYSELF)
278                 return 0;
279         if (media_substream_type(mss) != MTYPE_AUDIO)
280                 return 0;
281
282
283         /* fetch the decoder context and our audio props */
284         if (!(madd = media_stream_data(ms)))
285                 return 0;
286         if (!(mtap = media_substream_type_properties(mss).aprops))
287                 return 0;
288
289         /* fetch framesize */
290         framesize = mtap->framesize;
291
292         /* prepare mad */
293         mads = madd->stream;
294         mady = madd->synth;
295         madf = madd->frame;
296
297         MAD_DEBUG("req:%d\n", length);
298         while (size <= length) {
299                 unsigned int nchannels, nframes;
300                 mad_fixed_t const *left_ch, *right_ch;
301                 struct mad_pcm *pcm = &mady->pcm;
302
303                 if (!madd->have_frame) {
304                         MAD_DEBUG_DEC("no frames atm, fetching new ones\n");
305                         madd->have_frame = (mad_frame_decode(madf, mads) == 0);
306                 }
307                 if (!madd->have_frame) {
308                         MAD_DEBUG_DEC("no frames there :(\n");
309                         return size;
310                 }
311
312                 mad_synth_frame(mady, madf);
313
314                 nchannels = pcm->channels;
315                 nframes  = pcm->length;
316                 left_ch   = pcm->samples[0];
317                 right_ch  = pcm->samples[1];
318
319                 size += nframes;
320           
321                 MAD_DEBUG_S("frames: %d, samples: %d, size:%d\n",
322                             nframes, nframes*nchannels, size);
323
324                 if (nchannels == 2) {
325                         while (nframes--) {
326                                 *tmpbuf++ = *left_ch++;
327                                 *tmpbuf++ = *right_ch++;
328                         }
329                 } else if (nchannels == 1) {
330                         while (nframes--)
331                                 *tmpbuf++ = *left_ch++;
332                 }
333
334                 madd->have_frame = 0;
335         }
336
337         /* upsample the thing */
338         MEDIA_SAMPLE_FORMAT_UPSAMPLE(sxe_msf_MAD)(
339                 outbuf, outbuf, size*mtap->channels);
340
341         return size;
342 }
343
344 static void
345 media_mad_rewind(media_substream *mss)
346 {
347 /* rewind the stream to the first frame */
348         /* libavformat */
349         mad_decoder_t *madd;
350         Lisp_Media_Stream *ms = mss->up;
351         unsigned char *sdd = NULL;
352         size_t sdl = 0;
353
354         /* check the integrity of the media stream */
355         if (media_stream_driver(ms) != MYSELF)
356                 return;
357
358         /* fetch the format context */
359         if (!(madd = media_stream_data(ms)))
360                 return;
361
362         sdd = (unsigned char*)madd->sd->data;
363         sdl = madd->sd->length;
364
365         /* ... and reset the stream */
366         madd->have_frame=0;
367         mad_synth_init(madd->synth);
368         mad_stream_init(madd->stream);
369         mad_frame_init(madd->frame);
370
371         mad_stream_buffer(madd->stream, sdd, sdl);
372
373         return;
374 }
375
376 #undef MYSELF