cff531af |
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 | */ |
da42200b |
9 | |
10 | #include <stdio.h> |
11 | #include <string.h> |
340e528f |
12 | #include <dlfcn.h> |
da42200b |
13 | |
7c34867a |
14 | #include <pico/pico_int.h> |
3167aa9a |
15 | /*#include "helix/pub/mp3dec.h"*/ |
7c34867a |
16 | #include "mp3.h" |
da42200b |
17 | |
3167aa9a |
18 | #ifndef _MP3DEC_H |
19 | typedef void *HMP3Decoder; |
20 | #define ERR_MP3_INDATA_UNDERFLOW -1 |
21 | #define ERR_MP3_MAINDATA_UNDERFLOW -2 |
22 | #endif |
23 | |
24 | static void *mp3dec; |
fc11dd05 |
25 | static unsigned char mp3_input_buffer[2 * 1024]; |
da42200b |
26 | |
7c34867a |
27 | #ifdef __GP2X__ |
340e528f |
28 | #define mp3dec_decode _mp3dec_decode |
29 | #define mp3dec_start _mp3dec_start |
7c34867a |
30 | #endif |
da42200b |
31 | |
340e528f |
32 | static void *libhelix; |
33 | HMP3Decoder (*p_MP3InitDecoder)(void); |
34 | void (*p_MP3FreeDecoder)(HMP3Decoder); |
35 | int (*p_MP3Decode)(HMP3Decoder, unsigned char **, int *, short *, int); |
36 | |
fc11dd05 |
37 | int mp3dec_decode(FILE *f, int *file_pos, int file_len) |
da42200b |
38 | { |
39 | unsigned char *readPtr; |
40 | int bytesLeft; |
41 | int offset; // mp3 frame offset from readPtr |
7c34867a |
42 | int had_err; |
43 | int err = 0; |
faedc4f1 |
44 | int retry = 3; |
da42200b |
45 | |
46 | do |
47 | { |
fc11dd05 |
48 | if (*file_pos >= file_len) |
7c34867a |
49 | return 1; /* EOF, nothing to do */ |
da42200b |
50 | |
fc11dd05 |
51 | fseek(f, *file_pos, SEEK_SET); |
52 | bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f); |
da42200b |
53 | |
7c18e34a |
54 | offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft); |
da42200b |
55 | if (offset < 0) { |
fc11dd05 |
56 | lprintf("find_sync_word (%i/%i) err %i\n", |
57 | *file_pos, file_len, offset); |
58 | *file_pos = file_len; |
da42200b |
59 | return 1; // EOF |
60 | } |
61 | readPtr = mp3_input_buffer + offset; |
62 | bytesLeft -= offset; |
63 | |
7c34867a |
64 | had_err = err; |
340e528f |
65 | err = p_MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0); |
da42200b |
66 | if (err) { |
7c34867a |
67 | if (err == ERR_MP3_MAINDATA_UNDERFLOW && !had_err) { |
68 | // just need another frame |
fc11dd05 |
69 | *file_pos += readPtr - mp3_input_buffer; |
7c34867a |
70 | continue; |
71 | } |
72 | if (err == ERR_MP3_INDATA_UNDERFLOW && !had_err) { |
da42200b |
73 | if (offset == 0) |
74 | // something's really wrong here, frame had to fit |
fc11dd05 |
75 | *file_pos = file_len; |
da42200b |
76 | else |
fc11dd05 |
77 | *file_pos += offset; |
da42200b |
78 | continue; |
7c34867a |
79 | } |
80 | if (-12 <= err && err <= -6) { |
da42200b |
81 | // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_* |
82 | // just try to skip the offending frame.. |
fc11dd05 |
83 | *file_pos += offset + 1; |
da42200b |
84 | continue; |
85 | } |
fc11dd05 |
86 | lprintf("MP3Decode err (%i/%i) %i\n", |
87 | *file_pos, file_len, err); |
88 | *file_pos = file_len; |
da42200b |
89 | return 1; |
90 | } |
fc11dd05 |
91 | *file_pos += readPtr - mp3_input_buffer; |
da42200b |
92 | } |
faedc4f1 |
93 | while (err && --retry > 0); |
da42200b |
94 | |
faedc4f1 |
95 | return !!err; |
da42200b |
96 | } |
97 | |
75a30842 |
98 | int mp3dec_start(FILE *f, int fpos_start) |
da42200b |
99 | { |
340e528f |
100 | if (libhelix == NULL) { |
101 | libhelix = dlopen("./libhelix.so", RTLD_NOW); |
102 | if (libhelix == NULL) { |
103 | lprintf("mp3dec: load libhelix.so: %s\n", dlerror()); |
104 | return -1; |
105 | } |
106 | |
107 | p_MP3InitDecoder = dlsym(libhelix, "MP3InitDecoder"); |
108 | p_MP3FreeDecoder = dlsym(libhelix, "MP3FreeDecoder"); |
109 | p_MP3Decode = dlsym(libhelix, "MP3Decode"); |
110 | |
111 | if (p_MP3InitDecoder == NULL || p_MP3FreeDecoder == NULL |
112 | || p_MP3Decode == NULL) |
113 | { |
114 | lprintf("mp3dec: missing symbol(s) in libhelix.so\n"); |
115 | dlclose(libhelix); |
116 | libhelix = NULL; |
117 | return -1; |
118 | } |
119 | } |
120 | |
7c34867a |
121 | // must re-init decoder for new track |
122 | if (mp3dec) |
340e528f |
123 | p_MP3FreeDecoder(mp3dec); |
124 | mp3dec = p_MP3InitDecoder(); |
da42200b |
125 | |
fc11dd05 |
126 | return (mp3dec == 0) ? -1 : 0; |
da42200b |
127 | } |