1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *
8  *  Copyright (C) 2011 by
9  *  Nicholai Main
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
13  *  as published by the Free Software Foundation; either version 2
14  *  of the 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
19  *  GNU 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  * DESCRIPTION:
27  *
28  *---------------------------------------------------------------------
29  */
30 
31 
32 
33 #include "config.h"
34 
35 #include "musicplayer.h"
36 
37 #ifndef HAVE_LIBMAD
38 #include <string.h>
39 
mp_name(void)40 static const char *mp_name (void)
41 {
42   return "mad mp3 player (DISABLED)";
43 }
44 
45 
mp_init(int samplerate)46 static int mp_init (int samplerate)
47 {
48   return 0;
49 }
50 
51 const music_player_t mp_player =
52 {
53   mp_name,
54   mp_init,
55   NULL,
56   NULL,
57   NULL,
58   NULL,
59   NULL,
60   NULL,
61   NULL,
62   NULL,
63   NULL
64 };
65 
66 #else // HAVE_LIBMAD
67 
68 
69 #include <stdlib.h>
70 #include <string.h>
71 #include "lprintf.h"
72 
73 #include "../libmad/mad.h"
74 
75 #include "i_sound.h"
76 
77 static struct mad_stream Stream;
78 static struct mad_frame  Frame;
79 static struct mad_synth  Synth;
80 static struct mad_header Header;
81 
82 
83 static int mp_looping = 0;
84 static int mp_volume = 0; // 0-15
85 static int mp_samplerate_target = 0;
86 static int mp_paused = 0;
87 static int mp_playing = 0;
88 
89 static const void *mp_data;
90 static int mp_len;
91 
92 
93 static int mp_leftoversamps = 0; // number of extra samples
94                                  // left over in mad decoder
95 static int mp_leftoversamppos = 0;
96 
97 
mp_name(void)98 static const char *mp_name (void)
99 {
100   return "mad mp3 player";
101 }
102 
103 
mp_init(int samplerate)104 static int mp_init (int samplerate)
105 {
106   mad_stream_init (&Stream);
107   mad_frame_init (&Frame);
108   mad_synth_init (&Synth);
109   mad_header_init (&Header);
110   mp_samplerate_target = samplerate;
111   return 1;
112 }
113 
mp_shutdown(void)114 static void mp_shutdown (void)
115 {
116 
117   mad_synth_finish (&Synth);
118   mad_frame_finish (&Frame);
119   mad_stream_finish (&Stream);
120   mad_header_finish (&Header);
121 }
122 
mp_registersong(const void * data,unsigned len)123 static const void *mp_registersong (const void *data, unsigned len)
124 {
125   int i;
126   int maxtry;
127   int success = 0;
128 
129   // the MP3 standard doesn't include any global file header.  the only way to tell filetype
130   // is to start decoding stuff.  you can't be too strict however because MP3 is resilient to
131   // crap in the stream.
132 
133   // this routine is a bit slower than it could be, but apparently there are lots of files out
134   // there with some dodgy stuff at the beginning.
135 
136   // if the stream begins with an ID3v2 magic, search hard and long for our first valid header
137   if (memcmp (data, "ID3", 3) == 0)
138     maxtry = 100;
139   // otherwise, search for not so long
140   else
141     maxtry = 20;
142 
143   mad_stream_buffer (&Stream, data, len);
144 
145   for (i = 0; i < maxtry; i++)
146   {
147     if (mad_header_decode (&Header, &Stream) != 0)
148     {
149       if (!MAD_RECOVERABLE (Stream.error))
150       {
151         lprintf (LO_WARN, "mad_registersong failed: %s\n", mad_stream_errorstr (&Stream));
152         return NULL;
153       }
154     }
155     else
156     {
157       success++;
158     }
159   }
160 
161   // 80% to pass
162   if (success < maxtry * 8 / 10)
163   {
164     lprintf (LO_WARN, "mad_registersong failed\n");
165     return NULL;
166   }
167 
168   lprintf (LO_INFO, "mad_registersong succeed. bitrate %lu samplerate %d\n", Header.bitrate, Header.samplerate);
169 
170   mp_data = data;
171   mp_len = len;
172   // handle not used
173   return data;
174 }
175 
mp_setvolume(int v)176 static void mp_setvolume (int v)
177 {
178   mp_volume = v;
179 }
180 
mp_pause(void)181 static void mp_pause (void)
182 {
183   mp_paused = 1;
184 }
185 
mp_resume(void)186 static void mp_resume (void)
187 {
188   mp_paused = 0;
189 }
190 
mp_unregistersong(const void * handle)191 static void mp_unregistersong (const void *handle)
192 { // nothing to do
193   mp_data = NULL;
194   mp_playing = 0;
195 }
196 
mp_play(const void * handle,int looping)197 static void mp_play (const void *handle, int looping)
198 {
199   mad_stream_buffer (&Stream, mp_data, mp_len);
200 
201   mp_playing = 1;
202   mp_looping = looping;
203   mp_leftoversamps = 0;
204   mp_leftoversamppos = 0;
205 }
206 
mp_stop(void)207 static void mp_stop (void)
208 {
209   mp_playing = 0;
210 }
211 
212 // convert from mad's internal fixed point representation
mp_fixtoshort(mad_fixed_t f)213 static INLINE short mp_fixtoshort (mad_fixed_t f)
214 {
215   // clip
216   if (f < -MAD_F_ONE)
217     f = -MAD_F_ONE;
218   if (f > MAD_F_ONE)
219     f = MAD_F_ONE;
220   // apply volume before conversion to 16bit
221   f /= 15;
222   f *= mp_volume;
223   f >>= (MAD_F_FRACBITS - 15);
224 
225   return (short) f;
226 }
227 
mp_render_ex(void * dest,unsigned nsamp)228 static void mp_render_ex (void *dest, unsigned nsamp)
229 {
230   short *sout = (short *) dest;
231 
232   int localerrors = 0;
233 
234   if (!mp_playing || mp_paused)
235   {
236     memset (dest, 0, nsamp * 4);
237     return;
238   }
239 
240   while (1)
241   {
242     // write any leftover data from last MP3 frame
243     while (mp_leftoversamps > 0 && nsamp > 0)
244     {
245       short s = mp_fixtoshort (Synth.pcm.samples[0][mp_leftoversamppos]);
246       *sout++ = s;
247       if (Synth.pcm.channels == 2)
248         s = mp_fixtoshort (Synth.pcm.samples[1][mp_leftoversamppos]);
249       // if mono, just duplicate the first channel again
250       *sout++ = s;
251 
252       mp_leftoversamps -= 1;
253       mp_leftoversamppos += 1;
254       nsamp -= 1;
255     }
256     if (nsamp == 0)
257       return; // done
258 
259     // decode next valid MP3 frame
260     while (mad_frame_decode (&Frame, &Stream) != 0)
261     {
262       if (MAD_RECOVERABLE (Stream.error))
263       { // unspecified problem with one frame.
264         // try the next frame, but bail if we get a bunch of crap in a row;
265         // likely indicates a larger problem (and if we don't bail, we could
266         // spend arbitrarily long amounts of time looking for the next good
267         // packet)
268         localerrors++;
269         if (localerrors == 10)
270         {
271           lprintf (LO_WARN, "mad_frame_decode: Lots of errors.  Most recent %s\n", mad_stream_errorstr (&Stream));
272           mp_playing = 0;
273           memset (sout, 0, nsamp * 4);
274           return;
275         }
276       }
277       else if (Stream.error == MAD_ERROR_BUFLEN)
278       { // EOF
279         // FIXME: in order to not drop the last frame, there must be at least MAD_BUFFER_GUARD
280         // of extra bytes (with value 0) at the end of the file.  current implementation
281         // drops last frame
282         if (mp_looping)
283         { // rewind, then go again
284           mad_stream_buffer (&Stream, mp_data, mp_len);
285           continue;
286         }
287         else
288         { // stop
289           mp_playing = 0;
290           memset (sout, 0, nsamp * 4);
291           return;
292         }
293       }
294       else
295       { // oh well.
296         lprintf (LO_WARN, "mad_frame_decode: Unrecoverable error %s\n", mad_stream_errorstr (&Stream));
297         mp_playing = 0;
298         memset (sout, 0, nsamp * 4);
299         return;
300       }
301     }
302 
303     // got a good frame, so synth it and dispatch it.
304     mad_synth_frame (&Synth, &Frame);
305     mp_leftoversamps = Synth.pcm.length;
306     mp_leftoversamppos = 0;
307 
308   }
309   // NOT REACHED
310 }
311 
312 void I_ResampleStream (void *dest, unsigned nsamp, void (*proc)(void *dest, unsigned nsamp),
313       unsigned sratein, unsigned srateout);
314 
mp_render(void * dest,unsigned nsamp)315 static void mp_render (void *dest, unsigned nsamp)
316 {
317   I_ResampleStream (dest, nsamp, mp_render_ex, Header.samplerate, mp_samplerate_target);
318 }
319 
320 
321 const music_player_t mp_player =
322 {
323   mp_name,
324   mp_init,
325   mp_shutdown,
326   mp_setvolume,
327   mp_pause,
328   mp_resume,
329   mp_registersong,
330   mp_unregistersong,
331   mp_play,
332   mp_stop,
333   mp_render
334 };
335 
336 #endif // HAVE_LIBMAD
337