function GenerateID3v2FrameData($frame_name, $frame_data, $majorversion = 4, $showerrors = FALSE)
{
    if (!IsValidID3v2FrameName($frame_name, $majorversion)) {
        return FALSE;
    }
    if ($majorversion == 2) {
        ksort($frame_data);
        reset($frame_data);
        switch ($frame_name) {
            case 'TXX':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'WXX':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'IPL':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'MCI':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'ETC':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'MLL':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'STC':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'ULT':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'SLT':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'COM':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'RVA':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'EQU':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'REV':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'PIC':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'GEO':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'CNT':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'POP':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'BUF':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'CRM':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'CRA':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            case 'LNK':
                $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                break;
            default:
                if ($frame_name[0] == 'T') {
                    // T??
                    $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                } else {
                    if ($frame_name[0] == 'W') {
                        // W??
                        $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                    } else {
                        $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                        return FALSE;
                    }
                }
        }
    } else {
        // $majorversion > 2
        switch ($frame_name) {
            case 'UFID':
                // 4.1   UFID Unique file identifier
                // Owner identifier        <text string> $00
                // Identifier              <up to 64 bytes binary data>
                if (strlen($frame_data['data']) > 64) {
                    $error .= 'Identifier not allowed to be longer than 64 bytes in ' . $frame_name . ' (supplied data was ' . strlen($frame_data['data']) . ' bytes long)<BR>';
                } else {
                    $framedata .= str_replace(chr(0), '', $frame_data['ownerid']) . chr(0);
                    $framedata .= substr($frame_data['data'], 0, 64);
                    // max 64 bytes - truncate anything longer
                }
                break;
            case 'TXXX':
                // 4.2.2 TXXX User defined text information frame
                // Text encoding     $xx
                // Description       <text string according to encoding> $00 (00)
                // Value             <text string according to encoding>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    $framedata .= chr($frame_data['encodingid']);
                    $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                    $framedata .= $frame_data['data'];
                }
                break;
            case 'WXXX':
                // 4.3.2 WXXX User defined URL link frame
                // Text encoding     $xx
                // Description       <text string according to encoding> $00 (00)
                // URL               <text string>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    if (!IsValidURL($frame_data['url'], FALSE, FALSE)) {
                        $error .= 'Invalid URL in ' . $frame_name . ' (' . $frame_data['url'] . ')<BR>';
                    } else {
                        $framedata .= chr($frame_data['encodingid']);
                        $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                        $framedata .= $frame_data['url'];
                    }
                }
                break;
            case 'IPLS':
                // 4.4  IPLS Involved people list (ID3v2.3 only)
                // Text encoding     $xx
                // People list strings    <textstrings>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    $framedata .= chr($frame_data['encodingid']);
                    $framedata .= $frame_data['data'];
                }
                break;
            case 'MCDI':
                // 4.4   MCDI Music CD identifier
                // CD TOC                <binary data>
                $framedata .= $frame_data['data'];
                break;
            case 'ETCO':
                // 4.5   ETCO Event timing codes
                // 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.
                if ($frame_data['timestampformat'] > 2 || $frame_data['timestampformat'] < 1) {
                    $error .= 'Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $frame_data['timestampformat'] . ')<BR>';
                } else {
                    $framedata .= chr($frame_data['timestampformat']);
                    foreach ($frame_data as $key => $val) {
                        if (!IsValidETCOevent($val['typeid'], $majorversion)) {
                            $error .= 'Invalid Event Type byte in ' . $frame_name . ' (' . $val['typeid'] . ')<BR>';
                        } else {
                            if ($key != 'timestampformat' && $key != 'flags') {
                                if ($val['timestamp'] > 0 && $previousETCOtimestamp >= $val['timestamp']) {
                                    //   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.
                                    $error .= 'Out-of-order timestamp in ' . $frame_name . ' (' . $val['timestamp'] . ') for Event Type (' . $val['typeid'] . ')<BR>';
                                } else {
                                    $framedata .= chr($val['typeid']);
                                    $framedata .= BigEndian2String($val['timestamp'], 4, FALSE);
                                }
                            }
                        }
                    }
                }
                break;
            case 'MLLT':
                // 4.6   MLLT MPEG location lookup table
                // 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....
                if ($frame_data['framesbetweenreferences'] > 0 && $frame_data['framesbetweenreferences'] <= 65535) {
                    $framedata .= BigEndian2String($frame_data['framesbetweenreferences'], 2, FALSE);
                } else {
                    $error .= 'Invalid MPEG Frames Between References in ' . $frame_name . ' (' . $frame_data['framesbetweenreferences'] . ')<BR>';
                }
                if ($frame_data['bytesbetweenreferences'] > 0 && $frame_data['bytesbetweenreferences'] <= 16777215) {
                    $framedata .= BigEndian2String($frame_data['bytesbetweenreferences'], 3, FALSE);
                } else {
                    $error .= 'Invalid bytes Between References in ' . $frame_name . ' (' . $frame_data['bytesbetweenreferences'] . ')<BR>';
                }
                if ($frame_data['msbetweenreferences'] > 0 && $frame_data['msbetweenreferences'] <= 16777215) {
                    $framedata .= BigEndian2String($frame_data['msbetweenreferences'], 3, FALSE);
                } else {
                    $error .= 'Invalid Milliseconds Between References in ' . $frame_name . ' (' . $frame_data['msbetweenreferences'] . ')<BR>';
                }
                if (!IsWithinBitRange($frame_data['bitsforbytesdeviation'], 8, FALSE)) {
                    if ($frame_data['bitsforbytesdeviation'] % 4 == 0) {
                        $framedata .= chr($frame_data['bitsforbytesdeviation']);
                    } else {
                        $error .= 'Bits For Bytes Deviation in ' . $frame_name . ' (' . $frame_data['bitsforbytesdeviation'] . ') must be a multiple of 4.<BR>';
                    }
                } else {
                    $error .= 'Invalid Bits For Bytes Deviation in ' . $frame_name . ' (' . $frame_data['bitsforbytesdeviation'] . ')<BR>';
                }
                if (!IsWithinBitRange($frame_data['bitsformsdeviation'], 8, FALSE)) {
                    if ($frame_data['bitsformsdeviation'] % 4 == 0) {
                        $framedata .= chr($frame_data['bitsformsdeviation']);
                    } else {
                        $error .= 'Bits For Milliseconds Deviation in ' . $frame_name . ' (' . $frame_data['bitsforbytesdeviation'] . ') must be a multiple of 4.<BR>';
                    }
                } else {
                    $error .= 'Invalid Bits For Milliseconds Deviation in ' . $frame_name . ' (' . $frame_data['bitsformsdeviation'] . ')<BR>';
                }
                foreach ($frame_data as $key => $val) {
                    if ($key != 'framesbetweenreferences' && $key != 'bytesbetweenreferences' && $key != 'msbetweenreferences' && $key != 'bitsforbytesdeviation' && $key != 'bitsformsdeviation' && $key != 'flags') {
                        $unwrittenbitstream .= str_pad(Dec2Bin($val['bytedeviation']), $frame_data['bitsforbytesdeviation'], '0', STR_PAD_LEFT);
                        $unwrittenbitstream .= str_pad(Dec2Bin($val['msdeviation']), $frame_data['bitsformsdeviation'], '0', STR_PAD_LEFT);
                    }
                }
                for ($i = 0; $i < strlen($unwrittenbitstream); $i += 8) {
                    $highnibble = bindec(substr($unwrittenbitstream, $i, 4)) << 4;
                    $lownibble = bindec(substr($unwrittenbitstream, $i + 4, 4));
                    $framedata .= chr($highnibble & $lownibble);
                }
                break;
            case 'SYTC':
                // 4.7   SYTC Synchronised tempo codes
                // 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
                if ($frame_data['timestampformat'] > 2 || $frame_data['timestampformat'] < 1) {
                    $error .= 'Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $frame_data['timestampformat'] . ')<BR>';
                } else {
                    $framedata .= chr($frame_data['timestampformat']);
                    foreach ($frame_data as $key => $val) {
                        if (!IsValidETCOevent($val['typeid'], $majorversion)) {
                            $error .= 'Invalid Event Type byte in ' . $frame_name . ' (' . $val['typeid'] . ')<BR>';
                        } else {
                            if ($key != 'timestampformat' && $key != 'flags') {
                                if ($val['tempo'] < 0 || $val['tempo'] > 510) {
                                    $error .= 'Invalid Tempo (max = 510) in ' . $frame_name . ' (' . $val['tempo'] . ') at timestamp (' . $val['timestamp'] . ')<BR>';
                                } else {
                                    if ($val['tempo'] > 255) {
                                        $framedata .= chr(255);
                                        $val['tempo'] -= 255;
                                    }
                                    $framedata .= chr($val['tempo']);
                                    $framedata .= BigEndian2String($val['timestamp'], 4, FALSE);
                                }
                            }
                        }
                    }
                }
                break;
            case 'USLT':
                // 4.8   USLT Unsynchronised lyric/text transcription
                // Text encoding        $xx
                // Language             $xx xx xx
                // Content descriptor   <text string according to encoding> $00 (00)
                // Lyrics/text          <full text string according to encoding>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    if (LanguageLookup($frame_data['language'], TRUE) == '') {
                        $error .= 'Invalid Language in ' . $frame_name . ' (' . $frame_data['language'] . ')<BR>';
                    } else {
                        $framedata .= chr($frame_data['encodingid']);
                        $framedata .= strtolower($frame_data['language']);
                        $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                        $framedata .= $frame_data['data'];
                    }
                }
                break;
            case 'SYLT':
                // 4.9   SYLT Synchronised lyric/text
                // 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 ...)
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    if (LanguageLookup($frame_data['language'], TRUE) == '') {
                        $error .= 'Invalid Language in ' . $frame_name . ' (' . $frame_data['language'] . ')<BR>';
                    } else {
                        if ($frame_data['timestampformat'] > 2 || $frame_data['timestampformat'] < 1) {
                            $error .= 'Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $frame_data['timestampformat'] . ')<BR>';
                        } else {
                            if (!IsValidSYLTtype($frame_data['contenttypeid'], $majorversion)) {
                                $error .= 'Invalid Content Type byte in ' . $frame_name . ' (' . $frame_data['contenttypeid'] . ')<BR>';
                            } else {
                                if (!is_array($frame_data['data'])) {
                                    $error .= 'Invalid Lyric/Timestamp data in ' . $frame_name . ' (must be an array)<BR>';
                                } else {
                                    $framedata .= chr($frame_data['encodingid']);
                                    $framedata .= strtolower($frame_data['language']);
                                    $framedata .= chr($frame_data['timestampformat']);
                                    $framedata .= chr($frame_data['contenttypeid']);
                                    $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                                    ksort($frame_data['data']);
                                    foreach ($frame_data['data'] as $key => $val) {
                                        $framedata .= $val['data'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                                        $framedata .= BigEndian2String($val['timestamp'], 4, FALSE);
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            case 'COMM':
                // 4.10  COMM Comments
                // 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>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    if (LanguageLookup($frame_data['language'], TRUE) == '') {
                        $error .= 'Invalid Language in ' . $frame_name . ' (' . $frame_data['language'] . ')<BR>';
                    } else {
                        $framedata .= chr($frame_data['encodingid']);
                        $framedata .= strtolower($frame_data['language']);
                        $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                        $framedata .= $frame_data['data'];
                    }
                }
                break;
            case 'RVA2':
                // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
                // 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 ...)
                $framedata .= str_replace(chr(0), '', $frame_data['description']) . chr(0);
                foreach ($frame_data as $key => $val) {
                    if ($key != 'description') {
                        $framedata .= chr($val['channeltypeid']);
                        $framedata .= substr(str_pad(dechex($val['volumeadjust']), 8, '0', STR_PAD_LEFT), 4, 4);
                        // signed 16-bit
                        if (!IsWithinBitRange($frame_data['bitspeakvolume'], 8, FALSE)) {
                            $framedata .= chr($val['bitspeakvolume']);
                            if ($val['bitspeakvolume'] > 0) {
                                $framedata .= BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), FALSE);
                            }
                        } else {
                            $error .= 'Invalid Bits Representing Peak Volume in ' . $frame_name . ' (' . $val['bitspeakvolume'] . ') (range = 0 to 255)<BR>';
                        }
                    }
                }
                break;
            case 'RVAD':
                // 4.12  RVAD Relative volume adjustment (ID3v2.3 only)
                // 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 ...)
                // 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 ...)
                // Relative volume change, center     $xx xx (xx ...) // e
                // Peak volume center                 $xx xx (xx ...)
                // Relative volume change, bass       $xx xx (xx ...) // f
                // Peak volume bass                   $xx xx (xx ...)
                if (!IsWithinBitRange($frame_data['bitsvolume'], 8, FALSE)) {
                    $error .= 'Invalid Bits For Volume Description byte in ' . $frame_name . ' (' . $frame_data['bitsvolume'] . ') (range = 1 to 255)<BR>';
                } else {
                    $incdecflag .= '00';
                    $incdecflag .= Bool2IntString($frame_data['incdec']['right']);
                    // a - Relative volume change, right
                    $incdecflag .= Bool2IntString($frame_data['incdec']['left']);
                    // b - Relative volume change, left
                    $incdecflag .= Bool2IntString($frame_data['incdec']['rightrear']);
                    // c - Relative volume change, right back
                    $incdecflag .= Bool2IntString($frame_data['incdec']['leftrear']);
                    // d - Relative volume change, left back
                    $incdecflag .= Bool2IntString($frame_data['incdec']['center']);
                    // e - Relative volume change, center
                    $incdecflag .= Bool2IntString($frame_data['incdec']['bass']);
                    // f - Relative volume change, bass
                    $framedata .= chr(bindec($incdecflag));
                    $framedata .= chr($frame_data['bitsvolume']);
                    $framedata .= BigEndian2String($frame_data['volumechange']['right'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    $framedata .= BigEndian2String($frame_data['volumechange']['left'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    $framedata .= BigEndian2String($frame_data['peakvolume']['right'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    $framedata .= BigEndian2String($frame_data['peakvolume']['left'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    if ($frame_data['volumechange']['rightrear'] || $frame_data['volumechange']['leftrear'] || $frame_data['peakvolume']['rightrear'] || $frame_data['peakvolume']['leftrear'] || $frame_data['volumechange']['center'] || $frame_data['peakvolume']['center'] || $frame_data['volumechange']['bass'] || $frame_data['peakvolume']['bass']) {
                        $framedata .= BigEndian2String($frame_data['volumechange']['rightrear'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                        $framedata .= BigEndian2String($frame_data['volumechange']['leftrear'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                        $framedata .= BigEndian2String($frame_data['peakvolume']['rightrear'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                        $framedata .= BigEndian2String($frame_data['peakvolume']['leftrear'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    }
                    if ($frame_data['volumechange']['center'] || $frame_data['peakvolume']['center'] || $frame_data['volumechange']['bass'] || $frame_data['peakvolume']['bass']) {
                        $framedata .= BigEndian2String($frame_data['volumechange']['center'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                        $framedata .= BigEndian2String($frame_data['peakvolume']['center'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    }
                    if ($frame_data['volumechange']['bass'] || $frame_data['peakvolume']['bass']) {
                        $framedata .= BigEndian2String($frame_data['volumechange']['bass'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                        $framedata .= BigEndian2String($frame_data['peakvolume']['bass'], ceil($frame_data['bitsvolume'] / 8), FALSE);
                    }
                }
                break;
            case 'EQU2':
                // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
                // 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
                if ($frame_data['interpolationmethod'] < 0 || $frame_data['interpolationmethod'] > 1) {
                    $error .= 'Invalid Interpolation Method byte in ' . $frame_name . ' (' . $frame_data['interpolationmethod'] . ') (valid = 0 or 1)<BR>';
                } else {
                    $framedata .= chr($frame_data['interpolationmethod']);
                    $framedata .= str_replace(chr(0), '', $frame_data['description']) . chr(0);
                    foreach ($frame_data['data'] as $key => $val) {
                        $framedata .= BigEndian2String(round($key * 2), 2, FALSE);
                        $framedata .= substr(str_pad(dechex($val), 4, '0', STR_PAD_LEFT), 4, 4);
                        // signed 16-bit
                    }
                }
                break;
            case 'EQUA':
                // 4.12  EQUA Equalisation (ID3v2.3 only)
                // 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 ...)
                if (!IsWithinBitRange($frame_data['bitsvolume'], 8, FALSE)) {
                    $error .= 'Invalid Adjustment Bits byte in ' . $frame_name . ' (' . $frame_data['bitsvolume'] . ') (range = 1 to 255)<BR>';
                } else {
                    $framedata .= chr($frame_data['adjustmentbits']);
                    foreach ($frame_data as $key => $val) {
                        if ($key != 'bitsvolume') {
                            if ($key > 32767 || $key < 0) {
                                $error .= 'Invalid Frequency in ' . $frame_name . ' (' . $key . ') (range = 0 to 32767)<BR>';
                            } else {
                                if ($val >= 0) {
                                    // put MSB of frequency to 1 if increment, 0 if decrement
                                    $key |= 0x8000;
                                }
                                $framedata .= BigEndian2String($key, 2, FALSE);
                                $framedata .= BigEndian2String($val, ceil($frame_data['adjustmentbits'] / 8), FALSE);
                            }
                        }
                    }
                }
                break;
            case 'RVRB':
                // 4.13  RVRB Reverb
                // 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
                if (!IsWithinBitRange($frame_data['left'], 16, FALSE)) {
                    $error .= 'Invalid Reverb Left in ' . $frame_name . ' (' . $frame_data['left'] . ') (range = 0 to 65535)<BR>';
                } else {
                    if (!IsWithinBitRange($frame_data['right'], 16, FALSE)) {
                        $error .= 'Invalid Reverb Left in ' . $frame_name . ' (' . $frame_data['right'] . ') (range = 0 to 65535)<BR>';
                    } else {
                        if (!IsWithinBitRange($frame_data['bouncesL'], 8, FALSE)) {
                            $error .= 'Invalid Reverb Bounces, Left in ' . $frame_name . ' (' . $frame_data['bouncesL'] . ') (range = 0 to 255)<BR>';
                        } else {
                            if (!IsWithinBitRange($frame_data['bouncesR'], 8, FALSE)) {
                                $error .= 'Invalid Reverb Bounces, Right in ' . $frame_name . ' (' . $frame_data['bouncesR'] . ') (range = 0 to 255)<BR>';
                            } else {
                                if (!IsWithinBitRange($frame_data['feedbackLL'], 8, FALSE)) {
                                    $error .= 'Invalid Reverb Feedback, Left-To-Left in ' . $frame_name . ' (' . $frame_data['feedbackLL'] . ') (range = 0 to 255)<BR>';
                                } else {
                                    if (!IsWithinBitRange($frame_data['feedbackLR'], 8, FALSE)) {
                                        $error .= 'Invalid Reverb Feedback, Left-To-Right in ' . $frame_name . ' (' . $frame_data['feedbackLR'] . ') (range = 0 to 255)<BR>';
                                    } else {
                                        if (!IsWithinBitRange($frame_data['feedbackRR'], 8, FALSE)) {
                                            $error .= 'Invalid Reverb Feedback, Right-To-Right in ' . $frame_name . ' (' . $frame_data['feedbackRR'] . ') (range = 0 to 255)<BR>';
                                        } else {
                                            if (!IsWithinBitRange($frame_data['feedbackRL'], 8, FALSE)) {
                                                $error .= 'Invalid Reverb Feedback, Right-To-Left in ' . $frame_name . ' (' . $frame_data['feedbackRL'] . ') (range = 0 to 255)<BR>';
                                            } else {
                                                if (!IsWithinBitRange($frame_data['premixLR'], 8, FALSE)) {
                                                    $error .= 'Invalid Premix, Left-To-Right in ' . $frame_name . ' (' . $frame_data['premixLR'] . ') (range = 0 to 255)<BR>';
                                                } else {
                                                    if (!IsWithinBitRange($frame_data['premixRL'], 8, FALSE)) {
                                                        $error .= 'Invalid Premix, Right-To-Left in ' . $frame_name . ' (' . $frame_data['premixRL'] . ') (range = 0 to 255)<BR>';
                                                    } else {
                                                        $framedata .= BigEndian2String($frame_data['left'], 2, FALSE);
                                                        $framedata .= BigEndian2String($frame_data['right'], 2, FALSE);
                                                        $framedata .= chr($frame_data['bouncesL']);
                                                        $framedata .= chr($frame_data['bouncesR']);
                                                        $framedata .= chr($frame_data['feedbackLL']);
                                                        $framedata .= chr($frame_data['feedbackLR']);
                                                        $framedata .= chr($frame_data['feedbackRR']);
                                                        $framedata .= chr($frame_data['feedbackRL']);
                                                        $framedata .= chr($frame_data['premixLR']);
                                                        $framedata .= chr($frame_data['premixRL']);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            case 'APIC':
                // 4.14  APIC Attached picture
                // Text encoding      $xx
                // MIME type          <text string> $00
                // Picture type       $xx
                // Description        <text string according to encoding> $00 (00)
                // Picture data       <binary data>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    if (!IsValidAPICpicturetype($frame_data['picturetypeid'], $majorversion)) {
                        $error .= 'Invalid Picture Type byte in ' . $frame_name . ' (' . $frame_data['picturetypeid'] . ') for ID3v2.' . $majorversion . '<BR>';
                    } else {
                        if ($majorversion >= 3 && !IsValidAPICimageformat($frame_data['mime'], $majorversion)) {
                            $error .= 'Invalid MIME Type in ' . $frame_name . ' (' . $frame_data['mime'] . ') for ID3v2.' . $majorversion . '<BR>';
                        } else {
                            if ($frame_data['mime'] == '-->' && !IsValidURL($frame_data['data'], FALSE, FALSE)) {
                                $error .= 'Invalid URL in ' . $frame_name . ' (' . $frame_data['data'] . ')<BR>';
                            } else {
                                $framedata .= chr($frame_data['encodingid']);
                                $framedata .= str_replace(chr(0), '', $frame_data['mime']) . chr(0);
                                $framedata .= chr($frame_data['picturetypeid']);
                                $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                                $framedata .= $frame_data['data'];
                            }
                        }
                    }
                }
                break;
            case 'GEOB':
                // 4.15  GEOB General encapsulated object
                // 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>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                } else {
                    if (!IsValidMIMEstring($frame_data['mime'])) {
                        $error .= 'Invalid MIME Type in ' . $frame_name . ' (' . $frame_data['mime'] . ')<BR>';
                    } else {
                        if (!$frame_data['description']) {
                            $error .= 'Missing Description in ' . $frame_name . '<BR>';
                        } else {
                            $framedata .= chr($frame_data['encodingid']);
                            $framedata .= str_replace(chr(0), '', $frame_data['mime']) . chr(0);
                            $framedata .= $frame_data['filename'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                            $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                            $framedata .= $frame_data['data'];
                        }
                    }
                }
                break;
            case 'PCNT':
                // 4.16  PCNT Play counter
                //   When the counter reaches all one's, one byte is inserted in
                //   front of the counter thus making the counter eight bits bigger
                // Counter        $xx xx xx xx (xx ...)
                $framedata .= BigEndian2String($frame_data['data'], 4, FALSE);
                break;
            case 'POPM':
                // 4.17  POPM Popularimeter
                //   When the counter reaches all one's, one byte is inserted in
                //   front of the counter thus making the counter eight bits bigger
                // Email to user   <text string> $00
                // Rating          $xx
                // Counter         $xx xx xx xx (xx ...)
                if (!IsWithinBitRange($frame_data['rating'], 8, FALSE)) {
                    $error .= 'Invalid Rating byte in ' . $frame_name . ' (' . $frame_data['rating'] . ') (range = 0 to 255)<BR>';
                } else {
                    if (!IsValidEmail($frame_data['email'])) {
                        $error .= 'Invalid Email in ' . $frame_name . ' (' . $frame_data['email'] . ')<BR>';
                    } else {
                        $framedata .= str_replace(chr(0), '', $frame_data['email']) . chr(0);
                        $framedata .= chr($frame_data['rating']);
                        $framedata .= BigEndian2String($frame_data['data'], 4, FALSE);
                    }
                }
                break;
            case 'RBUF':
                // 4.18  RBUF Recommended buffer size
                // Buffer size               $xx xx xx
                // Embedded info flag        %0000000x
                // Offset to next tag        $xx xx xx xx
                if (!IsWithinBitRange($frame_data['buffersize'], 24, FALSE)) {
                    $error .= 'Invalid Buffer Size in ' . $frame_name . '<BR>';
                } else {
                    if (!IsWithinBitRange($frame_data['nexttagoffset'], 32, FALSE)) {
                        $error .= 'Invalid Offset To Next Tag in ' . $frame_name . '<BR>';
                    } else {
                        $framedata .= BigEndian2String($frame_data['buffersize'], 3, FALSE);
                        $flag .= '0000000';
                        $flag .= Bool2IntString($frame_data['flags']['embededinfo']);
                        $framedata .= chr(bindec($flag));
                        $framedata .= BigEndian2String($frame_data['nexttagoffset'], 4, FALSE);
                    }
                }
                break;
            case 'AENC':
                // 4.19  AENC Audio encryption
                // Owner identifier   <text string> $00
                // Preview start      $xx xx
                // Preview length     $xx xx
                // Encryption info    <binary data>
                if (!IsWithinBitRange($frame_data['previewstart'], 16, FALSE)) {
                    $error .= 'Invalid Preview Start in ' . $frame_name . ' (' . $frame_data['previewstart'] . ')<BR>';
                } else {
                    if (!IsWithinBitRange($frame_data['previewlength'], 16, FALSE)) {
                        $error .= 'Invalid Preview Length in ' . $frame_name . ' (' . $frame_data['previewlength'] . ')<BR>';
                    } else {
                        $framedata .= str_replace(chr(0), '', $frame_data['ownerid']) . chr(0);
                        $framedata .= BigEndian2String($frame_data['previewstart'], 2, FALSE);
                        $framedata .= BigEndian2String($frame_data['previewlength'], 2, FALSE);
                        $framedata .= $frame_data['encryptioninfo'];
                    }
                }
                break;
            case 'LINK':
                // 4.20  LINK Linked information
                // Frame identifier               $xx xx xx xx
                // URL                            <text string> $00
                // ID and additional data         <text string(s)>
                if (!IsValidID3v2FrameName($frame_data['frameid'], $majorversion)) {
                    $error .= 'Invalid Frame Identifier in ' . $frame_name . ' (' . $frame_data['frameid'] . ')<BR>';
                } else {
                    if (!IsValidURL($frame_data['url'], TRUE, FALSE)) {
                        $error .= 'Invalid URL in ' . $frame_name . ' (' . $frame_data['url'] . ')<BR>';
                    } else {
                        if (($frame_data['frameid'] == 'AENC' || $frame_data['frameid'] == 'APIC' || $frame_data['frameid'] == 'GEOB' || $frame_data['frameid'] == 'TXXX') && $frame_data['additionaldata'] == '') {
                            $error .= 'Content Descriptor must be specified as additional data for Frame Identifier of ' . $frame_data['frameid'] . ' in ' . $frame_name . '<BR>';
                        } else {
                            if ($frame_data['frameid'] == 'USER' && LanguageLookup($frame_data['additionaldata'], TRUE) == '') {
                                $error .= 'Language must be specified as additional data for Frame Identifier of ' . $frame_data['frameid'] . ' in ' . $frame_name . '<BR>';
                            } else {
                                if ($frame_data['frameid'] == 'PRIV' && $frame_data['additionaldata'] == '') {
                                    $error .= 'Owner Identifier must be specified as additional data for Frame Identifier of ' . $frame_data['frameid'] . ' in ' . $frame_name . '<BR>';
                                } else {
                                    if (($frame_data['frameid'] == 'COMM' || $frame_data['frameid'] == 'SYLT' || $frame_data['frameid'] == 'USLT') && (LanguageLookup(substr($frame_data['additionaldata'], 0, 3), TRUE) == '' || substr($frame_data['additionaldata'], 3) == '')) {
                                        $error .= 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of ' . $frame_data['frameid'] . ' in ' . $frame_name . '<BR>';
                                    } else {
                                        $framedata .= $frame_data['frameid'];
                                        $framedata .= str_replace(chr(0), '', $frame_data['url']) . chr(0);
                                        switch ($frame_data['frameid']) {
                                            case 'COMM':
                                            case 'SYLT':
                                            case 'USLT':
                                            case 'PRIV':
                                            case 'USER':
                                            case 'AENC':
                                            case 'APIC':
                                            case 'GEOB':
                                            case 'TXXX':
                                                $framedata .= $frame_data['additionaldata'];
                                                break;
                                            case 'ASPI':
                                            case 'ETCO':
                                            case 'EQU2':
                                            case 'MCID':
                                            case 'MLLT':
                                            case 'OWNE':
                                            case 'RVA2':
                                            case 'RVRB':
                                            case 'SYTC':
                                            case 'IPLS':
                                            case 'RVAD':
                                            case 'EQUA':
                                                // no additional data required
                                                break;
                                            case 'RBUF':
                                                if ($majorversion == 3) {
                                                    // no additional data required
                                                } else {
                                                    $error .= $frame_data['frameid'] . ' is not a valid Frame Identifier in ' . $frame_name . ' (in ID3v2.' . $majorversion . ')<BR>';
                                                }
                                            default:
                                                if (substr($frame_data['frameid'], 0, 1) == 'T' || substr($frame_data['frameid'], 0, 1) == 'W') {
                                                    // no additional data required
                                                } else {
                                                    $error .= $frame_data['frameid'] . ' is not a valid Frame Identifier in ' . $frame_name . ' (in ID3v2.' . $majorversion . ')<BR>';
                                                }
                                                break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            case 'POSS':
                // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
                // Time stamp format         $xx
                // Position                  $xx (xx ...)
                if ($frame_data['timestampformat'] < 1 || $frame_data['timestampformat'] > 2) {
                    $error .= 'Invalid Time Stamp Format in ' . $frame_name . ' (' . $frame_data['timestampformat'] . ') (valid = 1 or 2)<BR>';
                } else {
                    if (!IsWithinBitRange($frame_data['position'], 32, FALSE)) {
                        $error .= 'Invalid Position in ' . $frame_name . ' (' . $frame_data['position'] . ') (range = 0 to 4294967295)<BR>';
                    } else {
                        $framedata .= chr($frame_data['timestampformat']);
                        $framedata .= BigEndian2String($frame_data['position'], 4, FALSE);
                    }
                }
                break;
            case 'USER':
                // 4.22  USER Terms of use (ID3v2.3+ only)
                // Text encoding        $xx
                // Language             $xx xx xx
                // The actual text      <text string according to encoding>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ')<BR>';
                } else {
                    if (LanguageLookup($frame_data['language'], TRUE) == '') {
                        $error .= 'Invalid Language in ' . $frame_name . ' (' . $frame_data['language'] . ')<BR>';
                    } else {
                        $framedata .= chr($frame_data['encodingid']);
                        $framedata .= strtolower($frame_data['language']);
                        $framedata .= $frame_data['data'];
                    }
                }
                break;
            case 'OWNE':
                // 4.23  OWNE Ownership frame (ID3v2.3+ only)
                // Text encoding     $xx
                // Price paid        <text string> $00
                // Date of purch.    <text string>
                // Seller            <text string according to encoding>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ')<BR>';
                } else {
                    if (!IsANumber($frame_data['pricepaid']['value'], FALSE)) {
                        $error .= 'Invalid Price Paid in ' . $frame_name . ' (' . $frame_data['pricepaid']['value'] . ')<BR>';
                    } else {
                        if (!IsValidDateStampString($frame_data['purchasedate'])) {
                            $error .= 'Invalid Date Of Purchase in ' . $frame_name . ' (' . $frame_data['purchasedate'] . ') (format = YYYYMMDD)<BR>';
                        } else {
                            $framedata .= chr($frame_data['encodingid']);
                            $framedata .= str_replace(chr(0), '', $frame_data['pricepaid']['value']) . chr(0);
                            $framedata .= $frame_data['purchasedate'];
                            $framedata .= $frame_data['seller'];
                        }
                    }
                }
                break;
            case 'COMR':
                // 4.24  COMR Commercial frame (ID3v2.3+ only)
                // 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>
                if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                    $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ')<BR>';
                } else {
                    if (!IsValidDateStampString($frame_data['pricevaliduntil'])) {
                        $error .= 'Invalid Valid Until date in ' . $frame_name . ' (' . $frame_data['pricevaliduntil'] . ') (format = YYYYMMDD)<BR>';
                    } else {
                        if (!IsValidURL($frame_data['contacturl'], FALSE, TRUE)) {
                            $error .= 'Invalid Contact URL in ' . $frame_name . ' (' . $frame_data['contacturl'] . ') (allowed schemes: http, https, ftp, mailto)<BR>';
                        } else {
                            if (!IsValidCOMRreceivedas($frame_data['receivedasid'], $majorversion)) {
                                $error .= 'Invalid Received As byte in ' . $frame_name . ' (' . $frame_data['contacturl'] . ') (range = 0 to 8)<BR>';
                            } else {
                                if (!IsValidMIMEstring($frame_data['mime'])) {
                                    $error .= 'Invalid MIME Type in ' . $frame_name . ' (' . $frame_data['mime'] . ')<BR>';
                                } else {
                                    $framedata .= chr($frame_data['encodingid']);
                                    unset($pricestring);
                                    foreach ($frame_data['price'] as $key => $val) {
                                        if (IsValidPriceString($key . $val['value'])) {
                                            $pricestrings[] = $key . $val['value'];
                                        } else {
                                            $error .= 'Invalid Price String in ' . $frame_name . ' (' . $key . $val['value'] . ')<BR>';
                                        }
                                    }
                                    $framedata .= implode('/', $pricestrings);
                                    $framedata .= $frame_data['pricevaliduntil'];
                                    $framedata .= str_replace(chr(0), '', $frame_data['contacturl']) . chr(0);
                                    $framedata .= chr($frame_data['receivedasid']);
                                    $framedata .= $frame_data['sellername'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                                    $framedata .= $frame_data['description'] . TextEncodingLookup('terminator', $frame_data['encodingid']);
                                    $framedata .= $frame_data['mime'] . chr(0);
                                    $framedata .= $frame_data['logo'];
                                }
                            }
                        }
                    }
                }
                break;
            case 'ENCR':
                // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
                // Owner identifier    <text string> $00
                // Method symbol       $xx
                // Encryption data     <binary data>
                if (!IsWithinBitRange($frame_data['methodsymbol'], 8, FALSE)) {
                    $error .= 'Invalid Group Symbol in ' . $frame_name . ' (' . $frame_data['methodsymbol'] . ') (range = 0 to 255)<BR>';
                } else {
                    $framedata .= str_replace(chr(0), '', $frame_data['ownerid']) . chr(0);
                    $framedata .= ord($frame_data['methodsymbol']);
                    $framedata .= $frame_data['data'];
                }
                break;
            case 'GRID':
                // 4.26  GRID Group identification registration (ID3v2.3+ only)
                // Owner identifier      <text string> $00
                // Group symbol          $xx
                // Group dependent data  <binary data>
                if (!IsWithinBitRange($frame_data['groupsymbol'], 8, FALSE)) {
                    $error .= 'Invalid Group Symbol in ' . $frame_name . ' (' . $frame_data['groupsymbol'] . ') (range = 0 to 255)<BR>';
                } else {
                    $framedata .= str_replace(chr(0), '', $frame_data['ownerid']) . chr(0);
                    $framedata .= ord($frame_data['groupsymbol']);
                    $framedata .= $frame_data['data'];
                }
                break;
            case 'PRIV':
                // 4.27  PRIV Private frame (ID3v2.3+ only)
                // Owner identifier      <text string> $00
                // The private data      <binary data>
                $framedata .= str_replace(chr(0), '', $frame_data['ownerid']) . chr(0);
                $framedata .= $frame_data['data'];
                break;
            case 'SIGN':
                // 4.28  SIGN Signature frame (ID3v2.4+ only)
                // Group symbol      $xx
                // Signature         <binary data>
                if (!IsWithinBitRange($frame_data['groupsymbol'], 8, FALSE)) {
                    $error .= 'Invalid Group Symbol in ' . $frame_name . ' (' . $frame_data['groupsymbol'] . ') (range = 0 to 255)<BR>';
                } else {
                    $framedata .= ord($frame_data['groupsymbol']);
                    $framedata .= $frame_data['data'];
                }
                break;
            case 'SEEK':
                // 4.29  SEEK Seek frame (ID3v2.4+ only)
                // Minimum offset to next tag       $xx xx xx xx
                if (!IsWithinBitRange($frame_data['data'], 32, FALSE)) {
                    $error .= 'Invalid Minimum Offset in ' . $frame_name . ' (' . $frame_data['data'] . ') (range = 0 to 4294967295)<BR>';
                } else {
                    $framedata .= BigEndian2String($frame_data['data'], 4, FALSE);
                }
                break;
            case 'ASPI':
                // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
                // 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)
                if (!IsWithinBitRange($frame_data['datastart'], 32, FALSE)) {
                    $error .= 'Invalid Indexed Data Start in ' . $frame_name . ' (' . $frame_data['datastart'] . ') (range = 0 to 4294967295)<BR>';
                } else {
                    if (!IsWithinBitRange($frame_data['datalength'], 32, FALSE)) {
                        $error .= 'Invalid Indexed Data Length in ' . $frame_name . ' (' . $frame_data['datalength'] . ') (range = 0 to 4294967295)<BR>';
                    } else {
                        if (!IsWithinBitRange($frame_data['indexpoints'], 16, FALSE)) {
                            $error .= 'Invalid Number Of Index Points in ' . $frame_name . ' (' . $frame_data['indexpoints'] . ') (range = 0 to 65535)<BR>';
                        } else {
                            if (!IsWithinBitRange($frame_data['bitsperpoint'], 8, FALSE)) {
                                $error .= 'Invalid Bits Per Index Point in ' . $frame_name . ' (' . $frame_data['bitsperpoint'] . ') (range = 0 to 255)<BR>';
                            } else {
                                if ($frame_data['indexpoints'] != count($frame_data['indexes'])) {
                                    $error .= 'Number Of Index Points does not match actual supplied data in ' . $frame_name . '<BR>';
                                } else {
                                    $framedata .= BigEndian2String($frame_data['datastart'], 4, FALSE);
                                    $framedata .= BigEndian2String($frame_data['datalength'], 4, FALSE);
                                    $framedata .= BigEndian2String($frame_data['indexpoints'], 2, FALSE);
                                    $framedata .= BigEndian2String($frame_data['bitsperpoint'], 1, FALSE);
                                    foreach ($frame_data['indexes'] as $key => $val) {
                                        $framedata .= BigEndian2String($val, ceil($frame_data['bitsperpoint'] / 8), FALSE);
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            case 'RGAD':
                //   RGAD Replay Gain Adjustment
                //   http://privatewww.essex.ac.uk/~djmrob/replaygain/
                // 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
                if ($frame_data['radio_adjustment'] > 51 || $frame_data['radio_adjustment'] < -51) {
                    $error .= 'Invalid Radio Adjustment in ' . $frame_name . ' (' . $frame_data['radio_adjustment'] . ') (range = -51.0 to +51.0)<BR>';
                } else {
                    if ($frame_data['audiophile_adjustment'] > 51 || $frame_data['audiophile_adjustment'] < -51) {
                        $error .= 'Invalid Audiophile Adjustment in ' . $frame_name . ' (' . $frame_data['audiophile_adjustment'] . ') (range = -51.0 to +51.0)<BR>';
                    } else {
                        if (!IsValidRGADname($frame_data['raw']['radio_name'], $majorversion)) {
                            $error .= 'Invalid Radio Name Code in ' . $frame_name . ' (' . $frame_data['raw']['radio_name'] . ') (range = 0 to 2)<BR>';
                        } else {
                            if (!IsValidRGADname($frame_data['raw']['audiophile_name'], $majorversion)) {
                                $error .= 'Invalid Audiophile Name Code in ' . $frame_name . ' (' . $frame_data['raw']['audiophile_name'] . ') (range = 0 to 2)<BR>';
                            } else {
                                if (!IsValidRGADoriginator($frame_data['raw']['radio_originator'], $majorversion)) {
                                    $error .= 'Invalid Radio Originator Code in ' . $frame_name . ' (' . $frame_data['raw']['radio_originator'] . ') (range = 0 to 3)<BR>';
                                } else {
                                    if (!IsValidRGADoriginator($frame_data['raw']['audiophile_originator'], $majorversion)) {
                                        $error .= 'Invalid Audiophile Originator Code in ' . $frame_name . ' (' . $frame_data['raw']['audiophile_originator'] . ') (range = 0 to 3)<BR>';
                                    } else {
                                        $framedata .= Float2String($frame_data['peakamplitude'], 32);
                                        $framedata .= RGADgainString($frame_data['raw']['radio_name'], $frame_data['raw']['radio_originator'], $frame_data['radio_adjustment']);
                                        $framedata .= RGADgainString($frame_data['raw']['audiophile_name'], $frame_data['raw']['audiophile_originator'], $frame_data['audiophile_adjustment']);
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            default:
                if ($frame_name[0] == 'T') {
                    // 4.2. T???  Text information frames
                    // Text encoding                $xx
                    // Information                  <text string(s) according to encoding>
                    if (!IsValidTextEncoding($frame_data['encodingid'], $majorversion)) {
                        $error .= 'Invalid Text Encoding in ' . $frame_name . ' (' . $frame_data['encodingid'] . ') for ID3v2.' . $majorversion . '<BR>';
                    } else {
                        $framedata .= chr($frame_data['encodingid']);
                        $framedata .= $frame_data['data'];
                    }
                } else {
                    if ($frame_name[0] == 'W') {
                        // 4.3. W???  URL link frames
                        // URL              <text string>
                        if (!IsValidURL($frame_data['url'], FALSE, FALSE)) {
                            $error .= 'Invalid URL in ' . $frame_name . ' (' . $frame_data['url'] . ')<BR>';
                        } else {
                            $framedata .= $frame_data['url'];
                        }
                    } else {
                        $error .= $frame_name . ' not yet supported in putid3.php<BR>';
                    }
                }
                break;
        }
    }
    if ($error) {
        if ($showerrors) {
            echo $error;
        }
        return FALSE;
    } else {
        return $framedata;
    }
}
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;
}