PageRenderTime 64ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/scalr-2/tags/scalr-2.0.0/app/src/Lib/Media/Audio/write.id3v2.php

http://scalr.googlecode.com/
PHP | 1143 lines | 609 code | 132 blank | 402 comment | 169 complexity | 787caceb89d84e9db40ae3c17f741dbe MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 5 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2 of the GPL license, |
  8. // | that is bundled with this package in the file license.txt and is |
  9. // | available through the world-wide-web at the following url: |
  10. // | http://www.gnu.org/copyleft/gpl.html |
  11. // +----------------------------------------------------------------------+
  12. // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
  13. // +----------------------------------------------------------------------+
  14. // | Authors: James Heinrich <info?getid3*org> |
  15. // | Allan Hansen <ah?artemis*dk> |
  16. // +----------------------------------------------------------------------+
  17. // | write.id3v1.php |
  18. // | writing module for id3v1 tags |
  19. // | dependencies: module.tag.id3v1.php. |
  20. // +----------------------------------------------------------------------+
  21. //
  22. // $Id: write.id3v2.php,v 1.9 2006/12/25 23:44:23 ah Exp $
  23. class getid3_write_id3v2 extends getid3_handler_write
  24. {
  25. // NOTE: This module ONLY writes tags in UTF-8. All strings must be UTF-8 encoded.
  26. // For multiple values, specify "array of type" instead of type for all T??? and IPLS params except TXXX.
  27. /**2.4
  28. // For multiple values, specify "array of type" instead of type for all T??? params except TXXX.
  29. */
  30. // Identification frames
  31. public $content_group_description; // TIT1 string
  32. public $title; // TIT2 string
  33. public $subtitle; // TIT3 string
  34. public $album; // TALB string
  35. public $original_album_title; // TOAL string
  36. public $track; // TRCK integer or "integer/integer" e.g. "10/12"
  37. public $part_of_set; // TPOS integer or "integer/integer" e.g. "10/12"
  38. public $isrc; // TSRC string
  39. // Involved persons frames
  40. public $artist; // TPE1 string
  41. public $band; // TPE2 string
  42. public $conductor; // TPE3 string
  43. public $remixer; // TPE4 string
  44. public $original_artist; // TOPE string
  45. public $lyricist; // TEXT string
  46. public $original_lyricist; // TOLY string
  47. public $composer; // TCOM string
  48. public $encoded_by; // TENC string
  49. // Derived and subjective properties frames
  50. public $beats_per_minute; // TBPM integer
  51. public $length; // TLEN integer
  52. public $initial_key; // TKEY string
  53. public $language; // TLAN string - ISO-639-2
  54. public $genre; // TCON string or integer
  55. public $file_type; // TFLT string
  56. public $media_type; // TMED string
  57. // Rights and license frames
  58. public $copyright; // TCOP string - must begin with YEAR and a space
  59. public $date; // TDAT string - DDMM
  60. public $year; // TYER string - YYYY
  61. public $original_release_year; // TORY string - YYYY
  62. public $recording_dates; // TRDA string
  63. public $time; // TIME string - HHMM
  64. public $publisher; // TPUB string
  65. public $file_owner; // TOWN string
  66. public $internet_radio_station_name; // TRSN string
  67. public $internet_radio_station_owner; // TRSO string
  68. public $involved_people_list; // IPLS string
  69. // Other text frames
  70. public $original_filename; // TOFN string
  71. public $playlist_delay; // TDLY integer
  72. public $encoder_settings; // TSSE string
  73. // User defined text information frame
  74. public $user_text; // TXXX array of ( unique_description(string) => value(string) )
  75. // Comments
  76. public $comment; // COMM
  77. // URL link frames - details
  78. public $commercial_information; // WCOM url(string)
  79. public $copyright_information; // WCOP url(string)
  80. public $url_file; // WOAF url(string)
  81. public $url_artist; // WOAR url(string)
  82. public $url_source; // WOAS url(string)
  83. public $url_station; // WORS url(string)
  84. public $payment; // WPAY url(string)
  85. public $url_publisher; // WPUB url(string)
  86. // User defined URL link frame
  87. public $url_user; // WXXX array of ( unique_description(string) => url(string) )
  88. // Unique file identifier
  89. public $unique_file_identifier; // UFID
  90. // Music CD identifier
  91. public $music_cd_identifier; // MCDI
  92. // Event timing codes
  93. public $event_timing_codes; // ETCO
  94. // MPEG location lookup table
  95. public $mpeg_location_lookup_table; // MLLT
  96. // Synchronised tempo codes
  97. public $synchronised_tempo_codes; // SYTC
  98. // Unsynchronised lyrics/text transcription
  99. public $unsynchronised_lyrics; // USLT
  100. // Synchronised lyrics/text
  101. public $synchronised_lyrics; // SYLT
  102. // Relative volume adjustment (1)
  103. public $relative_volume_adjustment; // RVAD
  104. // Equalisation (1)
  105. public $equalisation; // EQUA
  106. // Reverb
  107. public $reverb; // RVRB
  108. // Attached picture
  109. public $attached_picture; // APIC
  110. // General encapsulated object
  111. public $general_encapsulated_object; // GEOB
  112. // Play counter
  113. public $play_counter; // PCNT
  114. // Popularimeter
  115. public $popularimeter; // POPM
  116. // Recommended buffer size
  117. public $recommended_buffer_size; // RBUF
  118. // Audio encryption
  119. public $audio_encryption; // AENC
  120. // Linked information
  121. public $linked_information; // LINK
  122. // Position synchronisation frame
  123. public $position_synchronisation; // POSS
  124. // Terms of use frame
  125. public $terms_of_use; // USER
  126. // Ownership frame
  127. public $ownership; // OWNE
  128. // Commercial frame
  129. public $commercial; // COMR
  130. // Encryption method registration
  131. public $encryption_method_registration; // ENCR
  132. // Group identification registration
  133. public $group_identification_registration; // GRID
  134. // Private frame
  135. public $private; // PRIV
  136. /**2.4
  137. // Identification frames
  138. public $content_group_description; // TIT1 string
  139. public $title; // TIT2 string
  140. public $subtitle; // TIT3 string
  141. public $album; // TALB string
  142. public $original_album_title; // TOAL string
  143. public $track; // TRCK integer or "integer/integer" e.g. "10/12"
  144. public $part_of_set; // TPOS integer or "integer/integer" e.g. "10/12"
  145. public $set_subtitle; // TSST string
  146. public $isrc; // TSRC string
  147. // Involved persons frames
  148. public $artist; // TPE1 string
  149. public $band; // TPE2 string
  150. public $conductor; // TPE3 string
  151. public $remixer; // TPE4 string
  152. public $original_artist; // TOPE string
  153. public $lyricist; // TEXT string
  154. public $original_lyricist; // TOLY string
  155. public $composer; // TCOM string
  156. public $musician_credits_list; // TMCL string
  157. public $involved_people_list; // TIPL string
  158. public $encoded_by; // TENC string
  159. // Derived and subjective properties frames
  160. public $beats_per_minute; // TBPM integer
  161. public $length; // TLEN integer
  162. public $initial_key; // TKEY string
  163. public $language; // TLAN string - ISO-639-2
  164. public $genre; // TCON string or integer
  165. public $file_type; // TFLT string
  166. public $media_type; // TMED string
  167. public $mood; // TMOO string
  168. // Rights and license frames
  169. public $copyright; // TCOP string - must begin with YEAR and a space
  170. // TPRO strign - must begin with YEAR and a space
  171. public $publisher; // TPUB string
  172. public $file_owner; // TOWN string
  173. public $internet_radio_station_name; // TRSN string
  174. public $internet_radio_station_owner; // TRSO string
  175. // Other text frames
  176. public $original_filename; // TOFN string
  177. public $playlist_delay; // TDLY integer
  178. public $encoding_time; // TDEN timestamp(string) - yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm, yyyy-MM-ddTHH:mm:ss. All time stamps are UTC.
  179. public $original_release_time; // TDOR timestamp(string) - yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm, yyyy-MM-ddTHH:mm:ss. All time stamps are UTC.
  180. public $recording_time; // TDRC timestamp(string) - yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm, yyyy-MM-ddTHH:mm:ss. All time stamps are UTC.
  181. public $release_time; // TDRL timestamp(string) - yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm, yyyy-MM-ddTHH:mm:ss. All time stamps are UTC.
  182. public $tagging_time; // TDTG timestamp(string) - yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm, yyyy-MM-ddTHH:mm:ss. All time stamps are UTC.
  183. public $encoder_settings; // TSSE string
  184. public $album_sort_order; // TSOA string
  185. public $performer_sort_order; // TSOP string
  186. public $title_sort_order; // TSOT string
  187. // User defined text information frame
  188. public $user_text; // TXXX array of ( unique_description(string) => value(string) )
  189. // Comments
  190. public $comment; // COMM
  191. // URL link frames - details
  192. public $commercial_information; // WCOM url(string)
  193. public $copyright_information; // WCOP url(string)
  194. public $url_file; // WOAF url(string)
  195. public $url_artist; // WOAR url(string)
  196. public $url_source; // WOAS url(string)
  197. public $url_station; // WORS url(string)
  198. public $payment; // WPAY url(string)
  199. public $url_publisher; // WPUB url(string)
  200. // User defined URL link frame
  201. public $url_user; // WXXX array of ( unique_description(string) => url(string) )
  202. // Unique file identifier
  203. public $unique_file_identifier; // UFID
  204. // Music CD identifier
  205. public $music_cd_identifier; // MCDI
  206. // Event timing codes
  207. public $event_timing_codes; // ETCO
  208. // MPEG location lookup table
  209. public $mpeg_location_lookup_table; // MLLT
  210. // Synchronised tempo codes
  211. public $synchronised_tempo_codes; // SYTC
  212. // Unsynchronised lyrics/text transcription
  213. public $unsynchronised_lyrics; // USLT
  214. // Synchronised lyrics/text
  215. public $synchronised_lyrics; // SYLT
  216. // Relative volume adjustment (2)
  217. public $relative_volume_adjustment; // RVA2
  218. // Equalisation (2)
  219. public $equalisation; // EQU2
  220. // Reverb
  221. public $reverb; // RVRB
  222. // Attached picture
  223. public $attached_picture; // APIC
  224. // General encapsulated object
  225. public $general_encapsulated_object; // GEOB
  226. // Play counter
  227. public $play_counter; // PCNT
  228. // Popularimeter
  229. public $popularimeter; // POPM
  230. // Recommended buffer size
  231. public $recommended_buffer_size; // RBUF
  232. // Audio encryption
  233. public $audio_encryption; // AENC
  234. // Linked information
  235. public $linked_information; // LINK
  236. // Position synchronisation frame
  237. public $position_synchronisation; // POSS
  238. // Terms of use frame
  239. public $terms_of_use; // USER
  240. // Ownership frame
  241. public $ownership; // OWNE
  242. // Commercial frame
  243. public $commercial; // COMR
  244. // Encryption method registration
  245. public $encryption_method_registration; // ENCR
  246. // Group identification registration
  247. public $group_identification_registration; // GRID
  248. // Private frame
  249. public $private; // PRIV
  250. // Signature frame
  251. public $signature; // SIGN
  252. // Seek frame
  253. public $seek; // SEEK
  254. // Audio seek point index
  255. public $audio_seek_point_index; // ASPI
  256. */
  257. // internal logic
  258. protected $padded_length = 4096; // minimum length of ID3v2 tag in bytes
  259. protected $previous_frames = array ();
  260. const major_version = 3;
  261. public function read() {
  262. }
  263. public function write() {
  264. $engine = new getid3;
  265. $engine->filename = $this->filename;
  266. $engine->fp = fopen($this->filename, 'rb');
  267. $engine->include_module('tag.id3v2');
  268. $tag = new getid3_id3v2($engine);
  269. $tag->Analyze();
  270. if (!(int)@$engine->info['avdataoffset']) {
  271. throw new getid3_exception('No audio data found.');
  272. }
  273. $this->padded_length = max(@$engine->info['id3v2']['headerlength'], $this->padded_length);
  274. $tag = $this->generate_tag();
  275. // insert-overwrite existing tag (padded to length of old tag if neccesary)
  276. if (@$engine->info['id3v2']['headerlength'] && ($engine->info['id3v2']['headerlength'] == strlen($tag))) {
  277. if (!$fp = fopen($this->filename, 'r+b')) {
  278. throw new getid3_exception('Could not open '.$this->filename.' mode "r+b"');
  279. }
  280. fwrite($fp, $tag, strlen($tag));
  281. fclose($fp);
  282. }
  283. // rewrite file - no tag present or new tag longer than old tag
  284. else
  285. if (!$fp_source = @fopen($this->filename, 'rb')) {
  286. throw new getid3_exception('Could not open '.$this->filename.' mode "rb"');
  287. }
  288. fseek($fp_source, $engine->info['avdataoffset'], SEEK_SET);
  289. if (!$fp_temp = @fopen($this->filename.'getid3tmp', 'w+b')) {
  290. throw new getid3_exception('Could not open '.$this->filename.'getid3tmp mode "w+b"');
  291. }
  292. fwrite($fp, $tag, strlen($tag));
  293. while ($buffer = fread($fp_source, 16384)) {
  294. fwrite($fp_temp, $buffer, strlen($buffer));
  295. }
  296. fclose($fp_temp);
  297. fclose($fp_source);
  298. $this->save_permissions();
  299. unlink($this->filename);
  300. rename($this->filename.'getid3tmp', $this->filename);
  301. $this->restore_permissions();
  302. }
  303. clearstatcache();
  304. return true;
  305. }
  306. public function remove() {
  307. $engine = new getid3;
  308. $engine->filename = $this->filename;
  309. $engine->fp = fopen($this->filename, 'rb');
  310. $engine->include_module('tag.id3v2');
  311. $tag = new getid3_id3v2($engine);
  312. $tag->Analyze();
  313. if ((int)@$engine->info['avdataoffset']) {
  314. if (!$fp_source = @fopen($this->filename, 'rb')) {
  315. throw new getid3_exception('Could not open '.$this->filename.' mode "rb"');
  316. }
  317. fseek($fp_source, $engine->info['avdataoffset'], SEEK_SET);
  318. if (!$fp_temp = @fopen($this->filename.'getid3tmp', 'w+b')) {
  319. throw new getid3_exception('Could not open '.$this->filename.'getid3tmp mode "w+b"');
  320. }
  321. while ($buffer = fread($fp_source, 16384)) {
  322. fwrite($fp_temp, $buffer, strlen($buffer));
  323. }
  324. fclose($fp_temp);
  325. fclose($fp_source);
  326. $this->save_permissions();
  327. unlink($this->filename);
  328. rename($this->filename.'getid3tmp', $this->filename);
  329. $this->restore_permissions();
  330. clearstatcache();
  331. }
  332. // success when removing non-existant tag
  333. return true;
  334. }
  335. protected function generate_tag() {
  336. $result = '';
  337. $some_array = array (
  338. 'content_group_description' => 'TIT1',
  339. 'title' => 'TIT2',
  340. 'subtitle' => 'TIT3',
  341. );
  342. foreach ($some_array as $key => $frame_name) {
  343. if ($frame_data = $this->generate_frame_data($frame_name, $this->$key)) {
  344. $frame_length = $this->BigEndian2String(strlen($frame_data), 4, false);
  345. $frame_flags = $this->generate_frame_flags();
  346. }
  347. $result .= $frame_name.$frame_length.$frame_flags.$frame_data;
  348. }
  349. // calc padded length of tag
  350. while ($this->padded_length < (strlen($result) + 10)) {
  351. $this->padded_length += 1024;
  352. }
  353. // pad up to $padded_length bytes if unpadded tag is shorter than $padded_length
  354. if ($this->padded_length > (strlen($result) + 10)) {
  355. $result .= @str_repeat("\x00", $this->padded_length - strlen($result) - 10);
  356. }
  357. $header = 'ID3';
  358. $header .= chr(getid3_id3v2_write::major_version);
  359. $header .= chr(0);
  360. $header .= $this->generate_tag_flags();
  361. $header .= getid3_lib::BigEndian2String(strlen($result), 4, true);
  362. return $header.$result;
  363. }
  364. protected function generate_tag_flags($flags) {
  365. // %abc00000
  366. $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
  367. $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header
  368. $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator
  369. $flag .= '00000';
  370. /**2.4
  371. // %abcd0000
  372. $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
  373. $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header
  374. $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator
  375. $flag .= (@$flags['footer'] ? '1' : '0'); // d - Footer present
  376. $flag .= '0000';
  377. */
  378. return chr(bindec($flag));
  379. }
  380. protected function generate_frame_flags($flags) {
  381. // %abc00000 %ijk00000
  382. $flag1 = (@$flags['tag_alter'] ? '1' : '0'); // a - Tag alter preservation (true == discard)
  383. $flag1 .= (@$flags['file_alter'] ? '1' : '0'); // b - File alter preservation (true == discard)
  384. $flag1 .= (@$flags['read_only'] ? '1' : '0'); // c - Read only (true == read only)
  385. $flag1 .= '00000';
  386. $flag2 = (@$flags['compression'] ? '1' : '0'); // i - Compression (true == compressed)
  387. $flag2 .= (@$flags['encryption'] ? '1' : '0'); // j - Encryption (true == encrypted)
  388. $flag2 .= (@$flags['grouping_identity'] ? '1' : '0'); // k - Grouping identity (true == contains group information)
  389. $flag2 .= '00000';
  390. /**2.4
  391. // %0abc0000 %0h00kmnp
  392. $flag1 = '0';
  393. $flag1 = (@$flags['tag_alter'] ? '1' : '0'); // a - Tag alter preservation (true == discard)
  394. $flag1 .= (@$flags['file_alter'] ? '1' : '0'); // b - File alter preservation (true == discard)
  395. $flag1 .= (@$flags['read_only'] ? '1' : '0'); // c - Read only (true == read only)
  396. $flag1 .= '0000';
  397. $flag2 = '0';
  398. $flag2 .= (@$flags['grouping_identity'] ? '1' : '0'); // h - Grouping identity (true == contains group information)
  399. $flag2 .= '00';
  400. $flag2 = (@$flags['compression'] ? '1' : '0'); // k - Compression (true == compressed)
  401. $flag2 .= (@$flags['encryption'] ? '1' : '0'); // m - Encryption (true == encrypted)
  402. $flag2 .= (@$flags['unsynchronisation'] ? '1' : '0'); // n - Unsynchronisation (true == unsynchronised)
  403. $flag2 .= (@$flags['data_length_indicator'] ? '1' : '0'); // p - Data length indicator (true == data length indicator added)
  404. */
  405. return chr(bindec($flag1)).chr(bindec($flag2));
  406. }
  407. protected function generate_frame_data($frame_name, $source_data_array) {
  408. $frame_data = '';
  409. switch ($frame_name) {
  410. case 'UFID':
  411. // 4.1 UFID Unique file identifier
  412. // Owner identifier <text string> $00
  413. // Identifier <up to 64 bytes binary data>
  414. if (strlen($source_data_array['data']) > 64) {
  415. throw new getid3_exception('Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($source_data_array['data']).' bytes long)');
  416. }
  417. $frame_data .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
  418. $frame_data .= substr($source_data_array['data'], 0, 64); // max 64 bytes - truncate anything longer
  419. break;
  420. case 'TXXX':
  421. // 4.2.2 TXXX User defined text information frame
  422. // Text encoding $xx
  423. // Description <text string according to encoding> $00 (00)
  424. // Value <text string according to encoding>
  425. $frame_data .= chr(3); // UTF-8 encoding
  426. $frame_data .= $source_data_array['description']."\x00";
  427. $frame_data .= $source_data_array['data'];
  428. break;
  429. case 'WXXX':
  430. // 4.3.2 WXXX User defined URL link frame
  431. // Text encoding $xx
  432. // Description <text string according to encoding> $00 (00)
  433. // URL <text string>
  434. if (!isset($source_data_array['data']) || !$this->valid_url($source_data_array['data'], false, false)) {
  435. throw new getid3_exception('Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')');
  436. }
  437. $frame_data .= chr(3); // UTF-8 encoding
  438. $frame_data .= $source_data_array['description']."\x00";
  439. $frame_data .= $source_data_array['data'];
  440. break;
  441. case 'IPLS':
  442. // 4.4 IPLS Involved people list (ID3v2.3 only)
  443. // Text encoding $xx
  444. // People list strings <textstrings>
  445. $frame_data .= chr(3); // UTF-8 encoding
  446. $frame_data .= $source_data_array['data'];
  447. break;
  448. case 'MCDI':
  449. // 4.4 MCDI Music CD identifier
  450. // CD TOC <binary data>
  451. $frame_data .= $source_data_array['data'];
  452. break;
  453. case 'ETCO':
  454. // 4.5 ETCO Event timing codes
  455. // Time stamp format $xx
  456. // Where time stamp format is:
  457. // $01 (32-bit value) MPEG frames from beginning of file
  458. // $02 (32-bit value) milliseconds from beginning of file
  459. // Followed by a list of key events in the following format:
  460. // Type of event $xx
  461. // Time stamp $xx (xx ...)
  462. // The 'Time stamp' is set to zero if directly at the beginning of the sound
  463. // or after the previous event. All events MUST be sorted in chronological order.
  464. if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
  465. throw new getid3_exception('Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')');
  466. }
  467. $frame_data .= chr($source_data_array['timestampformat']);
  468. foreach ($source_data_array as $key => $val) {
  469. if (!$this->ID3v2IsValidETCOevent($val['typeid'])) {
  470. throw new getid3_exception('Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')');
  471. }
  472. if (($key != 'timestampformat') && ($key != 'flags')) {
  473. if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) {
  474. // The 'Time stamp' is set to zero if directly at the beginning of the sound
  475. // or after the previous event. All events MUST be sorted in chronological order.
  476. throw new getid3_exception('Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')');
  477. }
  478. $frame_data .= chr($val['typeid']);
  479. $frame_data .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
  480. }
  481. }
  482. break;
  483. case 'MLLT':
  484. // 4.6 MLLT MPEG location lookup table
  485. // MPEG frames between reference $xx xx
  486. // Bytes between reference $xx xx xx
  487. // Milliseconds between reference $xx xx xx
  488. // Bits for bytes deviation $xx
  489. // Bits for milliseconds dev. $xx
  490. // Then for every reference the following data is included;
  491. // Deviation in bytes %xxx....
  492. // Deviation in milliseconds %xxx....
  493. if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535)) {
  494. $frame_data .= getid3_lib::BigEndian2String($source_data_array['framesbetweenreferences'], 2, false);
  495. }
  496. else {
  497. throw new getid3_exception('Invalid MPEG Frames Between References in '.$frame_name.' ('.$source_data_array['framesbetweenreferences'].')');
  498. }
  499. if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215)) {
  500. $frame_data .= getid3_lib::BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false);
  501. }
  502. else {
  503. throw new getid3_exception('Invalid bytes Between References in '.$frame_name.' ('.$source_data_array['bytesbetweenreferences'].')');
  504. }
  505. if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215)) {
  506. $frame_data .= getid3_lib::BigEndian2String($source_data_array['msbetweenreferences'], 3, false);
  507. }
  508. else {
  509. throw new getid3_exception('Invalid Milliseconds Between References in '.$frame_name.' ('.$source_data_array['msbetweenreferences'].')');
  510. }
  511. if (!$this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false)) {
  512. if (($source_data_array['bitsforbytesdeviation'] % 4) == 0) {
  513. $frame_data .= chr($source_data_array['bitsforbytesdeviation']);
  514. }
  515. else {
  516. throw new getid3_exception('Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.');
  517. }
  518. }
  519. else {
  520. throw new getid3_exception('Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].')');
  521. }
  522. if (!$this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false)) {
  523. if (($source_data_array['bitsformsdeviation'] % 4) == 0) {
  524. $frame_data .= chr($source_data_array['bitsformsdeviation']);
  525. }
  526. else {
  527. throw new getid3_exception('Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.');
  528. }
  529. }
  530. else {
  531. throw new getid3_exception('Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsformsdeviation'].')');
  532. }
  533. foreach ($source_data_array as $key => $val) {
  534. if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags')) {
  535. $unwritten_bit_stream .= str_pad(getid3_lib::Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT);
  536. $unwritten_bit_stream .= str_pad(getid3_lib::Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT);
  537. }
  538. }
  539. for ($i = 0; $i < strlen($unwritten_bit_stream); $i += 8) {
  540. $high_nibble = bindec(substr($unwritten_bit_stream, $i, 4)) << 4;
  541. $low_nibble = bindec(substr($unwritten_bit_stream, $i + 4, 4));
  542. $frame_data .= chr($high_nibble & $low_nibble);
  543. }
  544. break;
  545. case 'SYTC':
  546. // 4.7 SYTC Synchronised tempo codes
  547. // Time stamp format $xx
  548. // Tempo data <binary data>
  549. // Where time stamp format is:
  550. // $01 (32-bit value) MPEG frames from beginning of file
  551. // $02 (32-bit value) milliseconds from beginning of file
  552. if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
  553. throw new getid3_exception('Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')');
  554. }
  555. $frame_data .= chr($source_data_array['timestampformat']);
  556. foreach ($source_data_array as $key => $val) {
  557. if (!$this->ID3v2IsValidETCOevent($val['typeid'])) {
  558. throw new getid3_exception('Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')');
  559. }
  560. if (($key != 'timestampformat') && ($key != 'flags')) {
  561. if (($val['tempo'] < 0) || ($val['tempo'] > 510)) {
  562. throw new getid3_exception('Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')');
  563. }
  564. if ($val['tempo'] > 255) {
  565. $frame_data .= chr(255);
  566. $val['tempo'] -= 255;
  567. }
  568. $frame_data .= chr($val['tempo']);
  569. $frame_data .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
  570. }
  571. }
  572. break;
  573. case 'USLT':
  574. // 4.8 USLT Unsynchronised lyric/text transcription
  575. // Text encoding $xx
  576. // Language $xx xx xx
  577. // Content descriptor <text string according to encoding> $00 (00)
  578. // Lyrics/text <full text string according to encoding>
  579. if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
  580. throw new getid3_exception('Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')');
  581. }
  582. $frame_data .= chr(3); // UTF-8 encoding
  583. $frame_data .= strtolower($source_data_array['language']);
  584. $frame_data .= $source_data_array['description']."\x00";
  585. $frame_data .= $source_data_array['data'];
  586. break;
  587. case 'SYLT':
  588. // 4.9 SYLT Synchronised lyric/text
  589. // Text encoding $xx
  590. // Language $xx xx xx
  591. // Time stamp format $xx
  592. // $01 (32-bit value) MPEG frames from beginning of file
  593. // $02 (32-bit value) milliseconds from beginning of file
  594. // Content type $xx
  595. // Content descriptor <text string according to encoding> $00 (00)
  596. // Terminated text to be synced (typically a syllable)
  597. // Sync identifier (terminator to above string) $00 (00)
  598. // Time stamp $xx (xx ...)
  599. if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
  600. throw new getid3_exception('Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')');
  601. }
  602. if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
  603. throw new getid3_exception('Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')');
  604. }
  605. if (!$this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid'])) {
  606. throw new getid3_exception('Invalid Content Type byte in '.$frame_name.' ('.$source_data_array['contenttypeid'].')');
  607. }
  608. if (!is_array($source_data_array['data'])) {
  609. throw new getid3_exception('Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)');
  610. }
  611. $frame_data .= chr(3); // UTF-8 encoding
  612. $frame_data .= strtolower($source_data_array['language']);
  613. $frame_data .= chr($source_data_array['timestampformat']);
  614. $frame_data .= chr($source_data_array['contenttypeid']);
  615. $frame_data .= $source_data_array['description']."\x00";
  616. ksort($source_data_array['data']);
  617. foreach ($source_data_array['data'] as $key => $val) {
  618. $frame_data .= $val['data']."\x00";
  619. $frame_data .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
  620. }
  621. break;
  622. case 'COMM':
  623. // 4.10 COMM Comments
  624. // Text encoding $xx
  625. // Language $xx xx xx
  626. // Short content descrip. <text string according to encoding> $00 (00)
  627. // The actual text <full text string according to encoding>
  628. if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
  629. throw new getid3_exception('Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')');
  630. }
  631. $frame_data .= chr(3); // UTF-8 encoding
  632. $frame_data .= strtolower($source_data_array['language']);
  633. $frame_data .= $source_data_array['description']."\x00";
  634. $frame_data .= $source_data_array['data'];
  635. break;
  636. case 'RVA2':
  637. // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
  638. // Identification <text string> $00
  639. // The 'identification' string is used to identify the situation and/or
  640. // device where this adjustment should apply. The following is then
  641. // repeated for every channel:
  642. // Type of channel $xx
  643. // Volume adjustment $xx xx
  644. // Bits representing peak $xx
  645. // Peak volume $xx (xx ...)
  646. $frame_data .= str_replace("\x00", '', $source_data_array['description'])."\x00";
  647. foreach ($source_data_array as $key => $val) {
  648. if ($key != 'description') {
  649. $frame_data .= chr($val['channeltypeid']);
  650. $frame_data .= getid3_lib::BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit
  651. if (!$this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false)) {
  652. $frame_data .= chr($val['bitspeakvolume']);
  653. if ($val['bitspeakvolume'] > 0) {
  654. $frame_data .= getid3_lib::BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false);
  655. }
  656. } else {
  657. throw new getid3_exception('Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)');
  658. }
  659. }
  660. }
  661. break;
  662. case 'RVAD':
  663. // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
  664. // Increment/decrement %00fedcba
  665. // Bits used for volume descr. $xx
  666. // Relative volume change, right $xx xx (xx ...) // a
  667. // Relative volume change, left $xx xx (xx ...) // b
  668. // Peak volume right $xx xx (xx ...)
  669. // Peak volume left $xx xx (xx ...)
  670. // Relative volume change, right back $xx xx (xx ...) // c
  671. // Relative volume change, left back $xx xx (xx ...) // d
  672. // Peak volume right back $xx xx (xx ...)
  673. // Peak volume left back $xx xx (xx ...)
  674. // Relative volume change, center $xx xx (xx ...) // e
  675. // Peak volume center $xx xx (xx ...)
  676. // Relative volume change, bass $xx xx (xx ...) // f
  677. // Peak volume bass $xx xx (xx ...)
  678. if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) {
  679. throw new getid3_exception('Invalid Bits For Volume Description byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)');
  680. } else {
  681. $inc_dec_flag .= '00';
  682. $inc_dec_flag .= $source_data_array['incdec']['right'] ? '1' : '0'; // a - Relative volume change, right
  683. $inc_dec_flag .= $source_data_array['incdec']['left'] ? '1' : '0'; // b - Relative volume change, left
  684. $inc_dec_flag .= $source_data_array['incdec']['rightrear'] ? '1' : '0'; // c - Relative volume change, right back
  685. $inc_dec_flag .= $source_data_array['incdec']['leftrear'] ? '1' : '0'; // d - Relative volume change, left back
  686. $inc_dec_flag .= $source_data_array['incdec']['center'] ? '1' : '0'; // e - Relative volume change, center
  687. $inc_dec_flag .= $source_data_array['incdec']['bass'] ? '1' : '0'; // f - Relative volume change, bass
  688. $frame_data .= chr(bindec($inc_dec_flag));
  689. $frame_data .= chr($source_data_array['bitsvolume']);
  690. $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
  691. $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
  692. $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
  693. $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
  694. if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] ||
  695. $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] ||
  696. $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] ||
  697. $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
  698. $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume']/8), false);
  699. $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume']/8), false);
  700. $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume']/8), false);
  701. $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume']/8), false);
  702. }
  703. if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] ||
  704. $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
  705. $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume']/8), false);
  706. $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume']/8), false);
  707. }
  708. if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
  709. $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume']/8), false);
  710. $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume']/8), false);
  711. }
  712. }
  713. break;
  714. case 'EQU2':
  715. // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
  716. // Interpolation method $xx
  717. // $00 Band
  718. // $01 Linear
  719. // Identification <text string> $00
  720. // The following is then repeated for every adjustment point
  721. // Frequency $xx xx
  722. // Volume adjustment $xx xx
  723. if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1)) {
  724. throw new getid3_exception('Invalid Interpolation Method byte in '.$frame_name.' ('.$source_data_array['interpolationmethod'].') (valid = 0 or 1)');
  725. }
  726. $frame_data .= chr($source_data_array['interpolationmethod']);
  727. $frame_data .= str_replace("\x00", '', $source_data_array['description'])."\x00";
  728. foreach ($source_data_array['data'] as $key => $val) {
  729. $frame_data .= getid3_lib::BigEndian2String(intval(round($key * 2)), 2, false);
  730. $frame_data .= getid3_lib::BigEndian2String($val, 2, false, true); // signed 16-bit
  731. }
  732. break;
  733. case 'EQUA':
  734. // 4.12 EQUA Equalisation (ID3v2.3 only)
  735. // Adjustment bits $xx
  736. // This is followed by 2 bytes + ('adjustment bits' rounded up to the
  737. // nearest byte) for every equalisation band in the following format,
  738. // giving a frequency range of 0 - 32767Hz:
  739. // Increment/decrement %x (MSB of the Frequency)
  740. // Frequency (lower 15 bits)
  741. // Adjustment $xx (xx ...)
  742. if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) {
  743. throw new getid3_exception('Invalid Adjustment Bits byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)');
  744. }
  745. $frame_data .= chr($source_data_array['adjustmentbits']);
  746. foreach ($source_data_array as $key => $val) {
  747. if ($key != 'bitsvolume') {
  748. if (($key > 32767) || ($key < 0)) {
  749. throw new getid3_exception('Invalid Frequency in '.$frame_name.' ('.$key.') (range = 0 to 32767)');
  750. } else {
  751. if ($val >= 0) {
  752. // put MSB of frequency to 1 if increment, 0 if decrement

Large files files are truncated, but you can click here to view the full file