1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: snd_mp3.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include <mad.h>
29
30 #include "gamedefs.h"
31 #include "snd_local.h"
32
33 // MACROS ------------------------------------------------------------------
34
35 // TYPES -------------------------------------------------------------------
36
37 class VMp3AudioCodec : public VAudioCodec
38 {
39 public:
40 enum { INPUT_BUFFER_SIZE = 5 * 8192 };
41
42 VStream* Strm;
43 bool FreeStream;
44 int BytesLeft;
45 bool Initialised;
46
47 mad_stream Stream;
48 mad_frame Frame;
49 mad_synth Synth;
50 byte InputBuffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
51 int FramePos;
52 bool HaveFrame;
53
54 VMp3AudioCodec(VStream*, bool);
55 ~VMp3AudioCodec();
56 bool Init();
57 int Decode(short*, int);
58 int ReadData();
59 bool Finished();
60 void Restart();
61 static VAudioCodec* Create(VStream*);
62 };
63
64 class VMp3SampleLoader : public VSampleLoader
65 {
66 public:
67 void Load(sfxinfo_t&, VStream&);
68 };
69
70 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
71
72 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
73
74 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
75
76 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
77
78 // PUBLIC DATA DEFINITIONS -------------------------------------------------
79
80 // PRIVATE DATA DEFINITIONS ------------------------------------------------
81
82 IMPLEMENT_AUDIO_CODEC(VMp3AudioCodec, "MP3");
83
84 VMp3SampleLoader Mp3SampleLoader;
85
86 // CODE --------------------------------------------------------------------
87
88 //==========================================================================
89 //
90 // VMp3AudioCodec::VMp3AudioCodec
91 //
92 //==========================================================================
93
VMp3AudioCodec(VStream * AStrm,bool AFreeStream)94 VMp3AudioCodec::VMp3AudioCodec(VStream* AStrm, bool AFreeStream)
95 : Strm(AStrm)
96 , FreeStream(AFreeStream)
97 , Initialised(false)
98 {
99 guard(VMp3AudioCodec::VMp3AudioCodec);
100 // Seek file to the begining
101 BytesLeft = Strm->TotalSize();
102 Strm->Seek(0);
103
104 // Initialise structures used by libmad
105 mad_stream_init(&Stream);
106 mad_frame_init(&Frame);
107 mad_synth_init(&Synth);
108 unguard;
109 }
110
111 //==========================================================================
112 //
113 // VMp3AudioCodec::~VMp3AudioCodec
114 //
115 //==========================================================================
116
~VMp3AudioCodec()117 VMp3AudioCodec::~VMp3AudioCodec()
118 {
119 guard(VMp3AudioCodec::~VMp3AudioCodec);
120 if (Initialised)
121 {
122 // Close file only if decoder has been initialised succesfully.
123 if (FreeStream)
124 {
125 Strm->Close();
126 delete Strm;
127 }
128 Strm = NULL;
129 }
130 // Clear structs used by libmad.
131 mad_synth_finish(&Synth);
132 mad_frame_finish(&Frame);
133 mad_stream_finish(&Stream);
134 unguard;
135 }
136
137 //==========================================================================
138 //
139 // VMp3AudioCodec::Init
140 //
141 //==========================================================================
142
Init()143 bool VMp3AudioCodec::Init()
144 {
145 guard(VMp3AudioCodec::Init);
146
147 // Check for ID3v2 header.
148 byte Id3Hdr[10];
149 int SavedPos = Strm->Tell();
150 Strm->Serialise(Id3Hdr, 10);
151 if (Id3Hdr[0] == 'I' && Id3Hdr[1] == 'D' && Id3Hdr[2] == '3')
152 {
153 // It's a ID3v3 header, skip it.
154 int HdrSize = Id3Hdr[9] + (Id3Hdr[8] << 7) + (Id3Hdr[7] << 14) +
155 (Id3Hdr[6] << 21);
156 if (HdrSize + 10 > BytesLeft)
157 return false;
158 Strm->Seek(Strm->Tell() + HdrSize);
159 BytesLeft -= 10 + HdrSize;
160 }
161 else
162 {
163 // Not a ID3v3 header, seek back to saved position.
164 Strm->Seek(SavedPos);
165 }
166
167 // Read some data.
168 ReadData();
169
170 // Decode first frame. If this fails we assume it's not a MP3 file.
171 if (mad_frame_decode(&Frame, &Stream))
172 {
173 // Not a valid stream.
174 return false;
175 }
176
177 // We are ready to read data.
178 mad_synth_frame(&Synth, &Frame);
179 FramePos = 0;
180 HaveFrame = true;
181
182 // Everything's OK.
183 SampleRate = Frame.header.samplerate;
184 Initialised = true;
185 return true;
186 unguard;
187 }
188
189 //==========================================================================
190 //
191 // VMp3AudioCodec::Decode
192 //
193 //==========================================================================
194
Decode(short * Data,int NumSamples)195 int VMp3AudioCodec::Decode(short* Data, int NumSamples)
196 {
197 guard(VMp3AudioCodec::Decode);
198 int CurSample = 0;
199 do
200 {
201 if (HaveFrame)
202 {
203 // Convert stream from fixed point to short.
204 for (; FramePos < Synth.pcm.length; FramePos++)
205 {
206 // Left channel
207 short Sample;
208 mad_fixed_t Fixed = Synth.pcm.samples[0][FramePos];
209 if (Fixed >= MAD_F_ONE)
210 Sample = 0x7fff;
211 else if (Fixed <= -MAD_F_ONE)
212 Sample = -0x7fff;
213 else
214 Sample = Fixed >> (MAD_F_FRACBITS - 15);
215 Data[CurSample * 2] = Sample;
216
217 // Right channel. If the decoded stream is monophonic then
218 // the right output channel is the same as the left one.
219 if (MAD_NCHANNELS(&Frame.header) == 2)
220 {
221 Fixed = Synth.pcm.samples[1][FramePos];
222 if (Fixed >= MAD_F_ONE)
223 Sample = 0x7fff;
224 else if (Fixed <= -MAD_F_ONE)
225 Sample = -0x7fff;
226 else
227 Sample = Fixed >> (MAD_F_FRACBITS - 15);
228 }
229 Data[CurSample * 2 + 1] = Sample;
230 CurSample++;
231 // Check if we already have decoded enough.
232 if (CurSample >= NumSamples)
233 return CurSample;
234 }
235 // We are done with the frame.
236 HaveFrame = false;
237 }
238
239 // Fill in input buffer if it becomes empty.
240 if (Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN)
241 {
242 if (!ReadData())
243 break;
244 }
245
246 // Decode the next frame.
247 if (mad_frame_decode(&Frame, &Stream))
248 {
249 if (MAD_RECOVERABLE(Stream.error) ||
250 Stream.error==MAD_ERROR_BUFLEN)
251 {
252 continue;
253 }
254 else
255 {
256 break;
257 }
258 }
259
260 // Once decoded the frame is synthesized to PCM samples.
261 mad_synth_frame(&Synth, &Frame);
262 FramePos = 0;
263 HaveFrame = true;
264 } while(1);
265 return CurSample;
266 unguard;
267 }
268
269 //==========================================================================
270 //
271 // VMp3AudioCodec::ReadData
272 //
273 //==========================================================================
274
ReadData()275 int VMp3AudioCodec::ReadData()
276 {
277 guard(VMp3AudioCodec::ReadData);
278 int ReadSize;
279 int Remaining;
280 byte* ReadStart;
281
282 // If there are some bytes left, move them to the beginning of the
283 // buffer.
284 if (Stream.next_frame != NULL)
285 {
286 Remaining = Stream.bufend - Stream.next_frame;
287 memmove(InputBuffer, Stream.next_frame, Remaining);
288 ReadStart = InputBuffer + Remaining;
289 ReadSize = INPUT_BUFFER_SIZE - Remaining;
290 }
291 else
292 {
293 ReadSize = INPUT_BUFFER_SIZE;
294 ReadStart = InputBuffer;
295 Remaining = 0;
296 }
297 // Fill-in the buffer.
298 if (ReadSize > BytesLeft)
299 ReadSize = BytesLeft;
300 if (!ReadSize)
301 return 0;
302 Strm->Serialise(ReadStart, ReadSize);
303 BytesLeft -= ReadSize;
304
305 // When decoding the last frame of a file, it must be followed by
306 // MAD_BUFFER_GUARD zero bytes if one wants to decode that last frame.
307 if (!BytesLeft)
308 {
309 memset(ReadStart + ReadSize + Remaining, 0, MAD_BUFFER_GUARD);
310 ReadSize += MAD_BUFFER_GUARD;
311 }
312
313 // Pipe the new buffer content to libmad's stream decoder facility.
314 mad_stream_buffer(&Stream, InputBuffer, ReadSize + Remaining);
315 Stream.error = MAD_ERROR_NONE;
316 return ReadSize + Remaining;
317 unguard;
318 }
319
320 //==========================================================================
321 //
322 // VMp3AudioCodec::Finished
323 //
324 //==========================================================================
325
Finished()326 bool VMp3AudioCodec::Finished()
327 {
328 guard(VMp3AudioCodec::Finished);
329 // We are done if there's no more data and last frame has been decoded.
330 return !BytesLeft && !HaveFrame;
331 unguard;
332 }
333
334 //==========================================================================
335 //
336 // VMp3AudioCodec::Restart
337 //
338 //==========================================================================
339
Restart()340 void VMp3AudioCodec::Restart()
341 {
342 guard(VMp3AudioCodec::Restart);
343 // Seek to the beginning of the file.
344 Strm->Seek(0);
345 BytesLeft = Strm->TotalSize();
346 unguard;
347 }
348
349 //==========================================================================
350 //
351 // VMp3AudioCodec::Create
352 //
353 //==========================================================================
354
Create(VStream * InStrm)355 VAudioCodec* VMp3AudioCodec::Create(VStream* InStrm)
356 {
357 guard(VMp3AudioCodec::Create);
358 VMp3AudioCodec* Codec = new VMp3AudioCodec(InStrm, true);
359 if (!Codec->Init())
360 {
361 delete Codec;
362 Codec = NULL;
363 return NULL;
364 }
365 return Codec;
366 unguard;
367 }
368
369 //==========================================================================
370 //
371 // VMp3SampleLoader::Create
372 //
373 //==========================================================================
374
Load(sfxinfo_t & Sfx,VStream & Stream)375 void VMp3SampleLoader::Load(sfxinfo_t& Sfx, VStream& Stream)
376 {
377 guard(VMp3SampleLoader::Load);
378 VMp3AudioCodec* Codec = new VMp3AudioCodec(&Stream, false);
379 if (!Codec->Init())
380 {
381 delete Codec;
382 Codec = NULL;
383 return;
384 }
385
386 TArray<short> Data;
387 do
388 {
389 short Buf[16 * 2048];
390 int SamplesDecoded = Codec->Decode(Buf, 16 * 1024);
391 if (SamplesDecoded > 0)
392 {
393 int OldPos = Data.Num();
394 Data.SetNumWithReserve(Data.Num() + SamplesDecoded);
395 for (int i = 0; i < SamplesDecoded; i++)
396 {
397 Data[OldPos + i] = Buf[i * 2];
398 }
399 }
400 }
401 while (!Codec->Finished());
402 if (!Data.Num())
403 {
404 delete Codec;
405 Codec = NULL;
406 return;
407 }
408
409 // Copy parameters.
410 Sfx.SampleRate = Codec->SampleRate;
411 Sfx.SampleBits = Codec->SampleBits;
412
413 // Copy data.
414 Sfx.DataSize = Data.Num() * 2;
415 Sfx.Data = Z_Malloc(Data.Num() * 2);
416 memcpy(Sfx.Data, Data.Ptr(), Data.Num() * 2);
417
418 delete Codec;
419 Codec = NULL;
420 unguard;
421 }
422