root/sweep/trunk/src/file_mad.c

Revision 720, 10.7 kB (checked in by erikd, 2 years ago)

src/file_mad.c : Fix compiler warning.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  * Copyright (C) 2002 CSIRO Australia
6  *
7  */
8
9 /*
10  * This file adapted from "player.c" in the "mad MPEG audio decoder"
11  * source distribution:
12  *
13  * Copyright (C) 2000-2001 Robert Leslie
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34
35 #ifdef HAVE_MAD
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <fcntl.h>
45 #include <math.h>
46 #include <pthread.h>
47 #include <errno.h>
48 #include <ctype.h>
49
50 #include <mad.h>
51
52 #define BUFFER_LEN 4096
53
54 #include <glib.h>
55 #include <gdk/gdkkeysyms.h>
56 #include <gtk/gtk.h>
57
58 #include <sweep/sweep_i18n.h>
59 #include <sweep/sweep_types.h>
60 #include <sweep/sweep_typeconvert.h>
61 #include <sweep/sweep_sample.h>
62 #include <sweep/sweep_undo.h>
63 #include <sweep/sweep_sounddata.h>
64
65 #include "sample.h"
66 #include "interface.h"
67 #include "file_dialogs.h"
68 #include "file_sndfile.h"
69 #include "question_dialogs.h"
70 #include "preferences.h"
71 #include "print.h"
72 #include "view.h"
73
74
75 static gboolean
76 file_is_mpeg_audio (const char * pathname)
77 {
78   int fd;
79
80 /* FIXME
81  * the mpeg frame marker can occur in non mpeg files so
82  * one blind check for a marker can produce a false postive.
83  * similarly, due to the metadata tags, the max
84  * frame size may also not be a large enough window within
85  * which to find a frame in a legal mpegfile.
86  *
87  * reimplement this check as a contextual verfification of
88  * a sequence of frames, starting from somewhere in the middle
89  * of a file. in the mean time, raise size of buf from 2048 to 8192
90  * to mitigate the chance of a false negative. (with an increased
91  * change of a false positive as a result.)
92  */
93   unsigned char buf[8192];
94   int n, i;
95
96   fd = open (pathname, O_RDONLY);
97   if (fd == -1) goto out_false;
98
99   n = read (fd, buf, sizeof (buf));
100   if (n < 4) goto out_false;
101
102   /* Check for MPEG frame marker */
103   for (i = 0; i < sizeof (buf)-1; i++) {
104     if ((buf[i] & 0xff) == 0xff && (buf[i+1] & 0xe0) == 0xe0) {
105       goto out_true;
106     }
107   }
108
109  out_false:
110   close (fd);
111   return FALSE;
112
113  out_true:
114   close (fd);
115   return TRUE;
116
117 }
118
119 /*
120  * This is a private message structure. A generic pointer to this structure
121  * is passed to each of the callback functions. Put here any data you need
122  * to access from within the callbacks.
123  */
124
125 struct mad_info {
126   sw_sample * sample;
127
128   /* file size */
129   size_t length;
130
131   /* input buffer */
132   unsigned char const *start;
133   unsigned long offset;
134   unsigned long remaining;
135   unsigned char * end_buffer;
136   int eof;
137
138   /* output */
139   sw_framecount_t nr_frames;
140
141 };
142
143 /*
144  * This is the input callback. The purpose of this callback is to (re)fill
145  * the stream buffer which is to be decoded. In this example, an entire file
146  * has been mapped into memory, so we just call mad_stream_buffer() with the
147  * address and length of the mapping. When this callback is called a second
148  * time, we are finished decoding.
149  */
150
151 static enum mad_flow
152 input(void *data, struct mad_stream *stream)
153 {
154   struct mad_info * info = data;
155   unsigned long n;
156
157   if (info->eof)
158     return MAD_FLOW_STOP;
159
160   if (stream->next_frame) {
161
162     info->offset = stream->next_frame - info->start;
163     info->remaining = info->length - info->offset;
164
165     n = MIN (info->remaining, BUFFER_LEN);
166
167     if (n == info->remaining) {
168
169       info->end_buffer = g_malloc0 (info->remaining + MAD_BUFFER_GUARD);
170       if (info->end_buffer == NULL)
171         return MAD_FLOW_BREAK;
172      
173       info->eof = 1;
174      
175       memcpy (info->end_buffer, info->start + info->offset, info->remaining);
176      
177       mad_stream_buffer (stream, info->end_buffer,
178                          info->remaining + MAD_BUFFER_GUARD);
179
180       info->offset += n;
181       info->remaining -= n;
182      
183       return MAD_FLOW_CONTINUE;
184     }
185   } else {
186     n = MIN (info->remaining, BUFFER_LEN);
187   }
188
189   mad_stream_buffer(stream, info->start + info->offset, n);
190
191   info->offset += n;
192   info->remaining -= n;
193
194   return MAD_FLOW_CONTINUE;
195 }
196
197 /*
198  * This is the output callback function. It is called after each frame of
199  * MPEG audio data has been completely decoded. The purpose of this callback
200  * is to output (or play) the decoded PCM audio.
201  */
202
203 static
204 enum mad_flow output(void *data,
205                      struct mad_header const *header,
206                      struct mad_pcm *pcm)
207 {
208   struct mad_info * info = data;
209   sw_sample * sample = info->sample;
210   sw_framecount_t data_start;
211   sw_audio_t * d;
212   int i, j;
213   gint percent;
214
215   gboolean active = TRUE;
216
217   g_mutex_lock (sample->ops_mutex);
218
219   if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
220     active = FALSE;
221   } else {
222
223     sample->sounddata->format->channels = pcm->channels;
224     sample->sounddata->format->rate = pcm->samplerate;
225    
226     data_start = info->nr_frames;
227    
228     info->nr_frames += pcm->length;
229
230     if (info->nr_frames > sample->sounddata->nr_frames) {
231                 g_mutex_lock(sample->sounddata->data_mutex);
232                
233                 sample->sounddata->data = g_realloc(sample->sounddata->data,
234                    frames_to_bytes (sample->sounddata->format,
235                                     info->nr_frames));
236             g_mutex_unlock(sample->sounddata->data_mutex);
237
238     }
239    
240     sample->sounddata->nr_frames = info->nr_frames;
241    
242     d = (sw_audio_t *)sample->sounddata->data;
243     d = &d[data_start * pcm->channels];
244    
245     for (i = 0; i < pcm->channels; i++) {
246       for (j = 0; j < pcm->length; j++) {
247         d[j*pcm->channels + i] =
248           (sw_audio_t)mad_f_todouble(pcm->samples[i][j]);
249       }
250     }
251    
252     percent = (info->length - info->remaining) * 100 / info->length;
253     sample_set_progress_percent (info->sample, percent);
254    
255 #ifdef DEBUG
256     printf ("decoded %u samples, %d%% percent complete (%u / %u)\n",
257             nsamples, percent, info->remaining, info->length);
258 #endif
259    
260   }
261   g_mutex_unlock (sample->ops_mutex);
262
263   return (active ? MAD_FLOW_CONTINUE : MAD_FLOW_STOP);
264 }
265
266 /*
267  * This is the error callback function. It is called whenever a decoding
268  * error occurs. The error is indicated by stream->error; the list of
269  * possible MAD_ERROR_* errors can be found in the mad.h (or
270  * libmad/stream.h) header file.
271  */
272
273 static
274 enum mad_flow error(void *data,
275                     struct mad_stream *stream,
276                     struct mad_frame *frame)
277 {
278   struct mad_info * info = data;
279
280   switch (stream->error) {
281   case MAD_ERROR_BADDATAPTR:
282     return MAD_FLOW_CONTINUE;
283   case MAD_ERROR_LOSTSYNC:
284     if (stream->next_frame)
285       return MAD_FLOW_CONTINUE;
286     /* else fall through */
287   default:
288
289     fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %ld\n",
290             stream->error, mad_stream_errorstr(stream),
291             stream->this_frame - info->start);
292     break;
293   }
294
295   if (MAD_RECOVERABLE (stream->error))
296     return MAD_FLOW_CONTINUE;
297   else
298     return MAD_FLOW_BREAK;
299 }
300
301
302 static sw_sample *
303 sample_load_mad_data (sw_op_instance * inst)
304 {
305   sw_sample * sample = inst->sample;
306   int fd;
307   void * fdm;
308   struct stat statbuf;
309
310   struct mad_decoder decoder;
311   struct mad_info info;
312   int result;
313
314   fd = open (sample->pathname, O_RDONLY);
315
316   if (fstat (fd, &statbuf) == -1 || statbuf.st_size == 0) return NULL;
317
318   fdm = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
319   if (fdm == MAP_FAILED) {
320     perror (NULL);
321     close (fd);
322     return NULL;
323   }
324
325 #if defined (HAVE_MADVISE)
326   madvise (fdm, statbuf.st_size, MADV_SEQUENTIAL);
327 #endif
328
329   info.sample = sample;
330   info.length = statbuf.st_size;
331   info.start = fdm;
332   info.offset = 0;
333   info.remaining = (unsigned long) statbuf.st_size;
334   info.eof = 0;
335   info.end_buffer = NULL;
336   info.nr_frames = 0;
337
338   mad_decoder_init (&decoder, &info,
339                     input, 0 /* header */, 0 /* filter */, output,
340                     error, 0 /* message */);
341
342   result = mad_decoder_run (&decoder, MAD_DECODER_MODE_SYNC);
343
344   mad_decoder_finish (&decoder);
345
346   if (info.end_buffer != NULL) {
347     g_free (info.end_buffer);
348   }
349
350   if (munmap (fdm, statbuf.st_size) == -1) {
351     perror (NULL);
352   }
353
354   close (fd);
355
356   stat (sample->pathname, &statbuf);
357   sample->last_mtime = statbuf.st_mtime;
358   sample->edit_ignore_mtime = FALSE;
359   sample->modified = FALSE;
360
361   sample_set_edit_state (sample, SWEEP_EDIT_STATE_DONE);
362
363   return sample;
364 }
365
366 static sw_operation mad_load_op = {
367   SWEEP_EDIT_MODE_FILTER,
368   (SweepCallback)sample_load_mad_data,
369   (SweepFunction)NULL,
370   (SweepCallback)NULL, /* undo */
371   (SweepFunction)NULL,
372   (SweepCallback)NULL, /* redo */
373   (SweepFunction)NULL
374 };
375
376 static sw_sample *
377 sample_load_mad_info (sw_sample * sample, char * pathname)
378 {
379   char buf[128];
380
381   gboolean isnew = (sample == NULL);
382
383   sw_view * v;
384
385   if (!file_is_mpeg_audio (pathname)) return NULL;
386
387   /* Create the sample/sounddata, initially with length 0, to be grown
388    * as the file is decoded
389    */
390   if (sample == NULL) {
391     /* Channels and rate will be set during decoding and are basically
392      * irrelevent here. Set them to 2, 44100 assuming these are the most
393      * likely values, in which case the file info displayed in the window
394      * will not change suddenly
395      */
396     sample = sample_new_empty(pathname, 2, 44100, 0);
397   } else {
398     int channels, rate;
399
400     /* Set the channels and rate of the recreated sounddata to be the same
401      * as the old one, as they are most likely the same after a reload */
402     channels = sample->sounddata->format->channels;
403     rate = sample->sounddata->format->rate;
404
405     sounddata_destroy (sample->sounddata);
406     sample->sounddata = sounddata_new_empty (channels, rate, 0);
407   }
408
409   if(!sample) {
410     /*close (fd);*/
411     return NULL;
412   }
413
414   sample->file_method = SWEEP_FILE_METHOD_MP3;
415   /*sample->file_info = GINT_TO_POINTER(fd);*/
416
417   sample_bank_add(sample);
418
419   if (isnew) {
420     v = view_new_all (sample, 1.0);
421     sample_add_view (sample, v);
422   } else {
423     trim_registered_ops (sample, 0);
424   }
425
426   g_snprintf (buf, sizeof (buf), _("Loading %s"), g_basename (sample->pathname));
427
428   schedule_operation (sample, buf, &mad_load_op, sample);
429
430   return sample;
431 }
432
433 sw_sample *
434 mad_sample_reload (sw_sample * sample)
435 {
436   if (sample == NULL) return NULL;
437
438   return sample_load_mad_info (sample, sample->pathname);
439 }
440
441 sw_sample *
442 mad_sample_load (char * pathname)
443 {
444   if (pathname == NULL) return NULL;
445
446   return sample_load_mad_info (NULL, pathname);
447 }
448
449 #endif /* HAVE_MAD */
Note: See TracBrowser for help on using the browser.