support mp3 decoding over libavcodec
[picodrive.git] / platform / common / mp3_helix.c
1 /*
2  * Some mp3 related code for Sega/Mega CD.
3  * Uses the Helix Fixed-point MP3 decoder
4  * (C) notaz, 2007-2009
5  *
6  * This work is licensed under the terms of MAME license.
7  * See COPYING file in the top-level directory.
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 #include <pico/pico_int.h>
14 #include <pico/sound/mix.h>
15 #include "helix/pub/mp3dec.h"
16 #include "mp3.h"
17 #include "lprintf.h"
18
19 static HMP3Decoder mp3dec;
20 static unsigned char mp3_input_buffer[2 * 1024];
21
22 #ifdef __GP2X__
23 #define mp3_update mp3_update_local
24 #define mp3_start_play mp3_start_play_local
25 #endif
26
27 int mp3dec_decode(FILE *f, int *file_pos, int file_len)
28 {
29         unsigned char *readPtr;
30         int bytesLeft;
31         int offset; // mp3 frame offset from readPtr
32         int had_err;
33         int err = 0;
34
35         do
36         {
37                 if (*file_pos >= file_len)
38                         return 1; /* EOF, nothing to do */
39
40                 fseek(f, *file_pos, SEEK_SET);
41                 bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f);
42
43                 offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft);
44                 if (offset < 0) {
45                         lprintf("find_sync_word (%i/%i) err %i\n",
46                                 *file_pos, file_len, offset);
47                         *file_pos = file_len;
48                         return 1; // EOF
49                 }
50                 readPtr = mp3_input_buffer + offset;
51                 bytesLeft -= offset;
52
53                 had_err = err;
54                 err = MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
55                 if (err) {
56                         if (err == ERR_MP3_MAINDATA_UNDERFLOW && !had_err) {
57                                 // just need another frame
58                                 *file_pos += readPtr - mp3_input_buffer;
59                                 continue;
60                         }
61                         if (err == ERR_MP3_INDATA_UNDERFLOW && !had_err) {
62                                 if (offset == 0)
63                                         // something's really wrong here, frame had to fit
64                                         *file_pos = file_len;
65                                 else
66                                         *file_pos += offset;
67                                 continue;
68                         }
69                         if (-12 <= err && err <= -6) {
70                                 // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_*
71                                 // just try to skip the offending frame..
72                                 *file_pos += offset + 1;
73                                 continue;
74                         }
75                         lprintf("MP3Decode err (%i/%i) %i\n",
76                                 *file_pos, file_len, err);
77                         *file_pos = file_len;
78                         return 1;
79                 }
80                 *file_pos += readPtr - mp3_input_buffer;
81         }
82         while (0);
83
84         return 0;
85 }
86
87 int mp3dec_start(void)
88 {
89         // must re-init decoder for new track
90         if (mp3dec)
91                 MP3FreeDecoder(mp3dec);
92         mp3dec = MP3InitDecoder();
93
94         return (mp3dec == 0) ? -1 : 0;
95 }