1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at https://github.com/JamesHeinrich/getID3 //
// or https://www.getid3.org //
// or http://getid3.sourceforge.net //
// see readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.avr.php //
// module for analyzing AVR Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
exit;
}
class getid3_avr extends getid3_handler
{
/**
* @return bool
*/
public function Analyze() {
$info = &$this->getid3->info;
// http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
// http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
// offset type length name comments
// ---------------------------------------------------------------------
// 0 char 4 ID format ID == "2BIT"
// 4 char 8 name sample name (unused space filled with 0)
// 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo
// With stereo, samples are alternated,
// the first voice is the left :
// (LRLRLRLRLRLRLRLRLR...)
// 14 short 1 resolution 8, 12 or 16 (bits)
// 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed
// 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on
// 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127
// 0xFFFF means "no MIDI note defined"
// 22 byte 1 Replay speed Frequence in the Replay software
// 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz,
// 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz
// 6=43.885 Khz, 7=47.261 Khz
// -1 (0xFF)=no defined Frequence
// 23 byte 3 sample rate in Hertz
// 26 long 1 size in bytes (2 * bytes in stereo)
// 30 long 1 loop begin 0 for no loop
// 34 long 1 loop size equal to 'size' for no loop
// 38 short 2 Reserved, MIDI keyboard split */
// 40 short 2 Reserved, sample compression */
// 42 short 2 Reserved */
// 44 char 20; Additional filename space, used if (name[7] != 0)
// 64 byte 64 user data
// 128 bytes ? sample data (12 bits samples are coded on 16 bits:
// 0000 xxxx xxxx xxxx)
// ---------------------------------------------------------------------
// Note that all values are in motorola (big-endian) format, and that long is
// assumed to be 4 bytes, and short 2 bytes.
// When reading the samples, you should handle both signed and unsigned data,
// and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert
// 8-bit data between signed/unsigned just add 127 to the sample values.
// Simularly for 16-bit data you should add 32769
$info['fileformat'] = 'avr';
$this->fseek($info['avdataoffset']);
$AVRheader = $this->fread(128);
$info['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
$magic = '2BIT';
if ($info['avr']['raw']['magic'] != $magic) {
$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"');
unset($info['fileformat']);
unset($info['avr']);
return false;
}
$info['avdataoffset'] += 128;
$info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8));
$info['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2));
$info['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2));
$info['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2));
$info['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2));
$info['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2));
$info['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1));
$info['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3));
$info['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4));
$info['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4));
$info['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4));
$info['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2));
$info['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2));
$info['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2));
$info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20));
$info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64));
$info['avr']['flags']['stereo'] = (($info['avr']['raw']['mono'] == 0) ? false : true);
$info['avr']['flags']['signed'] = (($info['avr']['raw']['signed'] == 0) ? false : true);
$info['avr']['flags']['loop'] = (($info['avr']['raw']['loop'] == 0) ? false : true);
$info['avr']['midi_notes'] = array();
if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) {
$info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8;
}
if (($info['avr']['raw']['midi'] & 0x00FF) != 0x00FF) {
$info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0x00FF);
}
if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
$this->warning('Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']));
}
$info['audio']['dataformat'] = 'avr';
$info['audio']['lossless'] = true;
$info['audio']['bitrate_mode'] = 'cbr';
$info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample'];
$info['audio']['sample_rate'] = $info['avr']['sample_rate'];
$info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1);
$bits_per_sample = ($info['avr']['bits_per_sample'] == 8) ? 8 : 16;
$info['audio']['bitrate'] = $bits_per_sample * $info['audio']['channels'] * $info['avr']['sample_rate'];
$info['playtime_seconds'] = getid3_lib::SafeDiv($info['avr']['sample_length'] * $bits_per_sample, $info['audio']['bitrate']);
return true;
}
}
|