Added API doc
This commit is contained in:
parent
02c9b8bc07
commit
ca1959a672
5
public/api/index.php
Normal file
5
public/api/index.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$version = "v1";
|
||||||
|
|
||||||
|
header("Location: $version");
|
@ -1,5 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
|
include("$root/vendor/erusev/parsedown/Parsedown.php");
|
||||||
|
$Parsedown = new Parsedown();
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -21,6 +26,27 @@ $root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
|||||||
?>
|
?>
|
||||||
<section>
|
<section>
|
||||||
<h2>Documentation API v1</h2>
|
<h2>Documentation API v1</h2>
|
||||||
|
<?php
|
||||||
|
if (isset($_GET['page']) and file_exists("md/".$_GET['page'].".md")) {
|
||||||
|
$page = $_GET['page'].".md";
|
||||||
|
$md = file_get_contents("$root/api/v1/doc/md/$page", "r");
|
||||||
|
print_r($Parsedown->text($md));
|
||||||
|
} else {
|
||||||
|
$doc_paths = glob("$root/api/v1/doc/md/*.md");
|
||||||
|
?>
|
||||||
|
<ul>
|
||||||
|
<?php
|
||||||
|
foreach ($doc_paths as $path) {
|
||||||
|
$file = explode('.', basename($path))[0];
|
||||||
|
?>
|
||||||
|
<li><a href="?page=<?=$file?>"><?=$file?></a></li>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
</section>
|
</section>
|
||||||
<?php
|
<?php
|
||||||
include("$root/footer.php");
|
include("$root/footer.php");
|
||||||
|
30
public/api/v1/index.php
Executable file → Normal file
30
public/api/v1/index.php
Executable file → Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>API v1 Documentation | Chiro - Canto</title>
|
||||||
|
<link rel="stylesheet" href="/styles/style.css">
|
||||||
|
</head>
|
||||||
|
<?php
|
||||||
|
include("$root/analytics/matomo.php");
|
||||||
|
include("$root/analytics/owa.php");
|
||||||
|
?>
|
||||||
|
<body>
|
||||||
|
<?php
|
||||||
|
include("$root/menu.php");
|
||||||
|
include("$root/header.php");
|
||||||
|
?>
|
||||||
|
<section>
|
||||||
|
<h2>API v1</h2>
|
||||||
|
<a href="doc">Documentation</a>
|
||||||
|
</section>
|
||||||
|
<?php
|
||||||
|
include("$root/footer.php");
|
||||||
|
?>
|
||||||
|
</body>
|
||||||
|
</html>
|
88
public/discussion/index.php
Normal file
88
public/discussion/index.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
|
require "$root/database/credentials.php";
|
||||||
|
// Connect the database
|
||||||
|
try {
|
||||||
|
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
||||||
|
$user,
|
||||||
|
$password,
|
||||||
|
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
die("Error : ".$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$req = $db->prepare('SELECT id FROM `authors` WHERE username=:username');
|
||||||
|
$req->execute(array(
|
||||||
|
"username"=>$_SESSION['username']
|
||||||
|
));
|
||||||
|
$data = $req->fetch();
|
||||||
|
$user_id = $data['id'];
|
||||||
|
|
||||||
|
$req = $db->prepare('SELECT message_by, COUNT(message_by) AS n_msg FROM `messages` WHERE message_to=:user_id AND message_read=0');
|
||||||
|
$req->execute(array(
|
||||||
|
"user_id"=>$user_id
|
||||||
|
));
|
||||||
|
$result = $req->fetchAll();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Discussion | Chiro - Canto</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
||||||
|
</head>
|
||||||
|
<?php
|
||||||
|
include("$root/analytics/owa.php");
|
||||||
|
include("$root/analytics/matomo.php");
|
||||||
|
?>
|
||||||
|
<body>
|
||||||
|
<?php include("$root/menu.php");?>
|
||||||
|
<?php include("$root/header.php");?>
|
||||||
|
<section>
|
||||||
|
<h2>Discussion</h2>
|
||||||
|
<h3>New messages</h3>
|
||||||
|
<ul>
|
||||||
|
<?php
|
||||||
|
$no_msg = true;
|
||||||
|
foreach($result as $sender) {
|
||||||
|
$req = $db->prepare('SELECT username FROM `authors` WHERE id=:id');
|
||||||
|
$req->execute(array(
|
||||||
|
"id"=>$sender['message_by']
|
||||||
|
));
|
||||||
|
if($data = $req->fetch()) {
|
||||||
|
$username = $data['username'];
|
||||||
|
?>
|
||||||
|
<li>
|
||||||
|
<a href="messages/?author=<?=$sender['message_by']?>" class="notification">
|
||||||
|
<span><?=$username?></span>
|
||||||
|
<span class="badge"><?=$sender['n_msg']?></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php
|
||||||
|
$no_msg = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($no_msg) {
|
||||||
|
echo "No message received.\n";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
<h3>Send a message</h3>
|
||||||
|
<form action="messages" method="get">
|
||||||
|
<label for="author">Addressee</label>
|
||||||
|
<input type="text" name="author" id="author">
|
||||||
|
<input type="submit" value="Send">
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<?php include("$root/footer.php");?>
|
||||||
|
</body>
|
||||||
|
<script src="/scripts/script.js"></script>
|
||||||
|
</html>
|
@ -22,29 +22,38 @@ if (isset($_SESSION['username'])) {
|
|||||||
"username"=>$_SESSION['username']
|
"username"=>$_SESSION['username']
|
||||||
));
|
));
|
||||||
if ($data = $req->fetch()) {
|
if ($data = $req->fetch()) {
|
||||||
$user_id = $data['id'];
|
$sender_id = $data['id'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['error_msg'] = "You must be logged in to receive an send message.";
|
$_SESSION['error_msg'] = "You must be logged in to receive an send message.";
|
||||||
header('Location: /auth/login');
|
header('Location: /auth/login');
|
||||||
}
|
}
|
||||||
if (isset($_GET['author'])) {
|
if (isset($_GET['author'])) {
|
||||||
$req = $db->prepare('SELECT * FROM `messages` WHERE message_by=:user_id AND message_to=:author_id OR message_by=:author_id AND message_to=:user_id ORDER BY message_datetime ASC');
|
if (!is_numeric($_GET['author'])) {
|
||||||
|
$req = $db->prepare('SELECT id FROM `authors` WHERE username=:username');
|
||||||
|
$req->execute(array(
|
||||||
|
"username"=>$_GET['author']
|
||||||
|
));
|
||||||
|
if ($data = $req->fetch()) {
|
||||||
|
$user_id = $data['id'];
|
||||||
|
} else {
|
||||||
|
$user_id = $_GET['author'];
|
||||||
|
}
|
||||||
|
$req = $db->prepare('SELECT username FROM `authors` WHERE id=:id');
|
||||||
|
$req->execute(array(
|
||||||
|
"id"=>$sender_id
|
||||||
|
));
|
||||||
|
if ($data = $req->fetch()) {
|
||||||
|
$addressee = $data['username'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$req = $db->prepare('SELECT * FROM `messages` WHERE message_by=:sender_id AND message_to=:user_id OR message_by=:sender_id AND message_to=:user_id ORDER BY message_datetime ASC');
|
||||||
$req->execute(array(
|
$req->execute(array(
|
||||||
"author_id"=>$user_id,
|
"sender_id"=>$sender_id,
|
||||||
"user_id"=>$_GET['author']
|
"user_id"=>$user_id
|
||||||
));
|
));
|
||||||
$result = $req->fetchAll();
|
$result = $req->fetchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
$req = $db->prepare('SELECT username FROM `authors` WHERE id=:id');
|
|
||||||
$req->execute(array(
|
|
||||||
"id"=>$_GET['author']
|
|
||||||
));
|
|
||||||
if ($data = $req->fetch()) {
|
|
||||||
$destinator = $data['username'];
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -66,10 +75,15 @@ include("$root/analytics/matomo.php");
|
|||||||
<h2>Discussion</h2>
|
<h2>Discussion</h2>
|
||||||
<div class="messages">
|
<div class="messages">
|
||||||
<div class="author">
|
<div class="author">
|
||||||
<?=$destinator?>
|
<?=$addressee?>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
foreach($result as $message) {
|
foreach($result as $message) {
|
||||||
|
$message_id = $message['id'];
|
||||||
|
$req = $db->prepare('UPDATE `messages` SET message_read=1 WHERE id=:id');
|
||||||
|
$req->execute(array(
|
||||||
|
"id"=>$message_id
|
||||||
|
));
|
||||||
if ($message['message_by'] == $_SESSION['username']) {
|
if ($message['message_by'] == $_SESSION['username']) {
|
||||||
$class = "right";
|
$class = "right";
|
||||||
} else {
|
} else {
|
||||||
|
35
public/discussion/notification.php
Normal file
35
public/discussion/notification.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
|
require "$root/database/credentials.php";
|
||||||
|
// Connect the database
|
||||||
|
try {
|
||||||
|
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
||||||
|
$user,
|
||||||
|
$password,
|
||||||
|
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
die("Error : ".$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_SESSION['username'])) {
|
||||||
|
$req = $db->prepare('SELECT id FROM `authors` WHERE username=:username');
|
||||||
|
$req->execute(array(
|
||||||
|
"username"=>$_SESSION['username']
|
||||||
|
));
|
||||||
|
$data = $req->fetch();
|
||||||
|
$user_id = $data['id'];
|
||||||
|
$req = $db->prepare('SELECT COUNT(*) AS counter FROM `messages` WHERE message_to=:user_id AND message_read=0');
|
||||||
|
$req->execute(array(
|
||||||
|
"user_id"=>$user_id
|
||||||
|
));
|
||||||
|
$data = $req->fetch();
|
||||||
|
$new_msg_number = $data['counter'];
|
||||||
|
if ($new_msg_number != 0) {
|
||||||
|
?>
|
||||||
|
<span class="badge"><?=$new_msg_number?></span>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "";
|
||||||
|
}
|
@ -4,6 +4,29 @@ ini_set('display_errors', 1);
|
|||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>GUANO | Chiro-Canto</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
||||||
|
</head>
|
||||||
|
<?php
|
||||||
|
include("$root/analytics/owa.php");
|
||||||
|
include("$root/analytics/matomo.php");
|
||||||
|
?>
|
||||||
|
<body>
|
||||||
|
<?php include("$root/menu.php"); ?>
|
||||||
|
<?php include("$root/header.php"); ?>
|
||||||
|
<section>
|
||||||
|
<h2>GUANO v1.0</h2>
|
||||||
|
<?=isset($_SESSION['error_msg']) and $_SESSION['error_msg'] != "" ? '<div class="error">'.$_SESSION['error_msg'].'</div>' : "";?>
|
||||||
|
<a href="/articles">about GUANO</a>
|
||||||
|
<article id="guano">
|
||||||
|
<?php
|
||||||
require "$root/database/credentials.php";
|
require "$root/database/credentials.php";
|
||||||
// Connect the database
|
// Connect the database
|
||||||
try {
|
try {
|
||||||
@ -29,28 +52,7 @@ if ($data = $req->fetch()) {
|
|||||||
} else {
|
} else {
|
||||||
$_SESSION['error_msg'] = "Can't fetch data.";
|
$_SESSION['error_msg'] = "Can't fetch data.";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>GUANO | Chiro-Canto</title>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
|
||||||
</head>
|
|
||||||
<?php
|
|
||||||
include("$root/analytics/owa.php");
|
|
||||||
include("$root/analytics/matomo.php");
|
|
||||||
?>
|
|
||||||
<body>
|
|
||||||
<?php include("$root/menu.php"); ?>
|
|
||||||
<?php include("$root/header.php"); ?>
|
|
||||||
<section>
|
|
||||||
<h2>GUANO v1.0</h2>
|
|
||||||
<?=isset($_SESSION['error_msg']) and $_SESSION['error_msg'] != "" ? '<div class="error">'.$_SESSION['error_msg'].'</div>' : "";?>
|
|
||||||
<a href="/articles">about GUANO</a>
|
|
||||||
<article id="guano">
|
|
||||||
GUANO|Version: 1.0<br><br>
|
GUANO|Version: 1.0<br><br>
|
||||||
|
|
||||||
Original Filename: <?=$data['file_name']?><br>
|
Original Filename: <?=$data['file_name']?><br>
|
||||||
|
@ -4,27 +4,6 @@ ini_set('display_errors', 1);
|
|||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
require "$root/database/credentials.php";
|
|
||||||
// Connect the database
|
|
||||||
try {
|
|
||||||
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
|
||||||
$user,
|
|
||||||
$password,
|
|
||||||
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
|
||||||
));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
die("Error : ".$e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['id'])) {
|
|
||||||
$req = $db->prepare('SELECT * FROM `records` WHERE id=:id');
|
|
||||||
$req->execute(array(
|
|
||||||
"id"=>$_GET['id']
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
$req = $db->prepare('SELECT * FROM `records` ORDER BY date');
|
|
||||||
$req->execute();
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -45,6 +24,27 @@ include("$root/analytics/owa.php");
|
|||||||
<section>
|
<section>
|
||||||
<h3>Record</h3>
|
<h3>Record</h3>
|
||||||
<?php
|
<?php
|
||||||
|
require "$root/database/credentials.php";
|
||||||
|
// Connect the database
|
||||||
|
try {
|
||||||
|
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
||||||
|
$user,
|
||||||
|
$password,
|
||||||
|
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
die("Error : ".$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['id'])) {
|
||||||
|
$req = $db->prepare('SELECT * FROM `records` WHERE id=:id');
|
||||||
|
$req->execute(array(
|
||||||
|
"id"=>$_GET['id']
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$req = $db->prepare('SELECT * FROM `records` ORDER BY date');
|
||||||
|
$req->execute();
|
||||||
|
}
|
||||||
if ($data = $req->fetch()) {
|
if ($data = $req->fetch()) {
|
||||||
?>
|
?>
|
||||||
<div class="sound">
|
<div class="sound">
|
||||||
|
@ -56,21 +56,21 @@ if ($_SESSION['error_msg'] == "") {
|
|||||||
if ($and) {
|
if ($and) {
|
||||||
$sql .= " AND ";
|
$sql .= " AND ";
|
||||||
}
|
}
|
||||||
$sql .= ' species="'.$_SESSION['query']['species'].'"';
|
$sql .= ' species LIKE "%'.$_SESSION['query']['species'].'%"';
|
||||||
$and = True;
|
$and = True;
|
||||||
}
|
}
|
||||||
if (isset($_SESSION['query']['subspecies']) and $_SESSION['query']['subspecies'] != "") {
|
if (isset($_SESSION['query']['subspecies']) and $_SESSION['query']['subspecies'] != "") {
|
||||||
if ($and) {
|
if ($and) {
|
||||||
$sql .= " AND ";
|
$sql .= " AND ";
|
||||||
}
|
}
|
||||||
$sql .= ' subspecies="'.$_SESSION['query']['subspecies'].'"';
|
$sql .= ' subspecies LIKE "%'.$_SESSION['query']['subspecies'].'%"';
|
||||||
$and = True;
|
$and = True;
|
||||||
}
|
}
|
||||||
if (isset($_SESSION['query']['recordist']) and $_SESSION['query']['recordist'] != "") {
|
if (isset($_SESSION['query']['recordist']) and $_SESSION['query']['recordist'] != "") {
|
||||||
if ($and) {
|
if ($and) {
|
||||||
$sql .= " AND ";
|
$sql .= " AND ";
|
||||||
}
|
}
|
||||||
$sql .= ' recordist_name="'.$_SESSION['query']['recordist'].'"';
|
$sql .= ' recordist_name LIKE "%'.$_SESSION['query']['recordist'].'%"';
|
||||||
$and = True;
|
$and = True;
|
||||||
}
|
}
|
||||||
if (isset($_SESSION['query']['date-after']) and $_SESSION['query']['date-after'] != "") {
|
if (isset($_SESSION['query']['date-after']) and $_SESSION['query']['date-after'] != "") {
|
||||||
@ -96,10 +96,6 @@ if ($_SESSION['error_msg'] == "") {
|
|||||||
$and = True;
|
$and = True;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// echo $sql;
|
|
||||||
$req = $db->prepare($sql);
|
|
||||||
$req->execute();
|
|
||||||
$result = $req->fetchAll();
|
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['error_msg'] .= "You did not enter any query.\n";
|
$_SESSION['error_msg'] .= "You did not enter any query.\n";
|
||||||
header("Location: /explore/search");
|
header("Location: /explore/search");
|
||||||
@ -108,9 +104,7 @@ if ($_SESSION['error_msg'] == "") {
|
|||||||
} else {
|
} else {
|
||||||
header("Location: /explore/search");
|
header("Location: /explore/search");
|
||||||
}
|
}
|
||||||
|
?>
|
||||||
if (isset($result)) {
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -128,6 +122,11 @@ if (isset($result)) {
|
|||||||
<h3>Explore</h3>
|
<h3>Explore</h3>
|
||||||
<h4>Search Results</h4>
|
<h4>Search Results</h4>
|
||||||
<?php
|
<?php
|
||||||
|
// echo $sql;
|
||||||
|
$req = $db->prepare($sql);
|
||||||
|
$req->execute();
|
||||||
|
$result = $req->fetchAll();
|
||||||
|
// print_r($sql);
|
||||||
if (empty($result)) {
|
if (empty($result)) {
|
||||||
echo "No result for this query, please try again.\n";
|
echo "No result for this query, please try again.\n";
|
||||||
} else {
|
} else {
|
||||||
@ -164,5 +163,3 @@ if (isset($result)) {
|
|||||||
</body>
|
</body>
|
||||||
<script src="/scripts/script.js"></script>
|
<script src="/scripts/script.js"></script>
|
||||||
</html>
|
</html>
|
||||||
<?php
|
|
||||||
}
|
|
@ -6,6 +6,5 @@
|
|||||||
<h2>Bat sound sharing tools</h2>
|
<h2>Bat sound sharing tools</h2>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<?php include("$root/search/searchbar.php");?>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
34
public/larynx/g-spectrogram.html
Normal file
34
public/larynx/g-spectrogram.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<link rel="import" href="./bower_components/polymer/polymer.html">
|
||||||
|
<link rel="import" href="./g-spectrogram-controls.html">
|
||||||
|
<link rel="import" href="./g-oscillator.html">
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=Inconsolata' rel='stylesheet' type='text/css'>
|
||||||
|
|
||||||
|
<polymer-element name="g-spectrogram" attributes="controls log fftsize labels ticks oscillator speed color">
|
||||||
|
<template>
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
g-spectrogram-controls {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<canvas id="labels"></canvas>
|
||||||
|
<template if="{{controls}}">
|
||||||
|
<g-spectrogram-controls
|
||||||
|
log="{{log}}"
|
||||||
|
labels="{{labels}}"
|
||||||
|
speed="{{speed}}"
|
||||||
|
ticks="{{ticks}}"
|
||||||
|
color="{{color}}">
|
||||||
|
</g-spectrogram-controls>
|
||||||
|
</template>
|
||||||
|
<template if="{{oscillator}}">
|
||||||
|
<g-oscillator log={{log}} speed={{speed}}></g-oscillator>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<script src="g-spectrogram.js"></script>
|
||||||
|
</polymer-element>
|
@ -5,27 +5,6 @@ error_reporting(E_ALL);
|
|||||||
session_start();
|
session_start();
|
||||||
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
$version = "1.0";
|
$version = "1.0";
|
||||||
require "$root/database/credentials.php";
|
|
||||||
// Connect the database
|
|
||||||
try {
|
|
||||||
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
|
||||||
$user,
|
|
||||||
$password,
|
|
||||||
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
|
||||||
));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
die("Error : ".$e->getMessage());
|
|
||||||
}
|
|
||||||
if (isset($_GET['record'])) {
|
|
||||||
$req = $db->prepare('SELECT id, recordist_name, file_name, license, species, sound_type, date, time FROM `records` WHERE id=:id');
|
|
||||||
$req->execute(array(
|
|
||||||
"id"=>$_GET['record']
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
$req = $db->prepare('SELECT id, recordist_name, file_name, license, species, sound_type, date, time FROM `records` ORDER BY date DESC, time DESC LIMIT 1');
|
|
||||||
$req->execute();
|
|
||||||
}
|
|
||||||
$data = $req->fetch();
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -35,14 +14,15 @@ $data = $req->fetch();
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Larynx | Chiro - Canto</title>
|
<title>Larynx | Chiro - Canto</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
||||||
|
<link rel="import" href="/scripts/bower_components/polymer/polymer.html">
|
||||||
|
<link rel="import" href="./g-spectrogram-controls.html">
|
||||||
|
<link rel="import" href="./g-oscillator.html">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<?php
|
<?php
|
||||||
include("$root/analytics/owa.php");
|
include("$root/analytics/owa.php");
|
||||||
include("$root/analytics/matomo.php");
|
include("$root/analytics/matomo.php");
|
||||||
?>
|
?>
|
||||||
<?php
|
|
||||||
include("$root/analytics/matomo.php");
|
|
||||||
?>
|
|
||||||
<body>
|
<body>
|
||||||
<?php include("$root/menu.php");?>
|
<?php include("$root/menu.php");?>
|
||||||
<?php include("$root/header.php");?>
|
<?php include("$root/header.php");?>
|
||||||
@ -55,8 +35,31 @@ include("$root/analytics/matomo.php");
|
|||||||
</section>
|
</section>
|
||||||
<div id="larynx">
|
<div id="larynx">
|
||||||
<h2>Larynx v<?=$version?></h2>
|
<h2>Larynx v<?=$version?></h2>
|
||||||
|
<?php
|
||||||
<audio src="<?="/storage/records/".$data['file_name']?>" id="audio"></audio>
|
require "$root/database/credentials.php";
|
||||||
|
// Connect the database
|
||||||
|
try {
|
||||||
|
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
||||||
|
$user,
|
||||||
|
$password,
|
||||||
|
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
die("Error : ".$e->getMessage());
|
||||||
|
}
|
||||||
|
if (isset($_GET['record'])) {
|
||||||
|
$req = $db->prepare('SELECT id, recordist_name, file_name, license, species, sound_type, date, time FROM `records` WHERE id=:id');
|
||||||
|
$req->execute(array(
|
||||||
|
"id"=>$_GET['record']
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$req = $db->prepare('SELECT id, recordist_name, file_name, license, species, sound_type, date, time FROM `records` ORDER BY date DESC, time DESC LIMIT 1');
|
||||||
|
$req->execute();
|
||||||
|
}
|
||||||
|
if ($data = $req->fetch()) {
|
||||||
|
// print_r($data);
|
||||||
|
?>
|
||||||
|
<audio src="<?="/storage/records/".$data['file_name']?>" id="audio" controls></audio>
|
||||||
<div class="spectrogram">
|
<div class="spectrogram">
|
||||||
<div id="waveform"></div>
|
<div id="waveform"></div>
|
||||||
<div id="wave-spectrogram">
|
<div id="wave-spectrogram">
|
||||||
@ -90,7 +93,13 @@ include("$root/analytics/matomo.php");
|
|||||||
<script src="https://unpkg.com/wavesurfer.js/dist/plugin/wavesurfer.spectrogram.min.js" type="text/javascript"></script>
|
<script src="https://unpkg.com/wavesurfer.js/dist/plugin/wavesurfer.spectrogram.min.js" type="text/javascript"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/addons/p5.sound.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/addons/p5.sound.js"></script>
|
||||||
<script src="scripts/spectro.js"></script>
|
<script src="scripts/g-spectro.js"></script>
|
||||||
<!-- <script src="scripts/piano.js"></script> -->
|
<!-- <script src="scripts/piano.js"></script> -->
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
$_SESSION['error_msg'] = "Error: Can't retrieve audio from database in Larynx";
|
||||||
|
header('Location: /');
|
||||||
|
}
|
||||||
|
?>
|
261
public/larynx/scripts/g-spectro.js
Normal file
261
public/larynx/scripts/g-spectro.js
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
var AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
|
||||||
|
context = new AudioContext();
|
||||||
|
|
||||||
|
// Assumes context is an AudioContext defined outside of this class.
|
||||||
|
|
||||||
|
Polymer('g-spectrogram', {
|
||||||
|
// Show the controls UI.
|
||||||
|
controls: false,
|
||||||
|
// Log mode.
|
||||||
|
log: false,
|
||||||
|
// Show axis labels, and how many ticks.
|
||||||
|
labels: false,
|
||||||
|
ticks: 5,
|
||||||
|
speed: 2,
|
||||||
|
// FFT bin size,
|
||||||
|
fftsize: 2048,
|
||||||
|
oscillator: false,
|
||||||
|
color: false,
|
||||||
|
|
||||||
|
attachedCallback: function() {
|
||||||
|
this.tempCanvas = document.createElement('canvas'),
|
||||||
|
console.log('Created spectrogram');
|
||||||
|
// Get input from the microphone.
|
||||||
|
if (navigator.mozGetUserMedia) {
|
||||||
|
navigator.mozGetUserMedia({audio: true},
|
||||||
|
this.onStream.bind(this),
|
||||||
|
this.onStreamError.bind(this));
|
||||||
|
} else if (navigator.webkitGetUserMedia) {
|
||||||
|
navigator.webkitGetUserMedia({audio: true},
|
||||||
|
this.onStream.bind(this),
|
||||||
|
this.onStreamError.bind(this));
|
||||||
|
}
|
||||||
|
this.ctx = this.$.canvas.getContext('2d');
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
//console.log('Render');
|
||||||
|
this.width = window.innerWidth;
|
||||||
|
this.height = window.innerHeight;
|
||||||
|
|
||||||
|
var didResize = false;
|
||||||
|
// Ensure dimensions are accurate.
|
||||||
|
if (this.$.canvas.width != this.width) {
|
||||||
|
this.$.canvas.width = this.width;
|
||||||
|
this.$.labels.width = this.width;
|
||||||
|
didResize = true;
|
||||||
|
}
|
||||||
|
if (this.$.canvas.height != this.height) {
|
||||||
|
this.$.canvas.height = this.height;
|
||||||
|
this.$.labels.height = this.height;
|
||||||
|
didResize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.renderTimeDomain();
|
||||||
|
this.renderFreqDomain();
|
||||||
|
|
||||||
|
if (this.labels && didResize) {
|
||||||
|
this.renderAxesLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(this.render.bind(this));
|
||||||
|
|
||||||
|
var now = new Date();
|
||||||
|
if (this.lastRenderTime_) {
|
||||||
|
this.instantaneousFPS = now - this.lastRenderTime_;
|
||||||
|
}
|
||||||
|
this.lastRenderTime_ = now;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTimeDomain: function() {
|
||||||
|
var times = new Uint8Array(this.analyser.frequencyBinCount);
|
||||||
|
this.analyser.getByteTimeDomainData(times);
|
||||||
|
|
||||||
|
for (var i = 0; i < times.length; i++) {
|
||||||
|
var value = times[i];
|
||||||
|
var percent = value / 256;
|
||||||
|
var barHeight = this.height * percent;
|
||||||
|
var offset = this.height - barHeight - 1;
|
||||||
|
var barWidth = this.width/times.length;
|
||||||
|
this.ctx.fillStyle = 'black';
|
||||||
|
this.ctx.fillRect(i * barWidth, offset, 1, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
renderFreqDomain: function() {
|
||||||
|
var freq = new Uint8Array(this.analyser.frequencyBinCount);
|
||||||
|
this.analyser.getByteFrequencyData(freq);
|
||||||
|
|
||||||
|
var ctx = this.ctx;
|
||||||
|
// Copy the current canvas onto the temp canvas.
|
||||||
|
this.tempCanvas.width = this.width;
|
||||||
|
this.tempCanvas.height = this.height;
|
||||||
|
//console.log(this.$.canvas.height, this.tempCanvas.height);
|
||||||
|
var tempCtx = this.tempCanvas.getContext('2d');
|
||||||
|
tempCtx.drawImage(this.$.canvas, 0, 0, this.width, this.height);
|
||||||
|
|
||||||
|
// Iterate over the frequencies.
|
||||||
|
for (var i = 0; i < freq.length; i++) {
|
||||||
|
var value;
|
||||||
|
// Draw each pixel with the specific color.
|
||||||
|
if (this.log) {
|
||||||
|
logIndex = this.logScale(i, freq.length);
|
||||||
|
value = freq[logIndex];
|
||||||
|
} else {
|
||||||
|
value = freq[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.fillStyle = (this.color ? this.getFullColor(value) : this.getGrayColor(value));
|
||||||
|
|
||||||
|
var percent = i / freq.length;
|
||||||
|
var y = Math.round(percent * this.height);
|
||||||
|
|
||||||
|
// draw the line at the right side of the canvas
|
||||||
|
ctx.fillRect(this.width - this.speed, this.height - y,
|
||||||
|
this.speed, this.speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate the canvas.
|
||||||
|
ctx.translate(-this.speed, 0);
|
||||||
|
// Draw the copied image.
|
||||||
|
ctx.drawImage(this.tempCanvas, 0, 0, this.width, this.height,
|
||||||
|
0, 0, this.width, this.height);
|
||||||
|
|
||||||
|
// Reset the transformation matrix.
|
||||||
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an index and the total number of entries, return the
|
||||||
|
* log-scaled value.
|
||||||
|
*/
|
||||||
|
logScale: function(index, total, opt_base) {
|
||||||
|
var base = opt_base || 2;
|
||||||
|
var logmax = this.logBase(total + 1, base);
|
||||||
|
var exp = logmax * index / total;
|
||||||
|
return Math.round(Math.pow(base, exp) - 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
logBase: function(val, base) {
|
||||||
|
return Math.log(val) / Math.log(base);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderAxesLabels: function() {
|
||||||
|
var canvas = this.$.labels;
|
||||||
|
canvas.width = this.width;
|
||||||
|
canvas.height = this.height;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var startFreq = 440;
|
||||||
|
var nyquist = context.sampleRate/2;
|
||||||
|
var endFreq = nyquist - startFreq;
|
||||||
|
var step = (endFreq - startFreq) / this.ticks;
|
||||||
|
var yLabelOffset = 5;
|
||||||
|
// Render the vertical frequency axis.
|
||||||
|
for (var i = 0; i <= this.ticks; i++) {
|
||||||
|
var freq = startFreq + (step * i);
|
||||||
|
// Get the y coordinate from the current label.
|
||||||
|
var index = this.freqToIndex(freq);
|
||||||
|
var percent = index / this.getFFTBinCount();
|
||||||
|
var y = (1-percent) * this.height;
|
||||||
|
var x = this.width - 60;
|
||||||
|
// Get the value for the current y coordinate.
|
||||||
|
var label;
|
||||||
|
if (this.log) {
|
||||||
|
// Handle a logarithmic scale.
|
||||||
|
var logIndex = this.logScale(index, this.getFFTBinCount());
|
||||||
|
// Never show 0 Hz.
|
||||||
|
freq = Math.max(1, this.indexToFreq(logIndex));
|
||||||
|
}
|
||||||
|
var label = this.formatFreq(freq);
|
||||||
|
var units = this.formatUnits(freq);
|
||||||
|
ctx.font = '16px Inconsolata';
|
||||||
|
// Draw the value.
|
||||||
|
ctx.textAlign = 'right';
|
||||||
|
ctx.fillText(label, x, y + yLabelOffset);
|
||||||
|
// Draw the units.
|
||||||
|
ctx.textAlign = 'left';
|
||||||
|
ctx.fillText(units, x + 10, y + yLabelOffset);
|
||||||
|
// Draw a tick mark.
|
||||||
|
ctx.fillRect(x + 40, y, 30, 2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearAxesLabels: function() {
|
||||||
|
var canvas = this.$.labels;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
ctx.clearRect(0, 0, this.width, this.height);
|
||||||
|
},
|
||||||
|
|
||||||
|
formatFreq: function(freq) {
|
||||||
|
return (freq >= 1000 ? (freq/1000).toFixed(1) : Math.round(freq));
|
||||||
|
},
|
||||||
|
|
||||||
|
formatUnits: function(freq) {
|
||||||
|
return (freq >= 1000 ? 'KHz' : 'Hz');
|
||||||
|
},
|
||||||
|
|
||||||
|
indexToFreq: function(index) {
|
||||||
|
var nyquist = context.sampleRate/2;
|
||||||
|
return nyquist/this.getFFTBinCount() * index;
|
||||||
|
},
|
||||||
|
|
||||||
|
freqToIndex: function(frequency) {
|
||||||
|
var nyquist = context.sampleRate/2;
|
||||||
|
return Math.round(frequency/nyquist * this.getFFTBinCount());
|
||||||
|
},
|
||||||
|
|
||||||
|
getFFTBinCount: function() {
|
||||||
|
return this.fftsize / 2;
|
||||||
|
},
|
||||||
|
|
||||||
|
onStream: function(stream) {
|
||||||
|
var input = context.createMediaStreamSource(stream);
|
||||||
|
var analyser = context.createAnalyser();
|
||||||
|
analyser.smoothingTimeConstant = 0;
|
||||||
|
analyser.fftSize = this.fftsize;
|
||||||
|
|
||||||
|
// Connect graph.
|
||||||
|
input.connect(analyser);
|
||||||
|
|
||||||
|
this.analyser = analyser;
|
||||||
|
// Setup a timer to visualize some stuff.
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
onStreamError: function(e) {
|
||||||
|
console.error(e);
|
||||||
|
},
|
||||||
|
|
||||||
|
getGrayColor: function(value) {
|
||||||
|
return 'rgb(V, V, V)'.replace(/V/g, 255 - value);
|
||||||
|
},
|
||||||
|
|
||||||
|
getFullColor: function(value) {
|
||||||
|
var fromH = 62;
|
||||||
|
var toH = 0;
|
||||||
|
var percent = value / 255;
|
||||||
|
var delta = percent * (toH - fromH);
|
||||||
|
var hue = fromH + delta;
|
||||||
|
return 'hsl(H, 100%, 50%)'.replace(/H/g, hue);
|
||||||
|
},
|
||||||
|
|
||||||
|
logChanged: function() {
|
||||||
|
if (this.labels) {
|
||||||
|
this.renderAxesLabels();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ticksChanged: function() {
|
||||||
|
if (this.labels) {
|
||||||
|
this.renderAxesLabels();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
labelsChanged: function() {
|
||||||
|
if (this.labels) {
|
||||||
|
this.renderAxesLabels();
|
||||||
|
} else {
|
||||||
|
this.clearAxesLabels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
101
public/larynx/v/2.0/index.php
Normal file
101
public/larynx/v/2.0/index.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
session_start();
|
||||||
|
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||||
|
$version = "2.0";
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Larynx | Chiro - Canto</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
||||||
|
</head>
|
||||||
|
<?php
|
||||||
|
include("$root/analytics/owa.php");
|
||||||
|
include("$root/analytics/matomo.php");
|
||||||
|
?>
|
||||||
|
<body>
|
||||||
|
<?php include("$root/menu.php");?>
|
||||||
|
<?php include("$root/header.php");?>
|
||||||
|
<section>
|
||||||
|
<h2>Larynx</h2>
|
||||||
|
<p>A web tool for bat sound analysis</p>
|
||||||
|
<a href="#larynx" title="Launch Larynx v<?=$version?>" id="launch-larynx">
|
||||||
|
<div class="arrow bounce"></div>
|
||||||
|
</a>
|
||||||
|
</section>
|
||||||
|
<div id="larynx">
|
||||||
|
<h2>Larynx v<?=$version?></h2>
|
||||||
|
<?php
|
||||||
|
require "$root/database/credentials.php";
|
||||||
|
// Connect the database
|
||||||
|
try {
|
||||||
|
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8",
|
||||||
|
$user,
|
||||||
|
$password,
|
||||||
|
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
die("Error : ".$e->getMessage());
|
||||||
|
}
|
||||||
|
if (isset($_GET['record'])) {
|
||||||
|
$req = $db->prepare('SELECT id, recordist_name, file_name, license, species, sound_type, date, time FROM `records` WHERE id=:id');
|
||||||
|
$req->execute(array(
|
||||||
|
"id"=>$_GET['record']
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$req = $db->prepare('SELECT id, recordist_name, file_name, license, species, sound_type, date, time FROM `records` ORDER BY date DESC, time DESC LIMIT 1');
|
||||||
|
$req->execute();
|
||||||
|
}
|
||||||
|
if ($data = $req->fetch()) {
|
||||||
|
// print_r($data);
|
||||||
|
?>
|
||||||
|
<audio src="<?="/storage/records/".$data['file_name']?>" id="audio" controls></audio>
|
||||||
|
<div class="spectrogram">
|
||||||
|
<div id="waveform"></div>
|
||||||
|
<div id="wave-spectrogram">
|
||||||
|
<canvas id="spectrogram-canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="container row">
|
||||||
|
<div class="measures">
|
||||||
|
T:
|
||||||
|
<span id="cursor-time"></span>
|
||||||
|
s F:
|
||||||
|
<span id="cursor-frequency"></span>
|
||||||
|
kHz
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="button" name="play" value="play" id="play">
|
||||||
|
<input type="button" value="pause" id="pause">
|
||||||
|
<input type="button" value="restart" id="restart">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="license"><?=$data['license']?> <?=$data['recordist_name']?></p>
|
||||||
|
<div class="settings">
|
||||||
|
<input type="checkbox" name="exp_x10" id="exp_x10">
|
||||||
|
<label for="exp_x10">exp x10</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php include("$root/footer.php");?>
|
||||||
|
</body>
|
||||||
|
<script src="/scripts/script.js"></script>
|
||||||
|
<!-- <script src="https://unpkg.com/wavesurfer.js"></script> -->
|
||||||
|
<!-- <script src="https://unpkg.com/wavesurfer.js/dist/plugin/wavesurfer.spectrogram.min.js" type="text/javascript"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/addons/p5.sound.js"></script> -->
|
||||||
|
<script src="scripts/spectro.js"></script>
|
||||||
|
<!-- <script src="scripts/piano.js"></script> -->
|
||||||
|
|
||||||
|
</html>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
$_SESSION['error_msg'] = "Error: Can't retrieve audio from database in Larynx";
|
||||||
|
header('Location: /');
|
||||||
|
}
|
||||||
|
?>
|
263
public/larynx/v/2.0/scripts/script.js
Normal file
263
public/larynx/v/2.0/scripts/script.js
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
let analyser;
|
||||||
|
let context;
|
||||||
|
let fftsize = 2048;
|
||||||
|
let oscillator = true;
|
||||||
|
let log;
|
||||||
|
let percent;
|
||||||
|
let times;
|
||||||
|
let speed = 0.1;
|
||||||
|
let bufferLength;
|
||||||
|
let labels;
|
||||||
|
let color = true;
|
||||||
|
let width = window.innerwidth;
|
||||||
|
let height = window.innerheight;
|
||||||
|
|
||||||
|
|
||||||
|
let canvas = document.getElementById('spectrogram-canvas');
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
let lastRenderTime = new Date();
|
||||||
|
let instantaneousFPS = 0;
|
||||||
|
|
||||||
|
let audio = document.getElementById('audio');
|
||||||
|
|
||||||
|
document.getElementById("launch-larynx").addEventListener('click', function () {
|
||||||
|
loadSound(audio.src)
|
||||||
|
startLarynx();
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadSound(url) {
|
||||||
|
let AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
|
||||||
|
context = new AudioContext();
|
||||||
|
let source = context.createMediaElementSource(audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startLarynx() {
|
||||||
|
analyser = context.createAnalyser();
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
let didResize = false;
|
||||||
|
|
||||||
|
analyser = context.createAnalyser();
|
||||||
|
|
||||||
|
// Ensure dimensions are accurate.
|
||||||
|
if (canvas.width != width) {
|
||||||
|
canvas.width = width;
|
||||||
|
didResize = true;
|
||||||
|
}
|
||||||
|
if (canvas.height != height) {
|
||||||
|
canvas.height = height;
|
||||||
|
didResize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTimeDomain();
|
||||||
|
renderFreqDomain();
|
||||||
|
|
||||||
|
if (labels && didResize) {
|
||||||
|
renderAxesLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = new Date();
|
||||||
|
if (lastRenderTime) {
|
||||||
|
instantaneousFPS = now - lastRenderTime;
|
||||||
|
}
|
||||||
|
lastRenderTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
drawVisual = requestAnimationFrame(draw);
|
||||||
|
analyser.getByteTimeDomainData(times);
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgb(200, 200, 200)';
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
ctx.linewidth = 2;
|
||||||
|
ctx.strokeStyle = 'rgb(0, 0, 0)';
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
|
||||||
|
var slicewidth = width * 1.0 / bufferLength;
|
||||||
|
var x = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < bufferLength; i++) {
|
||||||
|
|
||||||
|
var v = times[i] / 128.0;
|
||||||
|
var y = v * height / 2;
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
ctx.moveTo(x, y);
|
||||||
|
} else {
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
x += slicewidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.lineTo(canvas.width, canvas.height / 2);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTimeDomain() {
|
||||||
|
bufferLength = analyser.frequencyBinCount;
|
||||||
|
times = new Uint8Array(bufferLength);
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFreqDomain() {
|
||||||
|
let freq = new Uint8Array(analyser.frequencyBinCount);
|
||||||
|
analyser.getByteFrequencyData(freq);
|
||||||
|
|
||||||
|
for (let i = 0; i < freq.length; i++) {
|
||||||
|
let value;
|
||||||
|
// Draw each pixel with the specific color.
|
||||||
|
if (log) {
|
||||||
|
logIndex = logScale(i, freq.length);
|
||||||
|
value = freq[logIndex];
|
||||||
|
} else {
|
||||||
|
value = freq[i];
|
||||||
|
}
|
||||||
|
ctx.fillStyle = (color ? getFullColor(value) : getGrayColor(value));
|
||||||
|
|
||||||
|
let perceint = i / freq.length;
|
||||||
|
let y = Math.round(percent * height);
|
||||||
|
|
||||||
|
// Draw the line at the right side of the canvas.
|
||||||
|
ctx.fillRect(width - speed, height - y, speed, speed);
|
||||||
|
}
|
||||||
|
ctx.translate(-speed, 0);
|
||||||
|
// Reset the transformation matrix
|
||||||
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logScale(index, total, opt_base) {
|
||||||
|
let base = opt_base || 2;
|
||||||
|
let logmax = logBase(total + 1, base);
|
||||||
|
let exp = logmax * index / total;
|
||||||
|
return Math.round(Math.pow(base, exp) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logBase(val, base) {
|
||||||
|
return Math.log(val) / Math.log(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function renderAxesLabels() {
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let startFreq = 440;
|
||||||
|
let nyquist = context.sampleRate / 2;
|
||||||
|
let endFreq = nyquist - startFreq;
|
||||||
|
let step = (endFreq - startFreq) / ticks;
|
||||||
|
let yLabelOffset = 5;
|
||||||
|
// Render the vertical frequency axis.
|
||||||
|
for (let i = 0; i <= ticks; i++) {
|
||||||
|
let freq = startFreq + (step * i);
|
||||||
|
// Get the y coordinate from the current label.
|
||||||
|
let index = freqToIndex(freq);
|
||||||
|
let percent = index / getFFTBinCount();
|
||||||
|
let y = (1 - percent) * height;
|
||||||
|
let x = width - 60;
|
||||||
|
// Get the value for the current y coordinate.
|
||||||
|
let label;
|
||||||
|
if (log) {
|
||||||
|
// Handle a logarithmic scale.
|
||||||
|
let logIndex = logScale(index, getFFTBinCount());
|
||||||
|
// Never show 0 Hz.
|
||||||
|
freq = Math.max(1, indexToFreq(logIndex));
|
||||||
|
}
|
||||||
|
label = formatFreq(freq);
|
||||||
|
let units = formatUnits(freq);
|
||||||
|
ctx.font = '16px Inconsolata';
|
||||||
|
// Draw the value.
|
||||||
|
ctx.textAlign = 'right';
|
||||||
|
ctx.fillText(label, x, y + yLabelOffset);
|
||||||
|
// Draw the units.
|
||||||
|
ctx.textAlign = 'left';
|
||||||
|
ctx.fillText(units, x + 10, y + yLabelOffset);
|
||||||
|
// Draw a tick mark.
|
||||||
|
ctx.fillRect(x + 40, y, 30, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAxesLabels() {
|
||||||
|
let canvas = labels;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatFreq(freq) {
|
||||||
|
return (freq >= 1000 ? (freq / 1000).toFixed(1) : Math.round(freq));
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUnits(freq) {
|
||||||
|
return (freq >= 1000 ? 'KHz' : 'Hz');
|
||||||
|
}
|
||||||
|
|
||||||
|
function indexToFreq(index) {
|
||||||
|
let nyquist = context.sampleRate / 2;
|
||||||
|
return nyquist / getFFTBinCount() * index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function freqToIndex(frequency) {
|
||||||
|
let nyquist = context.sampleRate / 2;
|
||||||
|
return Math.round(frequency / nyquist * getFFTBinCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFFTBinCount() {
|
||||||
|
return fftsize / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// function onStream(stream) {
|
||||||
|
// let input = context.createMediaStreamSource(stream);
|
||||||
|
// let analyser = context.createAnalyser();
|
||||||
|
// analyser.smoothingTimeConstant = 0;
|
||||||
|
// analyser.fftSize = fftsize;
|
||||||
|
|
||||||
|
// // Connect graph.
|
||||||
|
// input.connect(analyser);
|
||||||
|
|
||||||
|
// // Setup a timer to visualize some stuff.
|
||||||
|
// render();
|
||||||
|
// }
|
||||||
|
|
||||||
|
function onStreamError(e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGrayColor(value) {
|
||||||
|
return 'rgb(V, V, V)'.replace(/V/g, 255 - value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFullColor(value) {
|
||||||
|
let fromH = 62;
|
||||||
|
let toH = 0;
|
||||||
|
let percent = value / 255;
|
||||||
|
let delta = percent * (toH - fromH);
|
||||||
|
let hue = fromH + delta;
|
||||||
|
return 'hsl(H, 100%, 50%)'.replace(/H/g, hue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logChanged() {
|
||||||
|
if (labels) {
|
||||||
|
renderAxesLabels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ticksChanged() {
|
||||||
|
if (labels) {
|
||||||
|
renderAxesLabels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function labelsChanged() {
|
||||||
|
if (labels) {
|
||||||
|
renderAxesLabels();
|
||||||
|
} else {
|
||||||
|
clearAxesLabels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
67
public/larynx/v/2.0/scripts/spectro.js
Normal file
67
public/larynx/v/2.0/scripts/spectro.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
var audio = document.getElementById('audio');
|
||||||
|
|
||||||
|
let button = document.getElementById('launch-larynx').addEventListener('click', function(){
|
||||||
|
loadSound(audio.src);
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
let audioCtx;
|
||||||
|
let source;
|
||||||
|
let analyser;
|
||||||
|
let canvasCtx = document.getElementById('spectrogram-canvas');
|
||||||
|
|
||||||
|
let WIDTH = canvasCtx.width;
|
||||||
|
let HEIGHT = canvasCtx.height;
|
||||||
|
|
||||||
|
function loadSound(url) {
|
||||||
|
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
source = audioCtx.createMediaElementSource(audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
analyser = audioCtx.createAnalyser();
|
||||||
|
|
||||||
|
analyser.fftSize = 2048;
|
||||||
|
var bufferLength = analyser.frequencyBinCount;
|
||||||
|
var dataArray = new Uint8Array(bufferLength);
|
||||||
|
analyser.getByteTimeDomainData(dataArray);
|
||||||
|
|
||||||
|
// draw an oscilloscope of the current audio source
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
|
||||||
|
drawVisual = requestAnimationFrame(draw);
|
||||||
|
|
||||||
|
analyser.getByteTimeDomainData(dataArray);
|
||||||
|
|
||||||
|
canvasCtx.fillStyle = 'rgb(200, 200, 200)';
|
||||||
|
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
canvasCtx.lineWidth = 2;
|
||||||
|
canvasCtx.strokeStyle = 'rgb(0, 0, 0)';
|
||||||
|
|
||||||
|
canvasCtx.beginPath();
|
||||||
|
|
||||||
|
var sliceWidth = WIDTH * 1.0 / bufferLength;
|
||||||
|
var x = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < bufferLength; i++) {
|
||||||
|
|
||||||
|
var v = dataArray[i] / 128.0;
|
||||||
|
var y = v * HEIGHT / 2;
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
canvasCtx.moveTo(x, y);
|
||||||
|
} else {
|
||||||
|
canvasCtx.lineTo(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
x += sliceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvasCtx.lineTo(canvas.width, canvas.height / 2);
|
||||||
|
canvasCtx.stroke();
|
||||||
|
};
|
||||||
|
|
||||||
|
draw();
|
||||||
|
}
|
@ -45,9 +45,16 @@
|
|||||||
<a href="/larynx">
|
<a href="/larynx">
|
||||||
<li>larynx</li>
|
<li>larynx</li>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="/api">
|
||||||
|
<li>API</li>
|
||||||
|
</a>
|
||||||
<a href="/forum">
|
<a href="/forum">
|
||||||
<li>forum</li>
|
<li>forum</li>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="/discussion" class="notification">
|
||||||
|
<li>messages</li>
|
||||||
|
<?php include("$root/discussion/notification.php")?>
|
||||||
|
</a>
|
||||||
<a href="/explore/mysteries">
|
<a href="/explore/mysteries">
|
||||||
<li>mysteries</li>
|
<li>mysteries</li>
|
||||||
</a>
|
</a>
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
<form id="searchbar" action="/search/index.php" method="post">
|
|
||||||
<input type="text" name="query" placeholder="Search recordings.." required>
|
|
||||||
<input type="submit" name="search" value="Search">
|
|
||||||
</form>
|
|
@ -1,5 +1,6 @@
|
|||||||
* {
|
* {
|
||||||
align-self: baseline;
|
align-self: baseline;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -278,9 +279,8 @@ table a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#searchbar {
|
#searchbar {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-self: right;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.breadcrumb {
|
ul.breadcrumb {
|
||||||
@ -631,3 +631,25 @@ i, .fa {
|
|||||||
background-color: lightgreen;
|
background-color: lightgreen;
|
||||||
border-radius: 8px 8px 0px 8px;
|
border-radius: 8px 8px 0px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
text-decoration: none;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification span {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .badge {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 0.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
top: -0.5em;
|
||||||
|
right: -0.5em;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user