├── .gitignore
├── README.md
├── inc
├── css
│ ├── bttn.css
│ └── sb.css
├── js
│ ├── filter.js
│ └── jquery-3.3.1.min.js
└── json
│ └── soundboard.json
├── index.html
├── node
├── .gitignore
├── config
│ ├── config.js
│ └── config.json
├── index.html
├── json_filename.js
├── package-lock.json
└── package.json
├── php
├── buildJSON_filename.php
├── buildJSON_id3.php
├── config.php
├── filename_version.php
├── getID3
│ ├── extension.cache.dbm.php
│ ├── extension.cache.mysql.php
│ ├── extension.cache.mysqli.php
│ ├── extension.cache.sqlite3.php
│ ├── getid3.lib.php
│ ├── getid3.php
│ ├── module.archive.gzip.php
│ ├── module.archive.rar.php
│ ├── module.archive.szip.php
│ ├── module.archive.tar.php
│ ├── module.archive.zip.php
│ ├── module.audio-video.asf.php
│ ├── module.audio-video.bink.php
│ ├── module.audio-video.flv.php
│ ├── module.audio-video.matroska.php
│ ├── module.audio-video.mpeg.php
│ ├── module.audio-video.nsv.php
│ ├── module.audio-video.quicktime.php
│ ├── module.audio-video.real.php
│ ├── module.audio-video.riff.php
│ ├── module.audio-video.swf.php
│ ├── module.audio-video.ts.php
│ ├── module.audio.aa.php
│ ├── module.audio.aac.php
│ ├── module.audio.ac3.php
│ ├── module.audio.amr.php
│ ├── module.audio.au.php
│ ├── module.audio.avr.php
│ ├── module.audio.bonk.php
│ ├── module.audio.dsf.php
│ ├── module.audio.dss.php
│ ├── module.audio.dts.php
│ ├── module.audio.flac.php
│ ├── module.audio.la.php
│ ├── module.audio.lpac.php
│ ├── module.audio.midi.php
│ ├── module.audio.mod.php
│ ├── module.audio.monkey.php
│ ├── module.audio.mp3.php
│ ├── module.audio.mpc.php
│ ├── module.audio.ogg.php
│ ├── module.audio.optimfrog.php
│ ├── module.audio.rkau.php
│ ├── module.audio.shorten.php
│ ├── module.audio.tta.php
│ ├── module.audio.voc.php
│ ├── module.audio.vqf.php
│ ├── module.audio.wavpack.php
│ ├── module.graphic.bmp.php
│ ├── module.graphic.efax.php
│ ├── module.graphic.gif.php
│ ├── module.graphic.jpg.php
│ ├── module.graphic.pcd.php
│ ├── module.graphic.png.php
│ ├── module.graphic.svg.php
│ ├── module.graphic.tiff.php
│ ├── module.misc.cue.php
│ ├── module.misc.exe.php
│ ├── module.misc.iso.php
│ ├── module.misc.msoffice.php
│ ├── module.misc.par2.php
│ ├── module.misc.pdf.php
│ ├── module.tag.apetag.php
│ ├── module.tag.id3v1.php
│ ├── module.tag.id3v2.php
│ ├── module.tag.lyrics3.php
│ ├── module.tag.xmp.php
│ ├── write.apetag.php
│ ├── write.id3v1.php
│ ├── write.id3v2.php
│ ├── write.lyrics3.php
│ ├── write.metaflac.php
│ ├── write.php
│ ├── write.real.php
│ └── write.vorbiscomment.php
└── index.php
└── sounds
├── Ayayayayayayayay!.mp3
├── Constipated.mp3
├── Do-do-do-do.mp3
├── Floridians-Dumb-as-dirt.mp3
├── Frosty-Nads[Q].mp3
├── Happy-Birthday.mp3
├── Happy-Purim.mp3
├── I-Don't-Believe-It.mp3
├── Idiotic-jerk.mp3
├── Laugh-Bird.mp3
├── Laugh-Brooke.mp3
├── Laugh-Gilbert.mp3
├── Laugh-Goofy.mp3
├── Laugh-Montage.mp3
├── Loan-me-50-Dollars.mp3
├── No.mp3
├── Only-in-the-Banana-Republic.mp3
├── Ya-mon!.mp3
├── Yank-it-baby.mp3
└── Yeeeeeeesss.mp3
/.gitignore:
--------------------------------------------------------------------------------
1 | sounds/
2 | .vscode/
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Simple Single Page Soundboard
2 |
3 | This code creates a Soundboard on a single HTML page that loads a JSON file. It uses Javascript, JQuery, HTML5, and CSS. The JSON file can be created by hand or built using PHP. I was motivated to create this in 2015 when Soundboard.com ignored my two feature requests. This version is better than Soundboard.com in at least 4 ways:
4 |
5 | 1. Loads way faster.
6 | 1. Tablet and Mobile friendly.
7 | 1. Sorts alphabetically automatically.
8 | 1. You can play multiple drops simultaneously. (optional)
9 |
10 | The original version required PHP. Now you can use PHP to build the JSON file of your Soundboard files, but it is not required.
11 |
12 | ## 2019 Update
13 |
14 | You can now filter the drops with the text input. It will search track titles and artists.
15 |
16 | ## 2020 Update
17 |
18 | I created a [Svelte version](https://github.com/digitalcolony/simple-soundboard-svelte) of the Simple Soundboard. Check it out!
19 |
20 | ## Getting Started
21 |
22 | 1. Create a new folder and place all the MP3 drops you wish to have on the soundboard. For this repo, I've added 20 drops to get you started.
23 | 1. Create or build a JSON file with the sound drops. I'll explain the format in the next section of this README.
24 | 1. Add a link to the JSON file on the Soundboard page. (EX: url: "./inc/json/soundboard.json")
25 | 1. Set the variable **_playOnlyOneSoundAtATime_** to true or false inside the javascript.
26 | 1. Deploy to any web server.
27 |
28 | ## JSON Format
29 |
30 | The Soundboard JSON file is a collection of files. Each file will have a name, duration, and mp3 file path. Duration is not used at this time, but could be in the future. The files do not have to be local. Any valid URL pointing to an MP3 file will work, provided that the host allows direct linking to audio files.
31 |
32 | ```javascript
33 | {
34 | "files": [
35 | {
36 | "name": "1 to 12 hour - Boca Britany Somers",
37 | "mp3":
38 | "/sounds/1-to-12-hour.mp3"
39 | },
40 | {
41 | "name": "2 of the Dumbest White Men - Mike Reineri",
42 | "mp3":
43 | "/sounds/2-of-the-Dumbest-White-Men.mp3"
44 | }
45 | ]
46 | }
47 | ```
48 |
49 | ## Creating the JSON file
50 |
51 | You can create the JSON file a few different ways.
52 |
53 | 1. By hand. With any editor, you can type up your own JSON file that describes your Soundboard. This is perfect if where you want to host the Soundboard does not support server-side code.
54 | 1. With PHP. Included in this repo is PHP code that will build the JSON file for you. PHP is widely supported with web hosts.
55 | 1. NodeJS. The filename version is now completed. The ID3 version is yet to be coded.
56 |
57 | ## Building the JSON with PHP
58 |
59 | There are 2 ways to build the JSON file using PHP.
60 |
61 | 1. Filename: If you want the buttons to draw their names using the filename, use the **buildJSON_filename.php** page for your Simple Soundboard. To display a ? on the button use [Q] in the file name. Example: **why[Q].mp3**.
62 | 1. ID3: If your MP3 files have Titles defined in the ID3 tags, you will want to use the **buildJSON_id3.php** page for your Simple Soundboard. The code will draw the buttons on the soundboard using the getID3 library to read the title and artist. The ID3 title will be used for the button text and the artist will be used for a tooltip on mouseover.
63 |
64 | The ID3 version is the better version to use. If you need a tool to help you edit the ID3 tags of your MP3 files so they all have titles, look into [Mp3Tag](https://www.mp3tag.de/en/). Artist is optional. Drops without an artist will not have a tooltip.
65 |
66 | ## Building the JSON with NodeJS
67 |
68 | 1. Filename: If you want the buttons to draw their names using the filename, use the **json_filename.js** page for your Simple Soundboard. To display a ? on the button use [Q] in the file name. Example: **why[Q].mp3**. From the node/ folder run node json_filename.js.
69 |
70 | 1. ID3: Not coded yet.
71 |
72 | ## Some Ideas For Your Soundboard
73 |
74 | 1. Search for "CSS Button Generator" to create your own custom super cool looking buttons. Place that CSS into the sb.css file.
75 | 1. Set the preload to **none** if you have a lot of drops or the drops are larger files to improve load time. If you have a small number of drops or know that your users all have fast connections, set the preload to **auto**.
76 |
77 | ## Resources
78 |
79 | 1. The ID3 version of the soundboard uses [getID3](https://github.com/JamesHeinrich/getID3/) from James Heinrich.
80 | 1. The ID3 version uses [Ballon.CSS](https://kazzkiq.github.io/balloon.css/) for the mouseover tooltips.
81 | 1. The styling for the soundboard buttons were created with help from [CSS Button Generator](http://css3buttongenerator.com/).
82 |
83 | ## Demo and Sharing
84 |
85 | This is the [Neil Rogers Soundboard](https://neilrogers.org/soundboard/) built using this code. Let me know if you build a Soundboard you would like to share. You can email me (digitalcolony@gmail.com) the link and I'll share it here for others to see.
86 |
87 | ## Future Development
88 |
89 | 1. Create Node.JS ID3 version
90 |
91 | 1. Move JQuery to Vanilla JS
92 |
--------------------------------------------------------------------------------
/inc/css/sb.css:
--------------------------------------------------------------------------------
1 | @CHARSET "ISO-8859-1";
2 | .myButton {
3 | -moz-box-shadow: 3px 4px 0px 0px #9fb4f2;
4 | -webkit-box-shadow: 3px 4px 0px 0px #9fb4f2;
5 | box-shadow: 3px 4px 0px 0px #9fb4f2;
6 | background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #7892c2), color-stop(1, #476e9e));
7 | background:-moz-linear-gradient(top, #7892c2 5%, #476e9e 100%);
8 | background:-webkit-linear-gradient(top, #7892c2 5%, #476e9e 100%);
9 | background:-o-linear-gradient(top, #7892c2 5%, #476e9e 100%);
10 | background:-ms-linear-gradient(top, #7892c2 5%, #476e9e 100%);
11 | background:linear-gradient(to bottom, #7892c2 5%, #476e9e 100%);
12 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#7892c2', endColorstr='#476e9e',GradientType=0);
13 | background-color:#7892c2;
14 | -moz-border-radius:18px;
15 | -webkit-border-radius:18px;
16 | border-radius:18px;
17 | border:1px solid #4e6096;
18 | display:inline-block;
19 | cursor:pointer;
20 | color:#ffffff;
21 | font-family:arial;
22 | font-size:17px;
23 | padding:7px 25px;
24 | text-decoration:none;
25 | text-shadow:0px 1px 0px #283966;
26 | margin: 3px;
27 | }
28 | .myButton:hover {
29 | background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #476e9e), color-stop(1, #7892c2));
30 | background:-moz-linear-gradient(top, #476e9e 5%, #7892c2 100%);
31 | background:-webkit-linear-gradient(top, #476e9e 5%, #7892c2 100%);
32 | background:-o-linear-gradient(top, #476e9e 5%, #7892c2 100%);
33 | background:-ms-linear-gradient(top, #476e9e 5%, #7892c2 100%);
34 | background:linear-gradient(to bottom, #476e9e 5%, #7892c2 100%);
35 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#476e9e', endColorstr='#7892c2',GradientType=0);
36 | background-color:#476e9e;
37 | }
38 | .myButton:active {
39 | position:relative;
40 | top:1px;
41 | }
42 | .btn-filter:focus, .btn-filter:active:focus, .btn-filter.active:focus{
43 | outline:none;
44 | box-shadow:none;
45 | }
46 |
--------------------------------------------------------------------------------
/inc/js/filter.js:
--------------------------------------------------------------------------------
1 | const filterInput = document.getElementById("filterInput");
2 | const filterClearBtn = document.getElementById("filterClearBtn");
3 |
4 | document.addEventListener("DOMContentLoaded", function(event) {
5 | registerEventListeners();
6 | });
7 |
8 | function registerEventListeners() {
9 | filterInput.addEventListener("input", filterDrops);
10 | filterClearBtn.addEventListener("click", filterClear);
11 | }
12 |
13 | function filterClear(e){
14 | filterInput.value = "";
15 | filterInput.dispatchEvent(new Event("input"));
16 | }
17 |
18 | function filterDrops(e) {
19 | const text = e.target.value.toLowerCase();
20 | document.querySelectorAll(".myButton").forEach(function(drop) {
21 | const title = drop.firstChild.textContent;
22 | let artist = drop.getAttribute("data-balloon");
23 | if (artist === null) {
24 | artist = "";
25 | }
26 | // Search both title and artist
27 | const track = title + artist;
28 |
29 | if (track.toLowerCase().indexOf(text) != -1) {
30 | drop.style.display = "inline";
31 | } else {
32 | drop.style.display = "none";
33 | }
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/inc/json/soundboard.json:
--------------------------------------------------------------------------------
1 | {"files":[{"name":"Ayayayayayayayay!","artist":"","mp3":"\/sounds\/Ayayayayayayayay!.mp3"},{"name":"Bird laugh","artist":"Glen Hill","mp3":"\/sounds\/Laugh-Bird.mp3"},{"name":"Do do do do","artist":"","mp3":"\/sounds\/Do-do-do-do.mp3"},{"name":"Floridians dumb as dirt","artist":"Jennifer Rehm","mp3":"\/sounds\/Floridians-Dumb-as-dirt.mp3"},{"name":"Frosty Nads","artist":"Jennifer Rehm","mp3":"\/sounds\/Frosty-Nads[Q].mp3"},{"name":"Happy Birthday","artist":"","mp3":"\/sounds\/Happy-Birthday.mp3"},{"name":"Happy Purim","artist":"Thanks for Calling Lady","mp3":"\/sounds\/Happy-Purim.mp3"},{"name":"I Don't Believe It","artist":"Jim Mandich","mp3":"\/sounds\/I-Don't-Believe-It.mp3"},{"name":"I Don't Do my Job as Well When I'm Constipated","artist":"","mp3":"\/sounds\/Constipated.mp3"},{"name":"Idiotic jerk","artist":"Old Boat Dude","mp3":"\/sounds\/Idiotic-jerk.mp3"},{"name":"Laugh Brooke","artist":"Brooke Daniels","mp3":"\/sounds\/Laugh-Brooke.mp3"},{"name":"Laugh Gilbert","artist":"Gilbert Solomon","mp3":"\/sounds\/Laugh-Gilbert.mp3"},{"name":"Laugh Goofy","artist":"","mp3":"\/sounds\/Laugh-Goofy.mp3"},{"name":"Laugh Montage","artist":"Gilbert\/Brooke Daniels","mp3":"\/sounds\/Laugh-Montage.mp3"},{"name":"Loan me 50 Dollars","artist":"Larry King","mp3":"\/sounds\/Loan-me-50-Dollars.mp3"},{"name":"No","artist":"Drew Michaels","mp3":"\/sounds\/No.mp3"},{"name":"Only in the Banana Republic","artist":"Jim Mandich","mp3":"\/sounds\/Only-in-the-Banana-Republic.mp3"},{"name":"Ya mon!","artist":"","mp3":"\/sounds\/Ya-mon!.mp3"},{"name":"Yank it baby","artist":"Jennifer Rehm","mp3":"\/sounds\/Yank-it-baby.mp3"},{"name":"Yeeeeeeesss","artist":"Jim Mandich","mp3":"\/sounds\/Yeeeeeeesss.mp3"}]}
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Simple Soundboard
8 |
9 |
10 |
11 |
17 |
22 |
23 |
24 |
28 |
33 |
34 |
35 |
36 |
40 | Simple Soundboard
41 |
48 |
49 |
50 | ×
51 |
52 |
53 |
54 |
55 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
130 |
131 |
132 | View the
133 | Simple Soundboard Repo
136 | on GitHub.
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/node/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/node/config/config.js:
--------------------------------------------------------------------------------
1 | var env = process.env.NODE_ENV || "soundboard";
2 |
3 | if (env === "soundboard") {
4 | const config = require("./config.json");
5 | let envConfig = config[env];
6 |
7 | Object.keys(envConfig).forEach(key => {
8 | process.env[key] = envConfig[key];
9 | });
10 | }
11 |
--------------------------------------------------------------------------------
/node/config/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "soundboard": {
3 | "MP3_DIRECTORY": "../sounds/",
4 | "JSON_FILENAME": "../inc/json/soundboard.json",
5 | "SOUNDBOARD_PAGE": "/"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/node/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Build Simple Soundboard JSON File (Node)
8 |
9 |
10 |
11 | Build Simple Soundboard JSON File (Node)
12 |
13 | Update the config/config.js before building your JSON file.
14 |
15 | File Name Version
16 | Use [Q] for ? and spaces will be replaced with dashes.
17 | node json_filename.js
18 |
19 | ID3 Version
20 |
21 | Use a tool such as MP3Tag to
22 | update the ID3 fields of your MP3s.
23 |
24 | ID3 version is not coded yet.
25 |
26 |
27 |
--------------------------------------------------------------------------------
/node/json_filename.js:
--------------------------------------------------------------------------------
1 | require("./config/config");
2 | const path = require("path");
3 | const fs = require("fs");
4 |
5 | String.prototype.replaceAll = function(search, replace) {
6 | if (replace === undefined) {
7 | return this.toString();
8 | }
9 | return this.split(search).join(replace);
10 | };
11 |
12 | var obj = {
13 | files: []
14 | };
15 | const getSoundFileName = val => {
16 | let soundname = path.parse(val).name;
17 | soundname = soundname.replaceAll("[Q]", "?").replaceAll("-", " ");
18 | return soundname;
19 | };
20 |
21 | fs.readdirSync(process.env["MP3_DIRECTORY"]).forEach(file => {
22 | obj.files.push({
23 | name: getSoundFileName(file),
24 | artist: "", // artist is not built with filename version
25 | mp3: process.env["MP3_DIRECTORY"] + file.toString()
26 | });
27 | });
28 |
29 | const json = JSON.stringify(obj);
30 | fs.writeFile(process.env["JSON_FILENAME"], json, "utf8", function(err) {
31 | if (err) {
32 | throw err;
33 | }
34 | });
35 |
--------------------------------------------------------------------------------
/node/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "inherits": {
8 | "version": "2.0.3",
9 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
10 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
11 | },
12 | "path": {
13 | "version": "0.12.7",
14 | "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
15 | "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
16 | "requires": {
17 | "process": "^0.11.1",
18 | "util": "^0.10.3"
19 | }
20 | },
21 | "process": {
22 | "version": "0.11.10",
23 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
24 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
25 | },
26 | "util": {
27 | "version": "0.10.4",
28 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
29 | "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
30 | "requires": {
31 | "inherits": "2.0.3"
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node",
3 | "version": "1.0.0",
4 | "description": "Build a JSON file for the Simple Soundboard",
5 | "main": "json_filename.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "path": "^0.12.7"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/php/buildJSON_filename.php:
--------------------------------------------------------------------------------
1 | MP3_DIRECTORY;
4 | $json_file = $configs->JSON_FILENAME;
5 |
6 | $files = array();
7 | $sounds = array();
8 |
9 | // confirm directory exists
10 | if (is_dir($mp3directory)) {
11 | // build an array of MP3 files
12 | $it = new RecursiveDirectoryIterator(realpath($mp3directory));
13 |
14 | foreach(new RecursiveIteratorIterator($it) as $fileinfo) {
15 | if ($fileinfo->isFile()) {
16 | $extension = $fileinfo->getExtension();
17 | if($extension == "mp3"){
18 | $file_title = $fileinfo->getFilename();
19 | $file_title = str_replace(".mp3","",$file_title);
20 | $file_title = str_replace("[Q]","?", $file_title);
21 | $file_title = str_replace("-"," ", $file_title);
22 | $file_artist = "";
23 |
24 | $file_name = $mp3directory . $fileinfo->getFilename();
25 | // Remove .. from path for Soundboard loading
26 | $file_name = str_replace("../","/", $file_name);
27 |
28 | $sounds[] = array('name'=> $file_title,
29 | 'artist'=> $file_artist,
30 | 'mp3'=> $file_name);
31 | }
32 | }
33 | }
34 | if(count($sounds) == 0){
35 | echo " ERROR: There are no MP3 files in the [". $mp3directory ."] directory. Add one or more and try again.";
36 | exit();
37 | }
38 | } else {
39 | echo "ERROR: Directory defined [". $mp3directory ."] is either undefined or does not exist.";
40 | exit();
41 | }
42 | // sort drops alphabetically
43 | sort($sounds);
44 | $files['files'] = $sounds;
45 | $fp = fopen($json_file, 'w');
46 | fwrite($fp, json_encode($files));
47 | fclose($fp);
48 | ?>
49 |
50 |
51 |
52 |
53 |
54 |
55 | Simple Soundboard JSON Built
56 |
57 |
58 | Simple Soundboard JSON Built successfully!
59 | Visit your Soundboard .
60 |
61 |
--------------------------------------------------------------------------------
/php/buildJSON_id3.php:
--------------------------------------------------------------------------------
1 | MP3_DIRECTORY;
4 | $json_file = $configs->JSON_FILENAME;
5 |
6 | $files = array();
7 | $sounds = array();
8 | require_once('getID3/getid3.php');
9 | $getid3_engine = new getID3;
10 | // confirm directory exists
11 | if (is_dir($mp3directory)) {
12 | // build an array of MP3 files
13 | $it = new RecursiveDirectoryIterator(realpath($mp3directory));
14 |
15 | foreach(new RecursiveIteratorIterator($it) as $fileinfo) {
16 | if ($fileinfo->isFile()) {
17 | $extension = $fileinfo->getExtension();
18 | if($extension == "mp3"){
19 | $id3_info = $getid3_engine->analyze($fileinfo);
20 | getid3_lib::CopyTagsToComments($id3_info);
21 | $file_title = htmlentities(!empty($id3_info['comments_html']['title']) ?
22 | implode(' ', $id3_info['comments_html']['title']) : "");
23 | $file_artist = htmlentities(!empty($id3_info['comments_html']['artist']) ?
24 | implode(' ', $id3_info['comments_html']['artist']) : "");
25 | // Not sure why, but getting a double quote to display right required a double decode.
26 | $file_title = html_entity_decode(html_entity_decode($file_title));
27 | $file_artist = html_entity_decode(html_entity_decode($file_artist));
28 | $file_name = $mp3directory . $fileinfo->getFilename();
29 | // Remove .. from path for Soundboard loading
30 | $file_name = str_replace("../","/", $file_name);
31 | if($file_title == ""){
32 | $file_title = str_replace(".mp3","",$file_name);
33 | }
34 |
35 | $sounds[] = array('name'=> $file_title,
36 | 'artist'=> $file_artist,
37 | 'mp3'=> $file_name);
38 | }
39 | }
40 | }
41 | if(count($sounds) == 0){
42 | echo " ERROR: There are no MP3 files in the [". $mp3directory ."] directory. Add one or more and try again.";
43 | exit();
44 | }
45 | } else {
46 | echo "ERROR: Directory defined [". $mp3directory ."] is either undefined or does not exist.";
47 | exit();
48 | }
49 | // sort drops alphabetically
50 | sort($sounds);
51 | $files['files'] = $sounds;
52 | $fp = fopen($json_file, 'w');
53 | fwrite($fp, json_encode($files));
54 | fclose($fp);
55 | ?>
56 |
57 |
58 |
59 |
60 |
61 |
62 | Simple Soundboard JSON Built
63 |
64 |
65 | Simple Soundboard JSON Built successfully!
66 | Visit your Soundboard .
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/php/config.php:
--------------------------------------------------------------------------------
1 | '../sounds/',
4 | 'JSON_FILENAME' => '../inc/json/soundboard.json',
5 | 'SOUNDBOARD_PAGE' => '/',
6 | 'TIME_ZONE' => 'America/Los_Angeles'
7 | );
8 | ?>
9 |
10 |
--------------------------------------------------------------------------------
/php/filename_version.php:
--------------------------------------------------------------------------------
1 | MP3_DIRECTORY;
4 | $mp3 = array();
5 | // confirm directory exists
6 | if (file_exists($mp3directory)) {
7 | // build an array of MP3 files
8 | $directory = new DirectoryIterator($mp3directory);
9 | foreach ($directory as $fileinfo) {
10 | if ($fileinfo->isFile()) {
11 | $extension = $fileinfo->getExtension();
12 | if($extension == "mp3"){
13 | $mp3[] = $fileinfo->getFilename();
14 | }
15 | }
16 | }
17 | if(count($mp3) == 0){
18 | echo "ERROR: There are no MP3 files in the [". $mp3directory ."] directory. Add one or more and try again.";
19 | exit();
20 | }
21 | } else {
22 | echo "ERROR: Directory defined [". $mp3directory ."] does not exist.";
23 | exit();
24 | }
25 | // sort drops alphabetically
26 | sort($mp3);
27 | ?>
28 |
29 |
30 |
31 |
32 | PAGE_TITLE); ?>
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
69 |
70 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/php/getID3/extension.cache.dbm.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // //
9 | // extension.cache.dbm.php - part of getID3() //
10 | // Please see readme.txt for more information //
11 | // ///
12 | /////////////////////////////////////////////////////////////////
13 | // //
14 | // This extension written by Allan Hansen //
15 | // ///
16 | /////////////////////////////////////////////////////////////////
17 |
18 |
19 | /**
20 | * This is a caching extension for getID3(). It works the exact same
21 | * way as the getID3 class, but return cached information very fast
22 | *
23 | * Example:
24 | *
25 | * Normal getID3 usage (example):
26 | *
27 | * require_once 'getid3/getid3.php';
28 | * $getID3 = new getID3;
29 | * $getID3->encoding = 'UTF-8';
30 | * $info1 = $getID3->analyze('file1.flac');
31 | * $info2 = $getID3->analyze('file2.wv');
32 | *
33 | * getID3_cached usage:
34 | *
35 | * require_once 'getid3/getid3.php';
36 | * require_once 'getid3/getid3/extension.cache.dbm.php';
37 | * $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm',
38 | * '/tmp/getid3_cache.lock');
39 | * $getID3->encoding = 'UTF-8';
40 | * $info1 = $getID3->analyze('file1.flac');
41 | * $info2 = $getID3->analyze('file2.wv');
42 | *
43 | *
44 | * Supported Cache Types
45 | *
46 | * SQL Databases: (use extension.cache.mysql)
47 | *
48 | * cache_type cache_options
49 | * -------------------------------------------------------------------
50 | * mysql host, database, username, password
51 | *
52 | *
53 | * DBM-Style Databases: (this extension)
54 | *
55 | * cache_type cache_options
56 | * -------------------------------------------------------------------
57 | * gdbm dbm_filename, lock_filename
58 | * ndbm dbm_filename, lock_filename
59 | * db2 dbm_filename, lock_filename
60 | * db3 dbm_filename, lock_filename
61 | * db4 dbm_filename, lock_filename (PHP5 required)
62 | *
63 | * PHP must have write access to both dbm_filename and lock_filename.
64 | *
65 | *
66 | * Recommended Cache Types
67 | *
68 | * Infrequent updates, many reads any DBM
69 | * Frequent updates mysql
70 | */
71 |
72 |
73 | class getID3_cached_dbm extends getID3
74 | {
75 |
76 | // public: constructor - see top of this file for cache type and cache_options
77 | public function __construct($cache_type, $dbm_filename, $lock_filename) {
78 |
79 | // Check for dba extension
80 | if (!extension_loaded('dba')) {
81 | throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.');
82 | }
83 |
84 | // Check for specific dba driver
85 | if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) {
86 | throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
87 | }
88 |
89 | // Create lock file if needed
90 | if (!file_exists($lock_filename)) {
91 | if (!touch($lock_filename)) {
92 | throw new Exception('failed to create lock file: '.$lock_filename);
93 | }
94 | }
95 |
96 | // Open lock file for writing
97 | if (!is_writeable($lock_filename)) {
98 | throw new Exception('lock file: '.$lock_filename.' is not writable');
99 | }
100 | $this->lock = fopen($lock_filename, 'w');
101 |
102 | // Acquire exclusive write lock to lock file
103 | flock($this->lock, LOCK_EX);
104 |
105 | // Create dbm-file if needed
106 | if (!file_exists($dbm_filename)) {
107 | if (!touch($dbm_filename)) {
108 | throw new Exception('failed to create dbm file: '.$dbm_filename);
109 | }
110 | }
111 |
112 | // Try to open dbm file for writing
113 | $this->dba = dba_open($dbm_filename, 'w', $cache_type);
114 | if (!$this->dba) {
115 |
116 | // Failed - create new dbm file
117 | $this->dba = dba_open($dbm_filename, 'n', $cache_type);
118 |
119 | if (!$this->dba) {
120 | throw new Exception('failed to create dbm file: '.$dbm_filename);
121 | }
122 |
123 | // Insert getID3 version number
124 | dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
125 | }
126 |
127 | // Init misc values
128 | $this->cache_type = $cache_type;
129 | $this->dbm_filename = $dbm_filename;
130 |
131 | // Register destructor
132 | register_shutdown_function(array($this, '__destruct'));
133 |
134 | // Check version number and clear cache if changed
135 | if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) {
136 | $this->clear_cache();
137 | }
138 |
139 | parent::__construct();
140 | }
141 |
142 |
143 |
144 | // public: destructor
145 | public function __destruct() {
146 |
147 | // Close dbm file
148 | dba_close($this->dba);
149 |
150 | // Release exclusive lock
151 | flock($this->lock, LOCK_UN);
152 |
153 | // Close lock file
154 | fclose($this->lock);
155 | }
156 |
157 |
158 |
159 | // public: clear cache
160 | public function clear_cache() {
161 |
162 | // Close dbm file
163 | dba_close($this->dba);
164 |
165 | // Create new dbm file
166 | $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type);
167 |
168 | if (!$this->dba) {
169 | throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename);
170 | }
171 |
172 | // Insert getID3 version number
173 | dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
174 |
175 | // Re-register shutdown function
176 | register_shutdown_function(array($this, '__destruct'));
177 | }
178 |
179 |
180 |
181 | // public: analyze file
182 | public function analyze($filename) {
183 |
184 | if (file_exists($filename)) {
185 |
186 | // Calc key filename::mod_time::size - should be unique
187 | $key = $filename.'::'.filemtime($filename).'::'.filesize($filename);
188 |
189 | // Loopup key
190 | $result = dba_fetch($key, $this->dba);
191 |
192 | // Hit
193 | if ($result !== false) {
194 | return unserialize($result);
195 | }
196 | }
197 |
198 | // Miss
199 | $result = parent::analyze($filename);
200 |
201 | // Save result
202 | if (file_exists($filename)) {
203 | dba_insert($key, serialize($result), $this->dba);
204 | }
205 |
206 | return $result;
207 | }
208 |
209 | }
210 |
--------------------------------------------------------------------------------
/php/getID3/extension.cache.mysql.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // //
9 | // extension.cache.mysql.php - part of getID3() //
10 | // Please see readme.txt for more information //
11 | // ///
12 | /////////////////////////////////////////////////////////////////
13 | // //
14 | // This extension written by Allan Hansen //
15 | // Table name mod by Carlo Capocasa //
16 | // ///
17 | /////////////////////////////////////////////////////////////////
18 |
19 |
20 | /**
21 | * This is a caching extension for getID3(). It works the exact same
22 | * way as the getID3 class, but return cached information very fast
23 | *
24 | * Example: (see also demo.cache.mysql.php in /demo/)
25 | *
26 | * Normal getID3 usage (example):
27 | *
28 | * require_once 'getid3/getid3.php';
29 | * $getID3 = new getID3;
30 | * $getID3->encoding = 'UTF-8';
31 | * $info1 = $getID3->analyze('file1.flac');
32 | * $info2 = $getID3->analyze('file2.wv');
33 | *
34 | * getID3_cached usage:
35 | *
36 | * require_once 'getid3/getid3.php';
37 | * require_once 'getid3/getid3/extension.cache.mysql.php';
38 | * // 5th parameter (tablename) is optional, default is 'getid3_cache'
39 | * $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password', 'tablename');
40 | * $getID3->encoding = 'UTF-8';
41 | * $info1 = $getID3->analyze('file1.flac');
42 | * $info2 = $getID3->analyze('file2.wv');
43 | *
44 | *
45 | * Supported Cache Types (this extension)
46 | *
47 | * SQL Databases:
48 | *
49 | * cache_type cache_options
50 | * -------------------------------------------------------------------
51 | * mysql host, database, username, password
52 | *
53 | *
54 | * DBM-Style Databases: (use extension.cache.dbm)
55 | *
56 | * cache_type cache_options
57 | * -------------------------------------------------------------------
58 | * gdbm dbm_filename, lock_filename
59 | * ndbm dbm_filename, lock_filename
60 | * db2 dbm_filename, lock_filename
61 | * db3 dbm_filename, lock_filename
62 | * db4 dbm_filename, lock_filename (PHP5 required)
63 | *
64 | * PHP must have write access to both dbm_filename and lock_filename.
65 | *
66 | *
67 | * Recommended Cache Types
68 | *
69 | * Infrequent updates, many reads any DBM
70 | * Frequent updates mysql
71 | */
72 |
73 |
74 | class getID3_cached_mysql extends getID3
75 | {
76 |
77 | // private vars
78 | private $cursor;
79 | private $connection;
80 |
81 |
82 | // public: constructor - see top of this file for cache type and cache_options
83 | public function __construct($host, $database, $username, $password, $table='getid3_cache') {
84 |
85 | // Check for mysql support
86 | if (!function_exists('mysql_pconnect')) {
87 | throw new Exception('PHP not compiled with mysql support.');
88 | }
89 |
90 | // Connect to database
91 | $this->connection = mysql_pconnect($host, $username, $password);
92 | if (!$this->connection) {
93 | throw new Exception('mysql_pconnect() failed - check permissions and spelling.');
94 | }
95 |
96 | // Select database
97 | if (!mysql_select_db($database, $this->connection)) {
98 | throw new Exception('Cannot use database '.$database);
99 | }
100 |
101 | // Set table
102 | $this->table = $table;
103 |
104 | // Create cache table if not exists
105 | $this->create_table();
106 |
107 | // Check version number and clear cache if changed
108 | $version = '';
109 | $SQLquery = 'SELECT `value`';
110 | $SQLquery .= ' FROM `'.mysql_real_escape_string($this->table).'`';
111 | $SQLquery .= ' WHERE (`filename` = \''.mysql_real_escape_string(getID3::VERSION).'\')';
112 | $SQLquery .= ' AND (`filesize` = -1)';
113 | $SQLquery .= ' AND (`filetime` = -1)';
114 | $SQLquery .= ' AND (`analyzetime` = -1)';
115 | if ($this->cursor = mysql_query($SQLquery, $this->connection)) {
116 | list($version) = mysql_fetch_array($this->cursor);
117 | }
118 | if ($version != getID3::VERSION) {
119 | $this->clear_cache();
120 | }
121 |
122 | parent::__construct();
123 | }
124 |
125 |
126 |
127 | // public: clear cache
128 | public function clear_cache() {
129 |
130 | $this->cursor = mysql_query('DELETE FROM `'.mysql_real_escape_string($this->table).'`', $this->connection);
131 | $this->cursor = mysql_query('INSERT INTO `'.mysql_real_escape_string($this->table).'` VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')', $this->connection);
132 | }
133 |
134 |
135 |
136 | // public: analyze file
137 | public function analyze($filename, $filesize=null, $original_filename='') {
138 |
139 | if (file_exists($filename)) {
140 |
141 | // Short-hands
142 | $filetime = filemtime($filename);
143 | $filesize = filesize($filename);
144 |
145 | // Lookup file
146 | $SQLquery = 'SELECT `value`';
147 | $SQLquery .= ' FROM `'.mysql_real_escape_string($this->table).'`';
148 | $SQLquery .= ' WHERE (`filename` = \''.mysql_real_escape_string($filename).'\')';
149 | $SQLquery .= ' AND (`filesize` = \''.mysql_real_escape_string($filesize).'\')';
150 | $SQLquery .= ' AND (`filetime` = \''.mysql_real_escape_string($filetime).'\')';
151 | $this->cursor = mysql_query($SQLquery, $this->connection);
152 | if (mysql_num_rows($this->cursor) > 0) {
153 | // Hit
154 | list($result) = mysql_fetch_array($this->cursor);
155 | return unserialize(base64_decode($result));
156 | }
157 | }
158 |
159 | // Miss
160 | $analysis = parent::analyze($filename, $filesize, $original_filename);
161 |
162 | // Save result
163 | if (file_exists($filename)) {
164 | $SQLquery = 'INSERT INTO `'.mysql_real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
165 | $SQLquery .= '\''.mysql_real_escape_string($filename).'\'';
166 | $SQLquery .= ', \''.mysql_real_escape_string($filesize).'\'';
167 | $SQLquery .= ', \''.mysql_real_escape_string($filetime).'\'';
168 | $SQLquery .= ', \''.mysql_real_escape_string(time() ).'\'';
169 | $SQLquery .= ', \''.mysql_real_escape_string(base64_encode(serialize($analysis))).'\')';
170 | $this->cursor = mysql_query($SQLquery, $this->connection);
171 | }
172 | return $analysis;
173 | }
174 |
175 |
176 |
177 | // private: (re)create sql table
178 | private function create_table($drop=false) {
179 |
180 | $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
181 | $SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
182 | $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
183 | $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
184 | $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
185 | $SQLquery .= ', `value` LONGTEXT NOT NULL';
186 | $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM CHARACTER SET=latin1 COLLATE=latin1_general_ci';
187 | $this->cursor = mysql_query($SQLquery, $this->connection);
188 | echo mysql_error($this->connection);
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/php/getID3/extension.cache.mysqli.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // //
9 | // extension.cache.mysqli.php - part of getID3() //
10 | // Please see readme.txt for more information //
11 | // ///
12 | /////////////////////////////////////////////////////////////////
13 | // //
14 | // This extension written by Allan Hansen //
15 | // Table name mod by Carlo Capocasa //
16 | // ///
17 | /////////////////////////////////////////////////////////////////
18 |
19 |
20 | /**
21 | * This is a caching extension for getID3(). It works the exact same
22 | * way as the getID3 class, but return cached information very fast
23 | *
24 | * Example: (see also demo.cache.mysql.php in /demo/)
25 | *
26 | * Normal getID3 usage (example):
27 | *
28 | * require_once 'getid3/getid3.php';
29 | * $getID3 = new getID3;
30 | * $getID3->encoding = 'UTF-8';
31 | * $info1 = $getID3->analyze('file1.flac');
32 | * $info2 = $getID3->analyze('file2.wv');
33 | *
34 | * getID3_cached usage:
35 | *
36 | * require_once 'getid3/getid3.php';
37 | * require_once 'getid3/getid3/extension.cache.mysqli.php';
38 | * // 5th parameter (tablename) is optional, default is 'getid3_cache'
39 | * $getID3 = new getID3_cached_mysqli('localhost', 'database', 'username', 'password', 'tablename');
40 | * $getID3->encoding = 'UTF-8';
41 | * $info1 = $getID3->analyze('file1.flac');
42 | * $info2 = $getID3->analyze('file2.wv');
43 | *
44 | *
45 | * Supported Cache Types (this extension)
46 | *
47 | * SQL Databases:
48 | *
49 | * cache_type cache_options
50 | * -------------------------------------------------------------------
51 | * mysqli host, database, username, password
52 | *
53 | *
54 | * DBM-Style Databases: (use extension.cache.dbm)
55 | *
56 | * cache_type cache_options
57 | * -------------------------------------------------------------------
58 | * gdbm dbm_filename, lock_filename
59 | * ndbm dbm_filename, lock_filename
60 | * db2 dbm_filename, lock_filename
61 | * db3 dbm_filename, lock_filename
62 | * db4 dbm_filename, lock_filename (PHP5 required)
63 | *
64 | * PHP must have write access to both dbm_filename and lock_filename.
65 | *
66 | *
67 | * Recommended Cache Types
68 | *
69 | * Infrequent updates, many reads any DBM
70 | * Frequent updates mysqli
71 | */
72 |
73 | class getID3_cached_mysqli extends getID3
74 | {
75 | // private vars
76 | private $mysqli;
77 | private $cursor;
78 |
79 |
80 | // public: constructor - see top of this file for cache type and cache_options
81 | public function __construct($host, $database, $username, $password, $table='getid3_cache') {
82 |
83 | // Check for mysqli support
84 | if (!function_exists('mysqli_connect')) {
85 | throw new Exception('PHP not compiled with mysqli support.');
86 | }
87 |
88 | // Connect to database
89 | $this->mysqli = new mysqli($host, $username, $password);
90 | if (!$this->mysqli) {
91 | throw new Exception('mysqli_connect() failed - check permissions and spelling.');
92 | }
93 |
94 | // Select database
95 | if (!$this->mysqli->select_db($database)) {
96 | throw new Exception('Cannot use database '.$database);
97 | }
98 |
99 | // Set table
100 | $this->table = $table;
101 |
102 | // Create cache table if not exists
103 | $this->create_table();
104 |
105 | // Check version number and clear cache if changed
106 | $version = '';
107 | $SQLquery = 'SELECT `value`';
108 | $SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
109 | $SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string(getID3::VERSION).'\')';
110 | $SQLquery .= ' AND (`filesize` = -1)';
111 | $SQLquery .= ' AND (`filetime` = -1)';
112 | $SQLquery .= ' AND (`analyzetime` = -1)';
113 | if ($this->cursor = $this->mysqli->query($SQLquery)) {
114 | list($version) = $this->cursor->fetch_array();
115 | }
116 | if ($version != getID3::VERSION) {
117 | $this->clear_cache();
118 | }
119 |
120 | parent::__construct();
121 | }
122 |
123 |
124 | // public: clear cache
125 | public function clear_cache() {
126 | $this->mysqli->query('DELETE FROM `'.$this->mysqli->real_escape_string($this->table).'`');
127 | $this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
128 | }
129 |
130 |
131 | // public: analyze file
132 | public function analyze($filename, $filesize=null, $original_filename='') {
133 |
134 | if (file_exists($filename)) {
135 |
136 | // Short-hands
137 | $filetime = filemtime($filename);
138 | $filesize = filesize($filename);
139 |
140 | // Lookup file
141 | $SQLquery = 'SELECT `value`';
142 | $SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
143 | $SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string($filename).'\')';
144 | $SQLquery .= ' AND (`filesize` = \''.$this->mysqli->real_escape_string($filesize).'\')';
145 | $SQLquery .= ' AND (`filetime` = \''.$this->mysqli->real_escape_string($filetime).'\')';
146 | $this->cursor = $this->mysqli->query($SQLquery);
147 | if ($this->cursor->num_rows > 0) {
148 | // Hit
149 | list($result) = $this->cursor->fetch_array();
150 | return unserialize(base64_decode($result));
151 | }
152 | }
153 |
154 | // Miss
155 | $analysis = parent::analyze($filename, $filesize, $original_filename);
156 |
157 | // Save result
158 | if (file_exists($filename)) {
159 | $SQLquery = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
160 | $SQLquery .= '\''.$this->mysqli->real_escape_string($filename).'\'';
161 | $SQLquery .= ', \''.$this->mysqli->real_escape_string($filesize).'\'';
162 | $SQLquery .= ', \''.$this->mysqli->real_escape_string($filetime).'\'';
163 | $SQLquery .= ', \''.$this->mysqli->real_escape_string(time() ).'\'';
164 | $SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\')';
165 | $this->cursor = $this->mysqli->query($SQLquery);
166 | }
167 | return $analysis;
168 | }
169 |
170 |
171 | // private: (re)create mysqli table
172 | private function create_table($drop=false) {
173 | $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.$this->mysqli->real_escape_string($this->table).'` (';
174 | $SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
175 | $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
176 | $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
177 | $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
178 | $SQLquery .= ', `value` LONGTEXT NOT NULL';
179 | $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM CHARACTER SET=latin1 COLLATE=latin1_general_ci';
180 | $this->cursor = $this->mysqli->query($SQLquery);
181 | echo $this->mysqli->error;
182 | }
183 | }
--------------------------------------------------------------------------------
/php/getID3/module.archive.rar.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.archive.rar.php //
12 | // module for analyzing RAR files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_rar extends getid3_handler
19 | {
20 |
21 | public $option_use_rar_extension = false;
22 |
23 | public function Analyze() {
24 | $info = &$this->getid3->info;
25 |
26 | $info['fileformat'] = 'rar';
27 |
28 | if ($this->option_use_rar_extension === true) {
29 | if (function_exists('rar_open')) {
30 | if ($rp = rar_open($info['filenamepath'])) {
31 | $info['rar']['files'] = array();
32 | $entries = rar_list($rp);
33 | foreach ($entries as $entry) {
34 | $info['rar']['files'] = getid3_lib::array_merge_clobber($info['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize()));
35 | }
36 | rar_close($rp);
37 | return true;
38 | } else {
39 | $this->error('failed to rar_open('.$info['filename'].')');
40 | }
41 | } else {
42 | $this->error('RAR support does not appear to be available in this PHP installation');
43 | }
44 | } else {
45 | $this->error('PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)');
46 | }
47 | return false;
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/php/getID3/module.archive.szip.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.archive.szip.php //
12 | // module for analyzing SZIP compressed files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_szip extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $SZIPHeader = $this->fread(6);
26 | if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") {
27 | $this->error('Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"');
28 | return false;
29 | }
30 | $info['fileformat'] = 'szip';
31 | $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
32 | $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
33 | $this->error('SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
34 | return false;
35 |
36 | while (!$this->feof()) {
37 | $NextBlockID = $this->fread(2);
38 | switch ($NextBlockID) {
39 | case 'SZ':
40 | // Note that szip files can be concatenated, this has the same effect as
41 | // concatenating the files. this also means that global header blocks
42 | // might be present between directory/data blocks.
43 | $this->fseek(4, SEEK_CUR);
44 | break;
45 |
46 | case 'BH':
47 | $BHheaderbytes = getid3_lib::BigEndian2Int($this->fread(3));
48 | $BHheaderdata = $this->fread($BHheaderbytes);
49 | $BHheaderoffset = 0;
50 | while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) {
51 | //filename as \0 terminated string (empty string indicates end)
52 | //owner as \0 terminated string (empty is same as last file)
53 | //group as \0 terminated string (empty is same as last file)
54 | //3 byte filelength in this block
55 | //2 byte access flags
56 | //4 byte creation time (like in unix)
57 | //4 byte modification time (like in unix)
58 | //4 byte access time (like in unix)
59 |
60 | $BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
61 | $BHheaderoffset += (strlen($BHdataArray['filename']) + 1);
62 |
63 | $BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
64 | $BHheaderoffset += (strlen($BHdataArray['owner']) + 1);
65 |
66 | $BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
67 | $BHheaderoffset += (strlen($BHdataArray['group']) + 1);
68 |
69 | $BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3));
70 | $BHheaderoffset += 3;
71 |
72 | $BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2));
73 | $BHheaderoffset += 2;
74 |
75 | $BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
76 | $BHheaderoffset += 4;
77 |
78 | $BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
79 | $BHheaderoffset += 4;
80 |
81 | $BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
82 | $BHheaderoffset += 4;
83 |
84 | $info['szip']['BH'][] = $BHdataArray;
85 | }
86 | break;
87 |
88 | default:
89 | break 2;
90 | }
91 | }
92 |
93 | return true;
94 |
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/php/getID3/module.archive.tar.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.archive.tar.php //
12 | // module for analyzing TAR files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 | // //
17 | // Module originally written by //
18 | // Mike Mozolin //
19 | // //
20 | /////////////////////////////////////////////////////////////////
21 |
22 |
23 | class getid3_tar extends getid3_handler
24 | {
25 |
26 | public function Analyze() {
27 | $info = &$this->getid3->info;
28 |
29 | $info['fileformat'] = 'tar';
30 | $info['tar']['files'] = array();
31 |
32 | $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix';
33 | $null_512k = str_repeat("\x00", 512); // end-of-file marker
34 |
35 | $this->fseek(0);
36 | while (!feof($this->getid3->fp)) {
37 | $buffer = $this->fread(512);
38 | if (strlen($buffer) < 512) {
39 | break;
40 | }
41 |
42 | // check the block
43 | $checksum = 0;
44 | for ($i = 0; $i < 148; $i++) {
45 | $checksum += ord($buffer{$i});
46 | }
47 | for ($i = 148; $i < 156; $i++) {
48 | $checksum += ord(' ');
49 | }
50 | for ($i = 156; $i < 512; $i++) {
51 | $checksum += ord($buffer{$i});
52 | }
53 | $attr = unpack($unpack_header, $buffer);
54 | $name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : '');
55 | $mode = octdec(isset($attr['mode'] ) ? trim($attr['mode'] ) : '');
56 | $uid = octdec(isset($attr['uid'] ) ? trim($attr['uid'] ) : '');
57 | $gid = octdec(isset($attr['gid'] ) ? trim($attr['gid'] ) : '');
58 | $size = octdec(isset($attr['size'] ) ? trim($attr['size'] ) : '');
59 | $mtime = octdec(isset($attr['mtime'] ) ? trim($attr['mtime'] ) : '');
60 | $chksum = octdec(isset($attr['chksum'] ) ? trim($attr['chksum'] ) : '');
61 | $typflag = (isset($attr['typflag']) ? trim($attr['typflag']) : '');
62 | $lnkname = (isset($attr['lnkname']) ? trim($attr['lnkname']) : '');
63 | $magic = (isset($attr['magic'] ) ? trim($attr['magic'] ) : '');
64 | $ver = (isset($attr['ver'] ) ? trim($attr['ver'] ) : '');
65 | $uname = (isset($attr['uname'] ) ? trim($attr['uname'] ) : '');
66 | $gname = (isset($attr['gname'] ) ? trim($attr['gname'] ) : '');
67 | $devmaj = octdec(isset($attr['devmaj'] ) ? trim($attr['devmaj'] ) : '');
68 | $devmin = octdec(isset($attr['devmin'] ) ? trim($attr['devmin'] ) : '');
69 | $prefix = (isset($attr['prefix'] ) ? trim($attr['prefix'] ) : '');
70 | if (($checksum == 256) && ($chksum == 0)) {
71 | // EOF Found
72 | break;
73 | }
74 | if ($prefix) {
75 | $name = $prefix.'/'.$name;
76 | }
77 | if ((preg_match('#/$#', $name)) && !$name) {
78 | $typeflag = 5;
79 | }
80 | if ($buffer == $null_512k) {
81 | // it's the end of the tar-file...
82 | break;
83 | }
84 |
85 | // Read to the next chunk
86 | $this->fseek($size, SEEK_CUR);
87 |
88 | $diff = $size % 512;
89 | if ($diff != 0) {
90 | // Padding, throw away
91 | $this->fseek((512 - $diff), SEEK_CUR);
92 | }
93 | // Protect against tar-files with garbage at the end
94 | if ($name == '') {
95 | break;
96 | }
97 | $info['tar']['file_details'][$name] = array (
98 | 'name' => $name,
99 | 'mode_raw' => $mode,
100 | 'mode' => self::display_perms($mode),
101 | 'uid' => $uid,
102 | 'gid' => $gid,
103 | 'size' => $size,
104 | 'mtime' => $mtime,
105 | 'chksum' => $chksum,
106 | 'typeflag' => self::get_flag_type($typflag),
107 | 'linkname' => $lnkname,
108 | 'magic' => $magic,
109 | 'version' => $ver,
110 | 'uname' => $uname,
111 | 'gname' => $gname,
112 | 'devmajor' => $devmaj,
113 | 'devminor' => $devmin
114 | );
115 | $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size));
116 | }
117 | return true;
118 | }
119 |
120 | // Parses the file mode to file permissions
121 | public function display_perms($mode) {
122 | // Determine Type
123 | if ($mode & 0x1000) $type='p'; // FIFO pipe
124 | elseif ($mode & 0x2000) $type='c'; // Character special
125 | elseif ($mode & 0x4000) $type='d'; // Directory
126 | elseif ($mode & 0x6000) $type='b'; // Block special
127 | elseif ($mode & 0x8000) $type='-'; // Regular
128 | elseif ($mode & 0xA000) $type='l'; // Symbolic Link
129 | elseif ($mode & 0xC000) $type='s'; // Socket
130 | else $type='u'; // UNKNOWN
131 |
132 | // Determine permissions
133 | $owner['read'] = (($mode & 00400) ? 'r' : '-');
134 | $owner['write'] = (($mode & 00200) ? 'w' : '-');
135 | $owner['execute'] = (($mode & 00100) ? 'x' : '-');
136 | $group['read'] = (($mode & 00040) ? 'r' : '-');
137 | $group['write'] = (($mode & 00020) ? 'w' : '-');
138 | $group['execute'] = (($mode & 00010) ? 'x' : '-');
139 | $world['read'] = (($mode & 00004) ? 'r' : '-');
140 | $world['write'] = (($mode & 00002) ? 'w' : '-');
141 | $world['execute'] = (($mode & 00001) ? 'x' : '-');
142 |
143 | // Adjust for SUID, SGID and sticky bit
144 | if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S';
145 | if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S';
146 | if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
147 |
148 | $s = sprintf('%1s', $type);
149 | $s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']);
150 | $s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']);
151 | $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']);
152 | return $s;
153 | }
154 |
155 | // Converts the file type
156 | public function get_flag_type($typflag) {
157 | static $flag_types = array(
158 | '0' => 'LF_NORMAL',
159 | '1' => 'LF_LINK',
160 | '2' => 'LF_SYNLINK',
161 | '3' => 'LF_CHR',
162 | '4' => 'LF_BLK',
163 | '5' => 'LF_DIR',
164 | '6' => 'LF_FIFO',
165 | '7' => 'LF_CONFIG',
166 | 'D' => 'LF_DUMPDIR',
167 | 'K' => 'LF_LONGLINK',
168 | 'L' => 'LF_LONGNAME',
169 | 'M' => 'LF_MULTIVOL',
170 | 'N' => 'LF_NAMES',
171 | 'S' => 'LF_SPARSE',
172 | 'V' => 'LF_VOLHDR'
173 | );
174 | return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : '');
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/php/getID3/module.audio-video.bink.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.bink.php //
12 | // module for analyzing Bink or Smacker audio-video files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_bink extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->error('Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']');
25 |
26 | $this->fseek($info['avdataoffset']);
27 | $fileTypeID = $this->fread(3);
28 | switch ($fileTypeID) {
29 | case 'BIK':
30 | return $this->ParseBink();
31 | break;
32 |
33 | case 'SMK':
34 | return $this->ParseSmacker();
35 | break;
36 |
37 | default:
38 | $this->error('Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"');
39 | return false;
40 | break;
41 | }
42 |
43 | return true;
44 |
45 | }
46 |
47 | public function ParseBink() {
48 | $info = &$this->getid3->info;
49 | $info['fileformat'] = 'bink';
50 | $info['video']['dataformat'] = 'bink';
51 |
52 | $fileData = 'BIK'.$this->fread(13);
53 |
54 | $info['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4));
55 | $info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2));
56 |
57 | if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) {
58 | $this->error('Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']));
59 | }
60 |
61 | return true;
62 | }
63 |
64 | public function ParseSmacker() {
65 | $info = &$this->getid3->info;
66 | $info['fileformat'] = 'smacker';
67 | $info['video']['dataformat'] = 'smacker';
68 |
69 | return true;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/php/getID3/module.audio-video.mpeg.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/php/getID3/module.audio-video.mpeg.php
--------------------------------------------------------------------------------
/php/getID3/module.audio-video.swf.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio-video.swf.php //
12 | // module for analyzing Shockwave Flash files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_swf extends getid3_handler
19 | {
20 | public $ReturnAllTagData = false;
21 |
22 | public function Analyze() {
23 | $info = &$this->getid3->info;
24 |
25 | $info['fileformat'] = 'swf';
26 | $info['video']['dataformat'] = 'swf';
27 |
28 | // http://www.openswf.org/spec/SWFfileformat.html
29 |
30 | $this->fseek($info['avdataoffset']);
31 |
32 | $SWFfileData = $this->fread($info['avdataend'] - $info['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data
33 |
34 | $info['swf']['header']['signature'] = substr($SWFfileData, 0, 3);
35 | switch ($info['swf']['header']['signature']) {
36 | case 'FWS':
37 | $info['swf']['header']['compressed'] = false;
38 | break;
39 |
40 | case 'CWS':
41 | $info['swf']['header']['compressed'] = true;
42 | break;
43 |
44 | default:
45 | $this->error('Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"');
46 | unset($info['swf']);
47 | unset($info['fileformat']);
48 | return false;
49 | break;
50 | }
51 | $info['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1));
52 | $info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4));
53 |
54 | if ($info['swf']['header']['compressed']) {
55 | $SWFHead = substr($SWFfileData, 0, 8);
56 | $SWFfileData = substr($SWFfileData, 8);
57 | if ($decompressed = @gzuncompress($SWFfileData)) {
58 | $SWFfileData = $SWFHead.$decompressed;
59 | } else {
60 | $this->error('Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)');
61 | return false;
62 | }
63 | }
64 |
65 | $FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3;
66 | $FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8);
67 | $FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT);
68 | for ($i = 1; $i < $FrameSizeDataLength; $i++) {
69 | $FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT);
70 | }
71 | list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1));
72 | $info['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2);
73 | $info['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2);
74 |
75 | // http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
76 | // Next in the header is the frame rate, which is kind of weird.
77 | // It is supposed to be stored as a 16bit integer, but the first byte
78 | // (or last depending on how you look at it) is completely ignored.
79 | // Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps.
80 |
81 | // Byte at (8 + $FrameSizeDataLength) is always zero and ignored
82 | $info['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1));
83 | $info['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2));
84 |
85 | $info['video']['frame_rate'] = $info['swf']['header']['frame_rate'];
86 | $info['video']['resolution_x'] = intval(round($info['swf']['header']['frame_width'] / 20));
87 | $info['video']['resolution_y'] = intval(round($info['swf']['header']['frame_height'] / 20));
88 | $info['video']['pixel_aspect_ratio'] = (float) 1;
89 |
90 | if (($info['swf']['header']['frame_count'] > 0) && ($info['swf']['header']['frame_rate'] > 0)) {
91 | $info['playtime_seconds'] = $info['swf']['header']['frame_count'] / $info['swf']['header']['frame_rate'];
92 | }
93 | //echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).' ';
94 |
95 |
96 | // SWF tags
97 |
98 | $CurrentOffset = 12 + $FrameSizeDataLength;
99 | $SWFdataLength = strlen($SWFfileData);
100 |
101 | while ($CurrentOffset < $SWFdataLength) {
102 | //echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).' ';
103 |
104 | $TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2));
105 | $TagID = ($TagIDTagLength & 0xFFFC) >> 6;
106 | $TagLength = ($TagIDTagLength & 0x003F);
107 | $CurrentOffset += 2;
108 | if ($TagLength == 0x3F) {
109 | $TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4));
110 | $CurrentOffset += 4;
111 | }
112 |
113 | unset($TagData);
114 | $TagData['offset'] = $CurrentOffset;
115 | $TagData['size'] = $TagLength;
116 | $TagData['id'] = $TagID;
117 | $TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength);
118 | switch ($TagID) {
119 | case 0: // end of movie
120 | break 2;
121 |
122 | case 9: // Set background color
123 | //$info['swf']['tags'][] = $TagData;
124 | $info['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT));
125 | break;
126 |
127 | default:
128 | if ($this->ReturnAllTagData) {
129 | $info['swf']['tags'][] = $TagData;
130 | }
131 | break;
132 | }
133 |
134 | $CurrentOffset += $TagLength;
135 | }
136 |
137 | return true;
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/php/getID3/module.audio-video.ts.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio-video.ts.php //
12 | // module for analyzing MPEG Transport Stream (.ts) files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_ts extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $TSheader = $this->fread(19);
26 | $magic = "\x47";
27 | if (substr($TSheader, 0, 1) != $magic) {
28 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.');
29 | return false;
30 | }
31 | $info['fileformat'] = 'ts';
32 |
33 | // http://en.wikipedia.org/wiki/.ts
34 |
35 | $offset = 0;
36 | $info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
37 | $pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
38 | $SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
39 | $info['ts']['packet']['flags']['transport_error_indicator'] = (bool) ($pid_flags_raw & 0x8000); // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error
40 | $info['ts']['packet']['flags']['payload_unit_start_indicator'] = (bool) ($pid_flags_raw & 0x4000); // 1 means start of PES data or PSI otherwise zero only.
41 | $info['ts']['packet']['flags']['transport_high_priority'] = (bool) ($pid_flags_raw & 0x2000); // 1 means higher priority than other packets with the same PID.
42 | $info['ts']['packet']['packet_id'] = ($pid_flags_raw & 0x1FFF) >> 0;
43 |
44 | $info['ts']['packet']['raw']['scrambling_control'] = ($SAC_raw & 0xC0) >> 6;
45 | $info['ts']['packet']['flags']['adaption_field_exists'] = (bool) ($SAC_raw & 0x20);
46 | $info['ts']['packet']['flags']['payload_exists'] = (bool) ($SAC_raw & 0x10);
47 | $info['ts']['packet']['continuity_counter'] = ($SAC_raw & 0x0F) >> 0; // Incremented only when a payload is present
48 | $info['ts']['packet']['scrambling_control'] = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']);
49 |
50 | if ($info['ts']['packet']['flags']['adaption_field_exists']) {
51 | $AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
52 | $info['ts']['packet']['adaption']['field_length'] = ($AdaptionField_raw & 0xFF00) >> 8; // Number of bytes in the adaptation field immediately following this byte
53 | $info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080); // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference
54 | $info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040); // Set to 1 if the PES packet in this TS packet starts a video/audio sequence
55 | $info['ts']['packet']['adaption']['flags']['high_priority'] = (bool) ($AdaptionField_raw & 0x0020); // 1 = higher priority
56 | $info['ts']['packet']['adaption']['flags']['pcr'] = (bool) ($AdaptionField_raw & 0x0010); // 1 means adaptation field does contain a PCR field
57 | $info['ts']['packet']['adaption']['flags']['opcr'] = (bool) ($AdaptionField_raw & 0x0008); // 1 means adaptation field does contain an OPCR field
58 | $info['ts']['packet']['adaption']['flags']['splice_point'] = (bool) ($AdaptionField_raw & 0x0004); // 1 means presence of splice countdown field in adaptation field
59 | $info['ts']['packet']['adaption']['flags']['private_data'] = (bool) ($AdaptionField_raw & 0x0002); // 1 means presence of private data bytes in adaptation field
60 | $info['ts']['packet']['adaption']['flags']['extension'] = (bool) ($AdaptionField_raw & 0x0001); // 1 means presence of adaptation field extension
61 | if ($info['ts']['packet']['adaption']['flags']['pcr']) {
62 | $info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
63 | }
64 | if ($info['ts']['packet']['adaption']['flags']['opcr']) {
65 | $info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
66 | }
67 | }
68 |
69 | $this->error('MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
70 | return false;
71 |
72 | }
73 |
74 |
75 | public function TSscramblingControlLookup($raw) {
76 | $TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key');
77 | return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid');
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.aa.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.aa.php //
12 | // module for analyzing Audible Audiobook files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_aa extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $AAheader = $this->fread(8);
26 |
27 | $magic = "\x57\x90\x75\x36";
28 | if (substr($AAheader, 4, 4) != $magic) {
29 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"');
30 | return false;
31 | }
32 |
33 | // shortcut
34 | $info['aa'] = array();
35 | $thisfile_aa = &$info['aa'];
36 |
37 | $info['fileformat'] = 'aa';
38 | $info['audio']['dataformat'] = 'aa';
39 | $this->error('Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
40 | return false;
41 | $info['audio']['bitrate_mode'] = 'cbr'; // is it?
42 | $thisfile_aa['encoding'] = 'ISO-8859-1';
43 |
44 | $thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AUheader, 0, 4));
45 | if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) {
46 | $this->warning('Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
47 | }
48 |
49 | $info['audio']['bits_per_sample'] = 16; // is it?
50 | $info['audio']['sample_rate'] = $thisfile_aa['sample_rate'];
51 | $info['audio']['channels'] = $thisfile_aa['channels'];
52 |
53 | //$info['playtime_seconds'] = 0;
54 | //$info['audio']['bitrate'] = 0;
55 |
56 | return true;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.ac3.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/php/getID3/module.audio.ac3.php
--------------------------------------------------------------------------------
/php/getID3/module.audio.amr.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.aa.php //
12 | // module for analyzing Audible Audiobook files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_amr extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $AMRheader = $this->fread(6);
26 |
27 | $magic = '#!AMR'."\x0A";
28 | if (substr($AMRheader, 0, 6) != $magic) {
29 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"');
30 | return false;
31 | }
32 |
33 | // shortcut
34 | $info['amr'] = array();
35 | $thisfile_amr = &$info['amr'];
36 |
37 | $info['fileformat'] = 'amr';
38 | $info['audio']['dataformat'] = 'amr';
39 | $info['audio']['bitrate_mode'] = 'vbr'; // within a small predefined range: 4.75kbps to 12.2kbps
40 | $info['audio']['bits_per_sample'] = 13; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz"
41 | $info['audio']['sample_rate'] = 8000; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz"
42 | $info['audio']['channels'] = 1;
43 | $thisfile_amr['frame_mode_count'] = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0);
44 |
45 | $buffer = '';
46 | do {
47 | if ((strlen($buffer) < $this->getid3->fread_buffer_size()) && !feof($this->getid3->fp)) {
48 | $buffer .= $this->fread($this->getid3->fread_buffer_size() * 2);
49 | }
50 | $AMR_frame_header = ord(substr($buffer, 0, 1));
51 | $codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR.
52 | if ($codec_mode_request > 7) {
53 | break;
54 | }
55 | $thisfile_amr['frame_mode_count'][$codec_mode_request]++;
56 | $buffer = substr($buffer, $this->amr_mode_bytes_per_frame($codec_mode_request));
57 | } while (strlen($buffer) > 0);
58 |
59 | $info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long
60 | $info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding
61 | $info['bitrate'] = $info['audio']['bitrate'];
62 |
63 | return true;
64 | }
65 |
66 |
67 | public function amr_mode_bitrate($key) {
68 | static $amr_mode_bitrate = array(
69 | 0 => 4750,
70 | 1 => 5150,
71 | 2 => 5900,
72 | 3 => 6700,
73 | 4 => 7400,
74 | 5 => 7950,
75 | 6 => 10200,
76 | 7 => 12200,
77 | );
78 | return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
79 | }
80 |
81 | public function amr_mode_bytes_per_frame($key) {
82 | static $amr_mode_bitrate = array(
83 | 0 => 13, // 1-byte frame header + 95 bits [padded to: 12 bytes] audio data
84 | 1 => 14, // 1-byte frame header + 103 bits [padded to: 13 bytes] audio data
85 | 2 => 16, // 1-byte frame header + 118 bits [padded to: 15 bytes] audio data
86 | 3 => 18, // 1-byte frame header + 134 bits [padded to: 17 bytes] audio data
87 | 4 => 20, // 1-byte frame header + 148 bits [padded to: 19 bytes] audio data
88 | 5 => 21, // 1-byte frame header + 159 bits [padded to: 20 bytes] audio data
89 | 6 => 27, // 1-byte frame header + 204 bits [padded to: 26 bytes] audio data
90 | 7 => 32, // 1-byte frame header + 244 bits [padded to: 31 bytes] audio data
91 | );
92 | return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
93 | }
94 |
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.au.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.au.php //
12 | // module for analyzing AU files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_au extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $AUheader = $this->fread(8);
26 |
27 | $magic = '.snd';
28 | if (substr($AUheader, 0, 4) != $magic) {
29 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"');
30 | return false;
31 | }
32 |
33 | // shortcut
34 | $info['au'] = array();
35 | $thisfile_au = &$info['au'];
36 |
37 | $info['fileformat'] = 'au';
38 | $info['audio']['dataformat'] = 'au';
39 | $info['audio']['bitrate_mode'] = 'cbr';
40 | $thisfile_au['encoding'] = 'ISO-8859-1';
41 |
42 | $thisfile_au['header_length'] = getid3_lib::BigEndian2Int(substr($AUheader, 4, 4));
43 | $AUheader .= $this->fread($thisfile_au['header_length'] - 8);
44 | $info['avdataoffset'] += $thisfile_au['header_length'];
45 |
46 | $thisfile_au['data_size'] = getid3_lib::BigEndian2Int(substr($AUheader, 8, 4));
47 | $thisfile_au['data_format_id'] = getid3_lib::BigEndian2Int(substr($AUheader, 12, 4));
48 | $thisfile_au['sample_rate'] = getid3_lib::BigEndian2Int(substr($AUheader, 16, 4));
49 | $thisfile_au['channels'] = getid3_lib::BigEndian2Int(substr($AUheader, 20, 4));
50 | $thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24));
51 |
52 | $thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']);
53 | $thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']);
54 | if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) {
55 | $info['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample'];
56 | } else {
57 | unset($thisfile_au['bits_per_sample']);
58 | }
59 |
60 | $info['audio']['sample_rate'] = $thisfile_au['sample_rate'];
61 | $info['audio']['channels'] = $thisfile_au['channels'];
62 |
63 | if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) {
64 | $this->warning('Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
65 | }
66 |
67 | $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
68 | $info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds'];
69 |
70 | return true;
71 | }
72 |
73 | public function AUdataFormatNameLookup($id) {
74 | static $AUdataFormatNameLookup = array(
75 | 0 => 'unspecified format',
76 | 1 => '8-bit mu-law',
77 | 2 => '8-bit linear',
78 | 3 => '16-bit linear',
79 | 4 => '24-bit linear',
80 | 5 => '32-bit linear',
81 | 6 => 'floating-point',
82 | 7 => 'double-precision float',
83 | 8 => 'fragmented sampled data',
84 | 9 => 'SUN_FORMAT_NESTED',
85 | 10 => 'DSP program',
86 | 11 => '8-bit fixed-point',
87 | 12 => '16-bit fixed-point',
88 | 13 => '24-bit fixed-point',
89 | 14 => '32-bit fixed-point',
90 |
91 | 16 => 'non-audio display data',
92 | 17 => 'SND_FORMAT_MULAW_SQUELCH',
93 | 18 => '16-bit linear with emphasis',
94 | 19 => '16-bit linear with compression',
95 | 20 => '16-bit linear with emphasis + compression',
96 | 21 => 'Music Kit DSP commands',
97 | 22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES',
98 | 23 => 'CCITT g.721 4-bit ADPCM',
99 | 24 => 'CCITT g.722 ADPCM',
100 | 25 => 'CCITT g.723 3-bit ADPCM',
101 | 26 => 'CCITT g.723 5-bit ADPCM',
102 | 27 => 'A-Law 8-bit'
103 | );
104 | return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false);
105 | }
106 |
107 | public function AUdataFormatBitsPerSampleLookup($id) {
108 | static $AUdataFormatBitsPerSampleLookup = array(
109 | 1 => 8,
110 | 2 => 8,
111 | 3 => 16,
112 | 4 => 24,
113 | 5 => 32,
114 | 6 => 32,
115 | 7 => 64,
116 |
117 | 11 => 8,
118 | 12 => 16,
119 | 13 => 24,
120 | 14 => 32,
121 |
122 | 18 => 16,
123 | 19 => 16,
124 | 20 => 16,
125 |
126 | 23 => 16,
127 |
128 | 25 => 16,
129 | 26 => 16,
130 | 27 => 8
131 | );
132 | return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false);
133 | }
134 |
135 | public function AUdataFormatUsedBitsPerSampleLookup($id) {
136 | static $AUdataFormatUsedBitsPerSampleLookup = array(
137 | 1 => 8,
138 | 2 => 8,
139 | 3 => 16,
140 | 4 => 24,
141 | 5 => 32,
142 | 6 => 32,
143 | 7 => 64,
144 |
145 | 11 => 8,
146 | 12 => 16,
147 | 13 => 24,
148 | 14 => 32,
149 |
150 | 18 => 16,
151 | 19 => 16,
152 | 20 => 16,
153 |
154 | 23 => 4,
155 |
156 | 25 => 3,
157 | 26 => 5,
158 | 27 => 8,
159 | );
160 | return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false);
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.avr.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.avr.php //
12 | // module for analyzing AVR Audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_avr extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | // http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
25 | // http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
26 | // offset type length name comments
27 | // ---------------------------------------------------------------------
28 | // 0 char 4 ID format ID == "2BIT"
29 | // 4 char 8 name sample name (unused space filled with 0)
30 | // 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo
31 | // With stereo, samples are alternated,
32 | // the first voice is the left :
33 | // (LRLRLRLRLRLRLRLRLR...)
34 | // 14 short 1 resolution 8, 12 or 16 (bits)
35 | // 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed
36 | // 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on
37 | // 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127
38 | // 0xFFFF means "no MIDI note defined"
39 | // 22 byte 1 Replay speed Frequence in the Replay software
40 | // 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz,
41 | // 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz
42 | // 6=43.885 Khz, 7=47.261 Khz
43 | // -1 (0xFF)=no defined Frequence
44 | // 23 byte 3 sample rate in Hertz
45 | // 26 long 1 size in bytes (2 * bytes in stereo)
46 | // 30 long 1 loop begin 0 for no loop
47 | // 34 long 1 loop size equal to 'size' for no loop
48 | // 38 short 2 Reserved, MIDI keyboard split */
49 | // 40 short 2 Reserved, sample compression */
50 | // 42 short 2 Reserved */
51 | // 44 char 20; Additional filename space, used if (name[7] != 0)
52 | // 64 byte 64 user data
53 | // 128 bytes ? sample data (12 bits samples are coded on 16 bits:
54 | // 0000 xxxx xxxx xxxx)
55 | // ---------------------------------------------------------------------
56 |
57 | // Note that all values are in motorola (big-endian) format, and that long is
58 | // assumed to be 4 bytes, and short 2 bytes.
59 | // When reading the samples, you should handle both signed and unsigned data,
60 | // and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert
61 | // 8-bit data between signed/unsigned just add 127 to the sample values.
62 | // Simularly for 16-bit data you should add 32769
63 |
64 | $info['fileformat'] = 'avr';
65 |
66 | $this->fseek($info['avdataoffset']);
67 | $AVRheader = $this->fread(128);
68 |
69 | $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
70 | $magic = '2BIT';
71 | if ($info['avr']['raw']['magic'] != $magic) {
72 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"');
73 | unset($info['fileformat']);
74 | unset($info['avr']);
75 | return false;
76 | }
77 | $info['avdataoffset'] += 128;
78 |
79 | $info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8));
80 | $info['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2));
81 | $info['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2));
82 | $info['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2));
83 | $info['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2));
84 | $info['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2));
85 | $info['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1));
86 | $info['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3));
87 | $info['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4));
88 | $info['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4));
89 | $info['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4));
90 | $info['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2));
91 | $info['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2));
92 | $info['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2));
93 | $info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20));
94 | $info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64));
95 |
96 | $info['avr']['flags']['stereo'] = (($info['avr']['raw']['mono'] == 0) ? false : true);
97 | $info['avr']['flags']['signed'] = (($info['avr']['raw']['signed'] == 0) ? false : true);
98 | $info['avr']['flags']['loop'] = (($info['avr']['raw']['loop'] == 0) ? false : true);
99 |
100 | $info['avr']['midi_notes'] = array();
101 | if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) {
102 | $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8;
103 | }
104 | if (($info['avr']['raw']['midi'] & 0x00FF) != 0x00FF) {
105 | $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0x00FF);
106 | }
107 |
108 | if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
109 | $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']));
110 | }
111 |
112 | $info['audio']['dataformat'] = 'avr';
113 | $info['audio']['lossless'] = true;
114 | $info['audio']['bitrate_mode'] = 'cbr';
115 | $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample'];
116 | $info['audio']['sample_rate'] = $info['avr']['sample_rate'];
117 | $info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1);
118 | $info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate'];
119 | $info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds'];
120 |
121 |
122 | return true;
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.dsf.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.dsf.php //
12 | // module for analyzing dsf/DSF Audio files //
13 | // dependencies: module.tag.id3v2.php //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
18 |
19 | class getid3_dsf extends getid3_handler
20 | {
21 |
22 | public function Analyze() {
23 | $info = &$this->getid3->info;
24 |
25 | $info['fileformat'] = 'dsf';
26 | $info['audio']['dataformat'] = 'dsf';
27 | $info['audio']['lossless'] = true;
28 | $info['audio']['bitrate_mode'] = 'cbr';
29 |
30 | $this->fseek($info['avdataoffset']);
31 | $dsfheader = $this->fread(28 + 12);
32 |
33 | $headeroffset = 0;
34 | $info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4);
35 | $headeroffset += 4;
36 | $magic = 'DSD ';
37 | if ($info['dsf']['dsd']['magic'] != $magic) {
38 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"');
39 | unset($info['fileformat']);
40 | unset($info['audio']);
41 | unset($info['dsf']);
42 | return false;
43 | }
44 | $info['dsf']['dsd']['dsd_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28
45 | $headeroffset += 8;
46 | $info['dsf']['dsd']['dsf_file_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
47 | $headeroffset += 8;
48 | $info['dsf']['dsd']['meta_chunk_offset'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
49 | $headeroffset += 8;
50 |
51 |
52 | $info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4);
53 | $headeroffset += 4;
54 | $magic = 'fmt ';
55 | if ($info['dsf']['fmt']['magic'] != $magic) {
56 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"');
57 | return false;
58 | }
59 | $info['dsf']['fmt']['fmt_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // usually 52 bytes
60 | $headeroffset += 8;
61 | $dsfheader .= $this->fread($info['dsf']['fmt']['fmt_chunk_size'] - 12 + 12); // we have already read the entire DSD chunk, plus 12 bytes of FMT. We now want to read the size of FMT, plus 12 bytes into the next chunk to get magic and size.
62 | if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) {
63 | $this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes');
64 | return false;
65 | }
66 | $info['dsf']['fmt']['format_version'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "1"
67 | $headeroffset += 4;
68 | $info['dsf']['fmt']['format_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "0" = "DSD Raw"
69 | $headeroffset += 4;
70 | $info['dsf']['fmt']['channel_type_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
71 | $headeroffset += 4;
72 | $info['dsf']['fmt']['channels'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
73 | $headeroffset += 4;
74 | $info['dsf']['fmt']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
75 | $headeroffset += 4;
76 | $info['dsf']['fmt']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
77 | $headeroffset += 4;
78 | $info['dsf']['fmt']['sample_count'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
79 | $headeroffset += 8;
80 | $info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
81 | $headeroffset += 4;
82 | $info['dsf']['fmt']['reserved'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled
83 | $headeroffset += 4;
84 |
85 |
86 | $info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4);
87 | $headeroffset += 4;
88 | $magic = 'data';
89 | if ($info['dsf']['data']['magic'] != $magic) {
90 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"');
91 | return false;
92 | }
93 | $info['dsf']['data']['data_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
94 | $headeroffset += 8;
95 | $info['avdataoffset'] = $headeroffset;
96 | $info['avdataend'] = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size'];
97 |
98 |
99 | if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) {
100 | $getid3_id3v2 = new getid3_id3v2($this->getid3);
101 | $getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset'];
102 | $getid3_id3v2->Analyze();
103 | unset($getid3_id3v2);
104 | }
105 |
106 |
107 | $info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']);
108 | $info['audio']['channelmode'] = $info['dsf']['fmt']['channel_type'];
109 | $info['audio']['bits_per_sample'] = $info['dsf']['fmt']['bits_per_sample'];
110 | $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate'];
111 | $info['audio']['channels'] = $info['dsf']['fmt']['channels'];
112 | $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
113 | $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
114 |
115 | return true;
116 | }
117 |
118 |
119 | public static function DSFchannelTypeLookup($channel_type_id) {
120 | static $DSFchannelTypeLookup = array(
121 | // interleaving order:
122 | 1 => 'mono', // 1: Mono
123 | 2 => 'stereo', // 1: Front-Left; 2: Front-Right
124 | 3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center
125 | 4 => 'quad', // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right
126 | 5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency
127 | 6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Back-Left 5: Back-Right
128 | 7 => '5.1', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency; 5: Back-Left; 6: Back-Right
129 | );
130 | return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : '');
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.dss.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.dss.php //
12 | // module for analyzing Digital Speech Standard (DSS) files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_dss extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $DSSheader = $this->fread(1540);
26 |
27 | if (!preg_match('#^[\\x02-\\x06]ds[s2]#', $DSSheader)) {
28 | $this->error('Expecting "[02-06] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"');
29 | return false;
30 | }
31 |
32 | // some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
33 | $info['encoding'] = 'ISO-8859-1'; // not certain, but assumed
34 | $info['dss'] = array();
35 |
36 | $info['fileformat'] = 'dss';
37 | $info['mime_type'] = 'audio/x-'.substr($DSSheader, 1, 3); // "audio/x-dss" or "audio/x-ds2"
38 | $info['audio']['dataformat'] = substr($DSSheader, 1, 3); // "dss" or "ds2"
39 | $info['audio']['bitrate_mode'] = 'cbr';
40 |
41 | $info['dss']['version'] = ord(substr($DSSheader, 0, 1));
42 | $info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400"
43 | $info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4));
44 | // 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen
45 | $info['dss']['date_create_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
46 | $info['dss']['date_complete_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
47 | $info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS
48 | if ($info['dss']['version'] <= 3) {
49 | $info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512
50 | $info['dss']['priority'] = ord(substr($DSSheader, 793, 1));
51 | $info['dss']['comments'] = trim(substr($DSSheader, 798, 100));
52 | $info['dss']['sample_rate_index'] = ord(substr($DSSheader, 1538, 1)); // this isn't certain, this may or may not be where the sample rate info is stored, but it seems consistent on my small selection of sample files
53 | $info['audio']['sample_rate'] = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']);
54 | } else {
55 | $this->getid3->warning('DSS above version 3 not fully supported in this version of getID3. Any additional documentation or format specifications would be welcome. This file is version '.$info['dss']['version']);
56 | }
57 |
58 | $info['audio']['bits_per_sample'] = 16; // maybe, maybe not -- most compressed audio formats don't have a fixed bits-per-sample value, but this is a reasonable approximation
59 | $info['audio']['channels'] = 1;
60 |
61 | if (!empty($info['dss']['playtime_ms']) && (floor($info['dss']['playtime_ms'] / 1000) == $info['dss']['playtime_sec'])) { // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check
62 | $info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000;
63 | } else {
64 | $info['playtime_seconds'] = $info['dss']['playtime_sec'];
65 | if (!empty($info['dss']['playtime_ms'])) {
66 | $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value');
67 | }
68 | }
69 | $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds'];
70 |
71 | return true;
72 | }
73 |
74 | public function DSSdateStringToUnixDate($datestring) {
75 | $y = substr($datestring, 0, 2);
76 | $m = substr($datestring, 2, 2);
77 | $d = substr($datestring, 4, 2);
78 | $h = substr($datestring, 6, 2);
79 | $i = substr($datestring, 8, 2);
80 | $s = substr($datestring, 10, 2);
81 | $y += (($y < 95) ? 2000 : 1900);
82 | return mktime($h, $i, $s, $m, $d, $y);
83 | }
84 |
85 | public function DSSsampleRateLookup($sample_rate_index) {
86 | static $dssSampleRateLookup = array(
87 | 0x0A => 16000,
88 | 0x0C => 11025,
89 | 0x0D => 12000,
90 | 0x15 => 8000,
91 | );
92 | if (!array_key_exists($sample_rate_index, $dssSampleRateLookup)) {
93 | $this->getid3->warning('unknown sample_rate_index: 0x'.strtoupper(dechex($sample_rate_index)));
94 | return false;
95 | }
96 | return $dssSampleRateLookup[$sample_rate_index];
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.lpac.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.lpac.php //
12 | // module for analyzing LPAC Audio files //
13 | // dependencies: module.audio-video.riff.php //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
18 |
19 | class getid3_lpac extends getid3_handler
20 | {
21 |
22 | public function Analyze() {
23 | $info = &$this->getid3->info;
24 |
25 | $this->fseek($info['avdataoffset']);
26 | $LPACheader = $this->fread(14);
27 | if (substr($LPACheader, 0, 4) != 'LPAC') {
28 | $this->error('Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"');
29 | return false;
30 | }
31 | $info['avdataoffset'] += 14;
32 |
33 | $info['fileformat'] = 'lpac';
34 | $info['audio']['dataformat'] = 'lpac';
35 | $info['audio']['lossless'] = true;
36 | $info['audio']['bitrate_mode'] = 'vbr';
37 |
38 | $info['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1));
39 | $flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1));
40 | $info['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4));
41 | $flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4));
42 |
43 | $info['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40);
44 | $info['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04);
45 | $info['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02);
46 | $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01);
47 |
48 | if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) {
49 | $this->warning('24-bit and 16-bit flags cannot both be set');
50 | }
51 |
52 | $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
53 | $info['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000);
54 | $info['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256;
55 | $info['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000);
56 | $info['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000);
57 | $info['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000);
58 | $info['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8;
59 | $info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F);
60 |
61 | if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) {
62 | $this->warning('max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"');
63 | }
64 | switch ($info['lpac']['file_version']) {
65 | case 6:
66 | if ($info['lpac']['flags']['adaptive_quantization']) {
67 | $this->warning('adaptive_quantization expected to be false in LPAC file stucture v6, actually true');
68 | }
69 | if ($info['lpac']['quantization'] != 20) {
70 | $this->warning('Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q']);
71 | }
72 | break;
73 |
74 | default:
75 | //$this->warning('This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org');
76 | break;
77 | }
78 |
79 | $getid3_temp = new getID3();
80 | $getid3_temp->openfile($this->getid3->filename);
81 | $getid3_temp->info = $info;
82 | $getid3_riff = new getid3_riff($getid3_temp);
83 | $getid3_riff->Analyze();
84 | $info['avdataoffset'] = $getid3_temp->info['avdataoffset'];
85 | $info['riff'] = $getid3_temp->info['riff'];
86 | $info['error'] = $getid3_temp->info['error'];
87 | $info['warning'] = $getid3_temp->info['warning'];
88 | $info['lpac']['comments']['comment'] = $getid3_temp->info['comments'];
89 | $info['audio']['sample_rate'] = $getid3_temp->info['audio']['sample_rate'];
90 | unset($getid3_temp, $getid3_riff);
91 |
92 | $info['audio']['channels'] = ($info['lpac']['flags']['stereo'] ? 2 : 1);
93 |
94 | if ($info['lpac']['flags']['24_bit']) {
95 | $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample'];
96 | } elseif ($info['lpac']['flags']['16_bit']) {
97 | $info['audio']['bits_per_sample'] = 16;
98 | } else {
99 | $info['audio']['bits_per_sample'] = 8;
100 | }
101 |
102 | if ($info['lpac']['flags']['fast_compress']) {
103 | // fast
104 | $info['audio']['encoder_options'] = '-1';
105 | } else {
106 | switch ($info['lpac']['max_prediction_order']) {
107 | case 20: // simple
108 | $info['audio']['encoder_options'] = '-2';
109 | break;
110 | case 30: // medium
111 | $info['audio']['encoder_options'] = '-3';
112 | break;
113 | case 40: // high
114 | $info['audio']['encoder_options'] = '-4';
115 | break;
116 | case 60: // extrahigh
117 | $info['audio']['encoder_options'] = '-5';
118 | break;
119 | }
120 | }
121 |
122 | $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate'];
123 | $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
124 |
125 | return true;
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.mod.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.mod.php //
12 | // module for analyzing MOD Audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_mod extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 | $this->fseek($info['avdataoffset']);
24 | $fileheader = $this->fread(1088);
25 | if (preg_match('#^IMPM#', $fileheader)) {
26 | return $this->getITheaderFilepointer();
27 | } elseif (preg_match('#^Extended Module#', $fileheader)) {
28 | return $this->getXMheaderFilepointer();
29 | } elseif (preg_match('#^.{44}SCRM#', $fileheader)) {
30 | return $this->getS3MheaderFilepointer();
31 | } elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) {
32 | return $this->getMODheaderFilepointer();
33 | }
34 | $this->error('This is not a known type of MOD file');
35 | return false;
36 | }
37 |
38 |
39 | public function getMODheaderFilepointer() {
40 | $info = &$this->getid3->info;
41 | $this->fseek($info['avdataoffset'] + 1080);
42 | $FormatID = $this->fread(4);
43 | if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
44 | $this->error('This is not a known type of MOD file');
45 | return false;
46 | }
47 |
48 | $info['fileformat'] = 'mod';
49 |
50 | $this->error('MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
51 | return false;
52 | }
53 |
54 | public function getXMheaderFilepointer() {
55 | $info = &$this->getid3->info;
56 | $this->fseek($info['avdataoffset']);
57 | $FormatID = $this->fread(15);
58 | if (!preg_match('#^Extended Module$#', $FormatID)) {
59 | $this->error('This is not a known type of XM-MOD file');
60 | return false;
61 | }
62 |
63 | $info['fileformat'] = 'xm';
64 |
65 | $this->error('XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
66 | return false;
67 | }
68 |
69 | public function getS3MheaderFilepointer() {
70 | $info = &$this->getid3->info;
71 | $this->fseek($info['avdataoffset'] + 44);
72 | $FormatID = $this->fread(4);
73 | if (!preg_match('#^SCRM$#', $FormatID)) {
74 | $this->error('This is not a ScreamTracker MOD file');
75 | return false;
76 | }
77 |
78 | $info['fileformat'] = 's3m';
79 |
80 | $this->error('ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
81 | return false;
82 | }
83 |
84 | public function getITheaderFilepointer() {
85 | $info = &$this->getid3->info;
86 | $this->fseek($info['avdataoffset']);
87 | $FormatID = $this->fread(4);
88 | if (!preg_match('#^IMPM$#', $FormatID)) {
89 | $this->error('This is not an ImpulseTracker MOD file');
90 | return false;
91 | }
92 |
93 | $info['fileformat'] = 'it';
94 |
95 | $this->error('ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
96 | return false;
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.rkau.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.shorten.php //
12 | // module for analyzing Shorten Audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_rkau extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $RKAUHeader = $this->fread(20);
26 | $magic = 'RKA';
27 | if (substr($RKAUHeader, 0, 3) != $magic) {
28 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"');
29 | return false;
30 | }
31 |
32 | $info['fileformat'] = 'rkau';
33 | $info['audio']['dataformat'] = 'rkau';
34 | $info['audio']['bitrate_mode'] = 'vbr';
35 |
36 | $info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1));
37 | $info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT);
38 | if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) {
39 | $this->error('This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')');
40 | unset($info['rkau']);
41 | return false;
42 | }
43 |
44 | $info['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4));
45 | $info['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4));
46 | $info['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1));
47 | $info['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1));
48 |
49 | $info['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1));
50 | $this->RKAUqualityLookup($info['rkau']);
51 |
52 | $info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1));
53 | $info['rkau']['flags']['joint_stereo'] = (bool) (!($info['rkau']['raw']['flags'] & 0x01));
54 | $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02);
55 | $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04);
56 |
57 | if ($info['rkau']['flags']['streaming']) {
58 | $info['avdataoffset'] += 20;
59 | $info['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4));
60 | } else {
61 | $info['avdataoffset'] += 16;
62 | $info['rkau']['compressed_bytes'] = $info['avdataend'] - $info['avdataoffset'] - 1;
63 | }
64 | // Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes,
65 | // sometimes it's more, sometimes less. No idea why(?)
66 |
67 | $info['audio']['lossless'] = $info['rkau']['lossless'];
68 | $info['audio']['channels'] = $info['rkau']['channels'];
69 | $info['audio']['bits_per_sample'] = $info['rkau']['bits_per_sample'];
70 | $info['audio']['sample_rate'] = $info['rkau']['sample_rate'];
71 |
72 | $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8));
73 | $info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds'];
74 |
75 | return true;
76 |
77 | }
78 |
79 |
80 | public function RKAUqualityLookup(&$RKAUdata) {
81 | $level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4;
82 | $quality = $RKAUdata['raw']['quality'] & 0x0F;
83 |
84 | $RKAUdata['lossless'] = (($quality == 0) ? true : false);
85 | $RKAUdata['compression_level'] = $level + 1;
86 | if (!$RKAUdata['lossless']) {
87 | $RKAUdata['quality_setting'] = $quality;
88 | }
89 |
90 | return true;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.shorten.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.shorten.php //
12 | // module for analyzing Shorten Audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_shorten extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 |
26 | $ShortenHeader = $this->fread(8);
27 | $magic = 'ajkg';
28 | if (substr($ShortenHeader, 0, 4) != $magic) {
29 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"');
30 | return false;
31 | }
32 | $info['fileformat'] = 'shn';
33 | $info['audio']['dataformat'] = 'shn';
34 | $info['audio']['lossless'] = true;
35 | $info['audio']['bitrate_mode'] = 'vbr';
36 |
37 | $info['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1));
38 |
39 | $this->fseek($info['avdataend'] - 12);
40 | $SeekTableSignatureTest = $this->fread(12);
41 | $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK');
42 | if ($info['shn']['seektable']['present']) {
43 | $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
44 | $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length'];
45 | $this->fseek($info['shn']['seektable']['offset']);
46 | $SeekTableMagic = $this->fread(4);
47 | $magic = 'SEEK';
48 | if ($SeekTableMagic != $magic) {
49 |
50 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"');
51 | return false;
52 |
53 | } else {
54 |
55 | // typedef struct tag_TSeekEntry
56 | // {
57 | // unsigned long SampleNumber;
58 | // unsigned long SHNFileByteOffset;
59 | // unsigned long SHNLastBufferReadPosition;
60 | // unsigned short SHNByteGet;
61 | // unsigned short SHNBufferOffset;
62 | // unsigned short SHNFileBitOffset;
63 | // unsigned long SHNGBuffer;
64 | // unsigned short SHNBitShift;
65 | // long CBuf0[3];
66 | // long CBuf1[3];
67 | // long Offset0[4];
68 | // long Offset1[4];
69 | // }TSeekEntry;
70 |
71 | $SeekTableData = $this->fread($info['shn']['seektable']['length'] - 16);
72 | $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80);
73 | //$info['shn']['seektable']['entries'] = array();
74 | //$SeekTableOffset = 0;
75 | //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) {
76 | // $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
77 | // $SeekTableOffset += 4;
78 | // $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
79 | // $SeekTableOffset += 4;
80 | // $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
81 | // $SeekTableOffset += 4;
82 | // $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
83 | // $SeekTableOffset += 2;
84 | // $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
85 | // $SeekTableOffset += 2;
86 | // $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
87 | // $SeekTableOffset += 2;
88 | // $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
89 | // $SeekTableOffset += 4;
90 | // $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
91 | // $SeekTableOffset += 2;
92 | // for ($j = 0; $j < 3; $j++) {
93 | // $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
94 | // $SeekTableOffset += 4;
95 | // }
96 | // for ($j = 0; $j < 3; $j++) {
97 | // $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
98 | // $SeekTableOffset += 4;
99 | // }
100 | // for ($j = 0; $j < 4; $j++) {
101 | // $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
102 | // $SeekTableOffset += 4;
103 | // }
104 | // for ($j = 0; $j < 4; $j++) {
105 | // $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
106 | // $SeekTableOffset += 4;
107 | // }
108 | //
109 | // $info['shn']['seektable']['entries'][] = $SeekTableEntry;
110 | //}
111 |
112 | }
113 |
114 | }
115 |
116 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
117 | $this->error('PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files');
118 | return false;
119 | }
120 |
121 | if (GETID3_OS_ISWINDOWS) {
122 |
123 | $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
124 | foreach ($RequiredFiles as $required_file) {
125 | if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
126 | $this->error(GETID3_HELPERAPPSDIR.$required_file.' does not exist');
127 | return false;
128 | }
129 | }
130 | $commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$info['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64';
131 | $commandline = str_replace('/', '\\', $commandline);
132 |
133 | } else {
134 |
135 | static $shorten_present;
136 | if (!isset($shorten_present)) {
137 | $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
138 | }
139 | if (!$shorten_present) {
140 | $this->error('shorten binary was not found in path or /usr/local/bin');
141 | return false;
142 | }
143 | $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64';
144 |
145 | }
146 |
147 | $output = `$commandline`;
148 |
149 | if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) {
150 |
151 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
152 |
153 | $fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4));
154 | $DecodedWAVFORMATEX = getid3_riff::parseWAVEFORMATex(substr($output, 20, $fmt_size));
155 | $info['audio']['channels'] = $DecodedWAVFORMATEX['channels'];
156 | $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample'];
157 | $info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate'];
158 |
159 | if (substr($output, 20 + $fmt_size, 4) == 'data') {
160 |
161 | $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec'];
162 |
163 | } else {
164 |
165 | $this->error('shorten failed to decode DATA chunk to expected location, cannot determine playtime');
166 | return false;
167 |
168 | }
169 |
170 | $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8;
171 |
172 | } else {
173 |
174 | $this->error('shorten failed to decode file to WAV for parsing');
175 | return false;
176 |
177 | }
178 |
179 | return true;
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.tta.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.tta.php //
12 | // module for analyzing TTA Audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_tta extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $info['fileformat'] = 'tta';
25 | $info['audio']['dataformat'] = 'tta';
26 | $info['audio']['lossless'] = true;
27 | $info['audio']['bitrate_mode'] = 'vbr';
28 |
29 | $this->fseek($info['avdataoffset']);
30 | $ttaheader = $this->fread(26);
31 |
32 | $info['tta']['magic'] = substr($ttaheader, 0, 3);
33 | $magic = 'TTA';
34 | if ($info['tta']['magic'] != $magic) {
35 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"');
36 | unset($info['fileformat']);
37 | unset($info['audio']);
38 | unset($info['tta']);
39 | return false;
40 | }
41 |
42 | switch ($ttaheader{3}) {
43 | case "\x01": // TTA v1.x
44 | case "\x02": // TTA v1.x
45 | case "\x03": // TTA v1.x
46 | // "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year."
47 | $info['tta']['major_version'] = 1;
48 | $info['avdataoffset'] += 16;
49 |
50 | $info['tta']['compression_level'] = ord($ttaheader{3});
51 | $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
52 | $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
53 | $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4));
54 | $info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
55 |
56 | $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level'];
57 | $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate'];
58 | break;
59 |
60 | case '2': // TTA v2.x
61 | // "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4."
62 | $info['tta']['major_version'] = 2;
63 | $info['avdataoffset'] += 20;
64 |
65 | $info['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
66 | $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
67 | $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
68 | $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2));
69 | $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
70 | $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4));
71 |
72 | $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level'];
73 | $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate'];
74 | break;
75 |
76 | case '1': // TTA v3.x
77 | // "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher."
78 | $info['tta']['major_version'] = 3;
79 | $info['avdataoffset'] += 26;
80 |
81 | $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::wFormatTagLookup()
82 | $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
83 | $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
84 | $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4));
85 | $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4));
86 | $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4);
87 | $info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4));
88 |
89 | $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate'];
90 | break;
91 |
92 | default:
93 | $this->error('This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3});
94 | return false;
95 | break;
96 | }
97 |
98 | $info['audio']['encoder'] = 'TTA v'.$info['tta']['major_version'];
99 | $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample'];
100 | $info['audio']['sample_rate'] = $info['tta']['sample_rate'];
101 | $info['audio']['channels'] = $info['tta']['channels'];
102 | $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
103 |
104 | return true;
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.voc.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.voc.php //
12 | // module for analyzing Creative VOC Audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_voc extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $OriginalAVdataOffset = $info['avdataoffset'];
25 | $this->fseek($info['avdataoffset']);
26 | $VOCheader = $this->fread(26);
27 |
28 | $magic = 'Creative Voice File';
29 | if (substr($VOCheader, 0, 19) != $magic) {
30 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"');
31 | return false;
32 | }
33 |
34 | // shortcuts
35 | $thisfile_audio = &$info['audio'];
36 | $info['voc'] = array();
37 | $thisfile_voc = &$info['voc'];
38 |
39 | $info['fileformat'] = 'voc';
40 | $thisfile_audio['dataformat'] = 'voc';
41 | $thisfile_audio['bitrate_mode'] = 'cbr';
42 | $thisfile_audio['lossless'] = true;
43 | $thisfile_audio['channels'] = 1; // might be overriden below
44 | $thisfile_audio['bits_per_sample'] = 8; // might be overriden below
45 |
46 | // byte # Description
47 | // ------ ------------------------------------------
48 | // 00-12 'Creative Voice File'
49 | // 13 1A (eof to abort printing of file)
50 | // 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation)
51 | // 16-17 Version number (minor,major) (VOC-HDR puts 0A 01)
52 | // 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11)
53 |
54 | $thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2));
55 | $thisfile_voc['header']['minor_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1));
56 | $thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1));
57 |
58 | do {
59 |
60 | $BlockOffset = $this->ftell();
61 | $BlockData = $this->fread(4);
62 | $BlockType = ord($BlockData{0});
63 | $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3));
64 | $ThisBlock = array();
65 |
66 | getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1);
67 | switch ($BlockType) {
68 | case 0: // Terminator
69 | // do nothing, we'll break out of the loop down below
70 | break;
71 |
72 | case 1: // Sound data
73 | $BlockData .= $this->fread(2);
74 | if ($info['avdataoffset'] <= $OriginalAVdataOffset) {
75 | $info['avdataoffset'] = $this->ftell();
76 | }
77 | $this->fseek($BlockSize - 2, SEEK_CUR);
78 |
79 | $ThisBlock['sample_rate_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 1));
80 | $ThisBlock['compression_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, 5, 1));
81 |
82 | $ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']);
83 | if ($ThisBlock['compression_type'] <= 3) {
84 | $thisfile_voc['compressed_bits_per_sample'] = getid3_lib::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name']));
85 | }
86 |
87 | // Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available)
88 | if (empty($thisfile_audio['sample_rate'])) {
89 | // SR byte = 256 - (1000000 / sample_rate)
90 | $thisfile_audio['sample_rate'] = getid3_lib::trunc((1000000 / (256 - $ThisBlock['sample_rate_id'])) / $thisfile_audio['channels']);
91 | }
92 | break;
93 |
94 | case 2: // Sound continue
95 | case 3: // Silence
96 | case 4: // Marker
97 | case 6: // Repeat
98 | case 7: // End repeat
99 | // nothing useful, just skip
100 | $this->fseek($BlockSize, SEEK_CUR);
101 | break;
102 |
103 | case 8: // Extended
104 | $BlockData .= $this->fread(4);
105 |
106 | //00-01 Time Constant:
107 | // Mono: 65536 - (256000000 / sample_rate)
108 | // Stereo: 65536 - (256000000 / (sample_rate * 2))
109 | $ThisBlock['time_constant'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 2));
110 | $ThisBlock['pack_method'] = getid3_lib::LittleEndian2Int(substr($BlockData, 6, 1));
111 | $ThisBlock['stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BlockData, 7, 1));
112 |
113 | $thisfile_audio['channels'] = ($ThisBlock['stereo'] ? 2 : 1);
114 | $thisfile_audio['sample_rate'] = getid3_lib::trunc((256000000 / (65536 - $ThisBlock['time_constant'])) / $thisfile_audio['channels']);
115 | break;
116 |
117 | case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit
118 | $BlockData .= $this->fread(12);
119 | if ($info['avdataoffset'] <= $OriginalAVdataOffset) {
120 | $info['avdataoffset'] = $this->ftell();
121 | }
122 | $this->fseek($BlockSize - 12, SEEK_CUR);
123 |
124 | $ThisBlock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4));
125 | $ThisBlock['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($BlockData, 8, 1));
126 | $ThisBlock['channels'] = getid3_lib::LittleEndian2Int(substr($BlockData, 9, 1));
127 | $ThisBlock['wFormat'] = getid3_lib::LittleEndian2Int(substr($BlockData, 10, 2));
128 |
129 | $ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']);
130 | if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) {
131 | $thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']);
132 | }
133 |
134 | $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate'];
135 | $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample'];
136 | $thisfile_audio['channels'] = $ThisBlock['channels'];
137 | break;
138 |
139 | default:
140 | $this->warning('Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset);
141 | $this->fseek($BlockSize, SEEK_CUR);
142 | break;
143 | }
144 |
145 | if (!empty($ThisBlock)) {
146 | $ThisBlock['block_offset'] = $BlockOffset;
147 | $ThisBlock['block_size'] = $BlockSize;
148 | $ThisBlock['block_type_id'] = $BlockType;
149 | $thisfile_voc['blocks'][] = $ThisBlock;
150 | }
151 |
152 | } while (!feof($this->getid3->fp) && ($BlockType != 0));
153 |
154 | // Terminator block doesn't have size field, so seek back 3 spaces
155 | $this->fseek(-3, SEEK_CUR);
156 |
157 | ksort($thisfile_voc['blocktypes']);
158 |
159 | if (!empty($thisfile_voc['compressed_bits_per_sample'])) {
160 | $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']);
161 | $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
162 | }
163 |
164 | return true;
165 | }
166 |
167 | public function VOCcompressionTypeLookup($index) {
168 | static $VOCcompressionTypeLookup = array(
169 | 0 => '8-bit',
170 | 1 => '4-bit',
171 | 2 => '2.6-bit',
172 | 3 => '2-bit'
173 | );
174 | return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels');
175 | }
176 |
177 | public function VOCwFormatLookup($index) {
178 | static $VOCwFormatLookup = array(
179 | 0x0000 => '8-bit unsigned PCM',
180 | 0x0001 => 'Creative 8-bit to 4-bit ADPCM',
181 | 0x0002 => 'Creative 8-bit to 3-bit ADPCM',
182 | 0x0003 => 'Creative 8-bit to 2-bit ADPCM',
183 | 0x0004 => '16-bit signed PCM',
184 | 0x0006 => 'CCITT a-Law',
185 | 0x0007 => 'CCITT u-Law',
186 | 0x2000 => 'Creative 16-bit to 4-bit ADPCM'
187 | );
188 | return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
189 | }
190 |
191 | public function VOCwFormatActualBitsPerSampleLookup($index) {
192 | static $VOCwFormatLookup = array(
193 | 0x0000 => 8,
194 | 0x0001 => 4,
195 | 0x0002 => 3,
196 | 0x0003 => 2,
197 | 0x0004 => 16,
198 | 0x0006 => 8,
199 | 0x0007 => 8,
200 | 0x2000 => 4
201 | );
202 | return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/php/getID3/module.audio.vqf.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.audio.vqf.php //
12 | // module for analyzing VQF audio files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_vqf extends getid3_handler
19 | {
20 | public function Analyze() {
21 | $info = &$this->getid3->info;
22 |
23 | // based loosely on code from TTwinVQ by Jurgen Faul
24 | // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
25 |
26 | $info['fileformat'] = 'vqf';
27 | $info['audio']['dataformat'] = 'vqf';
28 | $info['audio']['bitrate_mode'] = 'cbr';
29 | $info['audio']['lossless'] = false;
30 |
31 | // shortcut
32 | $info['vqf']['raw'] = array();
33 | $thisfile_vqf = &$info['vqf'];
34 | $thisfile_vqf_raw = &$thisfile_vqf['raw'];
35 |
36 | $this->fseek($info['avdataoffset']);
37 | $VQFheaderData = $this->fread(16);
38 |
39 | $offset = 0;
40 | $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
41 | $magic = 'TWIN';
42 | if ($thisfile_vqf_raw['header_tag'] != $magic) {
43 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"');
44 | unset($info['vqf']);
45 | unset($info['fileformat']);
46 | return false;
47 | }
48 | $offset += 4;
49 | $thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8);
50 | $offset += 8;
51 | $thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4));
52 | $offset += 4;
53 |
54 | while ($this->ftell() < $info['avdataend']) {
55 |
56 | $ChunkBaseOffset = $this->ftell();
57 | $chunkoffset = 0;
58 | $ChunkData = $this->fread(8);
59 | $ChunkName = substr($ChunkData, $chunkoffset, 4);
60 | if ($ChunkName == 'DATA') {
61 | $info['avdataoffset'] = $ChunkBaseOffset;
62 | break;
63 | }
64 | $chunkoffset += 4;
65 | $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
66 | $chunkoffset += 4;
67 | if ($ChunkSize > ($info['avdataend'] - $this->ftell())) {
68 | $this->error('Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset);
69 | break;
70 | }
71 | if ($ChunkSize > 0) {
72 | $ChunkData .= $this->fread($ChunkSize);
73 | }
74 |
75 | switch ($ChunkName) {
76 | case 'COMM':
77 | // shortcut
78 | $thisfile_vqf['COMM'] = array();
79 | $thisfile_vqf_COMM = &$thisfile_vqf['COMM'];
80 |
81 | $thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
82 | $chunkoffset += 4;
83 | $thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
84 | $chunkoffset += 4;
85 | $thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
86 | $chunkoffset += 4;
87 | $thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
88 | $chunkoffset += 4;
89 |
90 | $info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1;
91 | $info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']);
92 | $info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000;
93 | $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000);
94 |
95 | if ($info['audio']['bitrate'] == 0) {
96 | $this->error('Corrupt VQF file: bitrate_audio == zero');
97 | return false;
98 | }
99 | break;
100 |
101 | case 'NAME':
102 | case 'AUTH':
103 | case '(c) ':
104 | case 'FILE':
105 | case 'COMT':
106 | case 'ALBM':
107 | $thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8));
108 | break;
109 |
110 | case 'DSIZ':
111 | $thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4));
112 | break;
113 |
114 | default:
115 | $this->warning('Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset);
116 | break;
117 | }
118 | }
119 |
120 | $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate'];
121 |
122 | if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))))) {
123 | switch ($thisfile_vqf['DSIZ']) {
124 | case 0:
125 | case 1:
126 | $this->warning('Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0');
127 | $info['audio']['encoder'] = 'Ahead Nero';
128 | break;
129 |
130 | default:
131 | $this->warning('Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA')));
132 | break;
133 | }
134 | }
135 |
136 | return true;
137 | }
138 |
139 | public function VQFchannelFrequencyLookup($frequencyid) {
140 | static $VQFchannelFrequencyLookup = array(
141 | 11 => 11025,
142 | 22 => 22050,
143 | 44 => 44100
144 | );
145 | return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
146 | }
147 |
148 | public function VQFcommentNiceNameLookup($shortname) {
149 | static $VQFcommentNiceNameLookup = array(
150 | 'NAME' => 'title',
151 | 'AUTH' => 'artist',
152 | '(c) ' => 'copyright',
153 | 'FILE' => 'filename',
154 | 'COMT' => 'comment',
155 | 'ALBM' => 'album'
156 | );
157 | return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname);
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/php/getID3/module.graphic.efax.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.archive.efax.php //
12 | // module for analyzing eFax files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_efax extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $efaxheader = $this->fread(1024);
26 |
27 | $info['efax']['header']['magic'] = substr($efaxheader, 0, 2);
28 | if ($info['efax']['header']['magic'] != "\xDC\xFE") {
29 | $this->error('Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset']);
30 | return false;
31 | }
32 | $info['fileformat'] = 'efax';
33 |
34 | $info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4));
35 | if ($info['efax']['header']['filesize'] != $info['filesize']) {
36 | $this->error('Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes');
37 | }
38 | $info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "\x00");
39 | $info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "\x00");
40 | $info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "\x00");
41 |
42 | $info['efax']['header']['pages'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2));
43 | $info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4));
44 |
45 | $this->error('eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
46 | return false;
47 |
48 | return true;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/php/getID3/module.graphic.pcd.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.graphic.pcd.php //
12 | // module for analyzing PhotoCD (PCD) Image files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_pcd extends getid3_handler
19 | {
20 | public $ExtractData = 0;
21 |
22 | public function Analyze() {
23 | $info = &$this->getid3->info;
24 |
25 | $info['fileformat'] = 'pcd';
26 | $info['video']['dataformat'] = 'pcd';
27 | $info['video']['lossless'] = false;
28 |
29 |
30 | $this->fseek($info['avdataoffset'] + 72);
31 |
32 | $PCDflags = $this->fread(1);
33 | $PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false);
34 |
35 |
36 | if ($PCDisVertical) {
37 | $info['video']['resolution_x'] = 3072;
38 | $info['video']['resolution_y'] = 2048;
39 | } else {
40 | $info['video']['resolution_x'] = 2048;
41 | $info['video']['resolution_y'] = 3072;
42 | }
43 |
44 |
45 | if ($this->ExtractData > 3) {
46 |
47 | $this->error('Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.');
48 |
49 | } elseif ($this->ExtractData > 0) {
50 |
51 | $PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16
52 | $PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4
53 | $PCD_levels[3] = array( 768, 512, 0x30000); // BASE
54 | //$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption
55 | //$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption
56 | //$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only
57 |
58 | list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3];
59 |
60 | $this->fseek($info['avdataoffset'] + $PCD_dataOffset);
61 |
62 | for ($y = 0; $y < $PCD_height; $y += 2) {
63 | // The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h.
64 | // To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each
65 | // consisting of w bytes, where w is the width of the image-subtype. The first w bytes and
66 | // the first half of the third w bytes contain data for the first RGB-line, the second w bytes
67 | // and the second half of the third w bytes contain data for a second RGB-line.
68 |
69 | $PCD_data_Y1 = $this->fread($PCD_width);
70 | $PCD_data_Y2 = $this->fread($PCD_width);
71 | $PCD_data_Cb = $this->fread(intval(round($PCD_width / 2)));
72 | $PCD_data_Cr = $this->fread(intval(round($PCD_width / 2)));
73 |
74 | for ($x = 0; $x < $PCD_width; $x++) {
75 | if ($PCDisVertical) {
76 | $info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
77 | $info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
78 | } else {
79 | $info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
80 | $info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
81 | }
82 | }
83 | }
84 |
85 | // Example for plotting extracted data
86 | //getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
87 | //if ($PCDisVertical) {
88 | // $BMPinfo['resolution_x'] = $PCD_height;
89 | // $BMPinfo['resolution_y'] = $PCD_width;
90 | //} else {
91 | // $BMPinfo['resolution_x'] = $PCD_width;
92 | // $BMPinfo['resolution_y'] = $PCD_height;
93 | //}
94 | //$BMPinfo['bmp']['data'] = $info['pcd']['data'];
95 | //getid3_bmp::PlotBMP($BMPinfo);
96 | //exit;
97 |
98 | }
99 |
100 | }
101 |
102 | public function YCbCr2RGB($Y, $Cb, $Cr) {
103 | static $YCbCr_constants = array();
104 | if (empty($YCbCr_constants)) {
105 | $YCbCr_constants['red']['Y'] = 0.0054980 * 256;
106 | $YCbCr_constants['red']['Cb'] = 0.0000000 * 256;
107 | $YCbCr_constants['red']['Cr'] = 0.0051681 * 256;
108 | $YCbCr_constants['green']['Y'] = 0.0054980 * 256;
109 | $YCbCr_constants['green']['Cb'] = -0.0015446 * 256;
110 | $YCbCr_constants['green']['Cr'] = -0.0026325 * 256;
111 | $YCbCr_constants['blue']['Y'] = 0.0054980 * 256;
112 | $YCbCr_constants['blue']['Cb'] = 0.0079533 * 256;
113 | $YCbCr_constants['blue']['Cr'] = 0.0000000 * 256;
114 | }
115 |
116 | $RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
117 | foreach ($RGBcolor as $rgbname => $dummy) {
118 | $RGBcolor[$rgbname] = max(0,
119 | min(255,
120 | intval(
121 | round(
122 | ($YCbCr_constants[$rgbname]['Y'] * $Y) +
123 | ($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) +
124 | ($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137))
125 | )
126 | )
127 | )
128 | );
129 | }
130 | return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']);
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/php/getID3/module.graphic.svg.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.graphic.svg.php //
12 | // module for analyzing SVG Image files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_svg extends getid3_handler
19 | {
20 |
21 |
22 | public function Analyze() {
23 | $info = &$this->getid3->info;
24 |
25 | $this->fseek($info['avdataoffset']);
26 |
27 | $SVGheader = $this->fread(4096);
28 | if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) {
29 | $info['svg']['xml']['raw'] = $matches;
30 | }
31 | if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) {
32 | $info['svg']['doctype']['raw'] = $matches;
33 | }
34 | if (preg_match('#\]+)\>#i', $SVGheader, $matches)) {
35 | $info['svg']['svg']['raw'] = $matches;
36 | }
37 | if (isset($info['svg']['svg']['raw'])) {
38 |
39 | $sections_to_fix = array('xml', 'doctype', 'svg');
40 | foreach ($sections_to_fix as $section_to_fix) {
41 | if (!isset($info['svg'][$section_to_fix])) {
42 | continue;
43 | }
44 | $section_data = array();
45 | while (preg_match('/ "([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) {
46 | $section_data[] = $matches[1];
47 | $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]);
48 | }
49 | while (preg_match('/([^\s]+)="([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) {
50 | $section_data[] = $matches[0];
51 | $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]);
52 | }
53 | $section_data = array_merge($section_data, preg_split('/[\s,]+/', $info['svg'][$section_to_fix]['raw'][1]));
54 | foreach ($section_data as $keyvaluepair) {
55 | $keyvaluepair = trim($keyvaluepair);
56 | if ($keyvaluepair) {
57 | $keyvalueexploded = explode('=', $keyvaluepair);
58 | $key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : '');
59 | $value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : '');
60 | $info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"');
61 | }
62 | }
63 | }
64 |
65 | $info['fileformat'] = 'svg';
66 | $info['video']['dataformat'] = 'svg';
67 | $info['video']['lossless'] = true;
68 | //$info['video']['bits_per_sample'] = 24;
69 | $info['video']['pixel_aspect_ratio'] = (float) 1;
70 |
71 | if (!empty($info['svg']['svg']['sections']['width'])) {
72 | $info['svg']['width'] = intval($info['svg']['svg']['sections']['width']);
73 | }
74 | if (!empty($info['svg']['svg']['sections']['height'])) {
75 | $info['svg']['height'] = intval($info['svg']['svg']['sections']['height']);
76 | }
77 | if (!empty($info['svg']['svg']['sections']['version'])) {
78 | $info['svg']['version'] = $info['svg']['svg']['sections']['version'];
79 | }
80 | if (!isset($info['svg']['version']) && isset($info['svg']['doctype']['sections'])) {
81 | foreach ($info['svg']['doctype']['sections'] as $key => $value) {
82 | if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) {
83 | $info['svg']['version'] = $matches[1];
84 | break;
85 | }
86 | }
87 | }
88 |
89 | if (!empty($info['svg']['width'])) {
90 | $info['video']['resolution_x'] = $info['svg']['width'];
91 | }
92 | if (!empty($info['svg']['height'])) {
93 | $info['video']['resolution_y'] = $info['svg']['height'];
94 | }
95 |
96 | return true;
97 | }
98 | $this->error('Did not find expected tag');
99 | return false;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/php/getID3/module.graphic.tiff.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.archive.tiff.php //
12 | // module for analyzing TIFF files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_tiff extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $TIFFheader = $this->fread(4);
26 |
27 | switch (substr($TIFFheader, 0, 2)) {
28 | case 'II':
29 | $info['tiff']['byte_order'] = 'Intel';
30 | break;
31 | case 'MM':
32 | $info['tiff']['byte_order'] = 'Motorola';
33 | break;
34 | default:
35 | $this->error('Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']);
36 | return false;
37 | break;
38 | }
39 |
40 | $info['fileformat'] = 'tiff';
41 | $info['video']['dataformat'] = 'tiff';
42 | $info['video']['lossless'] = true;
43 | $info['tiff']['ifd'] = array();
44 | $CurrentIFD = array();
45 |
46 | $FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
47 |
48 | $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
49 |
50 | while ($nextIFDoffset > 0) {
51 |
52 | $CurrentIFD['offset'] = $nextIFDoffset;
53 |
54 | $this->fseek($info['avdataoffset'] + $nextIFDoffset);
55 | $CurrentIFD['fieldcount'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
56 |
57 | for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
58 | $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
59 | $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
60 | $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
61 | $CurrentIFD['fields'][$i]['raw']['offset'] = $this->fread(4);
62 |
63 | switch ($CurrentIFD['fields'][$i]['raw']['type']) {
64 | case 1: // BYTE An 8-bit unsigned integer.
65 | if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
66 | $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
67 | } else {
68 | $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
69 | }
70 | break;
71 |
72 | case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
73 | if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
74 | $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
75 | } else {
76 | $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
77 | }
78 | break;
79 |
80 | case 3: // SHORT A 16-bit (2-byte) unsigned integer.
81 | if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
82 | $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
83 | } else {
84 | $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
85 | }
86 | break;
87 |
88 | case 4: // LONG A 32-bit (4-byte) unsigned integer.
89 | if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
90 | $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
91 | } else {
92 | $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
93 | }
94 | break;
95 |
96 | case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
97 | break;
98 | }
99 | }
100 |
101 | $info['tiff']['ifd'][] = $CurrentIFD;
102 | $CurrentIFD = array();
103 | $nextIFDoffset = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
104 |
105 | }
106 |
107 | foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) {
108 | foreach ($IFDarray['fields'] as $key => $fieldarray) {
109 | switch ($fieldarray['raw']['tag']) {
110 | case 256: // ImageWidth
111 | case 257: // ImageLength
112 | case 258: // BitsPerSample
113 | case 259: // Compression
114 | if (!isset($fieldarray['value'])) {
115 | $this->fseek($fieldarray['offset']);
116 | $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
117 |
118 | }
119 | break;
120 |
121 | case 270: // ImageDescription
122 | case 271: // Make
123 | case 272: // Model
124 | case 305: // Software
125 | case 306: // DateTime
126 | case 315: // Artist
127 | case 316: // HostComputer
128 | if (isset($fieldarray['value'])) {
129 | $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
130 | } else {
131 | $this->fseek($fieldarray['offset']);
132 | $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $this->fread($fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
133 |
134 | }
135 | break;
136 | }
137 | switch ($fieldarray['raw']['tag']) {
138 | case 256: // ImageWidth
139 | $info['video']['resolution_x'] = $fieldarray['value'];
140 | break;
141 |
142 | case 257: // ImageLength
143 | $info['video']['resolution_y'] = $fieldarray['value'];
144 | break;
145 |
146 | case 258: // BitsPerSample
147 | if (isset($fieldarray['value'])) {
148 | $info['video']['bits_per_sample'] = $fieldarray['value'];
149 | } else {
150 | $info['video']['bits_per_sample'] = 0;
151 | for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
152 | $info['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $info['tiff']['byte_order']);
153 | }
154 | }
155 | break;
156 |
157 | case 259: // Compression
158 | $info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
159 | break;
160 |
161 | case 270: // ImageDescription
162 | case 271: // Make
163 | case 272: // Model
164 | case 305: // Software
165 | case 306: // DateTime
166 | case 315: // Artist
167 | case 316: // HostComputer
168 | $TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']);
169 | if (isset($info['tiff']['comments'][$TIFFcommentName])) {
170 | $info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
171 | } else {
172 | $info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']);
173 | }
174 | break;
175 |
176 | default:
177 | break;
178 | }
179 | }
180 | }
181 |
182 | return true;
183 | }
184 |
185 |
186 | public function TIFFendian2Int($bytestring, $byteorder) {
187 | if ($byteorder == 'Intel') {
188 | return getid3_lib::LittleEndian2Int($bytestring);
189 | } elseif ($byteorder == 'Motorola') {
190 | return getid3_lib::BigEndian2Int($bytestring);
191 | }
192 | return false;
193 | }
194 |
195 | public function TIFFcompressionMethod($id) {
196 | static $TIFFcompressionMethod = array();
197 | if (empty($TIFFcompressionMethod)) {
198 | $TIFFcompressionMethod = array(
199 | 1 => 'Uncompressed',
200 | 2 => 'Huffman',
201 | 3 => 'Fax - CCITT 3',
202 | 5 => 'LZW',
203 | 32773 => 'PackBits',
204 | );
205 | }
206 | return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
207 | }
208 |
209 | public function TIFFcommentName($id) {
210 | static $TIFFcommentName = array();
211 | if (empty($TIFFcommentName)) {
212 | $TIFFcommentName = array(
213 | 270 => 'imagedescription',
214 | 271 => 'make',
215 | 272 => 'model',
216 | 305 => 'software',
217 | 306 => 'datetime',
218 | 315 => 'artist',
219 | 316 => 'hostcomputer',
220 | );
221 | }
222 | return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
223 | }
224 |
225 | }
226 |
--------------------------------------------------------------------------------
/php/getID3/module.misc.exe.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.misc.exe.php //
12 | // module for analyzing EXE files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_exe extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $EXEheader = $this->fread(28);
26 |
27 | $magic = 'MZ';
28 | if (substr($EXEheader, 0, 2) != $magic) {
29 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($EXEheader, 0, 2)).'"');
30 | return false;
31 | }
32 |
33 | $info['fileformat'] = 'exe';
34 | $info['exe']['mz']['magic'] = 'MZ';
35 |
36 | $info['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2));
37 | $info['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2));
38 | $info['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2));
39 | $info['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2));
40 | $info['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2));
41 | $info['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2));
42 | $info['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2));
43 | $info['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2));
44 | $info['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2));
45 | $info['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4));
46 | $info['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2));
47 | $info['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2));
48 |
49 | $info['exe']['mz']['byte_size'] = (($info['exe']['mz']['raw']['page_count'] - 1)) * 512 + $info['exe']['mz']['raw']['last_page_size'];
50 | $info['exe']['mz']['header_size'] = $info['exe']['mz']['raw']['header_paragraphs'] * 16;
51 | $info['exe']['mz']['memory_minimum'] = $info['exe']['mz']['raw']['min_memory_paragraphs'] * 16;
52 | $info['exe']['mz']['memory_recommended'] = $info['exe']['mz']['raw']['max_memory_paragraphs'] * 16;
53 |
54 | $this->error('EXE parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
55 | return false;
56 |
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/php/getID3/module.misc.msoffice.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.misc.msoffice.php //
12 | // module for analyzing MS Office (.doc, .xls, etc) files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_msoffice extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $this->fseek($info['avdataoffset']);
25 | $DOCFILEheader = $this->fread(8);
26 | $magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1";
27 | if (substr($DOCFILEheader, 0, 8) != $magic) {
28 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.');
29 | return false;
30 | }
31 | $info['fileformat'] = 'msoffice';
32 |
33 | $this->error('MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
34 | return false;
35 |
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/php/getID3/module.misc.par2.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.misc.par2.php //
12 | // module for analyzing PAR2 files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_par2 extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $info['fileformat'] = 'par2';
25 |
26 | $this->error('PAR2 parsing not enabled in this version of getID3()');
27 | return false;
28 |
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/php/getID3/module.misc.pdf.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // module.misc.pdf.php //
12 | // module for analyzing PDF files //
13 | // dependencies: NONE //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_pdf extends getid3_handler
19 | {
20 |
21 | public function Analyze() {
22 | $info = &$this->getid3->info;
23 |
24 | $info['fileformat'] = 'pdf';
25 |
26 | $this->error('PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
27 | return false;
28 |
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/php/getID3/write.apetag.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // write.apetag.php //
12 | // module for writing APE tags //
13 | // dependencies: module.tag.apetag.php //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
19 |
20 | class getid3_write_apetag
21 | {
22 |
23 | public $filename;
24 | public $tag_data;
25 | public $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data
26 | public $warnings = array(); // any non-critical errors will be stored here
27 | public $errors = array(); // any critical errors will be stored here
28 |
29 | public function __construct() {
30 | return true;
31 | }
32 |
33 | public function WriteAPEtag() {
34 | // NOTE: All data passed to this function must be UTF-8 format
35 |
36 | $getID3 = new getID3;
37 | $ThisFileInfo = $getID3->analyze($this->filename);
38 |
39 | if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
40 | if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) {
41 | // Current APE tag between Lyrics3 and ID3v1/EOF
42 | // This break Lyrics3 functionality
43 | if (!$this->DeleteAPEtag()) {
44 | return false;
45 | }
46 | $ThisFileInfo = $getID3->analyze($this->filename);
47 | }
48 | }
49 |
50 | if ($this->always_preserve_replaygain) {
51 | $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain');
52 | foreach ($ReplayGainTagsToPreserve as $rg_key) {
53 | if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) {
54 | $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0];
55 | }
56 | }
57 | }
58 |
59 | if ($APEtag = $this->GenerateAPEtag()) {
60 | if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
61 | $oldignoreuserabort = ignore_user_abort(true);
62 | flock($fp, LOCK_EX);
63 |
64 | $PostAPEdataOffset = $ThisFileInfo['avdataend'];
65 | if (isset($ThisFileInfo['ape']['tag_offset_end'])) {
66 | $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']);
67 | }
68 | if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) {
69 | $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']);
70 | }
71 | fseek($fp, $PostAPEdataOffset);
72 | $PostAPEdata = '';
73 | if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) {
74 | $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset);
75 | }
76 |
77 | fseek($fp, $PostAPEdataOffset);
78 | if (isset($ThisFileInfo['ape']['tag_offset_start'])) {
79 | fseek($fp, $ThisFileInfo['ape']['tag_offset_start']);
80 | }
81 | ftruncate($fp, ftell($fp));
82 | fwrite($fp, $APEtag, strlen($APEtag));
83 | if (!empty($PostAPEdata)) {
84 | fwrite($fp, $PostAPEdata, strlen($PostAPEdata));
85 | }
86 | flock($fp, LOCK_UN);
87 | fclose($fp);
88 | ignore_user_abort($oldignoreuserabort);
89 | return true;
90 | }
91 | }
92 | return false;
93 | }
94 |
95 | public function DeleteAPEtag() {
96 | $getID3 = new getID3;
97 | $ThisFileInfo = $getID3->analyze($this->filename);
98 | if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) {
99 | if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
100 |
101 | flock($fp, LOCK_EX);
102 | $oldignoreuserabort = ignore_user_abort(true);
103 |
104 | fseek($fp, $ThisFileInfo['ape']['tag_offset_end']);
105 | $DataAfterAPE = '';
106 | if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) {
107 | $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']);
108 | }
109 |
110 | ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']);
111 | fseek($fp, $ThisFileInfo['ape']['tag_offset_start']);
112 |
113 | if (!empty($DataAfterAPE)) {
114 | fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE));
115 | }
116 |
117 | flock($fp, LOCK_UN);
118 | fclose($fp);
119 | ignore_user_abort($oldignoreuserabort);
120 |
121 | return true;
122 | }
123 | return false;
124 | }
125 | return true;
126 | }
127 |
128 |
129 | public function GenerateAPEtag() {
130 | // NOTE: All data passed to this function must be UTF-8 format
131 |
132 | $items = array();
133 | if (!is_array($this->tag_data)) {
134 | return false;
135 | }
136 | foreach ($this->tag_data as $key => $arrayofvalues) {
137 | if (!is_array($arrayofvalues)) {
138 | return false;
139 | }
140 |
141 | $valuestring = '';
142 | foreach ($arrayofvalues as $value) {
143 | $valuestring .= str_replace("\x00", '', $value)."\x00";
144 | }
145 | $valuestring = rtrim($valuestring, "\x00");
146 |
147 | // Length of the assigned value in bytes
148 | $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4);
149 |
150 | //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false);
151 | $tagitem .= "\x00\x00\x00\x00";
152 |
153 | $tagitem .= $this->CleanAPEtagItemKey($key)."\x00";
154 | $tagitem .= $valuestring;
155 |
156 | $items[] = $tagitem;
157 |
158 | }
159 |
160 | return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false);
161 | }
162 |
163 | public function GenerateAPEtagHeaderFooter(&$items, $isheader=false) {
164 | $tagdatalength = 0;
165 | foreach ($items as $itemdata) {
166 | $tagdatalength += strlen($itemdata);
167 | }
168 |
169 | $APEheader = 'APETAGEX';
170 | $APEheader .= getid3_lib::LittleEndian2String(2000, 4);
171 | $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4);
172 | $APEheader .= getid3_lib::LittleEndian2String(count($items), 4);
173 | $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false);
174 | $APEheader .= str_repeat("\x00", 8);
175 |
176 | return $APEheader;
177 | }
178 |
179 | public function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) {
180 | $APEtagFlags = array_fill(0, 4, 0);
181 | if ($header) {
182 | $APEtagFlags[0] |= 0x80; // Tag contains a header
183 | }
184 | if (!$footer) {
185 | $APEtagFlags[0] |= 0x40; // Tag contains no footer
186 | }
187 | if ($isheader) {
188 | $APEtagFlags[0] |= 0x20; // This is the header, not the footer
189 | }
190 |
191 | // 0: Item contains text information coded in UTF-8
192 | // 1: Item contains binary information °)
193 | // 2: Item is a locator of external stored information °°)
194 | // 3: reserved
195 | $APEtagFlags[3] |= ($encodingid << 1);
196 |
197 | if ($readonly) {
198 | $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only
199 | }
200 |
201 | return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]);
202 | }
203 |
204 | public function CleanAPEtagItemKey($itemkey) {
205 | $itemkey = preg_replace("#[^\x20-\x7E]#i", '', $itemkey);
206 |
207 | // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
208 | switch (strtoupper($itemkey)) {
209 | case 'EAN/UPC':
210 | case 'ISBN':
211 | case 'LC':
212 | case 'ISRC':
213 | $itemkey = strtoupper($itemkey);
214 | break;
215 |
216 | default:
217 | $itemkey = ucwords($itemkey);
218 | break;
219 | }
220 | return $itemkey;
221 |
222 | }
223 |
224 | }
225 |
--------------------------------------------------------------------------------
/php/getID3/write.id3v1.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // write.id3v1.php //
12 | // module for writing ID3v1 tags //
13 | // dependencies: module.tag.id3v1.php //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
18 |
19 | class getid3_write_id3v1
20 | {
21 | public $filename;
22 | public $filesize;
23 | public $tag_data;
24 | public $warnings = array(); // any non-critical errors will be stored here
25 | public $errors = array(); // any critical errors will be stored here
26 |
27 | public function __construct() {
28 | return true;
29 | }
30 |
31 | public function WriteID3v1() {
32 | // File MUST be writeable - CHMOD(646) at least
33 | if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) {
34 | $this->setRealFileSize();
35 | if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) {
36 | $this->errors[] = 'Unable to WriteID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
37 | return false;
38 | }
39 | if ($fp_source = fopen($this->filename, 'r+b')) {
40 | fseek($fp_source, -128, SEEK_END);
41 | if (fread($fp_source, 3) == 'TAG') {
42 | fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag
43 | } else {
44 | fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag
45 | }
46 | $this->tag_data['track'] = (isset($this->tag_data['track']) ? $this->tag_data['track'] : (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : (isset($this->tag_data['tracknumber']) ? $this->tag_data['tracknumber'] : '')));
47 |
48 | $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag(
49 | (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''),
50 | (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''),
51 | (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''),
52 | (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''),
53 | (isset($this->tag_data['genreid']) ? $this->tag_data['genreid'] : ''),
54 | (isset($this->tag_data['comment']) ? $this->tag_data['comment'] : ''),
55 | (isset($this->tag_data['track'] ) ? $this->tag_data['track'] : ''));
56 | fwrite($fp_source, $new_id3v1_tag_data, 128);
57 | fclose($fp_source);
58 | return true;
59 |
60 | } else {
61 | $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")';
62 | return false;
63 | }
64 | }
65 | $this->errors[] = 'File is not writeable: '.$this->filename;
66 | return false;
67 | }
68 |
69 | public function FixID3v1Padding() {
70 | // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces
71 | // This function rewrites the ID3v1 tag with correct padding
72 |
73 | // Initialize getID3 engine
74 | $getID3 = new getID3;
75 | $getID3->option_tag_id3v2 = false;
76 | $getID3->option_tag_apetag = false;
77 | $getID3->option_tags_html = false;
78 | $getID3->option_extra_info = false;
79 | $getID3->option_tag_id3v1 = true;
80 | $ThisFileInfo = $getID3->analyze($this->filename);
81 | if (isset($ThisFileInfo['tags']['id3v1'])) {
82 | foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) {
83 | $id3v1data[$key] = implode(',', $value);
84 | }
85 | $this->tag_data = $id3v1data;
86 | return $this->WriteID3v1();
87 | }
88 | return false;
89 | }
90 |
91 | public function RemoveID3v1() {
92 | // File MUST be writeable - CHMOD(646) at least
93 | if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) {
94 | $this->setRealFileSize();
95 | if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) {
96 | $this->errors[] = 'Unable to RemoveID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
97 | return false;
98 | }
99 | if ($fp_source = fopen($this->filename, 'r+b')) {
100 |
101 | fseek($fp_source, -128, SEEK_END);
102 | if (fread($fp_source, 3) == 'TAG') {
103 | ftruncate($fp_source, $this->filesize - 128);
104 | } else {
105 | // no ID3v1 tag to begin with - do nothing
106 | }
107 | fclose($fp_source);
108 | return true;
109 |
110 | } else {
111 | $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")';
112 | }
113 | } else {
114 | $this->errors[] = $this->filename.' is not writeable';
115 | }
116 | return false;
117 | }
118 |
119 | public function setRealFileSize() {
120 | if (PHP_INT_MAX > 2147483647) {
121 | $this->filesize = filesize($this->filename);
122 | return true;
123 | }
124 | // 32-bit PHP will not return correct values for filesize() if file is >=2GB
125 | // but getID3->analyze() has workarounds to get actual filesize
126 | $getID3 = new getID3;
127 | $getID3->option_tag_id3v1 = false;
128 | $getID3->option_tag_id3v2 = false;
129 | $getID3->option_tag_apetag = false;
130 | $getID3->option_tags_html = false;
131 | $getID3->option_extra_info = false;
132 | $ThisFileInfo = $getID3->analyze($this->filename);
133 | $this->filesize = $ThisFileInfo['filesize'];
134 | return true;
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/php/getID3/write.lyrics3.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // write.lyrics3.php //
12 | // module for writing Lyrics3 tags //
13 | // dependencies: module.tag.lyrics3.php //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_write_lyrics3
19 | {
20 | public $filename;
21 | public $tag_data;
22 | //public $lyrics3_version = 2; // 1 or 2
23 | public $warnings = array(); // any non-critical errors will be stored here
24 | public $errors = array(); // any critical errors will be stored here
25 |
26 | public function __construct() {
27 | return true;
28 | }
29 |
30 | public function WriteLyrics3() {
31 | $this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3';
32 | return false;
33 | }
34 | public function DeleteLyrics3() {
35 | // Initialize getID3 engine
36 | $getID3 = new getID3;
37 | $ThisFileInfo = $getID3->analyze($this->filename);
38 | if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
39 | if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) {
40 |
41 | flock($fp, LOCK_EX);
42 | $oldignoreuserabort = ignore_user_abort(true);
43 |
44 | fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end']);
45 | $DataAfterLyrics3 = '';
46 | if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) {
47 | $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']);
48 | }
49 |
50 | ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']);
51 |
52 | if (!empty($DataAfterLyrics3)) {
53 | fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start']);
54 | fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3));
55 | }
56 |
57 | flock($fp, LOCK_UN);
58 | fclose($fp);
59 | ignore_user_abort($oldignoreuserabort);
60 |
61 | return true;
62 |
63 | } else {
64 | $this->errors[] = 'Cannot fopen('.$this->filename.', "a+b")';
65 | return false;
66 | }
67 | }
68 | // no Lyrics3 present
69 | return true;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/php/getID3/write.metaflac.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // write.metaflac.php //
12 | // module for writing metaflac tags //
13 | // dependencies: /helperapps/metaflac.exe //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_write_metaflac
19 | {
20 |
21 | public $filename;
22 | public $tag_data;
23 | public $warnings = array(); // any non-critical errors will be stored here
24 | public $errors = array(); // any critical errors will be stored here
25 |
26 | public function __construct() {
27 | return true;
28 | }
29 |
30 | public function WriteMetaFLAC() {
31 |
32 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
33 | $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written';
34 | return false;
35 | }
36 |
37 | // Create file with new comments
38 | $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3');
39 | if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) {
40 | foreach ($this->tag_data as $key => $value) {
41 | foreach ($value as $commentdata) {
42 | fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n");
43 | }
44 | }
45 | fclose($fpcomments);
46 |
47 | } else {
48 | $this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$tempcommentsfilename.'", "wb")';
49 | return false;
50 | }
51 |
52 | $oldignoreuserabort = ignore_user_abort(true);
53 | if (GETID3_OS_ISWINDOWS) {
54 |
55 | if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
56 | //$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
57 | // metaflac works fine if you copy-paste the above commandline into a command prompt,
58 | // but refuses to work with `backtick` if there are "doublequotes" present around BOTH
59 | // the metaflac pathname and the target filename. For whatever reason...??
60 | // The solution is simply ensure that the metaflac pathname has no spaces,
61 | // and therefore does not need to be quoted
62 |
63 | // On top of that, if error messages are not always captured properly under Windows
64 | // To at least see if there was a problem, compare file modification timestamps before and after writing
65 | clearstatcache();
66 | $timestampbeforewriting = filemtime($this->filename);
67 |
68 | $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1';
69 | $metaflacError = `$commandline`;
70 |
71 | if (empty($metaflacError)) {
72 | clearstatcache();
73 | if ($timestampbeforewriting == filemtime($this->filename)) {
74 | $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written';
75 | }
76 | }
77 | } else {
78 | $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
79 | }
80 |
81 | } else {
82 |
83 | // It's simpler on *nix
84 | $commandline = 'metaflac --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1';
85 | $metaflacError = `$commandline`;
86 |
87 | }
88 |
89 | // Remove temporary comments file
90 | unlink($tempcommentsfilename);
91 | ignore_user_abort($oldignoreuserabort);
92 |
93 | if (!empty($metaflacError)) {
94 |
95 | $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
96 | return false;
97 |
98 | }
99 |
100 | return true;
101 | }
102 |
103 |
104 | public function DeleteMetaFLAC() {
105 |
106 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
107 | $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted';
108 | return false;
109 | }
110 |
111 | $oldignoreuserabort = ignore_user_abort(true);
112 | if (GETID3_OS_ISWINDOWS) {
113 |
114 | if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
115 | // To at least see if there was a problem, compare file modification timestamps before and after writing
116 | clearstatcache();
117 | $timestampbeforewriting = filemtime($this->filename);
118 |
119 | $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1';
120 | $metaflacError = `$commandline`;
121 |
122 | if (empty($metaflacError)) {
123 | clearstatcache();
124 | if ($timestampbeforewriting == filemtime($this->filename)) {
125 | $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted';
126 | }
127 | }
128 | } else {
129 | $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
130 | }
131 |
132 | } else {
133 |
134 | // It's simpler on *nix
135 | $commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1';
136 | $metaflacError = `$commandline`;
137 |
138 | }
139 |
140 | ignore_user_abort($oldignoreuserabort);
141 |
142 | if (!empty($metaflacError)) {
143 | $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
144 | return false;
145 | }
146 | return true;
147 | }
148 |
149 |
150 | public function CleanmetaflacName($originalcommentname) {
151 | // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
152 | // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
153 | // 0x7A inclusive (a-z).
154 |
155 | // replace invalid chars with a space, return uppercase text
156 | // Thanks Chris Bolt for improving this function
157 | // note: *reg_replace() replaces nulls with empty string (not space)
158 | return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname)));
159 |
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/php/getID3/write.vorbiscomment.php:
--------------------------------------------------------------------------------
1 | //
4 | // available at http://getid3.sourceforge.net //
5 | // or http://www.getid3.org //
6 | // also https://github.com/JamesHeinrich/getID3 //
7 | /////////////////////////////////////////////////////////////////
8 | // See readme.txt for more details //
9 | /////////////////////////////////////////////////////////////////
10 | // //
11 | // write.vorbiscomment.php //
12 | // module for writing VorbisComment tags //
13 | // dependencies: /helperapps/vorbiscomment.exe //
14 | // ///
15 | /////////////////////////////////////////////////////////////////
16 |
17 |
18 | class getid3_write_vorbiscomment
19 | {
20 |
21 | public $filename;
22 | public $tag_data;
23 | public $warnings = array(); // any non-critical errors will be stored here
24 | public $errors = array(); // any critical errors will be stored here
25 |
26 | public function __construct() {
27 | return true;
28 | }
29 |
30 | public function WriteVorbisComment() {
31 |
32 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
33 | $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written';
34 | return false;
35 | }
36 |
37 | // Create file with new comments
38 | $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3');
39 | if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) {
40 |
41 | foreach ($this->tag_data as $key => $value) {
42 | foreach ($value as $commentdata) {
43 | fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n");
44 | }
45 | }
46 | fclose($fpcomments);
47 |
48 | } else {
49 | $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
50 | return false;
51 | }
52 |
53 | $oldignoreuserabort = ignore_user_abort(true);
54 | if (GETID3_OS_ISWINDOWS) {
55 |
56 | if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
57 | //$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
58 | // vorbiscomment works fine if you copy-paste the above commandline into a command prompt,
59 | // but refuses to work with `backtick` if there are "doublequotes" present around BOTH
60 | // the metaflac pathname and the target filename. For whatever reason...??
61 | // The solution is simply ensure that the metaflac pathname has no spaces,
62 | // and therefore does not need to be quoted
63 |
64 | // On top of that, if error messages are not always captured properly under Windows
65 | // To at least see if there was a problem, compare file modification timestamps before and after writing
66 | clearstatcache();
67 | $timestampbeforewriting = filemtime($this->filename);
68 |
69 | $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
70 | $VorbiscommentError = `$commandline`;
71 |
72 | if (empty($VorbiscommentError)) {
73 | clearstatcache();
74 | if ($timestampbeforewriting == filemtime($this->filename)) {
75 | $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written';
76 | }
77 | }
78 | } else {
79 | $VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
80 | }
81 |
82 | } else {
83 |
84 | $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
85 | $VorbiscommentError = `$commandline`;
86 |
87 | }
88 |
89 | // Remove temporary comments file
90 | unlink($tempcommentsfilename);
91 | ignore_user_abort($oldignoreuserabort);
92 |
93 | if (!empty($VorbiscommentError)) {
94 |
95 | $this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError;
96 | return false;
97 |
98 | }
99 |
100 | return true;
101 | }
102 |
103 | public function DeleteVorbisComment() {
104 | $this->tag_data = array(array());
105 | return $this->WriteVorbisComment();
106 | }
107 |
108 | public function CleanVorbisCommentName($originalcommentname) {
109 | // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
110 | // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
111 | // 0x7A inclusive (a-z).
112 |
113 | // replace invalid chars with a space, return uppercase text
114 | // Thanks Chris Bolt for improving this function
115 | // note: *reg_replace() replaces nulls with empty string (not space)
116 | return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname)));
117 |
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/php/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Build Simple Soundboard JSON File
8 |
9 |
10 | Build Simple Soundboard JSON File
11 |
15 | MP3_DIRECTORY;
18 | $json_file = $configs->JSON_FILENAME;
19 | date_default_timezone_set($configs->TIME_ZONE);
20 |
21 | if(is_dir($mp3directory)){
22 | echo("MP3 Directory [".$mp3directory."] exists.
");
23 | if(is_file($json_file)){
24 | echo("JSON File [".$json_file."] was last built at ".date ("F d Y H:i:s", filemtime($json_file)).".
");
25 | } else {
26 | echo("JSON File [".$json_file."] has not been created.
");
27 | }
28 | } else {
29 | echo("MP3 Directory [".$mp3directory."] DOES NOT exist.
");
30 | }
31 | ?>
32 |
33 |
--------------------------------------------------------------------------------
/sounds/Ayayayayayayayay!.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Ayayayayayayayay!.mp3
--------------------------------------------------------------------------------
/sounds/Constipated.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Constipated.mp3
--------------------------------------------------------------------------------
/sounds/Do-do-do-do.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Do-do-do-do.mp3
--------------------------------------------------------------------------------
/sounds/Floridians-Dumb-as-dirt.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Floridians-Dumb-as-dirt.mp3
--------------------------------------------------------------------------------
/sounds/Frosty-Nads[Q].mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Frosty-Nads[Q].mp3
--------------------------------------------------------------------------------
/sounds/Happy-Birthday.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Happy-Birthday.mp3
--------------------------------------------------------------------------------
/sounds/Happy-Purim.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Happy-Purim.mp3
--------------------------------------------------------------------------------
/sounds/I-Don't-Believe-It.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/I-Don't-Believe-It.mp3
--------------------------------------------------------------------------------
/sounds/Idiotic-jerk.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Idiotic-jerk.mp3
--------------------------------------------------------------------------------
/sounds/Laugh-Bird.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Laugh-Bird.mp3
--------------------------------------------------------------------------------
/sounds/Laugh-Brooke.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Laugh-Brooke.mp3
--------------------------------------------------------------------------------
/sounds/Laugh-Gilbert.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Laugh-Gilbert.mp3
--------------------------------------------------------------------------------
/sounds/Laugh-Goofy.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Laugh-Goofy.mp3
--------------------------------------------------------------------------------
/sounds/Laugh-Montage.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Laugh-Montage.mp3
--------------------------------------------------------------------------------
/sounds/Loan-me-50-Dollars.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Loan-me-50-Dollars.mp3
--------------------------------------------------------------------------------
/sounds/No.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/No.mp3
--------------------------------------------------------------------------------
/sounds/Only-in-the-Banana-Republic.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Only-in-the-Banana-Republic.mp3
--------------------------------------------------------------------------------
/sounds/Ya-mon!.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Ya-mon!.mp3
--------------------------------------------------------------------------------
/sounds/Yank-it-baby.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Yank-it-baby.mp3
--------------------------------------------------------------------------------
/sounds/Yeeeeeeesss.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/digitalcolony/Simple-Soundboard/0b5afb02b611623362e0020a93fdf4088762b849/sounds/Yeeeeeeesss.mp3
--------------------------------------------------------------------------------