1 /* -*- C++ -*-
2 *
3 * MadWrapper.cpp - SMPEG compatible wrapper functions for MAD: Mpeg
4 * Audio Decoder
5 *
6 * Copyright (c) 2001-2005 Ogapee (original ONScripter, of which this
7 * is a fork).
8 *
9 * ogapee@aqua.dti2.ne.jp
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA
25 */
26
27 #include "MadWrapper.h"
28 #include <mad.h>
29
30 #define DEFAULT_AUDIOBUF 4096
31 #define INPUT_BUFFER_SIZE (5 * 8192)
32
MadFixedToUshort(mad_fixed_t Fixed)33 static inline unsigned short MadFixedToUshort(mad_fixed_t Fixed)
34 {
35 if (Fixed >= MAD_F_ONE)
36 Fixed = MAD_F_ONE - 1;
37 else if (Fixed < -MAD_F_ONE)
38 Fixed = -MAD_F_ONE;
39
40 Fixed = Fixed >> (MAD_F_FRACBITS - 15);
41 return (unsigned short) Fixed;
42 }
43
44
45 struct _MAD_WRAPPER {
46 SDL_RWops* src;
47 Uint32 length;
48 struct mad_stream Stream;
49 struct mad_frame Frame;
50 struct mad_synth Synth;
51 bool is_playing;
52 int volume;
53
54 unsigned char* input_buf;
55 unsigned char* output_buf;
56 long output_buf_index;
57 };
58
59 typedef struct _MAD_WRAPPER MAD_WRAPPER;
60
init(SDL_RWops * src)61 static MAD_WRAPPER* init(SDL_RWops* src)
62 {
63 MAD_WRAPPER* mad = new MAD_WRAPPER;
64
65 SDL_RWseek(src, 0, SEEK_END);
66 mad->length = SDL_RWtell(src);
67 SDL_RWseek(src, 0, SEEK_SET);
68
69 mad->src = src;
70
71 mad_stream_init(&mad->Stream);
72 mad_frame_init(&mad->Frame);
73 mad_synth_init(&mad->Synth);
74 mad->volume = 64;
75
76 mad->input_buf = new unsigned char[INPUT_BUFFER_SIZE];
77 mad->output_buf = new unsigned char[1152 * 4 * 5]; /* 1152 because that's what mad has as a max; *4 because */
78 mad->output_buf_index = 0;
79
80 mad->is_playing = false;
81
82 return mad;
83 }
84
85
MAD_WRAPPER_new(const char * file,void * info,int sdl_audio)86 MAD_WRAPPER* MAD_WRAPPER_new(const char* file, void* info, int sdl_audio)
87 {
88 SDL_RWops* src;
89
90 src = SDL_RWFromFile(file, "rb");
91 if (!src) return NULL;
92
93 return init(src);
94 }
95
96
MAD_WRAPPER_new_rwops(SDL_RWops * src,void * info,int sdl_audio)97 MAD_WRAPPER* MAD_WRAPPER_new_rwops(SDL_RWops* src, void* info, int sdl_audio)
98 {
99 return init(src);
100 }
101
102
MAD_WRAPPER_playAudio(void * userdata,Uint8 * stream,int len)103 int MAD_WRAPPER_playAudio(void* userdata, Uint8* stream, int len)
104 {
105 MAD_WRAPPER* mad = (MAD_WRAPPER*) userdata;
106
107 if (!mad->is_playing) return -1;
108
109 // pause
110
111 size_t ReadSize = 1, Remaining;
112 unsigned char* ReadStart;
113
114 do {
115 if (mad->Stream.buffer == NULL || mad->Stream.error == MAD_ERROR_BUFLEN) {
116 if (mad->Stream.next_frame != NULL) {
117 Remaining = mad->Stream.bufend - mad->Stream.next_frame;
118 memmove(mad->input_buf, mad->Stream.next_frame, Remaining);
119 ReadStart = mad->input_buf + Remaining;
120 ReadSize = INPUT_BUFFER_SIZE - Remaining;
121 }
122 else {
123 ReadSize = INPUT_BUFFER_SIZE;
124 ReadStart = mad->input_buf;
125 Remaining = 0;
126 }
127
128 ReadSize = SDL_RWread(mad->src, ReadStart, 1, ReadSize);
129 if (ReadSize <= 0) break;
130
131 // end of stream
132
133 mad_stream_buffer(&mad->Stream, mad->input_buf, ReadSize + Remaining);
134 mad->Stream.error = MAD_ERROR_NONE;
135 }
136
137 if (mad_frame_decode(&mad->Frame, &mad->Stream)) {
138 if (MAD_RECOVERABLE(mad->Stream.error)
139 || mad->Stream.error == MAD_ERROR_BUFLEN) {
140 continue;
141 }
142 else {
143 fprintf(stderr, "unrecoverable frame level error (%s).\n",
144 mad_stream_errorstr(&mad->Stream));
145 return 0; // error
146 }
147 }
148
149 #if defined (PDA) && !defined (PSP)
150 if (mad->Frame.header.samplerate == 44100)
151 mad->Frame.options |= MAD_OPTION_HALFSAMPLERATE;
152
153 #endif
154 mad_synth_frame(&mad->Synth, &mad->Frame);
155
156 char* ptr = (char*) mad->output_buf + mad->output_buf_index;
157
158 for (int i = 0; i < mad->Synth.pcm.length; i++) {
159 unsigned short Sample;
160
161 /* Left channel */
162 Sample = MadFixedToUshort(mad->Synth.pcm.samples[0][i]);
163 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
164 *(ptr++) = Sample & 0xff;
165 *(ptr++) = Sample >> 8;
166 #else
167 *(ptr++) = Sample >> 8;
168 *(ptr++) = Sample & 0xff;
169 #endif
170
171 /* Right channel, if exist. */
172 if (MAD_NCHANNELS(&mad->Frame.header) == 2)
173 Sample = MadFixedToUshort(mad->Synth.pcm.samples[1][i]);
174
175 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
176 *(ptr++) = Sample & 0xff;
177 *(ptr++) = Sample >> 8;
178 #else
179 *(ptr++) = Sample >> 8;
180 *(ptr++) = Sample & 0xff;
181 #endif
182 }
183
184 mad->output_buf_index += mad->Synth.pcm.length * 4;
185 }
186 while (mad->output_buf_index < len);
187
188 if (ReadSize <= 0) return 0;
189
190 // end of stream
191
192 if (mad->output_buf_index > len) {
193 SDL_MixAudio(stream, mad->output_buf, len, mad->volume);
194 memmove(mad->output_buf, mad->output_buf + len, mad->output_buf_index - len);
195 mad->output_buf_index -= len;
196 }
197 else {
198 SDL_MixAudio(stream, mad->output_buf, mad->output_buf_index, mad->volume);
199 len = mad->output_buf_index;
200 mad->output_buf_index = 0;
201 }
202
203 return len;
204 }
205
206
MAD_WRAPPER_play(MAD_WRAPPER * mad)207 void MAD_WRAPPER_play(MAD_WRAPPER* mad)
208 {
209 mad->is_playing = true;
210 }
211
212
MAD_WRAPPER_stop(MAD_WRAPPER * mad)213 void MAD_WRAPPER_stop(MAD_WRAPPER* mad)
214 {
215 mad->is_playing = false;
216 }
217
218
MAD_WRAPPER_delete(MAD_WRAPPER * mad)219 void MAD_WRAPPER_delete(MAD_WRAPPER* mad)
220 {
221 mad_synth_finish(&mad->Synth);
222 mad_frame_finish(&mad->Frame);
223 mad_stream_finish(&mad->Stream);
224
225 delete[] mad->input_buf;
226 delete[] mad->output_buf;
227 SDL_FreeRW(mad->src);
228 delete mad;
229 }
230
231
MAD_WRAPPER_setvolume(MAD_WRAPPER * mad,int volume)232 void MAD_WRAPPER_setvolume(MAD_WRAPPER* mad, int volume)
233 {
234 if ((volume >= 0) && (volume <= 100)) {
235 mad->volume = (volume * SDL_MIX_MAXVOLUME) / 100;
236 }
237 }
238
239
MAD_WRAPPER_error(MAD_WRAPPER * mad)240 const char* MAD_WRAPPER_error(MAD_WRAPPER* mad)
241 {
242 if (mad) return NULL;
243
244 return "Mad open error";
245 }
246
247
248 #ifdef DEBUG_MAD
mp3callback(void * userdata,Uint8 * stream,int len)249 void mp3callback(void* userdata, Uint8* stream, int len)
250 {
251 if (MAD_WRAPPER_playAudio(userdata, stream, len) == 0) {
252 printf("end of file\n");
253 exit(0);
254 }
255 }
256
257
main(void)258 int main(void)
259 {
260 if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO) < 0) {
261 fprintf(stderr,
262 "Couldn't initialize SDL: %s\n", SDL_GetError());
263 exit(1);
264 }
265
266 SDL_AudioSpec audio_format;
267
268 MAD_WRAPPER* mad = MAD_WRAPPER_new("travel.mp3", NULL, 0);
269
270 MAD_WRAPPER_play(mad);
271 Mix_HookMusic(mp3callback, mad);
272
273 if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF) < 0) {
274 fprintf(stderr, "Couldn't open audio device!\n"
275 " reason: [%s].\n", SDL_GetError());
276 exit(-1);
277 }
278 else {
279 int freq;
280 Uint16 format;
281 int channels;
282
283 Mix_QuerySpec(&freq, &format, &channels);
284 printf("Audio: %d Hz %d bit %s\n", freq,
285 (format & 0xFF),
286 (channels > 1) ? "stereo" : "mono");
287 audio_format.format = format;
288 audio_format.freq = freq;
289 audio_format.channels = channels;
290 }
291
292 getchar();
293 MAD_WRAPPER_stop(mad);
294 MAD_WRAPPER_delete(mad);
295 }
296
297
298 #endif
299