function Float2String($floatvalue, $bits)
 {
     // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
     switch ($bits) {
         case 32:
             $exponentbits = 8;
             $fractionbits = 23;
             break;
         case 64:
             $exponentbits = 11;
             $fractionbits = 52;
             break;
         default:
             return false;
             break;
     }
     if ($floatvalue >= 0) {
         $signbit = '0';
     } else {
         $signbit = '1';
     }
     $normalizedbinary = NormalizeBinaryPoint(Float2BinaryDecimal($floatvalue), $fractionbits);
     $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent'];
     // (127 or 1023) +/- exponent
     $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
     $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
     return BigEndian2String(Bin2Dec($signbit . $exponentbitstring . $fractionbitstring), $bits % 8, false);
 }
function Float2String($floatvalue, $bits)
{
    // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
    if ($bits != 32 && $bits != 64) {
        return FALSE;
    } else {
        if ($bits == 32) {
            $exponentbits = 8;
            $fractionbits = 23;
        } else {
            if ($bits == 64) {
                $exponentbits = 11;
                $fractionbits = 52;
            }
        }
    }
    if ($floatvalue >= 0) {
        $signbit = '0';
    } else {
        $signbit = '1';
    }
    $normalizedbinary = NormalizeBinaryPoint(Float2BinaryDecimal($floatvalue), $fractionbits);
    $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent'];
    // (127 or 1023) +/- exponent
    $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
    $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
    return BigEndian2String(Bin2Dec($signbit . $exponentbitstring . $fractionbitstring), $bits % 8, FALSE);
}
function GenerateID3v2Tag($data, $majorversion = 4, $minorversion = 0, $paddedlength = 0, $extendedheader = '', $footer = FALSE, $showerrors = TRUE, $noerrorsonly = TRUE)
{
    ID3v2FrameIsAllowed(NULL, '', '');
    // clear static array in case this isn't the first call to GenerateID3v2Tag()
    if (is_array($data)) {
        if (is_array($extendedheader)) {
            // not supported yet
        }
        foreach ($data as $frame_name => $frame_rawinputdata) {
            if (!is_array($frame_rawinputdata[0])) {
                // force everything to be arrayed so only one processing loop
                $frame_rawinputdata = array($frame_rawinputdata);
            }
            foreach ($frame_rawinputdata as $irrelevantindex => $frame_inputdata) {
                if (IsValidID3v2FrameName($frame_name, $majorversion)) {
                    unset($frame_length);
                    unset($frame_flags);
                    $frame_data = FALSE;
                    if (ID3v2FrameIsAllowed($frame_name, $frame_inputdata, $majorversion, $showerrors)) {
                        if ($frame_data = GenerateID3v2FrameData($frame_name, $frame_inputdata, $majorversion, $showerrors)) {
                            if ($majorversion >= 4) {
                                // frame-level unsynchronization
                                $FrameUnsynchronisation = FALSE;
                                $unsynchdata = Unsynchronise($frame_data);
                                if (strlen($unsynchdata) != strlen($frame_data)) {
                                    // unsynchronization needed
                                    $FrameUnsynchronisation = TRUE;
                                    $frame_data = $unsynchdata;
                                    if (isset($TagUnsynchronisation) && $TagUnsynchronisation === FALSE) {
                                        // only set to true if ALL frames are unsynchronised
                                    } else {
                                        $TagUnsynchronisation = TRUE;
                                    }
                                } else {
                                    if (isset($TagUnsynchronisation)) {
                                        $TagUnsynchronisation = FALSE;
                                    }
                                }
                                unset($unsynchdata);
                                $frame_length = BigEndian2String(strlen($frame_data), 4, TRUE);
                            } else {
                                $frame_length = BigEndian2String(strlen($frame_data), 4, FALSE);
                            }
                            $frame_flags = GenerateID3v2FrameFlags($majorversion, ID3v2FrameFlagsLookupTagAlter($frame_name, $majorversion), ID3v2FrameFlagsLookupFileAlter($frame_name, $majorversion), FALSE, FALSE, FALSE, FALSE, $FrameUnsynchronisation, FALSE);
                        }
                    } else {
                        if ($showerrors) {
                            echo 'Frame "' . $frame_name . '" is NOT allowed<BR>';
                        }
                    }
                    if ($frame_data === FALSE) {
                        if ($showerrors) {
                            echo 'GenerateID3v2FrameData() failed for "' . $frame_name . '"<BR>';
                            echo 'Error generated in getID3() v' . GETID3VERSION . '<BR>';
                        }
                        if ($noerrorsonly) {
                            return FALSE;
                        } else {
                            unset($frame_name);
                        }
                    }
                } else {
                    // ignore any invalid frame names, including 'title', 'header', etc
                    unset($frame_name);
                    unset($frame_length);
                    unset($frame_flags);
                    unset($frame_data);
                }
                $tagstring .= $frame_name . $frame_length . $frame_flags . $frame_data;
            }
        }
        if ($footer) {
            if ($showerrors) {
                echo 'Footer not supported (yet)<BR>';
            }
            return FALSE;
        }
        //echo number_format(strlen($tagstring));
        if ($majorversion <= 3) {
            // tag-level unsynchronization
            $unsynchdata = Unsynchronise($tagstring);
            if (strlen($unsynchdata) != strlen($tagstring)) {
                // unsynchronization needed
                $TagUnsynchronisation = TRUE;
                $tagstring = $unsynchdata;
            }
        }
        //echo ' - '.number_format(strlen($tagstring)).'<BR>';
        if (!$footer && $paddedlength > strlen($tagstring) + ID3v2HeaderLength($id3info['majorversion'])) {
            // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength
            // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag."
            $tagstring .= @str_repeat(chr(0), $paddedlength - strlen($tagstring));
        }
        if (substr($tagstring, strlen($tagstring) - 1, 1) == chr(255)) {
            // special unsynchronization case:
            // if last byte == $FF then appended a $00
            $TagUnsynchronisation = TRUE;
            $tagstring .= chr(0);
        }
        $tagheader = 'ID3';
        $tagheader .= chr($majorversion);
        $tagheader .= chr($minorversion);
        $tagheader .= GenerateID3v2TagFlags($majorversion, $TagUnsynchronisation, FALSE, (bool) $extendedheader, FALSE, $footer);
        $tagheader .= BigEndian2String(strlen($tagstring), 4, TRUE);
        return $tagheader . $tagstring;
    } else {
        return FALSE;
    }
}
 function GenerateRealTag()
 {
     $RealCONT = "";
     // object version
     $RealCONT .= BigEndian2String(strlen(@$this->tag_data['title']), 4);
     $RealCONT .= @$this->tag_data['title'];
     $RealCONT .= BigEndian2String(strlen(@$this->tag_data['artist']), 4);
     $RealCONT .= @$this->tag_data['artist'];
     $RealCONT .= BigEndian2String(strlen(@$this->tag_data['copyright']), 4);
     $RealCONT .= @$this->tag_data['copyright'];
     $RealCONT .= BigEndian2String(strlen(@$this->tag_data['comment']), 4);
     $RealCONT .= @$this->tag_data['comment'];
     if ($this->paddedlength > strlen($RealCONT) + 8) {
         $RealCONT .= str_repeat("", $this->paddedlength - strlen($RealCONT) - 8);
     }
     $RealCONT = 'CONT' . BigEndian2String(strlen($RealCONT) + 8, 4) . $RealCONT;
     // CONT chunk identifier + chunk length
     return $RealCONT;
 }