1 /*
2 * SampleFormatMP3.cpp
3 * -------------------
4 * Purpose: MP3 sample import.
5 * Notes :
6 * Authors: OpenMPT Devs
7 * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8 */
9
10
11 #include "stdafx.h"
12 #include "Sndfile.h"
13 #ifndef MODPLUG_NO_FILESAVE
14 #include "../common/mptFileIO.h"
15 #endif
16 #include "../common/misc_util.h"
17 #include "Tagging.h"
18 #include "Loaders.h"
19 #include "../common/FileReader.h"
20 #include "modsmp_ctrl.h"
21 #include "openmpt/soundbase/Copy.hpp"
22 #include "../soundlib/ModSampleCopy.h"
23 #include "../common/ComponentManager.h"
24 #ifdef MPT_ENABLE_MP3_SAMPLES
25 #include "MPEGFrame.h"
26 #endif // MPT_ENABLE_MP3_SAMPLES
27 #if defined(MPT_WITH_MINIMP3)
28 #include <minimp3/minimp3.h>
29 #endif // MPT_WITH_MINIMP3
30
31 // mpg123 must be last because of mpg123 large file support insanity
32 #if defined(MPT_WITH_MPG123)
33
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37
38 #include <mpg123.h>
39
40 #endif
41
42
43 OPENMPT_NAMESPACE_BEGIN
44
45
46 ///////////////////////////////////////////////////////////////////////////////////////////////////
47 // MP3 Samples
48
49 #if defined(MPT_WITH_MPG123)
50
51 typedef off_t mpg123_off_t;
52
53 typedef size_t mpg123_size_t;
54
55 // Check for exactly _MSC_VER as libmpg123 does, in order to also catch clang-cl.
56 #ifdef _MSC_VER
57 // ssize_t definition in libmpg123.h.in should never have existed at all.
58 // It got removed from libmpg23.h.in after 1.28.0 and before 1.28.1.
59 typedef ptrdiff_t mpg123_ssize_t;
60 #else
61 typedef ssize_t mpg123_ssize_t;
62 #endif
63
64 class ComponentMPG123
65 : public ComponentBuiltin
66 {
67 MPT_DECLARE_COMPONENT_MEMBERS(ComponentMPG123, "")
68
69 public:
70
FileReaderRead(void * fp,void * buf,mpg123_size_t count)71 static mpg123_ssize_t FileReaderRead(void *fp, void *buf, mpg123_size_t count)
72 {
73 FileReader &file = *static_cast<FileReader *>(fp);
74 std::size_t readBytes = std::min(count, static_cast<size_t>(file.BytesLeft()));
75 file.ReadRaw(mpt::span(mpt::void_cast<std::byte*>(buf), readBytes));
76 return readBytes;
77 }
FileReaderLSeek(void * fp,mpg123_off_t offset,int whence)78 static mpg123_off_t FileReaderLSeek(void *fp, mpg123_off_t offset, int whence)
79 {
80 FileReader &file = *static_cast<FileReader *>(fp);
81 FileReader::off_t oldpos = file.GetPosition();
82 if(whence == SEEK_CUR) file.Seek(file.GetPosition() + offset);
83 else if(whence == SEEK_END) file.Seek(file.GetLength() + offset);
84 else file.Seek(offset);
85 MPT_MAYBE_CONSTANT_IF(!mpt::in_range<mpg123_off_t>(file.GetPosition()))
86 {
87 file.Seek(oldpos);
88 return static_cast<mpg123_off_t>(-1);
89 }
90 return static_cast<mpg123_off_t>(file.GetPosition());
91 }
92
93 public:
ComponentMPG123()94 ComponentMPG123()
95 : ComponentBuiltin()
96 {
97 return;
98 }
DoInitialize()99 bool DoInitialize() override
100 {
101 if(mpg123_init() != 0)
102 {
103 return false;
104 }
105 return true;
106 }
~ComponentMPG123()107 virtual ~ComponentMPG123()
108 {
109 if(IsAvailable())
110 {
111 mpg123_exit();
112 }
113 }
114 };
115
116
ReadMPG123String(const mpg123_string & str)117 static mpt::ustring ReadMPG123String(const mpg123_string &str)
118 {
119 mpt::ustring result;
120 if(!str.p)
121 {
122 return result;
123 }
124 if(str.fill < 1)
125 {
126 return result;
127 }
128 result = mpt::ToUnicode(mpt::Charset::UTF8, std::string(str.p, str.p + str.fill - 1));
129 return result;
130 }
131
ReadMPG123String(const mpg123_string * str)132 static mpt::ustring ReadMPG123String(const mpg123_string *str)
133 {
134 mpt::ustring result;
135 if(!str)
136 {
137 return result;
138 }
139 result = ReadMPG123String(*str);
140 return result;
141 }
142
143 template <std::size_t N>
ReadMPG123String(const char (& str)[N])144 static mpt::ustring ReadMPG123String(const char (&str)[N])
145 {
146 return mpt::ToUnicode(mpt::Charset::ISO8859_1, mpt::String::ReadBuf(mpt::String::spacePadded, str));
147 }
148
149 #endif // MPT_WITH_MPG123
150
151
ReadMP3Sample(SAMPLEINDEX sample,FileReader & file,bool raw,bool mo3Decode)152 bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw, bool mo3Decode)
153 {
154 #if defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3)
155
156 // Check file for validity, or else mpg123 will happily munch many files that start looking vaguely resemble an MPEG stream mid-file.
157 file.Rewind();
158 while(file.CanRead(4))
159 {
160 uint8 magic[3];
161 file.ReadArray(magic);
162
163 if(!memcmp(magic, "ID3", 3))
164 {
165 // Skip ID3 tags
166 uint8 header[7];
167 file.ReadArray(header);
168
169 uint32 size = 0;
170 for(int i = 3; i < 7; i++)
171 {
172 if(header[i] & 0x80)
173 return false;
174 size = (size << 7) | header[i];
175 }
176 file.Skip(size);
177 } else if(!memcmp(magic, "APE", 3) && file.ReadMagic("TAGEX"))
178 {
179 // Skip APE tags
180 uint32 size = file.ReadUint32LE();
181 file.Skip(16 + size);
182 } else if(!memcmp(magic, "\x00\x00\x00", 3) || !memcmp(magic, "\xFF\x00\x00", 3))
183 {
184 // Some MP3 files are padded with zeroes...
185 } else if(magic[0] == 0)
186 {
187 // This might be some padding, followed by an MPEG header, so try again.
188 file.SkipBack(2);
189 } else if(MPEGFrame::IsMPEGHeader(magic))
190 {
191 // This is what we want!
192 break;
193 } else
194 {
195 // This, on the other hand, isn't.
196 return false;
197 }
198 }
199
200 #endif // MPT_WITH_MPG123 || MPT_WITH_MINIMP3
201
202 #if defined(MPT_WITH_MPG123)
203
204 ComponentHandle<ComponentMPG123> mpg123;
205 if(!IsComponentAvailable(mpg123))
206 {
207 return false;
208 }
209
210 struct MPG123Handle
211 {
212 mpg123_handle *mh;
213 MPG123Handle() : mh(mpg123_new(0, nullptr)) { }
214 ~MPG123Handle() { mpg123_delete(mh); }
215 operator mpg123_handle *() { return mh; }
216 };
217
218 bool hasLameXingVbriHeader = false;
219
220 if(!raw)
221 {
222
223 mpg123_off_t length_raw = 0;
224 mpg123_off_t length_hdr = 0;
225
226 // libmpg123 provides no way to determine whether it parsed ID3V2 or VBR tags.
227 // Thus, we use a pre-scan with those disabled and compare the resulting length.
228 // We ignore ID3V2 stream length here, althrough we parse the ID3V2 header.
229 // libmpg123 only accounts for the VBR info frame if gapless &&!ignore_infoframe,
230 // thus we switch both of those for comparison.
231 {
232 MPG123Handle mh;
233 if(!mh)
234 {
235 return false;
236 }
237 file.Rewind();
238 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0))
239 {
240 return false;
241 }
242 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0.0))
243 {
244 return false;
245 }
246 if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0.0))
247 {
248 return false;
249 }
250 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_IGNORE_INFOFRAME, 0.0))
251 {
252 return false;
253 }
254 if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_SKIP_ID3V2, 0.0))
255 {
256 return false;
257 }
258 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_IGNORE_STREAMLENGTH, 0.0))
259 {
260 return false;
261 }
262 if(mpg123_param(mh, MPG123_INDEX_SIZE, -1000, 0.0)) // auto-grow
263 {
264 return false;
265 }
266 if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0))
267 {
268 return false;
269 }
270 if(mpg123_open_handle(mh, &file))
271 {
272 return false;
273 }
274 if(mpg123_scan(mh))
275 {
276 return false;
277 }
278 long rate = 0;
279 int channels = 0;
280 int encoding = 0;
281 if(mpg123_getformat(mh, &rate, &channels, &encoding))
282 {
283 return false;
284 }
285 if((channels != 1 && channels != 2) || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED))
286 {
287 return false;
288 }
289 mpg123_frameinfo frameinfo;
290 MemsetZero(frameinfo);
291 if(mpg123_info(mh, &frameinfo))
292 {
293 return false;
294 }
295 if(frameinfo.layer < 1 || frameinfo.layer > 3)
296 {
297 return false;
298 }
299 if(mpg123_param(mh, MPG123_FORCE_RATE, rate, 0.0))
300 {
301 return false;
302 }
303 if(mpg123_param(mh, MPG123_ADD_FLAGS, (channels > 1) ? MPG123_FORCE_STEREO : MPG123_FORCE_MONO, 0.0))
304 {
305 return false;
306 }
307 length_raw = mpg123_length(mh);
308 }
309
310 {
311 MPG123Handle mh;
312 if(!mh)
313 {
314 return false;
315 }
316 file.Rewind();
317 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0))
318 {
319 return false;
320 }
321 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0.0))
322 {
323 return false;
324 }
325 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_GAPLESS, 0.0))
326 {
327 return false;
328 }
329 if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_IGNORE_INFOFRAME, 0.0))
330 {
331 return false;
332 }
333 if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_SKIP_ID3V2, 0.0))
334 {
335 return false;
336 }
337 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_IGNORE_STREAMLENGTH, 0.0))
338 {
339 return false;
340 }
341 if(mpg123_param(mh, MPG123_INDEX_SIZE, -1000, 0.0)) // auto-grow
342 {
343 return false;
344 }
345 if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0))
346 {
347 return false;
348 }
349 if(mpg123_open_handle(mh, &file))
350 {
351 return false;
352 }
353 if(mpg123_scan(mh))
354 {
355 return false;
356 }
357 long rate = 0;
358 int channels = 0;
359 int encoding = 0;
360 if(mpg123_getformat(mh, &rate, &channels, &encoding))
361 {
362 return false;
363 }
364 if((channels != 1 && channels != 2) || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED))
365 {
366 return false;
367 }
368 mpg123_frameinfo frameinfo;
369 MemsetZero(frameinfo);
370 if(mpg123_info(mh, &frameinfo))
371 {
372 return false;
373 }
374 if(frameinfo.layer < 1 || frameinfo.layer > 3)
375 {
376 return false;
377 }
378 if(mpg123_param(mh, MPG123_FORCE_RATE, rate, 0.0))
379 {
380 return false;
381 }
382 if(mpg123_param(mh, MPG123_ADD_FLAGS, (channels > 1) ? MPG123_FORCE_STEREO : MPG123_FORCE_MONO, 0.0))
383 {
384 return false;
385 }
386 length_hdr = mpg123_length(mh);
387 }
388
389 hasLameXingVbriHeader = (length_raw != length_hdr);
390
391 }
392
393 // Set up decoder...
394 MPG123Handle mh;
395 if(!mh)
396 {
397 return false;
398 }
399 file.Rewind();
400 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0))
401 {
402 return false;
403 }
404 if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_AUTO_RESAMPLE, 0.0))
405 {
406 return false;
407 }
408 if(mpg123_param(mh, raw ? MPG123_REMOVE_FLAGS : MPG123_ADD_FLAGS, MPG123_GAPLESS, 0.0))
409 {
410 return false;
411 }
412 if(mpg123_param(mh, raw ? MPG123_ADD_FLAGS : MPG123_REMOVE_FLAGS, MPG123_IGNORE_INFOFRAME, 0.0))
413 {
414 return false;
415 }
416 if(mpg123_param(mh, MPG123_REMOVE_FLAGS, MPG123_SKIP_ID3V2, 0.0))
417 {
418 return false;
419 }
420 if(mpg123_param(mh, raw ? MPG123_ADD_FLAGS : MPG123_REMOVE_FLAGS, MPG123_IGNORE_STREAMLENGTH, 0.0))
421 {
422 return false;
423 }
424 if(mpg123_param(mh, MPG123_INDEX_SIZE, -1000, 0.0)) // auto-grow
425 {
426 return false;
427 }
428 if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0))
429 {
430 return false;
431 }
432 if(mpg123_open_handle(mh, &file))
433 {
434 return false;
435 }
436 if(mpg123_scan(mh))
437 {
438 return false;
439 }
440 long rate = 0;
441 int channels = 0;
442 int encoding = 0;
443 if(mpg123_getformat(mh, &rate, &channels, &encoding))
444 {
445 return false;
446 }
447 if((channels != 1 && channels != 2) || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED))
448 {
449 return false;
450 }
451 mpg123_frameinfo frameinfo;
452 MemsetZero(frameinfo);
453 if(mpg123_info(mh, &frameinfo))
454 {
455 return false;
456 }
457 if(frameinfo.layer < 1 || frameinfo.layer > 3)
458 {
459 return false;
460 }
461 // We force samplerate, channels and sampleformat, which in
462 // combination with auto-resample (set above) will cause libmpg123
463 // to stay with the given format even for completely confused
464 // MPG123_FRANKENSTEIN streams.
465 // Note that we cannot rely on mpg123_length() for the way we
466 // decode the mpeg streams because it depends on the actual frame
467 // sample rate instead of the returned sample rate.
468 if(mpg123_param(mh, MPG123_FORCE_RATE, rate, 0.0))
469 {
470 return false;
471 }
472 if(mpg123_param(mh, MPG123_ADD_FLAGS, (channels > 1) ? MPG123_FORCE_STEREO : MPG123_FORCE_MONO, 0.0))
473 {
474 return false;
475 }
476
477 std::vector<int16> data;
478
479 // decoder delay
480 std::size_t data_skip_frames = 0;
481 if(!raw && !hasLameXingVbriHeader)
482 {
483 if(frameinfo.layer == 1)
484 {
485 data_skip_frames = 240 + 1;
486 } else if(frameinfo.layer == 2)
487 {
488 data_skip_frames = 240 + 1;
489 } else if(frameinfo.layer == 3)
490 {
491 data_skip_frames = 528 + 1;
492 }
493 }
494
495 std::vector<std::byte> buf_bytes;
496 std::vector<int16> buf_samples;
497 bool decode_error = false;
498 bool decode_done = false;
499 while(!decode_error && !decode_done)
500 {
501 buf_bytes.resize(mpg123_outblock(mh));
502 buf_samples.resize(buf_bytes.size() / sizeof(int16));
503 mpg123_size_t buf_bytes_decoded = 0;
504 int mpg123_read_result = mpg123_read(mh, mpt::byte_cast<unsigned char*>(buf_bytes.data()), buf_bytes.size(), &buf_bytes_decoded);
505 std::memcpy(buf_samples.data(), buf_bytes.data(), buf_bytes_decoded);
506 mpt::append(data, buf_samples.data(), buf_samples.data() + buf_bytes_decoded / sizeof(int16));
507 if((data.size() / channels) > MAX_SAMPLE_LENGTH)
508 {
509 break;
510 }
511 if(mpg123_read_result == MPG123_OK)
512 {
513 // continue
514 } else if(mpg123_read_result == MPG123_NEW_FORMAT)
515 {
516 // continue
517 } else if(mpg123_read_result == MPG123_DONE)
518 {
519 decode_done = true;
520 } else
521 {
522 decode_error = true;
523 }
524 }
525
526 if((data.size() / channels) > MAX_SAMPLE_LENGTH)
527 {
528 return false;
529 }
530
531 FileTags tags;
532 mpg123_id3v1 *id3v1 = nullptr;
533 mpg123_id3v2 *id3v2 = nullptr;
534 if(mpg123_id3(mh, &id3v1, &id3v2) == MPG123_OK)
535 {
536 if(id3v2)
537 {
538 if(tags.title.empty()) tags.title = ReadMPG123String(id3v2->title);
539 if(tags.artist.empty()) tags.artist = ReadMPG123String(id3v2->artist);
540 if(tags.album.empty()) tags.album = ReadMPG123String(id3v2->album);
541 if(tags.year.empty()) tags.year = ReadMPG123String(id3v2->year);
542 if(tags.genre.empty()) tags.genre = ReadMPG123String(id3v2->genre);
543 if(tags.comments.empty()) tags.comments = ReadMPG123String(id3v2->comment);
544 }
545 if(id3v1)
546 {
547 if(tags.title.empty()) tags.title = ReadMPG123String(id3v1->title);
548 if(tags.artist.empty()) tags.artist = ReadMPG123String(id3v1->artist);
549 if(tags.album.empty()) tags.album = ReadMPG123String(id3v1->album);
550 if(tags.year.empty()) tags.year = ReadMPG123String(id3v1->year);
551 if(tags.comments.empty()) tags.comments = ReadMPG123String(id3v1->comment);
552 }
553 }
554 mpt::ustring sampleName = GetSampleNameFromTags(tags);
555
556 DestroySampleThreadsafe(sample);
557 if(!mo3Decode)
558 {
559 m_szNames[sample] = mpt::ToCharset(GetCharsetInternal(), sampleName);
560 Samples[sample].Initialize();
561 Samples[sample].nC5Speed = rate;
562 }
563 Samples[sample].nLength = mpt::saturate_cast<SmpLength>((data.size() / channels) - data_skip_frames);
564
565 Samples[sample].uFlags.set(CHN_16BIT);
566 Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
567 Samples[sample].AllocateSample();
568
569 if(Samples[sample].HasSampleData())
570 {
571 std::memcpy(Samples[sample].sampleb(), data.data() + (data_skip_frames * channels), (data.size() - (data_skip_frames * channels)) * sizeof(int16));
572 }
573
574 if(!mo3Decode)
575 {
576 Samples[sample].Convert(MOD_TYPE_IT, GetType());
577 Samples[sample].PrecomputeLoops(*this, false);
578 }
579 return Samples[sample].HasSampleData();
580
581 #elif defined(MPT_WITH_MINIMP3)
582
583 MPT_UNREFERENCED_PARAMETER(raw);
584
585 file.Rewind();
586 FileReader::PinnedView rawDataView = file.GetPinnedView();
587 int64 bytes_left = rawDataView.size();
588 const uint8 *stream_pos = mpt::byte_cast<const uint8 *>(rawDataView.data());
589
590 std::vector<int16> raw_sample_data;
591
592 mp3dec_t mp3;
593 std::memset(&mp3, 0, sizeof(mp3dec_t));
594 mp3dec_init(&mp3);
595
596 int rate = 0;
597 int channels = 0;
598
599 mp3dec_frame_info_t info;
600 std::memset(&info, 0, sizeof(mp3dec_frame_info_t));
601 do
602 {
603 int16 sample_buf[MINIMP3_MAX_SAMPLES_PER_FRAME];
604 int frame_samples = mp3dec_decode_frame(&mp3, stream_pos, mpt::saturate_cast<int>(bytes_left), sample_buf, &info);
605 if(frame_samples < 0 || info.frame_bytes < 0) break; // internal error in minimp3
606 if(frame_samples > 0 && info.frame_bytes == 0) break; // internal error in minimp3
607 if(frame_samples == 0 && info.frame_bytes == 0) break; // end of stream, no progress
608 if(frame_samples == 0 && info.frame_bytes > 0) do { } while(0); // decoder skipped non-mp3 data
609 if(frame_samples > 0 && info.frame_bytes > 0) do { } while(0); // normal
610 if(info.frame_bytes > 0)
611 {
612 if(rate != 0 && rate != info.hz) break; // inconsistent stream
613 if(channels != 0 && channels != info.channels) break; // inconsistent stream
614 rate = info.hz;
615 channels = info.channels;
616 if(rate <= 0) break; // broken stream
617 if(channels != 1 && channels != 2) break; // broken stream
618 stream_pos += std::clamp(info.frame_bytes, 0, mpt::saturate_cast<int>(bytes_left));
619 bytes_left -= std::clamp(info.frame_bytes, 0, mpt::saturate_cast<int>(bytes_left));
620 if(frame_samples > 0)
621 {
622 try
623 {
624 mpt::append(raw_sample_data, sample_buf, sample_buf + frame_samples * channels);
625 } catch(mpt::out_of_memory e)
626 {
627 mpt::delete_out_of_memory(e);
628 break;
629 }
630 }
631 }
632 if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH)
633 {
634 break;
635 }
636 } while(bytes_left > 0);
637
638 if(rate == 0 || channels == 0 || raw_sample_data.empty())
639 {
640 return false;
641 }
642
643 if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH)
644 {
645 return false;
646 }
647
648 DestroySampleThreadsafe(sample);
649 if(!mo3Decode)
650 {
651 m_szNames[sample] = "";
652 Samples[sample].Initialize();
653 Samples[sample].nC5Speed = rate;
654 }
655 Samples[sample].nLength = mpt::saturate_cast<SmpLength>(raw_sample_data.size() / channels);
656
657 Samples[sample].uFlags.set(CHN_16BIT);
658 Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
659 Samples[sample].AllocateSample();
660
661 if(Samples[sample].HasSampleData())
662 {
663 std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].sample16());
664 }
665
666 if(!mo3Decode)
667 {
668 Samples[sample].Convert(MOD_TYPE_IT, GetType());
669 Samples[sample].PrecomputeLoops(*this, false);
670 }
671 return Samples[sample].HasSampleData();
672
673 #else
674
675 MPT_UNREFERENCED_PARAMETER(sample);
676 MPT_UNREFERENCED_PARAMETER(file);
677 MPT_UNREFERENCED_PARAMETER(raw);
678 MPT_UNREFERENCED_PARAMETER(mo3Decode);
679
680 #endif // MPT_WITH_MPG123 || MPT_WITH_MINIMP3
681
682 return false;
683 }
684
685
686 OPENMPT_NAMESPACE_END
687