function decodeMPEGaudioHeader($fd, $offset, &$ThisFileInfo, $recursivesearch = true, $ScanAsCBR = false, $FastMPEGheaderScan = false)
{
    static $MPEGaudioVersionLookup;
    static $MPEGaudioLayerLookup;
    static $MPEGaudioBitrateLookup;
    static $MPEGaudioFrequencyLookup;
    static $MPEGaudioChannelModeLookup;
    static $MPEGaudioModeExtensionLookup;
    static $MPEGaudioEmphasisLookup;
    if (empty($MPEGaudioVersionLookup)) {
        $MPEGaudioVersionLookup = MPEGaudioVersionArray();
        $MPEGaudioLayerLookup = MPEGaudioLayerArray();
        $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
        $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
        $MPEGaudioChannelModeLookup = MPEGaudioChannelModeArray();
        $MPEGaudioModeExtensionLookup = MPEGaudioModeExtensionArray();
        $MPEGaudioEmphasisLookup = MPEGaudioEmphasisArray();
    }
    if ($offset >= $ThisFileInfo['avdataend']) {
        $ThisFileInfo['error'] .= "\n" . 'end of file encounter looking for MPEG synch';
        return false;
    }
    fseek($fd, $offset, SEEK_SET);
    $headerstring = fread($fd, 1441);
    // worse-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
    // MP3 audio frame structure:
    // $aa $aa $aa $aa [$bb $bb] $cc...
    // where $aa..$aa is the four-byte mpeg-audio header (below)
    // $bb $bb is the optional 2-byte CRC
    // and $cc... is the audio data
    $head4 = substr($headerstring, 0, 4);
    static $MPEGaudioHeaderDecodeCache = array();
    if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
        $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
    } else {
        $MPEGheaderRawArray = MPEGaudioHeaderDecode($head4);
        $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
    }
    static $MPEGaudioHeaderValidCache = array();
    // Not in cache
    if (!isset($MPEGaudioHeaderValidCache[$head4])) {
        $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGheaderRawArray);
    }
    if ($MPEGaudioHeaderValidCache[$head4]) {
        $ThisFileInfo['mpeg']['audio']['raw'] = $MPEGheaderRawArray;
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Invalid MPEG audio header at offset ' . $offset;
        return false;
    }
    if (!$FastMPEGheaderScan) {
        $ThisFileInfo['mpeg']['audio']['version'] = $MPEGaudioVersionLookup[$ThisFileInfo['mpeg']['audio']['raw']['version']];
        $ThisFileInfo['mpeg']['audio']['layer'] = $MPEGaudioLayerLookup[$ThisFileInfo['mpeg']['audio']['raw']['layer']];
        $ThisFileInfo['mpeg']['audio']['channelmode'] = $MPEGaudioChannelModeLookup[$ThisFileInfo['mpeg']['audio']['raw']['channelmode']];
        $ThisFileInfo['mpeg']['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono' ? 1 : 2;
        $ThisFileInfo['mpeg']['audio']['sample_rate'] = $MPEGaudioFrequencyLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['raw']['sample_rate']];
        $ThisFileInfo['mpeg']['audio']['protection'] = !$ThisFileInfo['mpeg']['audio']['raw']['protection'];
        $ThisFileInfo['mpeg']['audio']['private'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['private'];
        $ThisFileInfo['mpeg']['audio']['modeextension'] = $MPEGaudioModeExtensionLookup[$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['modeextension']];
        $ThisFileInfo['mpeg']['audio']['copyright'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['copyright'];
        $ThisFileInfo['mpeg']['audio']['original'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['original'];
        $ThisFileInfo['mpeg']['audio']['emphasis'] = $MPEGaudioEmphasisLookup[$ThisFileInfo['mpeg']['audio']['raw']['emphasis']];
        $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
        $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
        if ($ThisFileInfo['mpeg']['audio']['protection']) {
            $ThisFileInfo['mpeg']['audio']['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['raw']['bitrate'] == 15) {
        // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
        $ThisFileInfo['warning'] .= "\n" . 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
        $ThisFileInfo['mpeg']['audio']['raw']['bitrate'] = 0;
    }
    $ThisFileInfo['mpeg']['audio']['padding'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['padding'];
    $ThisFileInfo['mpeg']['audio']['bitrate'] = $MPEGaudioBitrateLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['bitrate']];
    if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' && $offset == $ThisFileInfo['avdataoffset']) {
        // only skip multiple frame check if free-format bitstream found at beginning of file
        // otherwise is quite possibly simply corrupted data
        $recursivesearch = false;
    }
    // For Layer II there are some combinations of bitrate and mode which are not allowed.
    if (!$FastMPEGheaderScan && $ThisFileInfo['mpeg']['audio']['layer'] == 'II') {
        $ThisFileInfo['audio']['dataformat'] = 'mp2';
        switch ($ThisFileInfo['mpeg']['audio']['channelmode']) {
            case 'mono':
                if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' || $ThisFileInfo['mpeg']['audio']['bitrate'] <= 192) {
                    // these are ok
                } else {
                    $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
                    return false;
                }
                break;
            case 'stereo':
            case 'joint stereo':
            case 'dual channel':
                if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' || $ThisFileInfo['mpeg']['audio']['bitrate'] == 64 || $ThisFileInfo['mpeg']['audio']['bitrate'] >= 96) {
                    // these are ok
                } else {
                    $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
                    return false;
                }
                break;
        }
    }
    if ($ThisFileInfo['audio']['sample_rate'] > 0) {
        $ThisFileInfo['mpeg']['audio']['framelength'] = MPEGaudioFrameLength($ThisFileInfo['mpeg']['audio']['bitrate'], $ThisFileInfo['mpeg']['audio']['version'], $ThisFileInfo['mpeg']['audio']['layer'], (int) $ThisFileInfo['mpeg']['audio']['padding'], $ThisFileInfo['audio']['sample_rate']);
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate'] != 'free') {
        $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['bitrate'];
        if (isset($ThisFileInfo['mpeg']['audio']['framelength'])) {
            $nextframetestoffset = $offset + $ThisFileInfo['mpeg']['audio']['framelength'];
        } else {
            $ThisFileInfo['error'] .= "\n" . 'Frame at offset(' . $offset . ') is has an invalid frame length.';
            return false;
        }
    }
    $ExpectedNumberOfAudioBytes = 0;
    ////////////////////////////////////////////////////////////////////////////////////
    // Variable-bitrate headers
    if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
        // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
        // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
        $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
        $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Fraunhofer';
        $ThisFileInfo['audio']['codec'] = 'Fraunhofer';
        $SideInfoData = substr($headerstring, 4 + 2, 32);
        $FraunhoferVBROffset = 36;
        $ThisFileInfo['mpeg']['audio']['VBR_encoder_version'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2));
        $ThisFileInfo['mpeg']['audio']['VBR_encoder_delay'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2));
        $ThisFileInfo['mpeg']['audio']['VBR_quality'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2));
        $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4));
        $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4));
        $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2));
        //$ThisFileInfo['mpeg']['audio']['reserved']              = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 4)); // hardcoded $00 $01 $00 $02  - purpose unknown
        $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets_stride'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2));
        $ExpectedNumberOfAudioBytes = $ThisFileInfo['mpeg']['audio']['VBR_bytes'];
        $previousbyteoffset = $offset;
        for ($i = 0; $i < $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets']; $i++) {
            $Fraunhofer_OffsetN = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, 2));
            $FraunhoferVBROffset += 2;
            $ThisFileInfo['mpeg']['audio']['VBR_offsets_relative'][$i] = $Fraunhofer_OffsetN;
            $ThisFileInfo['mpeg']['audio']['VBR_offsets_absolute'][$i] = $Fraunhofer_OffsetN + $previousbyteoffset;
            $previousbyteoffset += $Fraunhofer_OffsetN;
        }
    } else {
        // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
        // depending on MPEG layer and number of channels
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-1 (mono)
                $VBRidOffset = 4 + 17;
                // 0x15
                $SideInfoData = substr($headerstring, 4 + 2, 17);
            } else {
                // MPEG-1 (stereo, joint-stereo, dual-channel)
                $VBRidOffset = 4 + 32;
                // 0x24
                $SideInfoData = substr($headerstring, 4 + 2, 32);
            }
        } else {
            // 2 or 2.5
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-2, MPEG-2.5 (mono)
                $VBRidOffset = 4 + 9;
                // 0x0D
                $SideInfoData = substr($headerstring, 4 + 2, 9);
            } else {
                // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
                $VBRidOffset = 4 + 17;
                // 0x15
                $SideInfoData = substr($headerstring, 4 + 2, 17);
            }
        }
        if (substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing' || substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info') {
            // 'Xing' is traditional Xing VBR frame
            // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
            $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
            $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Xing';
            $ThisFileInfo['mpeg']['audio']['xing_flags_raw'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4));
            $ThisFileInfo['mpeg']['audio']['xing_flags']['frames'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x1);
            $ThisFileInfo['mpeg']['audio']['xing_flags']['bytes'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x2);
            $ThisFileInfo['mpeg']['audio']['xing_flags']['toc'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x4);
            $ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x8);
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['frames']) {
                $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4));
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['bytes']) {
                $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4));
            }
            if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' && !empty($ThisFileInfo['mpeg']['audio']['VBR_frames']) && !empty($ThisFileInfo['mpeg']['audio']['VBR_bytes'])) {
                $framelengthfloat = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'];
                if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                    // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
                    $ThisFileInfo['audio']['bitrate'] = ($framelengthfloat / 4 - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate'] / 12;
                } else {
                    // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
                    $ThisFileInfo['audio']['bitrate'] = ($framelengthfloat - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate'] / 144;
                }
                $ThisFileInfo['mpeg']['audio']['framelength'] = floor($framelengthfloat);
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['toc']) {
                $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
                for ($i = 0; $i < 100; $i++) {
                    $ThisFileInfo['mpeg']['audio']['toc'][$i] = ord($LAMEtocData[$i]);
                }
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale']) {
                $ThisFileInfo['mpeg']['audio']['VBR_scale'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4));
            }
            // http://gabriel.mp3-tech.org/mp3infotag.html
            if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') {
                $ThisFileInfo['mpeg']['audio']['LAME']['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
                $ThisFileInfo['mpeg']['audio']['LAME']['short_version'] = substr($ThisFileInfo['mpeg']['audio']['LAME']['long_version'], 0, 9);
                $ThisFileInfo['mpeg']['audio']['LAME']['long_version'] = rtrim($ThisFileInfo['mpeg']['audio']['LAME']['long_version'], "UÂȘ");
                if ($ThisFileInfo['mpeg']['audio']['LAME']['short_version'] >= 'LAME3.90.') {
                    // It the LAME tag was only introduced in LAME v3.90
                    // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
                    // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
                    // are assuming a 'Xing' identifier offset of 0x24, which is the case for
                    // MPEG-1 non-mono, but not for other combinations
                    $LAMEtagOffsetContant = $VBRidOffset - 0x24;
                    // byte $9B  VBR Quality
                    // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
                    // Actually overwrites original Xing bytes
                    unset($ThisFileInfo['mpeg']['audio']['VBR_scale']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['vbr_quality'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9b, 1));
                    // bytes $9C-$A4  Encoder short VersionString
                    $ThisFileInfo['mpeg']['audio']['LAME']['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9c, 9);
                    $ThisFileInfo['mpeg']['audio']['LAME']['long_version'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
                    // byte $A5  Info Tag revision + VBR method
                    $LAMEtagRevisionVBRmethod = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xa5, 1));
                    $ThisFileInfo['mpeg']['audio']['LAME']['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xf0) >> 4;
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method'] = $LAMEtagRevisionVBRmethod & 0xf;
                    $ThisFileInfo['mpeg']['audio']['LAME']['vbr_method'] = LAMEvbrMethodLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method']);
                    // byte $A6  Lowpass filter value
                    $ThisFileInfo['mpeg']['audio']['LAME']['lowpass_frequency'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xa6, 1)) * 100;
                    // bytes $A7-$AE  Replay Gain
                    // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
                    // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] = BigEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xa7, 4));
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xab, 2));
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xad, 2));
                    if ($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] == 0) {
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] = false;
                    }
                    if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] != 0) {
                        require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['name'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0xe000) >> 13;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['originator'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0x1c00) >> 10;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['sign_bit'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0x200) >> 9;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['gain_adjust'] = $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0x1ff;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['name'] = RGADnameLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['name']);
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['originator']);
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['sign_bit']);
                        if ($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] !== false) {
                            $ThisFileInfo['replay_gain']['radio']['peak'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'];
                        }
                        $ThisFileInfo['replay_gain']['radio']['originator'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['originator'];
                        $ThisFileInfo['replay_gain']['radio']['adjustment'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['gain_db'];
                    }
                    if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] != 0) {
                        require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['name'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0xe000) >> 13;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['originator'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0x1c00) >> 10;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['sign_bit'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0x200) >> 9;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['gain_adjust'] = $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0x1ff;
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['name']);
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['originator']);
                        $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['sign_bit']);
                        if ($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] !== false) {
                            $ThisFileInfo['replay_gain']['audiophile']['peak'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'];
                        }
                        $ThisFileInfo['replay_gain']['audiophile']['originator'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['originator'];
                        $ThisFileInfo['replay_gain']['audiophile']['adjustment'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['gain_db'];
                    }
                    // byte $AF  Encoding flags + ATH Type
                    $EncodingFlagsATHtype = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xaf, 1));
                    $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
                    $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
                    $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
                    $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
                    $ThisFileInfo['mpeg']['audio']['LAME']['ath_type'] = $EncodingFlagsATHtype & 0xf;
                    // byte $B0  if ABR {specified bitrate} else {minimal bitrate}
                    $ABRbitrateMinBitrate = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xb0, 1));
                    if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method'] == 2) {
                        // Average BitRate (ABR)
                        $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_abr'] = $ABRbitrateMinBitrate;
                    } elseif ($ABRbitrateMinBitrate > 0) {
                        // Variable BitRate (VBR) - minimum bitrate
                        $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] = $ABRbitrateMinBitrate;
                    }
                    // bytes $B1-$B3  Encoder delays
                    $EncoderDelays = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xb1, 3));
                    $ThisFileInfo['mpeg']['audio']['LAME']['encoder_delay'] = ($EncoderDelays & 0xfff000) >> 12;
                    $ThisFileInfo['mpeg']['audio']['LAME']['end_padding'] = $EncoderDelays & 0xfff;
                    // byte $B4  Misc
                    $MiscByte = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xb4, 1));
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['noise_shaping'] = $MiscByte & 0x3;
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['stereo_mode'] = ($MiscByte & 0x1c) >> 2;
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['source_sample_freq'] = ($MiscByte & 0xc0) >> 6;
                    $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping'] = $ThisFileInfo['mpeg']['audio']['LAME']['raw']['noise_shaping'];
                    $ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode'] = LAMEmiscStereoModeLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['stereo_mode']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality'] = (bool) $ThisFileInfo['mpeg']['audio']['LAME']['raw']['not_optimal_quality'];
                    $ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq'] = LAMEmiscSourceSampleFrequencyLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['source_sample_freq']);
                    // byte $B5  MP3 Gain
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['mp3_gain'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xb5, 1), false, true);
                    $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] = 1.5 * $ThisFileInfo['mpeg']['audio']['LAME']['raw']['mp3_gain'];
                    $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_factor'] = pow(2, $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] / 6);
                    // bytes $B6-$B7  Preset and surround info
                    $PresetSurroundBytes = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xb6, 2));
                    // Reserved                                                    = ($PresetSurroundBytes & 0xC000);
                    $ThisFileInfo['mpeg']['audio']['LAME']['raw']['surround_info'] = $PresetSurroundBytes & 0x3800;
                    $ThisFileInfo['mpeg']['audio']['LAME']['surround_info'] = LAMEsurroundInfoLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['surround_info']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['preset_used_id'] = $PresetSurroundBytes & 0x7ff;
                    // bytes $B8-$BB  MusicLength
                    $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xb8, 4));
                    $ExpectedNumberOfAudioBytes = $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] > 0 ? $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] : $ThisFileInfo['mpeg']['audio']['VBR_bytes'];
                    // bytes $BC-$BD  MusicCRC
                    $ThisFileInfo['mpeg']['audio']['LAME']['music_crc'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xbc, 2));
                    // bytes $BE-$BF  CRC-16 of Info Tag
                    $ThisFileInfo['mpeg']['audio']['LAME']['lame_tag_crc'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xbe, 2));
                    // LAME CBR
                    if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method'] == 1) {
                        $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                        if (empty($ThisFileInfo['mpeg']['audio']['bitrate']) || $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] != 255) {
                            $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'];
                        }
                    }
                }
            }
        } else {
            // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
            $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
            if ($recursivesearch) {
                $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
                if (RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, true)) {
                    $recursivesearch = false;
                    $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                }
                if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr') {
                    $ThisFileInfo['warning'] .= "\n" . 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
                }
            }
        }
    }
    if ($ExpectedNumberOfAudioBytes > 0 && $ExpectedNumberOfAudioBytes != $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) {
        if ($ExpectedNumberOfAudioBytes - ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) == 1) {
            $ThisFileInfo['warning'] .= "\n" . 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
        } elseif ($ExpectedNumberOfAudioBytes > $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) {
            $ThisFileInfo['warning'] .= "\n" . 'Probable truncated file: expecting ' . $ExpectedNumberOfAudioBytes . ' bytes of audio data, only found ' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) . ' (short by ' . ($ExpectedNumberOfAudioBytes - ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'])) . ' bytes)';
        } else {
            $ThisFileInfo['warning'] .= "\n" . 'Too much data in file: expecting ' . $ExpectedNumberOfAudioBytes . ' bytes of audio data, found ' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) . ' (' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - $ExpectedNumberOfAudioBytes) . ' bytes too many)';
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' && empty($ThisFileInfo['audio']['bitrate'])) {
        if ($offset == $ThisFileInfo['avdataoffset'] && empty($ThisFileInfo['mpeg']['audio']['VBR_frames'])) {
            $framebytelength = FreeFormatFrameLength($fd, $offset, $ThisFileInfo, true);
            if ($framebytelength > 0) {
                $ThisFileInfo['mpeg']['audio']['framelength'] = $framebytelength;
                if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                    // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
                    $ThisFileInfo['audio']['bitrate'] = ($framebytelength / 4 - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate'] / 12;
                } else {
                    // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
                    $ThisFileInfo['audio']['bitrate'] = ($framebytelength - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate'] / 144;
                }
            } else {
                $ThisFileInfo['error'] .= "\n" . 'Error calculating frame length of free-format MP3 without Xing/LAME header';
            }
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr' && isset($ThisFileInfo['mpeg']['audio']['VBR_frames']) && $ThisFileInfo['mpeg']['audio']['VBR_frames'] > 1) {
        $ThisFileInfo['mpeg']['audio']['VBR_frames']--;
        // don't count the Xing / VBRI frame
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1' && $ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 384) / 1000;
        } elseif (($ThisFileInfo['mpeg']['audio']['version'] == '2' || $ThisFileInfo['mpeg']['audio']['version'] == '2.5') && $ThisFileInfo['mpeg']['audio']['layer'] == 'III') {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 576) / 1000;
        } else {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 1152) / 1000;
        }
        if ($ThisFileInfo['mpeg']['audio']['VBR_bitrate'] > 0) {
            $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
            $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
            // to avoid confusion
        }
    }
    // End variable-bitrate headers
    ////////////////////////////////////////////////////////////////////////////////////
    if ($recursivesearch) {
        if (!RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, $ScanAsCBR)) {
            return false;
        }
    }
    //if (false) {
    //	// experimental side info parsing section - not returning anything useful yet
    //
    //	$SideInfoBitstream = BigEndian2Bin($SideInfoData);
    //	$SideInfoOffset = 0;
    //
    //	if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
    //		if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
    //			// MPEG-1 (mono)
    //			$ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
    //			$SideInfoOffset += 9;
    //			$SideInfoOffset += 5;
    //		} else {
    //			// MPEG-1 (stereo, joint-stereo, dual-channel)
    //			$ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
    //			$SideInfoOffset += 9;
    //			$SideInfoOffset += 3;
    //		}
    //	} else { // 2 or 2.5
    //		if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
    //			// MPEG-2, MPEG-2.5 (mono)
    //			$ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
    //			$SideInfoOffset += 8;
    //			$SideInfoOffset += 1;
    //		} else {
    //			// MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
    //			$ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
    //			$SideInfoOffset += 8;
    //			$SideInfoOffset += 2;
    //		}
    //	}
    //
    //	if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
    //		for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
    //			for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
    //				$ThisFileInfo['mpeg']['audio']['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
    //				$SideInfoOffset += 2;
    //			}
    //		}
    //	}
    //	for ($granule = 0; $granule < (($ThisFileInfo['mpeg']['audio']['version'] == '1') ? 2 : 1); $granule++) {
    //		for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
    //			$ThisFileInfo['mpeg']['audio']['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
    //			$SideInfoOffset += 12;
    //			$ThisFileInfo['mpeg']['audio']['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
    //			$SideInfoOffset += 9;
    //			$ThisFileInfo['mpeg']['audio']['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
    //			$SideInfoOffset += 8;
    //			if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
    //				$ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
    //				$SideInfoOffset += 4;
    //			} else {
    //				$ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
    //				$SideInfoOffset += 9;
    //			}
    //			$ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
    //			$SideInfoOffset += 1;
    //
    //			if ($ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] == '1') {
    //
    //				$ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
    //				$SideInfoOffset += 2;
    //				$ThisFileInfo['mpeg']['audio']['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
    //				$SideInfoOffset += 1;
    //
    //				for ($region = 0; $region < 2; $region++) {
    //					$ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
    //					$SideInfoOffset += 5;
    //				}
    //				$ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][2] = 0;
    //
    //				for ($window = 0; $window < 3; $window++) {
    //					$ThisFileInfo['mpeg']['audio']['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
    //					$SideInfoOffset += 3;
    //				}
    //
    //			} else {
    //
    //				for ($region = 0; $region < 3; $region++) {
    //					$ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
    //					$SideInfoOffset += 5;
    //				}
    //
    //				$ThisFileInfo['mpeg']['audio']['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
    //				$SideInfoOffset += 4;
    //				$ThisFileInfo['mpeg']['audio']['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
    //				$SideInfoOffset += 3;
    //				$ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = 0;
    //			}
    //
    //			if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
    //				$ThisFileInfo['mpeg']['audio']['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
    //				$SideInfoOffset += 1;
    //			}
    //			$ThisFileInfo['mpeg']['audio']['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
    //			$SideInfoOffset += 1;
    //			$ThisFileInfo['mpeg']['audio']['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
    //			$SideInfoOffset += 1;
    //		}
    //	}
    //}
    return true;
}
Example #2
0
function decodeMPEGaudioHeader($fd, $offset, &$ThisFileInfo, $recursivesearch = true, $ScanAsCBR = false, $FastMPEGheaderScan = false)
{
    static $MPEGaudioVersionLookup;
    static $MPEGaudioLayerLookup;
    static $MPEGaudioBitrateLookup;
    static $MPEGaudioFrequencyLookup;
    static $MPEGaudioChannelModeLookup;
    static $MPEGaudioModeExtensionLookup;
    static $MPEGaudioEmphasisLookup;
    if (empty($MPEGaudioVersionLookup)) {
        $MPEGaudioVersionLookup = MPEGaudioVersionArray();
        $MPEGaudioLayerLookup = MPEGaudioLayerArray();
        $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
        $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
        $MPEGaudioChannelModeLookup = MPEGaudioChannelModeArray();
        $MPEGaudioModeExtensionLookup = MPEGaudioModeExtensionArray();
        $MPEGaudioEmphasisLookup = MPEGaudioEmphasisArray();
    }
    if ($offset >= $ThisFileInfo['avdataend']) {
        $ThisFileInfo['error'] .= "\n" . 'end of file encounter looking for MPEG synch';
        return false;
    }
    fseek($fd, $offset, SEEK_SET);
    $headerstring = fread($fd, 192);
    // MP3 audio frame structure:
    // $aa $aa $aa $aa [$bb $bb] $cc...
    // where $aa..$aa is the four-byte mpeg-audio header (below)
    // $bb $bb is the optional 2-byte CRC
    // and $cc... is the audio data
    $head4 = substr($headerstring, 0, 4);
    static $MPEGaudioHeaderDecodeCache = array();
    if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
        $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
    } else {
        $MPEGheaderRawArray = MPEGaudioHeaderDecode($head4);
        $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
    }
    static $MPEGaudioHeaderValidCache = array();
    // Not in cache
    if (!isset($MPEGaudioHeaderValidCache[$head4])) {
        $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGheaderRawArray);
    }
    if ($MPEGaudioHeaderValidCache[$head4]) {
        $ThisFileInfo['mpeg']['audio']['raw'] = $MPEGheaderRawArray;
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Invalid MPEG audio header at offset ' . $offset;
        return false;
    }
    if (!$FastMPEGheaderScan) {
        $ThisFileInfo['mpeg']['audio']['version'] = $MPEGaudioVersionLookup[$ThisFileInfo['mpeg']['audio']['raw']['version']];
        $ThisFileInfo['mpeg']['audio']['layer'] = $MPEGaudioLayerLookup[$ThisFileInfo['mpeg']['audio']['raw']['layer']];
        $ThisFileInfo['mpeg']['audio']['channelmode'] = $MPEGaudioChannelModeLookup[$ThisFileInfo['mpeg']['audio']['raw']['channelmode']];
        $ThisFileInfo['mpeg']['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono' ? 1 : 2;
        $ThisFileInfo['mpeg']['audio']['sample_rate'] = $MPEGaudioFrequencyLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['raw']['sample_rate']];
        $ThisFileInfo['mpeg']['audio']['protection'] = !$ThisFileInfo['mpeg']['audio']['raw']['protection'];
        $ThisFileInfo['mpeg']['audio']['private'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['private'];
        $ThisFileInfo['mpeg']['audio']['modeextension'] = $MPEGaudioModeExtensionLookup[$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['modeextension']];
        $ThisFileInfo['mpeg']['audio']['copyright'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['copyright'];
        $ThisFileInfo['mpeg']['audio']['original'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['original'];
        $ThisFileInfo['mpeg']['audio']['emphasis'] = $MPEGaudioEmphasisLookup[$ThisFileInfo['mpeg']['audio']['raw']['emphasis']];
        $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
        $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
        if ($ThisFileInfo['mpeg']['audio']['protection']) {
            $ThisFileInfo['mpeg']['audio']['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
        }
    }
    $ThisFileInfo['mpeg']['audio']['padding'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['padding'];
    $ThisFileInfo['mpeg']['audio']['bitrate'] = $MPEGaudioBitrateLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['bitrate']];
    // For Layer II there are some combinations of bitrate and mode which are not allowed.
    if (!$FastMPEGheaderScan && $ThisFileInfo['mpeg']['audio']['layer'] == 'II') {
        //$ThisFileInfo['fileformat']          = 'mp2';
        $ThisFileInfo['audio']['dataformat'] = 'mp2';
        switch ($ThisFileInfo['mpeg']['audio']['channelmode']) {
            case 'mono':
                if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' || $ThisFileInfo['mpeg']['audio']['bitrate'] <= 192) {
                    // these are ok
                } else {
                    $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
                    return false;
                }
                break;
            case 'stereo':
            case 'joint stereo':
            case 'dual channel':
                if ($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free' || $ThisFileInfo['mpeg']['audio']['bitrate'] == 64 || $ThisFileInfo['mpeg']['audio']['bitrate'] >= 96) {
                    // these are ok
                } else {
                    $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
                    return false;
                }
                break;
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate'] != 'free') {
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                $FrameLengthCoefficient = 48;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 4 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            } else {
                // Layer II / III
                $FrameLengthCoefficient = 144;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 1 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            }
        } else {
            // MPEG-2 / MPEG-2.5
            if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                $FrameLengthCoefficient = 24;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 4 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            } else {
                // Layer II / III
                $FrameLengthCoefficient = 72;
                $FrameLengthPadding = $ThisFileInfo['mpeg']['audio']['padding'] ? 1 : 0;
                // For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
            }
        }
        // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
        // http://66.96.216.160/cgi-bin/YaBB.pl?board=c&action=display&num=1018474068
        // -> [Finding the next frame synch] on www.r3mix.net forums if the above link goes dead
        if ($ThisFileInfo['audio']['sample_rate'] > 0) {
            $ThisFileInfo['mpeg']['audio']['framelength'] = (int) floor($FrameLengthCoefficient * 1000 * $ThisFileInfo['mpeg']['audio']['bitrate'] / $ThisFileInfo['audio']['sample_rate']) + $FrameLengthPadding;
        }
    }
    $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['bitrate'];
    if (isset($ThisFileInfo['mpeg']['audio']['framelength'])) {
        $nextframetestoffset = $offset + $ThisFileInfo['mpeg']['audio']['framelength'];
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Frame at offset(' . $offset . ') is has an invalid frame length.';
        return false;
    }
    ////////////////////////////////////////////////////////////////////////////////////
    // Variable-bitrate headers
    if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
        // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
        // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
        $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
        $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Fraunhofer';
        $ThisFileInfo['audio']['codec'] = 'Fraunhofer';
        $SideInfoData = substr($headerstring, 4 + 2, 32);
        $FraunhoferVBROffset = 4 + 32 + strlen('VBRI');
        $Fraunhofer_EncoderVersion = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_encoder_version'] = BigEndian2Int($Fraunhofer_EncoderVersion);
        $Fraunhofer_EncoderDelay = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_encoder_delay'] = BigEndian2Int($Fraunhofer_EncoderDelay);
        $Fraunhofer_quality = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_quality'] = BigEndian2Int($Fraunhofer_quality);
        $Fraunhofer_Bytes = substr($headerstring, $FraunhoferVBROffset, 4);
        $FraunhoferVBROffset += 4;
        $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int($Fraunhofer_Bytes);
        $Fraunhofer_Frames = substr($headerstring, $FraunhoferVBROffset, 4);
        $FraunhoferVBROffset += 4;
        $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int($Fraunhofer_Frames);
        $Fraunhofer_SeekOffsets = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets'] = BigEndian2Int($Fraunhofer_SeekOffsets);
        $FraunhoferVBROffset += 4;
        // hardcoded $00 $01 $00 $02  - purpose unknown
        $Fraunhofer_OffsetStride = substr($headerstring, $FraunhoferVBROffset, 2);
        $FraunhoferVBROffset += 2;
        $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets_stride'] = BigEndian2Int($Fraunhofer_OffsetStride);
        $previousbyteoffset = $offset;
        for ($i = 0; $i < $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets']; $i++) {
            $Fraunhofer_OffsetN = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, 2));
            $FraunhoferVBROffset += 2;
            $ThisFileInfo['mpeg']['audio']['VBR_offsets_relative'][$i] = $Fraunhofer_OffsetN;
            $ThisFileInfo['mpeg']['audio']['VBR_offsets_absolute'][$i] = $Fraunhofer_OffsetN + $previousbyteoffset;
            $previousbyteoffset += $Fraunhofer_OffsetN;
        }
    } else {
        // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
        // depending on MPEG layer and number of channels
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-1 (mono)
                $VBRidOffset = 4 + 17;
                // 0x15
                $SideInfoData = substr($headerstring, 4 + 2, 17);
            } else {
                // MPEG-1 (stereo, joint-stereo, dual-channel)
                $VBRidOffset = 4 + 32;
                // 0x24
                $SideInfoData = substr($headerstring, 4 + 2, 32);
            }
        } else {
            // 2 or 2.5
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-2, MPEG-2.5 (mono)
                $VBRidOffset = 4 + 9;
                // 0x0D
                $SideInfoData = substr($headerstring, 4 + 2, 9);
            } else {
                // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
                $VBRidOffset = 4 + 17;
                // 0x15
                $SideInfoData = substr($headerstring, 4 + 2, 17);
            }
        }
        if (substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing' || substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info') {
            // 'Xing' is traditional Xing VBR frame, 'Info' is LAME-encoded CBR
            // 'This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.'
            $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
            $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Xing';
            $XingVBROffset = $VBRidOffset + strlen('Xing');
            $ThisFileInfo['mpeg']['audio']['xing_flags_raw'] = substr($headerstring, $XingVBROffset, 4);
            $XingVBROffset += 4;
            $XingHeader_byte4 = BigEndian2Bin(substr($ThisFileInfo['mpeg']['audio']['xing_flags_raw'], 3, 1));
            $ThisFileInfo['mpeg']['audio']['xing_flags']['frames'] = (bool) $XingHeader_byte4[4];
            $ThisFileInfo['mpeg']['audio']['xing_flags']['bytes'] = (bool) $XingHeader_byte4[5];
            $ThisFileInfo['mpeg']['audio']['xing_flags']['toc'] = (bool) $XingHeader_byte4[6];
            $ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale'] = (bool) $XingHeader_byte4[7];
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['frames']) {
                $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['bytes']) {
                $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['toc']) {
                $LAMEtocData = substr($headerstring, $XingVBROffset, 100);
                $XingVBROffset += 100;
                for ($i = 0; $i < 100; $i++) {
                    $ThisFileInfo['mpeg']['audio']['toc'][$i] = ord($LAMEtocData[$i]);
                }
            }
            if ($ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale']) {
                $ThisFileInfo['mpeg']['audio']['VBR_scale'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
            }
            if (substr($headerstring, $XingVBROffset, 4) == 'LAME') {
                $ThisFileInfo['mpeg']['audio']['LAME']['short_version'] = substr($headerstring, $XingVBROffset, 9);
                $XingVBROffset += 9;
                $LAMEtagRevisionVBRmethod = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xf0) >> 4;
                $ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw'] = $LAMEtagRevisionVBRmethod & 0xf;
                $ThisFileInfo['mpeg']['audio']['LAME']['vbr_method'] = LAMEvbrMethodLookup($ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw']);
                $ThisFileInfo['mpeg']['audio']['LAME']['lowpass_frequency'] = 100 * BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
                $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] = BigEndian2Float(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
                $RadioReplayGainRaw = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                $XingVBROffset += 4;
                $ReplayGainID = ($RadioReplayGainRaw & 0xe000) >> 13;
                $ReplayGainNameKey = '';
                switch ($ReplayGainID) {
                    case 1:
                        $ReplayGainNameKey = 'radio';
                        break;
                    case 2:
                        $ReplayGainNameKey = 'audiophile';
                        break;
                    case 0:
                        // replay gain not set
                    // replay gain not set
                    default:
                        // reserved
                        break;
                }
                if ($ReplayGainNameKey) {
                    require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['name'] = ($RadioReplayGainRaw & 0xe000) >> 13;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['originator'] = ($RadioReplayGainRaw & 0x1c00) >> 10;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['sign_bit'] = ($RadioReplayGainRaw & 0x200) >> 9;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['gain_adjust'] = $RadioReplayGainRaw & 0x1ff;
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['name'] = RGADnameLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['name']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['originator']);
                    $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['raw']['sign_bit']);
                    $ThisFileInfo['replay_gain']["{$ReplayGainNameKey}"]['peak'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'];
                    $ThisFileInfo['replay_gain']["{$ReplayGainNameKey}"]['originator'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['originator'];
                    $ThisFileInfo['replay_gain']["{$ReplayGainNameKey}"]['adjustment'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']["{$ReplayGainNameKey}"]['gain_db'];
                }
                $EncodingFlagsATHtype = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
                $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
                $ThisFileInfo['mpeg']['audio']['LAME']['ath_type'] = $EncodingFlagsATHtype & 0xf;
                $ABRbitrateMinBitrate = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                if ($ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw'] == 2) {
                    // Average BitRate (ABR)
                    $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_abr'] = $ABRbitrateMinBitrate;
                } elseif ($ABRbitrateMinBitrate > 0) {
                    // Variable BitRate (VBR) - minimum bitrate
                    $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] = $ABRbitrateMinBitrate;
                }
                $EncoderDelays = BigEndian2Int(substr($headerstring, $XingVBROffset, 3));
                $XingVBROffset += 3;
                $ThisFileInfo['mpeg']['audio']['LAME']['encoder_delay'] = ($EncoderDelays & 0xfff000) >> 12;
                $ThisFileInfo['mpeg']['audio']['LAME']['end_padding'] = $EncoderDelays & 0xfff;
                $MiscByte = BigEndian2Int(substr($headerstring, $XingVBROffset, 1));
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping_raw'] = $EncodingFlagsATHtype & 0x3;
                $ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode_raw'] = ($EncodingFlagsATHtype & 0x1c) >> 2;
                $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality_raw'] = ($EncodingFlagsATHtype & 0x20) >> 5;
                $ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq_raw'] = ($EncodingFlagsATHtype & 0xc0) >> 6;
                $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping'] = $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping_raw'];
                $ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode'] = LAMEmiscStereoModeLookup($ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode_raw']);
                $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality'] = (bool) $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality_raw'];
                $ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq'] = LAMEmiscSourceSampleFrequencyLookup($ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq_raw']);
                $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_raw'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 1), false, true);
                $XingVBROffset += 1;
                $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] = 1.5 * $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_raw'];
                $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_factor'] = pow(2, $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] / 6);
                $PresetSurroundBytes = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                //$Reserved       = ($PresetSurroundBytes & 0xC000);
                $ThisFileInfo['mpeg']['audio']['LAME']['surround_info_id'] = $PresetSurroundBytes & 0x3800;
                $ThisFileInfo['mpeg']['audio']['LAME']['surround_info'] = LAMEsurroundInfoLookup($ThisFileInfo['mpeg']['audio']['LAME']['surround_info_id']);
                $ThisFileInfo['mpeg']['audio']['LAME']['preset_used_id'] = $PresetSurroundBytes & 0x7ff;
                $XingVBROffset += 2;
                $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 4));
                $XingVBROffset += 4;
                if ($ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] > $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) {
                    $ThisFileInfo['warning'] .= "\n" . 'Probable truncated file: expecting ' . $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] . ' bytes of audio data, only found ' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
                }
                $ThisFileInfo['mpeg']['audio']['LAME']['music_crc'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                $XingVBROffset += 2;
                $ThisFileInfo['mpeg']['audio']['LAME']['lame_tag_crc'] = BigEndian2Int(substr($headerstring, $XingVBROffset, 2));
                $XingVBROffset += 2;
                // LAME CBR
                if ($ThisFileInfo['mpeg']['audio']['LAME']['vbr_method_raw'] == 1) {
                    $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                    if (empty($ThisFileInfo['mpeg']['audio']['bitrate']) || $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] != 255) {
                        $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'];
                    }
                }
            }
        } else {
            // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
            $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
            if ($recursivesearch) {
                $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
                if (RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, true)) {
                    $recursivesearch = false;
                    $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                }
                if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr') {
                    $ThisFileInfo['warning'] .= "\n" . 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
                }
            }
        }
    }
    if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr' && isset($ThisFileInfo['mpeg']['audio']['VBR_frames']) && $ThisFileInfo['mpeg']['audio']['VBR_frames'] > 1) {
        $ThisFileInfo['mpeg']['audio']['VBR_frames']--;
        // don't count the Xing / VBRI frame
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1' && $ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 384) / 1000;
        } elseif (($ThisFileInfo['mpeg']['audio']['version'] == '2' || $ThisFileInfo['mpeg']['audio']['version'] == '2.5') && $ThisFileInfo['mpeg']['audio']['layer'] == 'III') {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 576) / 1000;
        } else {
            $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'] * 8 * ($ThisFileInfo['audio']['sample_rate'] / 1152) / 1000;
        }
        if ($ThisFileInfo['mpeg']['audio']['VBR_bitrate'] > 0) {
            $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
            $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
            // to avoid confusion
        }
    }
    // End variable-bitrate headers
    ////////////////////////////////////////////////////////////////////////////////////
    if ($recursivesearch) {
        if (!RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, $ScanAsCBR)) {
            return false;
        }
    }
    if (false) {
        // experimental side info parsing section - not returning anything useful yet
        $SideInfoBitstream = BigEndian2Bin($SideInfoData);
        $SideInfoOffset = 0;
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-1 (mono)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                $SideInfoOffset += 9;
                $SideInfoOffset += 5;
            } else {
                // MPEG-1 (stereo, joint-stereo, dual-channel)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                $SideInfoOffset += 9;
                $SideInfoOffset += 3;
            }
        } else {
            // 2 or 2.5
            if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
                // MPEG-2, MPEG-2.5 (mono)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
                $SideInfoOffset += 8;
                $SideInfoOffset += 1;
            } else {
                // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
                $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
                $SideInfoOffset += 8;
                $SideInfoOffset += 2;
            }
        }
        if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
            for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
                for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
                    $ThisFileInfo['mpeg']['audio']['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                    $SideInfoOffset += 2;
                }
            }
        }
        for ($granule = 0; $granule < ($ThisFileInfo['mpeg']['audio']['version'] == '1' ? 2 : 1); $granule++) {
            for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
                $ThisFileInfo['mpeg']['audio']['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
                $SideInfoOffset += 12;
                $ThisFileInfo['mpeg']['audio']['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                $SideInfoOffset += 9;
                $ThisFileInfo['mpeg']['audio']['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
                $SideInfoOffset += 8;
                if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
                    $ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
                    $SideInfoOffset += 4;
                } else {
                    $ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
                    $SideInfoOffset += 9;
                }
                $ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                $SideInfoOffset += 1;
                if ($ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] == '1') {
                    $ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
                    $SideInfoOffset += 2;
                    $ThisFileInfo['mpeg']['audio']['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                    $SideInfoOffset += 1;
                    for ($region = 0; $region < 2; $region++) {
                        $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
                        $SideInfoOffset += 5;
                    }
                    $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][2] = 0;
                    for ($window = 0; $window < 3; $window++) {
                        $ThisFileInfo['mpeg']['audio']['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
                        $SideInfoOffset += 3;
                    }
                } else {
                    for ($region = 0; $region < 3; $region++) {
                        $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
                        $SideInfoOffset += 5;
                    }
                    $ThisFileInfo['mpeg']['audio']['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
                    $SideInfoOffset += 4;
                    $ThisFileInfo['mpeg']['audio']['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
                    $SideInfoOffset += 3;
                    $ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = 0;
                }
                if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
                    $ThisFileInfo['mpeg']['audio']['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                    $SideInfoOffset += 1;
                }
                $ThisFileInfo['mpeg']['audio']['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                $SideInfoOffset += 1;
                $ThisFileInfo['mpeg']['audio']['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
                $SideInfoOffset += 1;
            }
        }
    }
    return true;
}
function ID3v2FrameProcessing($frame_name, $frame_flags, &$MP3fileInfo)
{
    // define $frame_arrayindex once here (used for many frames), override or ignore as neccesary
    $frame_arrayindex = count($MP3fileInfo['id3']['id3v2']["{$frame_name}"]);
    // 'data', 'datalength'
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'])) {
        $frame_arrayindex--;
    }
    if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'])) {
        $frame_arrayindex--;
    }
    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
        // frame flags are not part of the ID3v2.2 standard
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
            //	Frame Header Flags
            //	%abc00000 %ijk00000
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 0, 1);
            // a - Tag alter preservation
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 1, 1);
            // b - File alter preservation
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 2, 1);
            // c - Read only
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression'] = (bool) substr($frame_flags, 8, 1);
            // i - Compression
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Encryption'] = (bool) substr($frame_flags, 9, 1);
            // j - Encryption
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 10, 1);
            // k - Grouping identity
        } else {
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 4) {
                //	Frame Header Flags
                //	%0abc0000 %0h00kmnp
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 1, 1);
                // a - Tag alter preservation
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 2, 1);
                // b - File alter preservation
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 3, 1);
                // c - Read only
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 9, 1);
                // h - Grouping identity
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression'] = (bool) substr($frame_flags, 12, 1);
                // k - Compression
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Encryption'] = (bool) substr($frame_flags, 13, 1);
                // m - Encryption
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Unsynchronisation'] = (bool) substr($frame_flags, 14, 1);
                // n - Unsynchronisation
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['DataLengthIndicator'] = (bool) substr($frame_flags, 15, 1);
                // p - Data length indicator
            }
        }
        //	Frame-level de-unsynchronization - ID3v2.4
        if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['Unsynchronisation'])) {
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = DeUnSynchronise($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
        }
        //	Frame-level de-compression
        if (isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression'])) {
            // it's on the wishlist :)
        }
    }
    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'UFID' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'UFI') {
        // 4.1   UFI  Unique file identifier
        //   There may be more than one 'UFID' frame in a tag,
        //   but only one with the same 'Owner identifier'.
        // <Header for 'Unique file identifier', ID: 'UFID'>
        // Owner identifier        <text string> $00
        // Identifier              <up to 64 bytes binary data>
        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0));
        $frame_idstring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_idstring;
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
        }
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
    } else {
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'TXXX' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'TXX') {
            // 4.2.2 TXX  User defined text information frame
            //   There may be more than one 'TXXX' frame in each tag,
            //   but only one with the same description.
            // <Header for 'User defined text information frame', ID: 'TXXX'>
            // Text encoding     $xx
            // Description       <text string according to encoding> $00 (00)
            // Value             <text string according to encoding>
            $frame_offset = 0;
            $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
            if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                $frame_terminatorpos++;
                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
            }
            $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
            if (ord($frame_description) === 0) {
                $frame_description = '';
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
            if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
            if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'], $frame_textencoding);
            }
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
            }
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
        } else {
            if ($frame_name[0] == 'T') {
                // 4.2. T??[?] Text information frame
                //   There may only be one text information frame of its kind in an tag.
                // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
                // excluding 'TXXX' described in 4.2.6.>
                // Text encoding                $xx
                // Information                  <text string(s) according to encoding>
                $frame_offset = 0;
                $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                // $MP3fileInfo['id3']['id3v2']["$frame_name"]['data'] = substr($MP3fileInfo['id3']['id3v2']["$frame_name"]['data'], $frame_offset);
                // this one-line method should work, but as a safeguard against null-padded data, do it the safe way
                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                    $frame_terminatorpos++;
                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                }
                if ($frame_terminatorpos) {
                    // there are null bytes after the data - this is not according to spec
                    // only use data up to first null byte
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                } else {
                    // no null bytes following data, just use all data
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                }
                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression']) || !$MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['compression']) {
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_textencoding);
                }
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
            } else {
                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'WXXX' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'WXX') {
                    // 4.3.2 WXX  User defined URL link frame
                    //   There may be more than one 'WXXX' frame in each tag,
                    //   but only one with the same description
                    // <Header for 'User defined URL link frame', ID: 'WXXX'>
                    // Text encoding     $xx
                    // Description       <text string according to encoding> $00 (00)
                    // URL               <text string>
                    $frame_offset = 0;
                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                        $frame_terminatorpos++;
                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                    }
                    $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                    if (ord($frame_description) === 0) {
                        $frame_description = '';
                    }
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding));
                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                        $frame_terminatorpos++;
                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                    }
                    if ($frame_terminatorpos) {
                        // there are null bytes after the data - this is not according to spec
                        // only use data up to first null byte
                        $frame_urldata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
                    } else {
                        // no null bytes following data, just use all data
                        $frame_urldata = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'];
                    }
                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                    }
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['url'] = $frame_urldata;
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                    if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                    }
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                } else {
                    if ($frame_name[0] == 'W') {
                        // 4.3. W??? URL link frames
                        //   There may only be one URL link frame of its kind in a tag,
                        //   except when stated otherwise in the frame description
                        // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
                        // described in 4.3.2.>
                        // URL              <text string>
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['url'] = trim($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                        }
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                    } else {
                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3 && $frame_name == 'IPLS' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'IPL') {
                            // 4.4  IPL  Involved people list (ID3v2.2 only)
                            //   There may only be one 'IPL' frame in each tag
                            // <Header for 'User defined URL link frame', ID: 'IPL'>
                            // Text encoding     $xx
                            // People list strings    <textstrings>
                            $frame_offset = 0;
                            $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid']);
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_textencoding);
                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                        } else {
                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'MCDI' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'MCI') {
                                // 4.5   MCI  Music CD identifier
                                //   There may only be one 'MCDI' frame in each tag
                                // <Header for 'Music CD identifier', ID: 'MCDI'>
                                // CD TOC                <binary data>
                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                // no other special processing needed
                            } else {
                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'ETCO' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'ETC') {
                                    // 4.6   ETC  Event timing codes
                                    //   There may only be one 'ETCO' frame in each tag
                                    // <Header for 'Event timing codes', ID: 'ETCO'>
                                    // Time stamp format    $xx
                                    //   Where time stamp format is:
                                    // $01  (32-bit value) MPEG frames from beginning of file
                                    // $02  (32-bit value) milliseconds from beginning of file
                                    //   Followed by a list of key events in the following format:
                                    // Type of event   $xx
                                    // Time stamp      $xx (xx ...)
                                    //   The 'Time stamp' is set to zero if directly at the beginning of the sound
                                    //   or after the previous event. All events MUST be sorted in chronological order.
                                    $frame_offset = 0;
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                    while ($frame_offset < strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['typeid'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['type'] = ETCOEventLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['typeid']);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['timestamp'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                        $frame_offset += 4;
                                    }
                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                    }
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                } else {
                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'MLLT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'MLL') {
                                        // 4.7   MLL MPEG location lookup table
                                        //   There may only be one 'MLLT' frame in each tag
                                        // <Header for 'Location lookup table', ID: 'MLLT'>
                                        // MPEG frames between reference  $xx xx
                                        // Bytes between reference        $xx xx xx
                                        // Milliseconds between reference $xx xx xx
                                        // Bits for bytes deviation       $xx
                                        // Bits for milliseconds dev.     $xx
                                        //   Then for every reference the following data is included;
                                        // Deviation in bytes         %xxx....
                                        // Deviation in milliseconds  %xxx....
                                        $frame_offset = 0;
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framesbetweenreferences'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, 2));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bytesbetweenreferences'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 2, 3));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['msbetweenreferences'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 5, 3));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 8, 1));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsformsdeviation'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 9, 1));
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 10);
                                        while ($frame_offset < strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
                                            $deviationbitstream .= BigEndian2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                        }
                                        while (strlen($deviationbitstream)) {
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation']));
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['msdeviation'] = bindec(substr($deviationbitstream, $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation'], $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsformsdeviation']));
                                            $deviationbitstream = substr($deviationbitstream, $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsforbytesdeviation'] + $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsformsdeviation']);
                                            $frame_arrayindex++;
                                        }
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                    } else {
                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'SYTC' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'STC') {
                                            // 4.8   STC  Synchronised tempo codes
                                            //   There may only be one 'SYTC' frame in each tag
                                            // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
                                            // Time stamp format   $xx
                                            // Tempo data          <binary data>
                                            //   Where time stamp format is:
                                            // $01  (32-bit value) MPEG frames from beginning of file
                                            // $02  (32-bit value) milliseconds from beginning of file
                                            $frame_offset = 0;
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                            while ($frame_offset < strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'])) {
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['tempo'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['tempo'] == 255) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['tempo'] += ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                }
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['timestamp'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                $frame_offset += 4;
                                                $frame_arrayindex++;
                                            }
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                        } else {
                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'USLT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'ULT') {
                                                // 4.9   ULT  Unsynchronised lyric/text transcription
                                                //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
                                                //   in each tag, but only one with the same language and content descriptor.
                                                // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
                                                // Text encoding        $xx
                                                // Language             $xx xx xx
                                                // Content descriptor   <text string according to encoding> $00 (00)
                                                // Lyrics/text          <full text string according to encoding>
                                                $frame_offset = 0;
                                                $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                $frame_offset += 3;
                                                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                    $frame_terminatorpos++;
                                                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                }
                                                $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                if (ord($frame_description) === 0) {
                                                    $frame_description = '';
                                                }
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'];
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['language'] = $frame_language;
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'], $frame_textencoding);
                                                }
                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                }
                                                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'], $frame_textencoding);
                                                }
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                            } else {
                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'SYLT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'SLT') {
                                                    // 4.10  SLT  Synchronised lyric/text
                                                    //   There may be more than one 'SYLT' frame in each tag,
                                                    //   but only one with the same language and content descriptor.
                                                    // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
                                                    // Text encoding        $xx
                                                    // Language             $xx xx xx
                                                    // Time stamp format    $xx
                                                    //   $01  (32-bit value) MPEG frames from beginning of file
                                                    //   $02  (32-bit value) milliseconds from beginning of file
                                                    // Content type         $xx
                                                    // Content descriptor   <text string according to encoding> $00 (00)
                                                    //   Terminated text to be synced (typically a syllable)
                                                    //   Sync identifier (terminator to above string)   $00 (00)
                                                    //   Time stamp                                     $xx (xx ...)
                                                    $frame_offset = 0;
                                                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                    $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                    $frame_offset += 3;
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contenttypeid'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contenttype'] = SYTLContentTypeLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contenttypeid']);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['language'] = $frame_language;
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                    }
                                                    $timestampindex = 0;
                                                    $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                    while (strlen($frame_remainingdata)) {
                                                        $frame_offset = 0;
                                                        $frame_terminatorpos = strpos($frame_remainingdata, TextEncodingLookup('terminator', $frame_textencoding));
                                                        if ($frame_terminatorpos === FALSE) {
                                                            $frame_remainingdata = '';
                                                        } else {
                                                            if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                $frame_terminatorpos++;
                                                                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                            }
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
                                                            if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['data'], $frame_textencoding);
                                                            }
                                                            $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                            if ($timestampindex == 0 && ord($frame_remainingdata[0]) != 0) {
                                                                // timestamp probably omitted for first data item
                                                            } else {
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$timestampindex}"]['timestamp'] = BigEndian2Int(substr($frame_remainingdata, 0, 4));
                                                                $frame_remainingdata = substr($frame_remainingdata, 4);
                                                            }
                                                            $timestampindex++;
                                                        }
                                                    }
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                } else {
                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'COMM' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'COM') {
                                                        // 4.11  COM  Comments
                                                        //   There may be more than one comment frame in each tag,
                                                        //   but only one with the same language and content descriptor.
                                                        // <Header for 'Comment', ID: 'COMM'>
                                                        // Text encoding          $xx
                                                        // Language               $xx xx xx
                                                        // Short content descrip. <text string according to encoding> $00 (00)
                                                        // The actual text        <full text string according to encoding>
                                                        $frame_offset = 0;
                                                        $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                        $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                        $frame_offset += 3;
                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                        if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                            $frame_terminatorpos++;
                                                            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                        }
                                                        $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                        if (ord($frame_description) === 0) {
                                                            $frame_description = '';
                                                        }
                                                        $frame_text = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['language'] = $frame_language;
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = $frame_text;
                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                        }
                                                        if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                        }
                                                        if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidata'] = RoughTranslateUnicodeToASCII($frame_text, $frame_textencoding);
                                                        }
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                    } else {
                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'RVA2') {
                                                            // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
                                                            //   There may be more than one 'RVA2' frame in each tag,
                                                            //   but only one with the same identification string
                                                            // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
                                                            // Identification          <text string> $00
                                                            //   The 'identification' string is used to identify the situation and/or
                                                            //   device where this adjustment should apply. The following is then
                                                            //   repeated for every channel:
                                                            // Type of channel         $xx
                                                            // Volume adjustment       $xx xx
                                                            // Bits representing peak  $xx
                                                            // Peak volume             $xx (xx ...)
                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0));
                                                            $frame_idstring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
                                                            if (ord($frame_idstring) === 0) {
                                                                $frame_idstring = '';
                                                            }
                                                            $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_idstring;
                                                            while (strlen($frame_remainingdata)) {
                                                                $frame_offset = 0;
                                                                $frame_channeltypeid = substr($frame_remainingdata, $frame_offset++, 1);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['channeltypeid'] = $frame_channeltypeid;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['channeltype'] = RVA2ChannelTypeLookup($frame_channeltypeid);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['volumeadjust'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2)) - 0x7fff;
                                                                // 16-bit signed
                                                                $frame_offset += 2;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
                                                                $frame_bytespeakvolume = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_channeltypeid}"]['bitspeakvolume'] / 8);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['peakvolume'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
                                                                $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
                                                            }
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]["{$frame_channeltypeid}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                        } else {
                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3 && $frame_name == 'RVAD' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'RVA') {
                                                                // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
                                                                //   There may only be one 'RVA' frame in each tag
                                                                // <Header for 'Relative volume adjustment', ID: 'RVA'>
                                                                // ID3v2.2 => Increment/decrement     %000000ba
                                                                // ID3v2.3 => Increment/decrement     %00fedcba
                                                                // Bits used for volume descr.        $xx
                                                                // Relative volume change, right      $xx xx (xx ...) // a
                                                                // Relative volume change, left       $xx xx (xx ...) // b
                                                                // Peak volume right                  $xx xx (xx ...)
                                                                // Peak volume left                   $xx xx (xx ...)
                                                                //   ID3v2.3 only, optional (not present in ID3v2.2):
                                                                // Relative volume change, right back $xx xx (xx ...) // c
                                                                // Relative volume change, left back  $xx xx (xx ...) // d
                                                                // Peak volume right back             $xx xx (xx ...)
                                                                // Peak volume left back              $xx xx (xx ...)
                                                                //   ID3v2.3 only, optional (not present in ID3v2.2):
                                                                // Relative volume change, center     $xx xx (xx ...) // e
                                                                // Peak volume center                 $xx xx (xx ...)
                                                                //   ID3v2.3 only, optional (not present in ID3v2.2):
                                                                // Relative volume change, bass       $xx xx (xx ...) // f
                                                                // Peak volume bass                   $xx xx (xx ...)
                                                                $frame_offset = 0;
                                                                $frame_incrdecrflags = BigEndian2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsvolume'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                $frame_bytesvolume = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsvolume'] / 8);
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['right'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['right'] === FALSE) {
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['right'] *= -1;
                                                                }
                                                                $frame_offset += $frame_bytesvolume;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['left'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['left'] === FALSE) {
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['left'] *= -1;
                                                                }
                                                                $frame_offset += $frame_bytesvolume;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['right'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                $frame_offset += $frame_bytesvolume;
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['left'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                $frame_offset += $frame_bytesvolume;
                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                    if (strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']) > 0) {
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['rightrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['rightrear'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['rightrear'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['leftrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['leftrear'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['leftrear'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['rightrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['leftrear'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                    if (strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']) > 0) {
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['center'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['center'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['center'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['center'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                    if (strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']) > 0) {
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['bass'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['incdec']['bass'] === FALSE) {
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['volumechange']['bass'] *= -1;
                                                                        }
                                                                        $frame_offset += $frame_bytesvolume;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakvolume']['bass'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                                                                        $frame_offset += $frame_bytesvolume;
                                                                    }
                                                                }
                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                            } else {
                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'EQU2') {
                                                                    // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
                                                                    //   There may be more than one 'EQU2' frame in each tag,
                                                                    //   but only one with the same identification string
                                                                    // <Header of 'Equalisation (2)', ID: 'EQU2'>
                                                                    // Interpolation method  $xx
                                                                    //   $00  Band
                                                                    //   $01  Linear
                                                                    // Identification        <text string> $00
                                                                    //   The following is then repeated for every adjustment point
                                                                    // Frequency          $xx xx
                                                                    // Volume adjustment  $xx xx
                                                                    $frame_offset = 0;
                                                                    $frame_interpolationmethod = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                    $frame_idstring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                    if (ord($frame_idstring) === 0) {
                                                                        $frame_idstring = '';
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_idstring;
                                                                    $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
                                                                    while (strlen($frame_remainingdata)) {
                                                                        $frame_frequency = BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']["{$frame_frequency}"] = BigEndian2Int(substr($frame_remainingdata, 2, 2));
                                                                        $frame_remainingdata = substr($frame_remainingdata, 4);
                                                                    }
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['interpolationmethod'] = $frame_interpolationmethod;
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                } else {
                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3 && $frame_name == 'EQUA' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'EQU') {
                                                                        // 4.13  EQU  Equalisation (ID3v2.2 only)
                                                                        //   There may only be one 'EQUA' frame in each tag
                                                                        // <Header for 'Relative volume adjustment', ID: 'EQU'>
                                                                        // Adjustment bits    $xx
                                                                        //   This is followed by 2 bytes + ('adjustment bits' rounded up to the
                                                                        //   nearest byte) for every equalisation band in the following format,
                                                                        //   giving a frequency range of 0 - 32767Hz:
                                                                        // Increment/decrement   %x (MSB of the Frequency)
                                                                        // Frequency             (lower 15 bits)
                                                                        // Adjustment            $xx (xx ...)
                                                                        $frame_offset = 0;
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['adjustmentbits'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1);
                                                                        $frame_adjustmentbytes = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['adjustmentbits'] / 8);
                                                                        $frame_remainingdata = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                        while (strlen($frame_remainingdata)) {
                                                                            $frame_frequencystr = BigEndian2Bin(substr($frame_remainingdata, 0, 2));
                                                                            $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
                                                                            $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['incdec'] = $frame_incdec;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['adjustment'] = BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
                                                                            if ($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['incdec'] === FALSE) {
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_frequency}"]['adjustment'] *= -1;
                                                                            }
                                                                            $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
                                                                        }
                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                    } else {
                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'RVRB' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'REV') {
                                                                            // 4.14  REV  Reverb
                                                                            //   There may only be one 'RVRB' frame in each tag.
                                                                            // <Header for 'Reverb', ID: 'RVRB'>
                                                                            // Reverb left (ms)                 $xx xx
                                                                            // Reverb right (ms)                $xx xx
                                                                            // Reverb bounces, left             $xx
                                                                            // Reverb bounces, right            $xx
                                                                            // Reverb feedback, left to left    $xx
                                                                            // Reverb feedback, left to right   $xx
                                                                            // Reverb feedback, right to right  $xx
                                                                            // Reverb feedback, right to left   $xx
                                                                            // Premix left to right             $xx
                                                                            // Premix right to left             $xx
                                                                            $frame_offset = 0;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['left'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                            $frame_offset += 2;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['right'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                            $frame_offset += 2;
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bouncesL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bouncesR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackLL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackLR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackRR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['feedbackRL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['premixLR'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['premixRL'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                        } else {
                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'APIC' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'PIC') {
                                                                                // 4.15  PIC  Attached picture
                                                                                //   There may be several pictures attached to one file,
                                                                                //   each in their individual 'APIC' frame, but only one
                                                                                //   with the same content descriptor
                                                                                // <Header for 'Attached picture', ID: 'APIC'>
                                                                                // Text encoding      $xx
                                                                                // ID3v2.3+ => MIME type          <text string> $00
                                                                                // ID3v2.2  => Image format       $xx xx xx
                                                                                // Picture type       $xx
                                                                                // Description        <text string according to encoding> $00 (00)
                                                                                // Picture data       <binary data>
                                                                                $frame_offset = 0;
                                                                                $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                                                                                    $frame_imagetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                                                    if (strtolower($frame_imagetype) == 'ima') {
                                                                                        // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
                                                                                        // MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoff@pacbell.net)
                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                        $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                        if (ord($frame_mimetype) === 0) {
                                                                                            $frame_mimetype = '';
                                                                                        }
                                                                                        $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
                                                                                        if ($frame_imagetype == 'JPEG') {
                                                                                            $frame_imagetype = 'JPG';
                                                                                        }
                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                    } else {
                                                                                        $frame_offset += 3;
                                                                                    }
                                                                                }
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] > 2) {
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                    $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_mimetype) === 0) {
                                                                                        $frame_mimetype = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                }
                                                                                $frame_picturetype = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                    $frame_terminatorpos++;
                                                                                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                }
                                                                                $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                if (ord($frame_description) === 0) {
                                                                                    $frame_description = '';
                                                                                }
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['imagetype'] = $frame_imagetype;
                                                                                } else {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['mime'] = $frame_mimetype;
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['picturetypeid'] = $frame_picturetype;
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['picturetype'] = APICPictureTypeLookup($frame_picturetype);
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                                                                                include_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
                                                                                $imagechunkcheck = GetDataImageSize($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']);
                                                                                if ($imagechunkcheck[2] >= 1 && $imagechunkcheck[2] <= 3) {
                                                                                    $imagetypes = array(1 => 'image/gif', 2 => 'image/jpeg', 3 => 'image/png');
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_mime'] = $imagetypes["{$imagechunkcheck[2]}"];
                                                                                    if ($imagechunkcheck[0]) {
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_width'] = $imagechunkcheck[0];
                                                                                    }
                                                                                    if ($imagechunkcheck[1]) {
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_height'] = $imagechunkcheck[1];
                                                                                    }
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['image_bytes'] = strlen($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data']);
                                                                                    //$MP3fileInfo['id3']['id3v2']["$frame_name"]["$frame_arrayindex"]['image_offset']  = $MP3fileInfo['id3']['id3v2']["$frame_name"]['dataoffset'] + $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)) + ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
                                                                                }
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                            } else {
                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'GEOB' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'GEO') {
                                                                                    // 4.16  GEO  General encapsulated object
                                                                                    //   There may be more than one 'GEOB' frame in each tag,
                                                                                    //   but only one with the same content descriptor
                                                                                    // <Header for 'General encapsulated object', ID: 'GEOB'>
                                                                                    // Text encoding          $xx
                                                                                    // MIME type              <text string> $00
                                                                                    // Filename               <text string according to encoding> $00 (00)
                                                                                    // Content description    <text string according to encoding> $00 (00)
                                                                                    // Encapsulated object    <binary data>
                                                                                    $frame_offset = 0;
                                                                                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                    $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_mimetype) === 0) {
                                                                                        $frame_mimetype = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                        $frame_terminatorpos++;
                                                                                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                    }
                                                                                    $frame_filename = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_filename) === 0) {
                                                                                        $frame_filename = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                    if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                        $frame_terminatorpos++;
                                                                                        // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                    }
                                                                                    $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                    if (ord($frame_description) === 0) {
                                                                                        $frame_description = '';
                                                                                    }
                                                                                    $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['objectdata'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['mime'] = $frame_mimetype;
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['filename'] = $frame_filename;
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                        if (!isset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression']) || $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags']['compression'] === FALSE) {
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                                                        }
                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                    }
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                } else {
                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'PCNT' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'CNT') {
                                                                                        // 4.17  CNT  Play counter
                                                                                        //   There may only be one 'PCNT' frame in each tag.
                                                                                        //   When the counter reaches all one's, one byte is inserted in
                                                                                        //   front of the counter thus making the counter eight bits bigger
                                                                                        // <Header for 'Play counter', ID: 'PCNT'>
                                                                                        // Counter        $xx xx xx xx (xx ...)
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = BigEndian2Int($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                    } else {
                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'POPM' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'POP') {
                                                                                            // 4.18  POP  Popularimeter
                                                                                            //   There may be more than one 'POPM' frame in each tag,
                                                                                            //   but only one with the same email address
                                                                                            // <Header for 'Popularimeter', ID: 'POPM'>
                                                                                            // Email to user   <text string> $00
                                                                                            // Rating          $xx
                                                                                            // Counter         $xx xx xx xx (xx ...)
                                                                                            $frame_offset = 0;
                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                            $frame_emailaddress = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                            if (ord($frame_emailaddress) === 0) {
                                                                                                $frame_emailaddress = '';
                                                                                            }
                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                            $frame_rating = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset));
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['email'] = $frame_emailaddress;
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['rating'] = $frame_rating;
                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                            }
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                        } else {
                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'RBUF' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'BUF') {
                                                                                                // 4.19  BUF  Recommended buffer size
                                                                                                //   There may only be one 'RBUF' frame in each tag
                                                                                                // <Header for 'Recommended buffer size', ID: 'RBUF'>
                                                                                                // Buffer size               $xx xx xx
                                                                                                // Embedded info flag        %0000000x
                                                                                                // Offset to next tag        $xx xx xx xx
                                                                                                $frame_offset = 0;
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['buffersize'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3));
                                                                                                $frame_offset += 3;
                                                                                                $frame_embeddedinfoflags = BigEndian2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['nexttagoffset'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                            } else {
                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'CRM') {
                                                                                                    // 4.20  Encrypted meta frame (ID3v2.2 only)
                                                                                                    //   There may be more than one 'CRM' frame in a tag,
                                                                                                    //   but only one with the same 'owner identifier'
                                                                                                    // <Header for 'Encrypted meta frame', ID: 'CRM'>
                                                                                                    // Owner identifier      <textstring> $00 (00)
                                                                                                    // Content/explanation   <textstring> $00 (00)
                                                                                                    // Encrypted datablock   <binary data>
                                                                                                    $frame_offset = 0;
                                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                    $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                    if (ord($frame_ownerid) === 0) {
                                                                                                        $frame_ownerid = count($MP3fileInfo['id3']['id3v2']["{$frame_name}"]) - 1;
                                                                                                    }
                                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                    $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                    if (ord($frame_description) === 0) {
                                                                                                        $frame_description = '';
                                                                                                    }
                                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                } else {
                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'AENC' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'CRA') {
                                                                                                        // 4.21  CRA  Audio encryption
                                                                                                        //   There may be more than one 'AENC' frames in a tag,
                                                                                                        //   but only one with the same 'Owner identifier'
                                                                                                        // <Header for 'Audio encryption', ID: 'AENC'>
                                                                                                        // Owner identifier   <text string> $00
                                                                                                        // Preview start      $xx xx
                                                                                                        // Preview length     $xx xx
                                                                                                        // Encryption info    <binary data>
                                                                                                        $frame_offset = 0;
                                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                        $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                        if (ord($frame_ownerid) === 0) {
                                                                                                            $frame_ownerid == '';
                                                                                                        }
                                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['previewstart'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                        $frame_offset += 2;
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['previewlength'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                        $frame_offset += 2;
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encryptioninfo'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_ownerid}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                        }
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                    } else {
                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'LINK' || $MP3fileInfo['id3']['id3v2']['majorversion'] == 2 && $frame_name == 'LNK') {
                                                                                                            // 4.22  LNK  Linked information
                                                                                                            //   There may be more than one 'LINK' frame in a tag,
                                                                                                            //   but only one with the same contents
                                                                                                            // <Header for 'Linked information', ID: 'LINK'>
                                                                                                            // ID3v2.3+ => Frame identifier   $xx xx xx xx
                                                                                                            // ID3v2.2  => Frame identifier   $xx xx xx
                                                                                                            // URL                            <text string> $00
                                                                                                            // ID and additional data         <text string(s)>
                                                                                                            $frame_offset = 0;
                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['frameid'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                                                                                $frame_offset += 3;
                                                                                                            } else {
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['frameid'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4);
                                                                                                                $frame_offset += 4;
                                                                                                            }
                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                            $frame_url = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                            if (ord($frame_url) === 0) {
                                                                                                                $frame_url = '';
                                                                                                            }
                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['url'] = $frame_url;
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['additionaldata'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3) {
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                            }
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                        } else {
                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'POSS') {
                                                                                                                // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
                                                                                                                //   There may only be one 'POSS' frame in each tag
                                                                                                                // <Head for 'Position synchronisation', ID: 'POSS'>
                                                                                                                // Time stamp format         $xx
                                                                                                                // Position                  $xx (xx ...)
                                                                                                                $frame_offset = 0;
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['position'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset));
                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                            } else {
                                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'USER') {
                                                                                                                    // 4.22  USER Terms of use (ID3v2.3+ only)
                                                                                                                    //   There may be more than one 'Terms of use' frame in a tag,
                                                                                                                    //   but only one with the same 'Language'
                                                                                                                    // <Header for 'Terms of use frame', ID: 'USER'>
                                                                                                                    // Text encoding        $xx
                                                                                                                    // Language             $xx xx xx
                                                                                                                    // The actual text      <text string according to encoding>
                                                                                                                    $frame_offset = 0;
                                                                                                                    $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                    $frame_language = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
                                                                                                                    $frame_offset += 3;
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['language'] = $frame_language;
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['languagename'] = LanguageLookup($frame_language, FALSE);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['encodingid'] = $frame_textencoding;
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                    if (!$MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['flags']['compression']) {
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['asciidata'] = RoughTranslateUnicodeToASCII($MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['data'], $frame_textencoding);
                                                                                                                    }
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_language}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                } else {
                                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'OWNE') {
                                                                                                                        // 4.23  OWNE Ownership frame (ID3v2.3+ only)
                                                                                                                        //   There may only be one 'OWNE' frame in a tag
                                                                                                                        // <Header for 'Ownership frame', ID: 'OWNE'>
                                                                                                                        // Text encoding     $xx
                                                                                                                        // Price paid        <text string> $00
                                                                                                                        // Date of purch.    <text string>
                                                                                                                        // Seller            <text string according to encoding>
                                                                                                                        $frame_offset = 0;
                                                                                                                        $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                        $frame_pricepaid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['currency'] = LookupCurrency($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['currencyid'], 'units');
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['pricepaid']['value'] = substr($frame_pricepaid, 3);
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 8);
                                                                                                                        if (!IsValidDateStampString($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'])) {
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedateunix'] = mktime(0, 0, 0, substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'], 4, 2), substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'], 6, 2), substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['purchasedate'], 0, 4));
                                                                                                                        }
                                                                                                                        $frame_offset += 8;
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['seller'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                    } else {
                                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'COMR') {
                                                                                                                            // 4.24  COMR Commercial frame (ID3v2.3+ only)
                                                                                                                            //   There may be more than one 'commercial frame' in a tag,
                                                                                                                            //   but no two may be identical
                                                                                                                            // <Header for 'Commercial frame', ID: 'COMR'>
                                                                                                                            // Text encoding      $xx
                                                                                                                            // Price string       <text string> $00
                                                                                                                            // Valid until        <text string>
                                                                                                                            // Contact URL        <text string> $00
                                                                                                                            // Received as        $xx
                                                                                                                            // Name of seller     <text string according to encoding> $00 (00)
                                                                                                                            // Description        <text string according to encoding> $00 (00)
                                                                                                                            // Picture MIME type  <string> $00
                                                                                                                            // Seller logo        <binary data>
                                                                                                                            $frame_offset = 0;
                                                                                                                            $frame_textencoding = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                            $frame_pricestring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                            $frame_rawpricearray = explode('/', $frame_pricestring);
                                                                                                                            foreach ($frame_rawpricearray as $key => $val) {
                                                                                                                                $frame_currencyid = substr($val, 0, 3);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['price']["{$frame_currencyid}"]['currency'] = LookupCurrency($frame_currencyid, 'units');
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['price']["{$frame_currencyid}"]['value'] = substr($val, 3);
                                                                                                                            }
                                                                                                                            $frame_datestring = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 8);
                                                                                                                            $frame_offset += 8;
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                            $frame_contacturl = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                            $frame_receivedasid = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                                                            if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                                                                $frame_terminatorpos++;
                                                                                                                                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                                                            }
                                                                                                                            $frame_sellername = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            if (ord($frame_sellername) === 0) {
                                                                                                                                $frame_sellername = '';
                                                                                                                            }
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
                                                                                                                            if (ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                                                                                                                                $frame_terminatorpos++;
                                                                                                                                // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                                                                                                                            }
                                                                                                                            $frame_description = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            if (ord($frame_description) === 0) {
                                                                                                                                $frame_description = '';
                                                                                                                            }
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
                                                                                                                            $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                            $frame_mimetype = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                            $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                            $frame_sellerlogo = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encodingid'] = $frame_textencoding;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['pricevaliduntil'] = $frame_datestring;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['contacturl'] = $frame_contacturl;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['receivedasid'] = $frame_receivedasid;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['receivedas'] = COMRReceivedAsLookup($frame_receivedasid);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['sellername'] = $frame_sellername;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciisellername'] = RoughTranslateUnicodeToASCII($frame_sellername, $frame_textencoding);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['description'] = $frame_description;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['mime'] = $frame_mimetype;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['logo'] = $frame_sellerlogo;
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                        } else {
                                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'ENCR') {
                                                                                                                                // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
                                                                                                                                //   There may be several 'ENCR' frames in a tag,
                                                                                                                                //   but only one containing the same symbol
                                                                                                                                //   and only one containing the same owner identifier
                                                                                                                                // <Header for 'Encryption method registration', ID: 'ENCR'>
                                                                                                                                // Owner identifier    <text string> $00
                                                                                                                                // Method symbol       $xx
                                                                                                                                // Encryption data     <binary data>
                                                                                                                                $frame_offset = 0;
                                                                                                                                $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                                $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                                if (ord($frame_ownerid) === 0) {
                                                                                                                                    $frame_ownerid = '';
                                                                                                                                }
                                                                                                                                $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['methodsymbol'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                            } else {
                                                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'GRID') {
                                                                                                                                    // 4.26  GRID Group identification registration (ID3v2.3+ only)
                                                                                                                                    //   There may be several 'GRID' frames in a tag,
                                                                                                                                    //   but only one containing the same symbol
                                                                                                                                    //   and only one containing the same owner identifier
                                                                                                                                    // <Header for 'Group ID registration', ID: 'GRID'>
                                                                                                                                    // Owner identifier      <text string> $00
                                                                                                                                    // Group symbol          $xx
                                                                                                                                    // Group dependent data  <binary data>
                                                                                                                                    $frame_offset = 0;
                                                                                                                                    $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                                    $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                                    if (ord($frame_ownerid) === 0) {
                                                                                                                                        $frame_ownerid = '';
                                                                                                                                    }
                                                                                                                                    $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['groupsymbol'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                                } else {
                                                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'PRIV') {
                                                                                                                                        // 4.27  PRIV Private frame (ID3v2.3+ only)
                                                                                                                                        //   The tag may contain more than one 'PRIV' frame
                                                                                                                                        //   but only with different contents
                                                                                                                                        // <Header for 'Private frame', ID: 'PRIV'>
                                                                                                                                        // Owner identifier      <text string> $00
                                                                                                                                        // The private data      <binary data>
                                                                                                                                        $frame_offset = 0;
                                                                                                                                        $frame_terminatorpos = strpos($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                                                                                                                                        $frame_ownerid = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                                                                                                                                        if (ord($frame_ownerid) === 0) {
                                                                                                                                            $frame_ownerid = '';
                                                                                                                                        }
                                                                                                                                        $frame_offset = $frame_terminatorpos + strlen(chr(0));
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['ownerid'] = $frame_ownerid;
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                                    } else {
                                                                                                                                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'SIGN') {
                                                                                                                                            // 4.28  SIGN Signature frame (ID3v2.4+ only)
                                                                                                                                            //   There may be more than one 'signature frame' in a tag,
                                                                                                                                            //   but no two may be identical
                                                                                                                                            // <Header for 'Signature frame', ID: 'SIGN'>
                                                                                                                                            // Group symbol      $xx
                                                                                                                                            // Signature         <binary data>
                                                                                                                                            $frame_offset = 0;
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['groupsymbol'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['data'] = substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset);
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['flags'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags'];
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['flags']);
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['datalength'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'];
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength']);
                                                                                                                                            $MP3fileInfo['id3']['id3v2']["{$frame_name}"]["{$frame_arrayindex}"]['dataoffset'] = $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'];
                                                                                                                                            unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset']);
                                                                                                                                        } else {
                                                                                                                                            if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'SEEK') {
                                                                                                                                                // 4.29  SEEK Seek frame (ID3v2.4+ only)
                                                                                                                                                //   There may only be one 'seek frame' in a tag
                                                                                                                                                // <Header for 'Seek frame', ID: 'SEEK'>
                                                                                                                                                // Minimum offset to next tag       $xx xx xx xx
                                                                                                                                                $frame_offset = 0;
                                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                            } else {
                                                                                                                                                if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 4 && $frame_name == 'ASPI') {
                                                                                                                                                    // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
                                                                                                                                                    //   There may only be one 'audio seek point index' frame in a tag
                                                                                                                                                    // <Header for 'Seek Point Index', ID: 'ASPI'>
                                                                                                                                                    // Indexed data start (S)         $xx xx xx xx
                                                                                                                                                    // Indexed data length (L)        $xx xx xx xx
                                                                                                                                                    // Number of index points (N)     $xx xx
                                                                                                                                                    // Bits per index point (b)       $xx
                                                                                                                                                    //   Then for every index point the following data is included:
                                                                                                                                                    // Fraction at index (Fi)          $xx (xx)
                                                                                                                                                    $frame_offset = 0;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datastart'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                    $frame_offset += 4;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['indexeddatalength'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                    $frame_offset += 4;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['indexpoints'] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                                                                    $frame_offset += 2;
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsperpoint'] = ord(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
                                                                                                                                                    $frame_bytesperpoint = ceil($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['bitsperpoint'] / 8);
                                                                                                                                                    for ($i = 0; $i < $frame_indexpoints; $i++) {
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['indexes']["{$i}"] = BigEndian2Int(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesperpoint));
                                                                                                                                                        $frame_offset += $frame_bytesperpoint;
                                                                                                                                                    }
                                                                                                                                                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                                    unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                                } else {
                                                                                                                                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] >= 3 && $frame_name == 'RGAD') {
                                                                                                                                                        // Replay Gain Adjustment
                                                                                                                                                        // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
                                                                                                                                                        //   There may only be one 'RGAD' frame in a tag
                                                                                                                                                        // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
                                                                                                                                                        // Peak Amplitude                      $xx $xx $xx $xx
                                                                                                                                                        // Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
                                                                                                                                                        // Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
                                                                                                                                                        //   a - name code
                                                                                                                                                        //   b - originator code
                                                                                                                                                        //   c - sign bit
                                                                                                                                                        //   d - replay gain adjustment
                                                                                                                                                        $frame_offset = 0;
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['peakamplitude'] = BigEndian2Float(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
                                                                                                                                                        $frame_offset += 4;
                                                                                                                                                        $radioadjustment = Dec2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                                                                        $frame_offset += 2;
                                                                                                                                                        $audiophileadjustment = Dec2Bin(substr($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
                                                                                                                                                        $frame_offset += 2;
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['name'] = Bin2Dec(substr($radioadjustment, 0, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['originator'] = Bin2Dec(substr($radioadjustment, 3, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['signbit'] = Bin2Dec(substr($radioadjustment, 6, 1));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['adjustment'] = Bin2Dec(substr($radioadjustment, 7, 9));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['name'] = Bin2Dec(substr($audiophileadjustment, 0, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['originator'] = Bin2Dec(substr($audiophileadjustment, 3, 3));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['signbit'] = Bin2Dec(substr($audiophileadjustment, 6, 1));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['adjustment'] = Bin2Dec(substr($audiophileadjustment, 7, 9));
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['radio']['name'] = RGADnameLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['name']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['radio']['originator'] = RGADoriginatorLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['originator']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['radio']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['adjustment'], $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['radio']['signbit']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['audiophile']['name'] = RGADnameLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['name']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['audiophile']['originator'] = RGADoriginatorLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['originator']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['audiophile']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['adjustment'], $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['raw']['audiophile']['signbit']);
                                                                                                                                                        $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
                                                                                                                                                        unset($MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data']);
                                                                                                                                                    }
                                                                                                                                                }
                                                                                                                                            }
                                                                                                                                        }
                                                                                                                                    }
                                                                                                                                }
                                                                                                                            }
                                                                                                                        }
                                                                                                                    }
                                                                                                                }
                                                                                                            }
                                                                                                        }
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return TRUE;
}
Example #4
0
function getRIFFHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    $Original['avdataoffset'] = $ThisFileInfo['avdataoffset'];
    $Original['avdataend'] = $ThisFileInfo['avdataend'];
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $RIFFheader = fread($fd, 12);
    switch (substr($RIFFheader, 0, 4)) {
        case 'FORM':
            $ThisFileInfo['fileformat'] = 'aiff';
            $RIFFheaderSize = EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
            $ThisFileInfo['RIFF'][substr($RIFFheader, 8, 4)] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + $RIFFheaderSize, $ThisFileInfo);
            $ThisFileInfo['RIFF']['header_size'] = $RIFFheaderSize;
            break;
        case 'RIFF':
        case 'SDSS':
            // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
        // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
        case 'RMP3':
            // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
            $RIFFtype = substr($RIFFheader, 8, 4);
            if ($RIFFtype == 'RMP3') {
                $RIFFtype == 'WAVE';
            }
            $ThisFileInfo['fileformat'] = 'riff';
            $RIFFheaderSize = EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
            $ThisFileInfo['RIFF']["{$RIFFtype}"] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + $RIFFheaderSize, $ThisFileInfo);
            $ThisFileInfo['RIFF']['header_size'] = $RIFFheaderSize;
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
            unset($ThisFileInfo['fileformat']);
            return false;
            break;
    }
    $streamindex = 0;
    $arraykeys = array_keys($ThisFileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
        case 'RMP3':
            // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
            if (empty($ThisFileInfo['audio']['bitrate_mode'])) {
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            if (empty($ThisFileInfo['audio']['dataformat'])) {
                $ThisFileInfo['audio']['dataformat'] = 'wav';
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['size'];
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data']);
                if ($ThisFileInfo['RIFF']['audio'][$streamindex] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: bitrate_audio == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['fmt '] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                if (substr($ThisFileInfo['audio']['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
                    $ThisFileInfo['warning'] .= "\n" . 'Audio codec = ' . $ThisFileInfo['audio']['codec'];
                }
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                if ($ThisFileInfo['audio']['bits_per_sample'] == 0) {
                    unset($ThisFileInfo['audio']['bits_per_sample']);
                }
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
                if (isset($ThisFileInfo['RIFF']['WAVE']['data'][0]['offset']) && isset($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag'])) {
                    $ThisFileInfo['audio']['lossless'] = false;
                    switch ($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag']) {
                        case 1:
                            // PCM
                            $ThisFileInfo['audio']['lossless'] = true;
                            break;
                        default:
                            // do nothing
                            break;
                    }
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                $rgadData = $ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = EitherEndian2Int($ThisFileInfo, substr($rgadData, 4, 2));
                $ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = EitherEndian2Int($ThisFileInfo, substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['rgad']['peakamplitude'] = $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = EitherEndian2Int($ThisFileInfo, substr($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] > 0) {
                    $ThisFileInfo['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $ThisFileInfo['audio']['bitrate'] = CastAsInt($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['title'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 0, 256));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['author'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 256, 32));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['reference'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 288, 32));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'] = substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 320, 10);
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'] = substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 330, 8);
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['time_reference'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 338, 8));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['bwf_version'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 346, 1));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['reserved'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 347, 254));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['coding_history'] = explode("\r\n", trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 601)));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date_unix'] = mktime(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 0, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 3, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 6, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 5, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 8, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 0, 4));
                $ThisFileInfo['RIFF']['comments']['author'][] = $ThisFileInfo['RIFF']['WAVE']['bext'][0]['author'];
                $ThisFileInfo['RIFF']['comments']['title'][] = $ThisFileInfo['RIFF']['WAVE']['bext'][0]['title'];
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 0, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['homogenous'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x1);
                if ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['homogenous']) {
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['padding'] = InverseBoolean($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x2);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['22_or_44'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x4);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['free_format'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x8);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['nominal_frame_size'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 2, 2));
                }
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['anciliary_data_length'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 6, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 8, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_left'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x1);
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_free'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x2);
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_right'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x4);
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['version'] = substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 0, 4);
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['title'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 4, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['artist'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 68, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['cut_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 132, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['client_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 196, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['category'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 260, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['classification'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 324, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['out_cue'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 388, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['start_date'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 452, 10));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['start_time'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 462, 8));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['end_date'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 470, 10));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['end_time'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 480, 8));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['producer_app_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 488, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['producer_app_version'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 552, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['user_defined_text'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 616, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['zero_db_reference'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 680, 4), true);
                for ($i = 0; $i < 8; $i++) {
                    $ThisFileInfo['RIFF']['WAVE']['cart'][0]['post_time'][$i]['usage_fourcc'] = substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 684 + $i * 8, 4);
                    $ThisFileInfo['RIFF']['WAVE']['cart'][0]['post_time'][$i]['timer_value'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 684 + $i * 8 + 4, 4));
                }
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['url'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 748, 1024));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['tag_text'] = explode("\r\n", trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 1772)));
                $ThisFileInfo['RIFF']['comments']['artist'][] = $ThisFileInfo['RIFF']['WAVE']['cart'][0]['artist'];
                $ThisFileInfo['RIFF']['comments']['title'][] = $ThisFileInfo['RIFF']['WAVE']['cart'][0]['title'];
            }
            if (!isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
            }
            if (!empty($ThisFileInfo['wavpack'])) {
                $ThisFileInfo['audio']['dataformat'] = 'wavpack';
                $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
                $ThisFileInfo['audio']['encoder'] = 'WavPack v' . $ThisFileInfo['wavpack']['version'];
                // Reset to the way it was - RIFF parsing will have messed this up
                $ThisFileInfo['avdataend'] = $Original['avdataend'];
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
                fseek($fd, $ThisFileInfo['avdataoffset'] - 44, SEEK_SET);
                $RIFFdata = fread($fd, 44);
                $OrignalRIFFheaderSize = LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
                $OrignalRIFFdataSize = LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
                if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
                    $ThisFileInfo['avdataend'] -= $OrignalRIFFheaderSize - $OrignalRIFFdataSize;
                    fseek($fd, $ThisFileInfo['avdataend'], SEEK_SET);
                    $RIFFdata .= fread($fd, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
                }
                // move the data chunk after all other chunks (if any)
                // so that the RIFF parser doesn't see EOF when trying
                // to skip over the data chunk
                $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
                ParseRIFFdata($RIFFdata, $ThisFileInfo);
            }
            break;
        case 'AVI ':
            $ThisFileInfo['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['dataformat'] = 'avi';
            $ThisFileInfo['mime_type'] = 'video/avi';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['size'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                $avihData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'];
                $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 0, 4));
                // frame display rate (or 0L)
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 4, 4));
                // max. transfer rate
                $ThisFileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 12, 4));
                // the ever-present flags
                $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 16, 4));
                // # frames in file
                $ThisFileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 20, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStreams'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 24, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 28, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 32, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 36, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwScale'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 40, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwRate'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 44, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStart'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 48, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwLength'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 52, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] > 0) {
                    $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'] = $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'];
                    $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'];
                }
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] > 0) {
                    $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'] = $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'];
                    $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'];
                }
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'] = round(1000000 / $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                            $strhData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                            $strhfccType = substr($strhData, 0, 4);
                            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                $strfData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                switch ($strhfccType) {
                                    case 'auds':
                                        $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                                        $ThisFileInfo['audio']['dataformat'] = 'wav';
                                        if (isset($ThisFileInfo['RIFF']['audio']) && is_array($ThisFileInfo['RIFF']['audio'])) {
                                            $streamindex = count($ThisFileInfo['RIFF']['audio']);
                                        }
                                        $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($strfData);
                                        $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                                        unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                                        $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                                        $ThisFileInfo['audio']['lossless'] = false;
                                        switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['wFormatTag']) {
                                            case 1:
                                                // PCM
                                                $ThisFileInfo['audio']['lossless'] = true;
                                                break;
                                            case 85:
                                                // MPEG Layer 3
                                                $ThisFileInfo['audio']['dataformat'] = 'mp3';
                                                break;
                                            case 8192:
                                                // AC-3
                                                $ThisFileInfo['audio']['dataformat'] = 'ac3';
                                                break;
                                            default:
                                                $ThisFileInfo['audio']['dataformat'] = 'wav';
                                                break;
                                        }
                                        break;
                                    case 'iavs':
                                    case 'vids':
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccType'] = substr($strhData, 0, 4);
                                        // same as $strhfccType;
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler'] = substr($strhData, 4, 4);
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwFlags'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 8, 4));
                                        // Contains AVITF_* flags
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wPriority'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 12, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wLanguage'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 14, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwInitialFrames'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 16, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwScale'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 20, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwRate'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 24, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwStart'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 28, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwLength'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 32, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSuggestedBufferSize'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 36, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwQuality'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 40, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSampleSize'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 44, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['rcFrame'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 48, 4));
                                        $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']);
                                        if (!$ThisFileInfo['RIFF']['video'][$streamindex]['codec'] && isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                                        }
                                        $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                                        switch ($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']) {
                                            case 'HFYU':
                                                // Huffman Lossless Codec
                                            // Huffman Lossless Codec
                                            case 'IRAW':
                                                // Intel YUV Uncompressed
                                            // Intel YUV Uncompressed
                                            case 'YUY2':
                                                // Uncompressed YUV 4:2:2
                                                $ThisFileInfo['video']['lossless'] = true;
                                                break;
                                            default:
                                                $ThisFileInfo['video']['lossless'] = false;
                                                break;
                                        }
                                        switch ($strhfccType) {
                                            case 'vids':
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSize'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 0, 4));
                                                // number of bytes required by the BITMAPINFOHEADER structure
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biWidth'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 4, 4));
                                                // width of the bitmap in pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biHeight'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 8, 4));
                                                // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biPlanes'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 12, 2));
                                                // number of color planes on the target device. In most cases this value must be set to 1
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 14, 2));
                                                // Specifies the number of bits per pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'] = substr($strfData, 16, 4);
                                                //
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSizeImage'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 20, 4));
                                                // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biXPelsPerMeter'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 24, 4));
                                                // horizontal resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biYPelsPerMeter'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 28, 4));
                                                // vertical resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrUsed'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 32, 4));
                                                // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrImportant'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 36, 4));
                                                // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                                $ThisFileInfo['video']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'];
                                                if ($ThisFileInfo['RIFF']['video'][$streamindex]['codec'] == 'DV') {
                                                    $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 2;
                                                }
                                                break;
                                            case 'iavs':
                                                $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 1;
                                                break;
                                        }
                                        break;
                                    default:
                                        $ThisFileInfo['warning'] .= "\n" . 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                        break;
                                }
                            }
                        }
                        if (isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                            $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                            switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) {
                                case 'HFYU':
                                    // Huffman Lossless Codec
                                // Huffman Lossless Codec
                                case 'IRAW':
                                    // Intel YUV Uncompressed
                                // Intel YUV Uncompressed
                                case 'YUY2':
                                    // Uncompressed YUV 4:2:2
                                    $ThisFileInfo['video']['lossless'] = true;
                                    $ThisFileInfo['video']['bits_per_sample'] = 24;
                                    break;
                                default:
                                    $ThisFileInfo['video']['lossless'] = false;
                                    $ThisFileInfo['video']['bits_per_sample'] = 24;
                                    break;
                            }
                        }
                    }
                }
            }
            break;
        case 'CDDA':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'cda';
            $ThisFileInfo['audio']['lossless'] = true;
            unset($ThisFileInfo['mime_type']);
            $ThisFileInfo['avdataoffset'] = 44;
            if (isset($ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'])) {
                $fmtData = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'];
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown1'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 0, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 2, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['disc_id'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 4, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 8, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 12, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown6'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 16, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown7'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 20, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] / 75;
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] / 75;
                $ThisFileInfo['comments']['track'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'];
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'];
                // hardcoded data for CD-audio
                $ThisFileInfo['audio']['sample_rate'] = 44100;
                $ThisFileInfo['audio']['channels'] = 2;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['bits_per_sample'];
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            break;
        case 'AIFF':
        case 'AIFC':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'aiff';
            $ThisFileInfo['audio']['lossless'] = true;
            $ThisFileInfo['mime_type'] = 'audio/x-aiff';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['size'];
                if ($ThisFileInfo['avdataend'] > $ThisFileInfo['filesize']) {
                    if ($ThisFileInfo['avdataend'] == $ThisFileInfo['filesize'] + 1 && $ThisFileInfo['filesize'] % 2 == 1) {
                        // structures rounded to 2-byte boundary, but dumb encoders
                        // forget to pad end of file to make this actually work
                    } else {
                        $ThisFileInfo['warning'] .= "\n" . 'Probable truncated AIFF file: expecting ' . $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $ThisFileInfo['avdataoffset']) . ' bytes found';
                    }
                    $ThisFileInfo['avdataend'] = $ThisFileInfo['filesize'];
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'])) {
                $ThisFileInfo['RIFF']['audio']['channels'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 0, 2), true);
                $ThisFileInfo['RIFF']['audio']['total_samples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 2, 4), false);
                $ThisFileInfo['RIFF']['audio']['bits_per_sample'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 6, 2), true);
                $ThisFileInfo['RIFF']['audio']['sample_rate'] = (int) BigEndian2Float(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 8, 10));
                if ($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['size'] > 18) {
                    $ThisFileInfo['RIFF']['audio']['codec_fourcc'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 18, 4);
                    $CodecNameSize = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 22, 1), false);
                    $ThisFileInfo['RIFF']['audio']['codec_name'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 23, $CodecNameSize);
                    if ($ThisFileInfo['RIFF']['audio']['codec_name'] == 'NONE') {
                        $ThisFileInfo['audio']['codec'] = 'Pulse Code Modulation (PCM)';
                        $ThisFileInfo['audio']['lossless'] = true;
                    } else {
                        $ThisFileInfo['audio']['codec'] = $ThisFileInfo['RIFF']['audio']['codec_name'];
                        $ThisFileInfo['audio']['lossless'] = false;
                    }
                }
                $ThisFileInfo['audio']['channels'] = $ThisFileInfo['RIFF']['audio']['channels'];
                if ($ThisFileInfo['RIFF']['audio']['bits_per_sample'] > 0) {
                    $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['audio']['bits_per_sample'];
                }
                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['RIFF']['audio']['sample_rate'];
                if ($ThisFileInfo['audio']['sample_rate'] == 0) {
                    $ThisFileInfo['error'] .= "\n" . 'Corrupted AIFF file: sample_rate == zero';
                    return false;
                }
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['audio']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'])) {
                $offset = 0;
                $CommentCount = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), false);
                $offset += 2;
                for ($i = 0; $i < $CommentCount; $i++) {
                    $ThisFileInfo['comments_raw'][$i]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 4), false);
                    $offset += 4;
                    $ThisFileInfo['comments_raw'][$i]['marker_id'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), true);
                    $offset += 2;
                    $CommentLength = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), false);
                    $offset += 2;
                    $ThisFileInfo['comments_raw'][$i]['comment'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, $CommentLength);
                    $offset += $CommentLength;
                    $ThisFileInfo['comments_raw'][$i]['timestamp_unix'] = DateMac2Unix($ThisFileInfo['comments_raw'][$i]['timestamp']);
                    $ThisFileInfo['RIFF']['comments']['comment'][] = $ThisFileInfo['comments_raw'][$i]['comment'];
                }
            }
            $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
            foreach ($CommentsChunkNames as $key => $value) {
                if (isset($ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'])) {
                    $ThisFileInfo['RIFF']['comments'][$value][] = $ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'];
                }
            }
            if (isset($ThisFileInfo['RIFF']['comments'])) {
                CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
            }
            break;
        case '8SVX':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = '8svx';
            $ThisFileInfo['audio']['bits_per_sample'] = 8;
            $ThisFileInfo['audio']['channels'] = 1;
            // overridden below, if need be
            $ThisFileInfo['mime_type'] = 'audio/x-aiff';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['size'];
                if ($ThisFileInfo['avdataend'] > $ThisFileInfo['filesize']) {
                    $ThisFileInfo['warning'] .= "\n" . 'Probable truncated AIFF file: expecting ' . $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $ThisFileInfo['avdataoffset']) . ' bytes found';
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['offset'])) {
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['oneShotHiSamples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 0, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['repeatHiSamples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 4, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerHiCycle'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 8, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerSec'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 12, 2));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['ctOctave'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 14, 1));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['sCompression'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 15, 1));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['Volume'] = FixedPoint16_16(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 16, 4));
                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerSec'];
                switch ($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['sCompression']) {
                    case 0:
                        $ThisFileInfo['audio']['codec'] = 'Pulse Code Modulation (PCM)';
                        $ThisFileInfo['audio']['lossless'] = true;
                        $ActualBitsPerSample = 8;
                        break;
                    case 1:
                        $ThisFileInfo['audio']['codec'] = 'Fibonacci-delta encoding';
                        $ThisFileInfo['audio']['lossless'] = false;
                        $ActualBitsPerSample = 4;
                        break;
                    default:
                        $ThisFileInfo['warning'] .= "\n" . 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "' . sCompression . '"';
                        break;
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['CHAN'][0]['data'])) {
                $ChannelsIndex = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['CHAN'][0]['data'], 0, 4));
                switch ($ChannelsIndex) {
                    case 6:
                        // Stereo
                        $ThisFileInfo['audio']['channels'] = 2;
                        break;
                    case 2:
                        // Left channel only
                    // Left channel only
                    case 4:
                        // Right channel only
                        $ThisFileInfo['audio']['channels'] = 1;
                        break;
                    default:
                        $ThisFileInfo['warning'] .= "\n" . 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "' . $ChannelsIndex . '"';
                        break;
                }
            }
            $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
            foreach ($CommentsChunkNames as $key => $value) {
                if (isset($ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'])) {
                    $ThisFileInfo['RIFF']['comments'][$value][] = $ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'];
                }
            }
            if (isset($ThisFileInfo['RIFF']['comments'])) {
                CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
            }
            $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ActualBitsPerSample * $ThisFileInfo['audio']['channels'];
            if (!empty($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / ($ThisFileInfo['audio']['bitrate'] / 8);
            }
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|), found "' . $arraykeys[0] . '" instead';
            unset($ThisFileInfo['fileformat']);
            break;
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['DISP']) && is_array($ThisFileInfo['RIFF']['WAVE']['DISP'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $ThisFileInfo['RIFF']['comments']['title'][] = trim(substr($ThisFileInfo['RIFF']['WAVE']['DISP'][count($ThisFileInfo['RIFF']['WAVE']['DISP']) - 1]['data'], 4));
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']) && is_array($ThisFileInfo['RIFF']['WAVE']['INFO'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $RIFFinfoKeyLookup = array('IART' => 'artist', 'IGNR' => 'genre', 'ICMT' => 'comment', 'ICOP' => 'copyright', 'IENG' => 'engineers', 'IKEY' => 'keywords', 'IMED' => 'orignalmedium', 'INAM' => 'name', 'ISRC' => 'sourcesupplier', 'ITCH' => 'digitizer', 'ISBJ' => 'subject', 'ISRF' => 'digitizationsource', 'ISFT' => 'encoded_by');
        foreach ($RIFFinfoKeyLookup as $key => $value) {
            if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"])) {
                foreach ($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"] as $commentid => $commentdata) {
                    if (trim($commentdata['data']) != '') {
                        $ThisFileInfo['RIFF']['comments']["{$value}"][] = trim($commentdata['data']);
                    }
                }
            }
        }
    }
    if (!empty($ThisFileInfo['RIFF']['comments'])) {
        CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, false, true);
    }
    if (empty($ThisFileInfo['audio']['encoder']) && !empty($ThisFileInfo['mpeg']['audio']['LAME']['short_version'])) {
        $ThisFileInfo['audio']['encoder'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
    }
    if (!isset($ThisFileInfo['playtime_seconds'])) {
        $ThisFileInfo['playtime_seconds'] = 0;
    }
    if (isset($ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames']) && isset($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'])) {
        $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
    }
    if ($ThisFileInfo['playtime_seconds'] > 0) {
        if (isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['bitrate'])) {
                $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (isset($ThisFileInfo['RIFF']['audio']) && !isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (!isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['video']['bitrate'])) {
                $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        }
    }
    if (isset($ThisFileInfo['RIFF']['video']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0 && $ThisFileInfo['playtime_seconds'] > 0) {
        $ThisFileInfo['audio']['bitrate'] = 0;
        $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
        foreach ($ThisFileInfo['RIFF']['audio'] as $channelnumber => $audioinfoarray) {
            $ThisFileInfo['video']['bitrate'] -= $audioinfoarray['bitrate'];
            $ThisFileInfo['audio']['bitrate'] += $audioinfoarray['bitrate'];
        }
        if ($ThisFileInfo['video']['bitrate'] <= 0) {
            unset($ThisFileInfo['video']['bitrate']);
        }
        if ($ThisFileInfo['audio']['bitrate'] <= 0) {
            unset($ThisFileInfo['audio']['bitrate']);
        }
    }
    if (!empty($ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'] > 0) {
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
    }
    return true;
}
function getRIFFHeaderFilepointer(&$fd, &$MP3fileInfo)
{
    $offset = 0;
    rewind($fd);
    $MP3fileInfo['RIFF'] = ParseRIFF($fd, $offset, $MP3fileInfo['filesize']);
    $streamindex = 0;
    if (!is_array($MP3fileInfo['RIFF'])) {
        $MP3fileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
        unset($MP3fileInfo['RIFF']);
        unset($MP3fileInfo['fileformat']);
        return FALSE;
    }
    $arraykeys = array_keys($MP3fileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
            $MP3fileInfo['fileformat'] = 'wav';
            if (isset($MP3fileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $fmtData = $MP3fileInfo['RIFF']['WAVE']['fmt '][0]['data'];
                $MP3fileInfo['RIFF']['raw']['fmt ']['wFormatTag'] = LittleEndian2Int(substr($fmtData, 0, 2));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nChannels'] = LittleEndian2Int(substr($fmtData, 2, 2));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] = LittleEndian2Int(substr($fmtData, 4, 4));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] = LittleEndian2Int(substr($fmtData, 8, 4));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nBlockAlign'] = LittleEndian2Int(substr($fmtData, 12, 2));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'] = LittleEndian2Int(substr($fmtData, 14, 2));
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['format'] = RIFFwFormatTagLookup($MP3fileInfo['RIFF']['raw']['fmt ']['wFormatTag']);
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nChannels'];
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channelmode'] = $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] == 1 ? 'mono' : 'stereo';
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['frequency'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8;
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitspersample'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
            }
            if (isset($MP3fileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                $rgadData = $MP3fileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $MP3fileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $MP3fileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = LittleEndian2Int(substr($rgadData, 4, 2));
                $MP3fileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = LittleEndian2Int(substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($MP3fileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($MP3fileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $MP3fileInfo['RIFF']['rgad']['peakamplitude'] = $MP3fileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($MP3fileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $MP3fileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $MP3fileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($MP3fileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $MP3fileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($MP3fileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $MP3fileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $MP3fileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $MP3fileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $MP3fileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $MP3fileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($MP3fileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $MP3fileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = LittleEndian2Int(substr($MP3fileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) {
                    $MP3fileInfo['playtime_seconds'] = (double) $MP3fileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $MP3fileInfo['audiobytes'] = CastAsInt(round($MP3fileInfo['playtime_seconds'] * $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']));
                    $MP3fileInfo['bitrate'] = CastAsInt($MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (!isset($MP3fileInfo['audiobytes']) && isset($MP3fileInfo['RIFF']['WAVE']['data'][0]['size'])) {
                $MP3fileInfo['audiobytes'] = $MP3fileInfo['RIFF']['WAVE']['data'][0]['size'];
            }
            if (!isset($MP3fileInfo['bitrate']) && isset($MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate']) && isset($MP3fileInfo['audiobytes'])) {
                $MP3fileInfo['bitrate'] = $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate'];
                $MP3fileInfo['playtime_seconds'] = (double) ($MP3fileInfo['audiobytes'] * 8 / $MP3fileInfo['bitrate']);
            }
            break;
        case 'AVI ':
            $MP3fileInfo['fileformat'] = 'avi';
            if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['avih']["{$streamindex}"]['data'])) {
                $avihData = $MP3fileInfo['RIFF']['AVI ']['hdrl']['avih']["{$streamindex}"]['data'];
                $MP3fileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = LittleEndian2Int(substr($avihData, 0, 4));
                // frame display rate (or 0L)
                $MP3fileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = LittleEndian2Int(substr($avihData, 4, 4));
                // max. transfer rate
                $MP3fileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = LittleEndian2Int(substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] = LittleEndian2Int(substr($avihData, 12, 4));
                // the ever-present flags
                $MP3fileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = LittleEndian2Int(substr($avihData, 16, 4));
                // # frames in file
                $MP3fileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = LittleEndian2Int(substr($avihData, 20, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwStreams'] = LittleEndian2Int(substr($avihData, 24, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = LittleEndian2Int(substr($avihData, 28, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwWidth'] = LittleEndian2Int(substr($avihData, 32, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwHeight'] = LittleEndian2Int(substr($avihData, 36, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwScale'] = LittleEndian2Int(substr($avihData, 40, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwRate'] = LittleEndian2Int(substr($avihData, 44, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwStart'] = LittleEndian2Int(substr($avihData, 48, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwLength'] = LittleEndian2Int(substr($avihData, 52, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                $MP3fileInfo['RIFF']['video']["{$streamindex}"]['frame_width'] = $MP3fileInfo['RIFF']['raw']['avih']['dwWidth'];
                $MP3fileInfo['RIFF']['video']["{$streamindex}"]['frame_height'] = $MP3fileInfo['RIFF']['raw']['avih']['dwHeight'];
                $MP3fileInfo['RIFF']['video']["{$streamindex}"]['frame_rate'] = round(1000000 / $MP3fileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                $MP3fileInfo['playtime_seconds'] = $MP3fileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($MP3fileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
                $MP3fileInfo['bitrate'] = $MP3fileInfo['filesize'] / $MP3fileInfo['playtime_seconds'] * 8;
            }
            if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']["{$i}"]['data'])) {
                            $strhData = $MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']["{$i}"]['data'];
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccType'] = substr($strhData, 0, 4);
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccHandler'] = substr($strhData, 4, 4);
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwFlags'] = LittleEndian2Int(substr($strhData, 8, 4));
                            // Contains AVITF_* flags
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['wPriority'] = LittleEndian2Int(substr($strhData, 12, 2));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['wLanguage'] = LittleEndian2Int(substr($strhData, 14, 2));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwInitialFrames'] = LittleEndian2Int(substr($strhData, 16, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwScale'] = LittleEndian2Int(substr($strhData, 20, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwRate'] = LittleEndian2Int(substr($strhData, 24, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwStart'] = LittleEndian2Int(substr($strhData, 28, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwLength'] = LittleEndian2Int(substr($strhData, 32, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwSuggestedBufferSize'] = LittleEndian2Int(substr($strhData, 36, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwQuality'] = LittleEndian2Int(substr($strhData, 40, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwSampleSize'] = LittleEndian2Int(substr($strhData, 44, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['rcFrame'] = LittleEndian2Int(substr($strhData, 48, 4));
                            if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strf']["{$i}"]['data'])) {
                                $strfData = $MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strf']["{$i}"]['data'];
                                switch ($MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccType']) {
                                    case 'auds':
                                        if (isset($MP3fileInfo['RIFF']['audio']) && is_array($MP3fileInfo['RIFF']['audio'])) {
                                            $streamindex = count($MP3fileInfo['RIFF']['audio']);
                                        }
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['wFormatTag'] = LittleEndian2Int(substr($strfData, 0, 2));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nChannels'] = LittleEndian2Int(substr($strfData, 2, 2));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nSamplesPerSec'] = LittleEndian2Int(substr($strfData, 4, 4));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nAvgBytesPerSec'] = LittleEndian2Int(substr($strfData, 8, 4));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nBlockAlign'] = LittleEndian2Int(substr($strfData, 12, 2));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nBitsPerSample'] = LittleEndian2Int(substr($strfData, 14, 2));
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['format'] = RIFFwFormatTagLookup($MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['wFormatTag']);
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nChannels'];
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channelmode'] = $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] == 1 ? 'mono' : 'stereo';
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['frequency'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nSamplesPerSec'];
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nAvgBytesPerSec'] * 8;
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitspersample'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nBitsPerSample'];
                                        break;
                                    case 'vids':
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biSize'] = LittleEndian2Int(substr($strfData, 0, 4));
                                        // number of bytes required by the BITMAPINFOHEADER structure
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biWidth'] = LittleEndian2Int(substr($strfData, 4, 4));
                                        // width of the bitmap in pixels
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biHeight'] = LittleEndian2Int(substr($strfData, 8, 4));
                                        // height of the bitmap in pixels. If biHeight is positive, the bitmap is a "bottom-up" DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a "top-down" DIB and its origin is the upper left corner
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biPlanes'] = LittleEndian2Int(substr($strfData, 12, 2));
                                        // number of color planes on the target device. In most cases this value must be set to 1
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biBitCount'] = LittleEndian2Int(substr($strfData, 14, 2));
                                        // Specifies the number of bits per pixels
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['fourcc'] = substr($strfData, 16, 4);
                                        //
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biSizeImage'] = LittleEndian2Int(substr($strfData, 20, 4));
                                        // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biXPelsPerMeter'] = LittleEndian2Int(substr($strfData, 24, 4));
                                        // horizontal resolution, in pixels per metre, of the target device
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biYPelsPerMeter'] = LittleEndian2Int(substr($strfData, 28, 4));
                                        // vertical resolution, in pixels per metre, of the target device
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biClrUsed'] = LittleEndian2Int(substr($strfData, 32, 4));
                                        // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biClrImportant'] = LittleEndian2Int(substr($strfData, 36, 4));
                                        // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                        $MP3fileInfo['RIFF']['video']["{$streamindex}"]['codec'] = RIFFfourccLookup($MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccHandler']);
                                        if (!$MP3fileInfo['RIFF']['video']["{$streamindex}"]['codec'] && RIFFfourccLookup($MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['fourcc'])) {
                                            RIFFfourccLookup($MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['fourcc']);
                                        }
                                        break;
                                }
                            }
                        }
                    }
                }
            }
            break;
        default:
            unset($MP3fileInfo['fileformat']);
            break;
    }
    if (isset($MP3fileInfo['RIFF']['WAVE']['INFO']) && is_array($MP3fileInfo['RIFF']['WAVE']['INFO'])) {
        $MP3fileInfo['RIFF']['title'] = trim(substr($MP3fileInfo['RIFF']['WAVE']['INFO']['DISP'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['DISP']) - 1]['data'], 4));
        $MP3fileInfo['RIFF']['artist'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IART'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IART']) - 1]['data']);
        $MP3fileInfo['RIFF']['genre'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IGNR'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IGNR']) - 1]['data']);
        $MP3fileInfo['RIFF']['comment'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ICMT'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ICMT']) - 1]['data']);
        $MP3fileInfo['RIFF']['copyright'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ICOP'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ICOP']) - 1]['data']);
        $MP3fileInfo['RIFF']['engineers'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IENG'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IENG']) - 1]['data']);
        $MP3fileInfo['RIFF']['keywords'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IKEY'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IKEY']) - 1]['data']);
        $MP3fileInfo['RIFF']['originalmedium'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IMED'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IMED']) - 1]['data']);
        $MP3fileInfo['RIFF']['name'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['INAM'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['INAM']) - 1]['data']);
        $MP3fileInfo['RIFF']['sourcesupplier'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRC'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRC']) - 1]['data']);
        $MP3fileInfo['RIFF']['digitizer'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ITCH'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ITCH']) - 1]['data']);
        $MP3fileInfo['RIFF']['subject'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ISBJ'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ISBJ']) - 1]['data']);
        $MP3fileInfo['RIFF']['digitizationsource'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRF'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRF']) - 1]['data']);
    }
    foreach ($MP3fileInfo['RIFF'] as $key => $value) {
        if (!is_array($value) && !$value) {
            unset($MP3fileInfo['RIFF']["{$key}"]);
        }
    }
    return TRUE;
}
function getRIFFHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $RIFFheader = fread($fd, 12);
    switch (substr($RIFFheader, 0, 4)) {
        case 'RIFF':
        case 'SDSS':
            // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
            $ThisFileInfo['fileformat'] = 'riff';
            $ThisFileInfo['RIFF'][substr($RIFFheader, 8, 4)] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + LittleEndian2Int(substr($RIFFheader, 4, 4)), $ThisFileInfo);
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
            unset($ThisFileInfo['fileformat']);
            return false;
            break;
    }
    $streamindex = 0;
    $arraykeys = array_keys($ThisFileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'wav';
            if (isset($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data']);
                if ($ThisFileInfo['RIFF']['audio'][$streamindex] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: bitrate_audio == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['fmt '] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
                if (isset($ThisFileInfo['RIFF']['WAVE']['data'][0]['offset']) && isset($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag'])) {
                    switch ($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag']) {
                        case 85:
                            // LAME ACM
                            require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                            getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['RIFF']['WAVE']['data'][0]['offset'], false);
                            $ThisFileInfo['audio']['dataformat'] = 'mp3';
                            if (isset($ThisFileInfo['mpeg']['audio'])) {
                                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
                                $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
                                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000;
                                $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate'];
                                $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']);
                            }
                            break;
                        default:
                            // do nothing
                            break;
                    }
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                $rgadData = $ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = LittleEndian2Int(substr($rgadData, 4, 2));
                $ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = LittleEndian2Int(substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['rgad']['peakamplitude'] = $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] > 0) {
                    $ThisFileInfo['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $ThisFileInfo['audio']['bitrate'] = CastAsInt($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (!isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
            }
            break;
        case 'AVI ':
            $ThisFileInfo['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['dataformat'] = 'avi';
            $ThisFileInfo['mime_type'] = 'video/avi';
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                $avihData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'];
                $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = LittleEndian2Int(substr($avihData, 0, 4));
                // frame display rate (or 0L)
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = LittleEndian2Int(substr($avihData, 4, 4));
                // max. transfer rate
                $ThisFileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = LittleEndian2Int(substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] = LittleEndian2Int(substr($avihData, 12, 4));
                // the ever-present flags
                $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = LittleEndian2Int(substr($avihData, 16, 4));
                // # frames in file
                $ThisFileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = LittleEndian2Int(substr($avihData, 20, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStreams'] = LittleEndian2Int(substr($avihData, 24, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = LittleEndian2Int(substr($avihData, 28, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] = LittleEndian2Int(substr($avihData, 32, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] = LittleEndian2Int(substr($avihData, 36, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwScale'] = LittleEndian2Int(substr($avihData, 40, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwRate'] = LittleEndian2Int(substr($avihData, 44, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStart'] = LittleEndian2Int(substr($avihData, 48, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwLength'] = LittleEndian2Int(substr($avihData, 52, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'] = $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'];
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'] = $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'];
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'] = round(1000000 / $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                if (!isset($ThisFileInfo['video']['resolution_x'])) {
                    $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'];
                }
                if (!isset($ThisFileInfo['video']['resolution_y'])) {
                    $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'];
                }
                $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                            $strhData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                            $strhfccType = substr($strhData, 0, 4);
                            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                $strfData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                switch ($strhfccType) {
                                    case 'auds':
                                        $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                                        $ThisFileInfo['audio']['dataformat'] = 'wav';
                                        if (isset($ThisFileInfo['RIFF']['audio']) && is_array($ThisFileInfo['RIFF']['audio'])) {
                                            $streamindex = count($ThisFileInfo['RIFF']['audio']);
                                        }
                                        $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($strfData);
                                        $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                                        unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                                        $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                                        switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['wFormatTag']) {
                                            case 85:
                                                $ThisFileInfo['audio']['dataformat'] = 'mp3';
                                                break;
                                            case 8192:
                                                $ThisFileInfo['audio']['dataformat'] = 'ac3';
                                                break;
                                            default:
                                                $ThisFileInfo['audio']['dataformat'] = 'wav';
                                                break;
                                        }
                                        break;
                                    case 'iavs':
                                    case 'vids':
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccType'] = substr($strhData, 0, 4);
                                        // same as $strhfccType;
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler'] = substr($strhData, 4, 4);
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwFlags'] = LittleEndian2Int(substr($strhData, 8, 4));
                                        // Contains AVITF_* flags
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wPriority'] = LittleEndian2Int(substr($strhData, 12, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wLanguage'] = LittleEndian2Int(substr($strhData, 14, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwInitialFrames'] = LittleEndian2Int(substr($strhData, 16, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwScale'] = LittleEndian2Int(substr($strhData, 20, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwRate'] = LittleEndian2Int(substr($strhData, 24, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwStart'] = LittleEndian2Int(substr($strhData, 28, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwLength'] = LittleEndian2Int(substr($strhData, 32, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSuggestedBufferSize'] = LittleEndian2Int(substr($strhData, 36, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwQuality'] = LittleEndian2Int(substr($strhData, 40, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSampleSize'] = LittleEndian2Int(substr($strhData, 44, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['rcFrame'] = LittleEndian2Int(substr($strhData, 48, 4));
                                        $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']);
                                        if (!$ThisFileInfo['RIFF']['video'][$streamindex]['codec'] && isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                                        }
                                        $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                                        switch ($strhfccType) {
                                            case 'vids':
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSize'] = LittleEndian2Int(substr($strfData, 0, 4));
                                                // number of bytes required by the BITMAPINFOHEADER structure
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biWidth'] = LittleEndian2Int(substr($strfData, 4, 4));
                                                // width of the bitmap in pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biHeight'] = LittleEndian2Int(substr($strfData, 8, 4));
                                                // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biPlanes'] = LittleEndian2Int(substr($strfData, 12, 2));
                                                // number of color planes on the target device. In most cases this value must be set to 1
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'] = LittleEndian2Int(substr($strfData, 14, 2));
                                                // Specifies the number of bits per pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'] = substr($strfData, 16, 4);
                                                //
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSizeImage'] = LittleEndian2Int(substr($strfData, 20, 4));
                                                // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biXPelsPerMeter'] = LittleEndian2Int(substr($strfData, 24, 4));
                                                // horizontal resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biYPelsPerMeter'] = LittleEndian2Int(substr($strfData, 28, 4));
                                                // vertical resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrUsed'] = LittleEndian2Int(substr($strfData, 32, 4));
                                                // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrImportant'] = LittleEndian2Int(substr($strfData, 36, 4));
                                                // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                                if ($ThisFileInfo['RIFF']['video'][$streamindex]['codec'] == 'DV') {
                                                    $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 2;
                                                }
                                                break;
                                            case 'iavs':
                                                $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 1;
                                                break;
                                        }
                                        break;
                                    default:
                                        $ThisFileInfo['warning'] .= "\n" . 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                        break;
                                }
                            }
                        }
                        if (isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                            $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                        }
                    }
                }
            }
            break;
        case 'CDDA':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'cda';
            unset($ThisFileInfo['mime_type']);
            if (isset($ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'])) {
                $fmtData = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'];
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown1'] = LittleEndian2Int(substr($fmtData, 0, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'] = LittleEndian2Int(substr($fmtData, 2, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['disc_id'] = LittleEndian2Int(substr($fmtData, 4, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] = LittleEndian2Int(substr($fmtData, 8, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] = LittleEndian2Int(substr($fmtData, 12, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown6'] = LittleEndian2Int(substr($fmtData, 16, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown7'] = LittleEndian2Int(substr($fmtData, 20, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] / 75;
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] / 75;
                $ThisFileInfo['comments']['track'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'];
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'];
                // hardcoded data for CD-audio
                $ThisFileInfo['audio']['sample_rate'] = 44100;
                $ThisFileInfo['audio']['channels'] = 2;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['bits_per_sample'];
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            break;
        default:
            unset($ThisFileInfo['fileformat']);
            break;
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['DISP']) && is_array($ThisFileInfo['RIFF']['WAVE']['DISP'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $ThisFileInfo['RIFF']['comments']['title'][] = trim(substr($ThisFileInfo['RIFF']['WAVE']['DISP'][count($ThisFileInfo['RIFF']['WAVE']['DISP']) - 1]['data'], 4));
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']) && is_array($ThisFileInfo['RIFF']['WAVE']['INFO'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $RIFFinfoKeyLookup = array('IART' => 'artist', 'IGNR' => 'genre', 'ICMT' => 'comment', 'ICOP' => 'copyright', 'IENG' => 'engineers', 'IKEY' => 'keywords', 'IMED' => 'orignalmedium', 'INAM' => 'name', 'ISRC' => 'sourcesupplier', 'ITCH' => 'digitizer', 'ISBJ' => 'subject', 'ISRF' => 'digitizationsource');
        foreach ($RIFFinfoKeyLookup as $key => $value) {
            foreach ($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"] as $commentid => $commentdata) {
                if (trim($commentdata['data']) != '') {
                    $ThisFileInfo['RIFF']['comments']["{$value}"][] = trim($commentdata['data']);
                }
            }
        }
    }
    if (!empty($ThisFileInfo['RIFF']['comments'])) {
        CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
    }
    if (!isset($ThisFileInfo['playtime_seconds'])) {
        $ThisFileInfo['playtime_seconds'] = 0;
    }
    if (isset($ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames']) && isset($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'])) {
        $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
    }
    if ($ThisFileInfo['playtime_seconds'] > 0) {
        if (isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['bitrate'])) {
                $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (isset($ThisFileInfo['RIFF']['audio']) && !isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (!isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['video']['bitrate'])) {
                $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        }
    }
    if (isset($ThisFileInfo['RIFF']['video']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0 && $ThisFileInfo['playtime_seconds'] > 0) {
        $ThisFileInfo['audio']['bitrate'] = 0;
        $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
        foreach ($ThisFileInfo['RIFF']['audio'] as $channelnumber => $audioinfoarray) {
            $ThisFileInfo['video']['bitrate'] -= $audioinfoarray['bitrate'];
            $ThisFileInfo['audio']['bitrate'] += $audioinfoarray['bitrate'];
        }
        if ($ThisFileInfo['video']['bitrate'] <= 0) {
            unset($ThisFileInfo['video']['bitrate']);
        }
        if ($ThisFileInfo['audio']['bitrate'] <= 0) {
            unset($ThisFileInfo['audio']['bitrate']);
        }
    }
    if (!empty($ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'])) {
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
    }
    // Skip RIFF header
    $ThisFileInfo['avdataoffset'] += 44;
    return true;
}