| 704 | | |
| 705 | | // Allocate a buffer list to use for seeking |
| 706 | | AudioBufferList *bufferList = calloc(sizeof(AudioBufferList) + (sizeof(AudioBuffer) * (_format.mChannelsPerFrame - 1)), 1); |
| 707 | | NSAssert(NULL != bufferList, @"Unable to allocate memory"); |
| 708 | | |
| 709 | | bufferList->mNumberBuffers = _format.mChannelsPerFrame; |
| 710 | | |
| 711 | | unsigned i; |
| 712 | | for(i = 0; i < bufferList->mNumberBuffers; ++i) { |
| 713 | | bufferList->mBuffers[i].mData = calloc(SEEK_BUFFER_SIZE, sizeof(float)); |
| 714 | | NSAssert(NULL != bufferList->mBuffers[i].mData, @"Unable to allocate memory"); |
| 715 | | |
| 716 | | bufferList->mBuffers[i].mNumberChannels = 1; |
| | 711 | |
| | 712 | for(;;) { |
| | 713 | // All requested frames were skipped or read |
| | 714 | if(_samplesDecoded >= frame) |
| | 715 | break; |
| | 716 | |
| | 717 | // If the file contains a Xing header but not LAME gapless information, |
| | 718 | // decode the number of MPEG frames specified by the Xing header |
| | 719 | if(_foundXingHeader && NO == _foundLAMEHeader && 1 + _mpegFramesDecoded == _totalMPEGFrames) |
| | 720 | break; |
| | 721 | |
| | 722 | // The LAME header indicates how many samples are in the file |
| | 723 | if(_foundLAMEHeader && [self totalFrames] == _samplesDecoded) |
| | 724 | break; |
| | 725 | |
| | 726 | // Feed the input buffer if necessary |
| | 727 | if(NULL == _mad_stream.buffer || MAD_ERROR_BUFLEN == _mad_stream.error) { |
| | 728 | if(NULL != _mad_stream.next_frame) { |
| | 729 | bytesRemaining = _mad_stream.bufend - _mad_stream.next_frame; |
| | 730 | memmove(_inputBuffer, _mad_stream.next_frame, bytesRemaining); |
| | 731 | |
| | 732 | readStartPointer = _inputBuffer + bytesRemaining; |
| | 733 | bytesToRead = INPUT_BUFFER_SIZE - bytesRemaining; |
| | 734 | } |
| | 735 | else { |
| | 736 | bytesToRead = INPUT_BUFFER_SIZE, |
| | 737 | readStartPointer = _inputBuffer, |
| | 738 | bytesRemaining = 0; |
| | 739 | } |
| | 740 | |
| | 741 | // Read raw bytes from the MP3 file |
| | 742 | size_t bytesRead = fread(readStartPointer, 1, bytesToRead, _file); |
| | 743 | if(ferror(_file)) { |
| | 744 | #if DEBUG |
| | 745 | NSLog(@"Read error: %s.", strerror(errno)); |
| | 746 | #endif |
| | 747 | break; |
| | 748 | } |
| | 749 | |
| | 750 | // MAD_BUFFER_GUARD zeroes are required to decode the last frame of the file |
| | 751 | if(feof(_file)) { |
| | 752 | memset(readStartPointer + bytesRead, 0, MAD_BUFFER_GUARD); |
| | 753 | bytesRead += MAD_BUFFER_GUARD; |
| | 754 | readEOF = YES; |
| | 755 | } |
| | 756 | |
| | 757 | mad_stream_buffer(&_mad_stream, _inputBuffer, bytesRead + bytesRemaining); |
| | 758 | _mad_stream.error = MAD_ERROR_NONE; |
| | 759 | } |
| | 760 | |
| | 761 | // Decode the header only of the MPEG frame for speed |
| | 762 | int result = mad_header_decode(&_mad_frame.header, &_mad_stream); |
| | 763 | if(-1 == result) { |
| | 764 | if(MAD_RECOVERABLE(_mad_stream.error)) { |
| | 765 | // Prevent ID3 tags from reporting recoverable frame errors |
| | 766 | const uint8_t *buffer = _mad_stream.this_frame; |
| | 767 | unsigned buflen = _mad_stream.bufend - _mad_stream.this_frame; |
| | 768 | uint32_t id3_length = 0; |
| | 769 | |
| | 770 | if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) { |
| | 771 | id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) | |
| | 772 | ((buffer[8] & 0x7F) << (1 * 7)) | ((buffer[9] & 0x7F) << (0 * 7))); |
| | 773 | |
| | 774 | // Add 10 bytes for ID3 header |
| | 775 | id3_length += 10; |
| | 776 | |
| | 777 | mad_stream_skip(&_mad_stream, id3_length); |
| | 778 | } |
| | 779 | #if DEBUG |
| | 780 | else |
| | 781 | NSLog(@"Recoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); |
| | 782 | #endif |
| | 783 | |
| | 784 | continue; |
| | 785 | } |
| | 786 | // EOS for non-Xing streams occurs when EOF is reached and no further frames can be decoded |
| | 787 | else if(MAD_ERROR_BUFLEN == _mad_stream.error && readEOF) |
| | 788 | break; |
| | 789 | else if(MAD_ERROR_BUFLEN == _mad_stream.error) |
| | 790 | continue; |
| | 791 | else { |
| | 792 | #if DEBUG |
| | 793 | NSLog(@"Unrecoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); |
| | 794 | #endif |
| | 795 | break; |
| | 796 | } |
| | 797 | } |
| | 798 | |
| | 799 | // Housekeeping |
| | 800 | ++_mpegFramesDecoded; |
| | 801 | |
| | 802 | // Skip any samples that remain from last frame |
| | 803 | // This can happen if the encoder delay is greater than the number of samples in a frame |
| | 804 | unsigned startingSample = _samplesToSkipInNextFrame; |
| | 805 | |
| | 806 | // Skip the Xing header (it contains empty audio) |
| | 807 | if(_foundXingHeader && 1 == _mpegFramesDecoded) |
| | 808 | continue; |
| | 809 | // Adjust the first real audio frame for gapless playback |
| | 810 | else if(_foundLAMEHeader && 2 == _mpegFramesDecoded) |
| | 811 | startingSample += _encoderDelay; |
| | 812 | |
| | 813 | // The number of samples in this frame |
| | 814 | unsigned sampleCount = 32 * MAD_NSBSAMPLES(&_mad_frame.header); |
| | 815 | |
| | 816 | // Skip this entire frame if necessary |
| | 817 | if(startingSample > sampleCount) { |
| | 818 | _samplesToSkipInNextFrame += startingSample - sampleCount; |
| | 819 | continue; |
| | 820 | } |
| | 821 | else |
| | 822 | _samplesToSkipInNextFrame = 0; |
| | 823 | |
| | 824 | // If a LAME header was found, the total number of audio frames (AKA samples) |
| | 825 | // is known. Ensure only that many are output |
| | 826 | if(_foundLAMEHeader && [self totalFrames] < _samplesDecoded + (sampleCount - startingSample)) |
| | 827 | sampleCount = [self totalFrames] - _samplesDecoded; |
| | 828 | |
| | 829 | // If this MPEG frame contains the desired seek frame, synthesize its audio to PCM |
| | 830 | if(_samplesDecoded + (sampleCount - startingSample) > frame) { |
| | 831 | // Finish decoding the MPEG frame |
| | 832 | result = mad_frame_decode(&_mad_frame, &_mad_stream); |
| | 833 | if(-1 == result) { |
| | 834 | if(MAD_RECOVERABLE(_mad_stream.error)) { |
| | 835 | #if DEBUG |
| | 836 | NSLog(@"Recoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); |
| | 837 | #endif |
| | 838 | continue; |
| | 839 | } |
| | 840 | else { |
| | 841 | #if DEBUG |
| | 842 | NSLog(@"Unrecoverable frame level error (%s)", mad_stream_errorstr(&_mad_stream)); |
| | 843 | #endif |
| | 844 | break; |
| | 845 | } |
| | 846 | } |
| | 847 | |
| | 848 | // Synthesize the frame into PCM |
| | 849 | mad_synth_frame(&_mad_synth, &_mad_frame); |
| | 850 | |
| | 851 | // Skip any audio frames before the sample we are seeking to |
| | 852 | unsigned additionalSamplesToSkip = frame - _samplesDecoded; |
| | 853 | |
| | 854 | // Output samples in 32-bit float PCM |
| | 855 | unsigned channel, sample; |
| | 856 | for(channel = 0; channel < MAD_NCHANNELS(&_mad_frame.header); ++channel) { |
| | 857 | float *floatBuffer = _bufferList->mBuffers[channel].mData; |
| | 858 | |
| | 859 | for(sample = startingSample + additionalSamplesToSkip; sample < sampleCount; ++sample) { |
| | 860 | audioSample = audio_linear_round(BIT_RESOLUTION, _mad_synth.pcm.samples[channel][sample]); |
| | 861 | |
| | 862 | if(0 <= audioSample) |
| | 863 | *floatBuffer++ = (float)(audioSample / (scaleFactor - 1)); |
| | 864 | else |
| | 865 | *floatBuffer++ = (float)(audioSample / scaleFactor); |
| | 866 | } |
| | 867 | |
| | 868 | _bufferList->mBuffers[channel].mNumberChannels = 1; |
| | 869 | _bufferList->mBuffers[channel].mDataByteSize = (sampleCount - (startingSample + additionalSamplesToSkip)) * sizeof(float); |
| | 870 | } |
| | 871 | |
| | 872 | // Only a portion of the frame was skipped- the rest was synthesized and stored in our buffers |
| | 873 | _samplesDecoded += additionalSamplesToSkip; |
| | 874 | } |
| | 875 | // The entire frame was skipped |
| | 876 | else |
| | 877 | _samplesDecoded += (sampleCount - startingSample); |