14
|
1 /*
|
|
2 * SDL_sound -- An abstract sound format decoding API.
|
|
3 * Copyright (C) 2001 Ryan C. Gordon.
|
|
4 *
|
|
5 * This library is free software; you can redistribute it and/or
|
|
6 * modify it under the terms of the GNU Lesser General Public
|
|
7 * License as published by the Free Software Foundation; either
|
|
8 * version 2.1 of the License, or (at your option) any later version.
|
|
9 *
|
|
10 * This library is distributed in the hope that it will be useful,
|
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13 * Lesser General Public License for more details.
|
|
14 *
|
|
15 * You should have received a copy of the GNU Lesser General Public
|
|
16 * License along with this library; if not, write to the Free Software
|
|
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
18 */
|
|
19
|
|
20 /*
|
|
21 * MPEG-1 Layer 3, or simply, "MP3", decoder for SDL_sound.
|
|
22 *
|
|
23 * This driver handles all those highly compressed songs you stole through
|
|
24 * Napster. :) It depends on the SMPEG library for decoding, which can
|
|
25 * be grabbed from: http://www.lokigames.com/development/smpeg.php3
|
|
26 *
|
|
27 * Please see the file LICENSE in the source's root directory.
|
|
28 *
|
|
29 * This file written by Ryan C. Gordon. (icculus@clutteredmind.org)
|
|
30 */
|
|
31
|
|
32 #include <stdio.h>
|
|
33 #include <stdlib.h>
|
|
34 #include <string.h>
|
|
35 #include <assert.h>
|
|
36
|
|
37 #include "smpeg.h"
|
|
38 #include "SDL_sound.h"
|
|
39 #include "extra_rwops.h"
|
|
40
|
|
41 #define __SDL_SOUND_INTERNAL__
|
|
42 #include "SDL_sound_internal.h"
|
|
43
|
|
44 #if (!defined SOUND_SUPPORTS_MP3)
|
|
45 #error SOUND_SUPPORTS_MP3 must be defined.
|
|
46 #endif
|
|
47
|
|
48
|
|
49 static int MP3_open(Sound_Sample *sample, const char *ext);
|
|
50 static void MP3_close(Sound_Sample *sample);
|
|
51 static Uint32 MP3_read(Sound_Sample *sample);
|
|
52
|
|
53 const Sound_DecoderFunctions __Sound_DecoderFunctions_MP3 =
|
|
54 {
|
|
55 {
|
|
56 "MP3",
|
|
57 "MPEG-1 Layer 3 audio through SMPEG",
|
|
58 "Ryan C. Gordon <icculus@clutteredmind.org>",
|
|
59 "http://www.icculus.org/SDL_sound/"
|
|
60 },
|
|
61
|
|
62 MP3_open, /* open() method */
|
|
63 MP3_close, /* close() method */
|
|
64 MP3_read /* read() method */
|
|
65 };
|
|
66
|
|
67 static __inline__ void output_version(void)
|
|
68 {
|
|
69 static int first_time = 1;
|
|
70
|
|
71 if (first_time)
|
|
72 {
|
|
73 SMPEG_version v;
|
|
74 SMPEG_VERSION(&v);
|
|
75 _D(("MP3: Compiled against SMPEG v%d.%d.%d.\n",
|
|
76 v.major, v.minor, v.patch));
|
|
77 first_time = 0;
|
|
78 } /* if */
|
|
79 } /* output_version */
|
|
80
|
|
81
|
|
82 static int MP3_open(Sound_Sample *sample, const char *ext)
|
|
83 {
|
|
84 SMPEG *smpeg;
|
|
85 SMPEG_Info smpeg_info;
|
|
86 SDL_AudioSpec spec;
|
|
87 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
|
88 SDL_RWops *refCounter;
|
|
89
|
|
90 output_version();
|
|
91
|
|
92 refCounter = RWops_RWRefCounter_new(internal->rw);
|
|
93 if (refCounter == NULL)
|
|
94 {
|
|
95 _D(("MP3: Failed to create reference counting RWops.\n"));
|
|
96 return(0);
|
|
97 } /* if */
|
|
98
|
|
99 /* replace original RWops. This is safe. Honest. :) */
|
|
100 internal->rw = refCounter;
|
|
101
|
|
102 /*
|
|
103 * increment the refcount, since SMPEG will nuke the RWops if it can't
|
|
104 * accept the contained data...
|
|
105 */
|
|
106 RWops_RWRefCounter_addRef(refCounter);
|
|
107 smpeg = SMPEG_new_rwops(refCounter, &smpeg_info, 0);
|
|
108
|
|
109 if (SMPEG_error(smpeg))
|
|
110 {
|
|
111 Sound_SetError(SMPEG_error(smpeg));
|
|
112 SMPEG_delete(smpeg);
|
|
113 return(0);
|
|
114 } /* if */
|
|
115
|
|
116 if (!smpeg_info.has_audio)
|
|
117 {
|
|
118 Sound_SetError("MP3: No audio stream found in data.");
|
|
119 SMPEG_delete(smpeg);
|
|
120 return(0);
|
|
121 } /* if */
|
|
122
|
|
123 _D(("MP3: Accepting data stream.\n"));
|
|
124 _D(("MP3: has_audio == %s.\n", smpeg_info.has_audio ? "TRUE" : "FALSE"));
|
|
125 _D(("MP3: has_video == %s.\n", smpeg_info.has_video ? "TRUE" : "FALSE"));
|
|
126 _D(("MP3: width == %d.\n", smpeg_info.width));
|
|
127 _D(("MP3: height == %d.\n", smpeg_info.height));
|
|
128 _D(("MP3: current_frame == %d.\n", smpeg_info.current_frame));
|
|
129 _D(("MP3: current_fps == %f.\n", smpeg_info.current_fps));
|
|
130 _D(("MP3: audio_string == [%s].\n", smpeg_info.audio_string));
|
|
131 _D(("MP3: audio_current_frame == %d.\n", smpeg_info.audio_current_frame));
|
|
132 _D(("MP3: current_offset == %d.\n", smpeg_info.current_offset));
|
|
133 _D(("MP3: total_size == %d.\n", smpeg_info.total_size));
|
|
134 _D(("MP3: current_time == %f.\n", smpeg_info.current_time));
|
|
135 _D(("MP3: total_time == %f.\n", smpeg_info.total_time));
|
|
136
|
|
137 SMPEG_enablevideo(smpeg, 0);
|
|
138 SMPEG_enableaudio(smpeg, 1);
|
|
139 SMPEG_loop(smpeg, 0);
|
|
140
|
|
141 SMPEG_wantedSpec(smpeg, &spec);
|
|
142 sample->actual.format = spec.format;
|
|
143 sample->actual.rate = spec.freq;
|
|
144 sample->actual.channels = spec.channels;
|
|
145 sample->flags = SOUND_SAMPLEFLAG_NONE;
|
|
146 internal->decoder_private = smpeg;
|
|
147
|
|
148 SMPEG_play(smpeg);
|
|
149 return(1);
|
|
150 } /* MP3_open */
|
|
151
|
|
152
|
|
153 static void MP3_close(Sound_Sample *sample)
|
|
154 {
|
|
155 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
|
156 SMPEG_delete((SMPEG *) internal->decoder_private);
|
|
157 } /* MP3_close */
|
|
158
|
|
159
|
|
160 static Uint32 MP3_read(Sound_Sample *sample)
|
|
161 {
|
|
162 Uint32 retval;
|
|
163 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
|
|
164 SMPEG *smpeg = (SMPEG *) internal->decoder_private;
|
|
165
|
|
166 retval = SMPEG_playAudio(smpeg, internal->buffer, internal->buffer_size);
|
|
167 if (retval < internal->buffer_size)
|
|
168 {
|
|
169 char *errMsg = SMPEG_error(smpeg);
|
|
170 if (errMsg == NULL)
|
|
171 sample->flags |= SOUND_SAMPLEFLAG_EOF;
|
|
172 else
|
|
173 {
|
|
174 Sound_SetError(errMsg);
|
|
175 sample->flags |= SOUND_SAMPLEFLAG_ERROR;
|
|
176 } /* else */
|
|
177 } /* if */
|
|
178
|
|
179 return(retval);
|
|
180 } /* MP3_read */
|
|
181
|
|
182 /* end of mp3.c ... */
|
|
183
|