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