638 {
639 Mp3Info info;
640
641
643 if (error_message) {
644 *error_message = "Empty MP3 data";
645 }
646 return info;
647 }
648
649
650 if (data.
size() < 128) {
651 if (error_message) {
652 *error_message = "MP3 data too small";
653 }
654 return info;
655 }
656
657
658 bool foundSync = false;
659 fl::size syncOffset = 0;
660
661 for (fl::size i = 0; i <= data.
size() - 4; i++) {
662 if (data[i] == 0xFF && (data[i + 1] & 0xE0) == 0xE0) {
663 foundSync = true;
664 syncOffset = i;
665 break;
666 }
667 }
668
669 if (!foundSync) {
670 if (error_message) {
671 *error_message = "Invalid MP3 stream - no sync word found";
672 }
673 return info;
674 }
675
676
678 if (!decoder.init()) {
679 if (error_message) {
680 *error_message = "Failed to initialize MP3 decoder";
681 }
682 return info;
683 }
684
685 const fl::u8* inptr = data.
data() + syncOffset;
686 fl::size bytes_left = data.
size() - syncOffset;
687
688
689 int offset = decoder.findSyncWord(inptr, bytes_left);
693
694 int result = decoder.decodeFrame(&inptr, &bytes_left);
696
697 info.sampleRate = decoder.mFrameInfo.samprate;
698 info.channels =
static_cast<fl::u8>(decoder.mFrameInfo.nChans);
699 info.bitrate = decoder.mFrameInfo.bitrate;
700 info.version =
static_cast<fl::u8>(decoder.mFrameInfo.version);
701 info.layer =
static_cast<fl::u8>(decoder.mFrameInfo.layer);
702 info.isValid = true;
703 } else if (error_message) {
704 *error_message = "Failed to decode MP3 frame header";
705 }
706 } else if (error_message) {
707 *error_message = "Failed to find MP3 sync word";
708 }
709
710 return info;
711}
constexpr bool empty() const FL_NO_EXCEPT
const T * data() const FL_NO_EXCEPT
constexpr fl::size size() const FL_NO_EXCEPT
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
Mp3Minimp3Decoder Mp3SelectedDecoder
expected< T, E > result
Alias for expected (Rust-style naming)