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
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||
include("$root/vendor/erusev/parsedown/Parsedown.php");
|
||||
$Parsedown = new Parsedown();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -21,6 +26,27 @@ $root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||
?>
|
||||
<section>
|
||||
<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>
|
||||
<?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']
|
||||
));
|
||||
if ($data = $req->fetch()) {
|
||||
$user_id = $data['id'];
|
||||
$sender_id = $data['id'];
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error_msg'] = "You must be logged in to receive an send message.";
|
||||
header('Location: /auth/login');
|
||||
}
|
||||
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(
|
||||
"author_id"=>$user_id,
|
||||
"user_id"=>$_GET['author']
|
||||
"sender_id"=>$sender_id,
|
||||
"user_id"=>$user_id
|
||||
));
|
||||
$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>
|
||||
<html lang="en">
|
||||
@ -66,10 +75,15 @@ include("$root/analytics/matomo.php");
|
||||
<h2>Discussion</h2>
|
||||
<div class="messages">
|
||||
<div class="author">
|
||||
<?=$destinator?>
|
||||
<?=$addressee?>
|
||||
</div>
|
||||
<?php
|
||||
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']) {
|
||||
$class = "right";
|
||||
} 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);
|
||||
error_reporting(E_ALL);
|
||||
$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";
|
||||
// Connect the database
|
||||
try {
|
||||
@ -29,28 +52,7 @@ if ($data = $req->fetch()) {
|
||||
} else {
|
||||
$_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>
|
||||
|
||||
Original Filename: <?=$data['file_name']?><br>
|
||||
|
@ -4,27 +4,6 @@ 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());
|
||||
}
|
||||
|
||||
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>
|
||||
<html lang="en">
|
||||
@ -45,6 +24,27 @@ include("$root/analytics/owa.php");
|
||||
<section>
|
||||
<h3>Record</h3>
|
||||
<?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()) {
|
||||
?>
|
||||
<div class="sound">
|
||||
|
@ -56,21 +56,21 @@ if ($_SESSION['error_msg'] == "") {
|
||||
if ($and) {
|
||||
$sql .= " AND ";
|
||||
}
|
||||
$sql .= ' species="'.$_SESSION['query']['species'].'"';
|
||||
$sql .= ' species LIKE "%'.$_SESSION['query']['species'].'%"';
|
||||
$and = True;
|
||||
}
|
||||
if (isset($_SESSION['query']['subspecies']) and $_SESSION['query']['subspecies'] != "") {
|
||||
if ($and) {
|
||||
$sql .= " AND ";
|
||||
}
|
||||
$sql .= ' subspecies="'.$_SESSION['query']['subspecies'].'"';
|
||||
$sql .= ' subspecies LIKE "%'.$_SESSION['query']['subspecies'].'%"';
|
||||
$and = True;
|
||||
}
|
||||
if (isset($_SESSION['query']['recordist']) and $_SESSION['query']['recordist'] != "") {
|
||||
if ($and) {
|
||||
$sql .= " AND ";
|
||||
}
|
||||
$sql .= ' recordist_name="'.$_SESSION['query']['recordist'].'"';
|
||||
$sql .= ' recordist_name LIKE "%'.$_SESSION['query']['recordist'].'%"';
|
||||
$and = True;
|
||||
}
|
||||
if (isset($_SESSION['query']['date-after']) and $_SESSION['query']['date-after'] != "") {
|
||||
@ -96,10 +96,6 @@ if ($_SESSION['error_msg'] == "") {
|
||||
$and = True;
|
||||
}
|
||||
}
|
||||
// echo $sql;
|
||||
$req = $db->prepare($sql);
|
||||
$req->execute();
|
||||
$result = $req->fetchAll();
|
||||
} else {
|
||||
$_SESSION['error_msg'] .= "You did not enter any query.\n";
|
||||
header("Location: /explore/search");
|
||||
@ -108,9 +104,7 @@ if ($_SESSION['error_msg'] == "") {
|
||||
} else {
|
||||
header("Location: /explore/search");
|
||||
}
|
||||
|
||||
if (isset($result)) {
|
||||
?>
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -128,6 +122,11 @@ if (isset($result)) {
|
||||
<h3>Explore</h3>
|
||||
<h4>Search Results</h4>
|
||||
<?php
|
||||
// echo $sql;
|
||||
$req = $db->prepare($sql);
|
||||
$req->execute();
|
||||
$result = $req->fetchAll();
|
||||
// print_r($sql);
|
||||
if (empty($result)) {
|
||||
echo "No result for this query, please try again.\n";
|
||||
} else {
|
||||
@ -163,6 +162,4 @@ if (isset($result)) {
|
||||
<?php include("$root/footer.php");?>
|
||||
</body>
|
||||
<script src="/scripts/script.js"></script>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
</html>
|
@ -5,7 +5,6 @@
|
||||
<h1>Chiro - Canto</h1>
|
||||
<h2>Bat sound sharing tools</h2>
|
||||
</a>
|
||||
</div>
|
||||
<?php include("$root/search/searchbar.php");?>
|
||||
</div>
|
||||
</div>
|
||||
</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();
|
||||
$root = realpath($_SERVER["DOCUMENT_ROOT"]);
|
||||
$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>
|
||||
<html lang="en">
|
||||
@ -35,14 +14,15 @@ $data = $req->fetch();
|
||||
<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">
|
||||
<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>
|
||||
<?php
|
||||
include("$root/analytics/owa.php");
|
||||
include("$root/analytics/matomo.php");
|
||||
?>
|
||||
<?php
|
||||
include("$root/analytics/matomo.php");
|
||||
?>
|
||||
<body>
|
||||
<?php include("$root/menu.php");?>
|
||||
<?php include("$root/header.php");?>
|
||||
@ -55,8 +35,31 @@ include("$root/analytics/matomo.php");
|
||||
</section>
|
||||
<div id="larynx">
|
||||
<h2>Larynx v<?=$version?></h2>
|
||||
|
||||
<audio src="<?="/storage/records/".$data['file_name']?>" id="audio"></audio>
|
||||
<?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">
|
||||
@ -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://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/g-spectro.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">
|
||||
<li>larynx</li>
|
||||
</a>
|
||||
<a href="/api">
|
||||
<li>API</li>
|
||||
</a>
|
||||
<a href="/forum">
|
||||
<li>forum</li>
|
||||
</a>
|
||||
<a href="/discussion" class="notification">
|
||||
<li>messages</li>
|
||||
<?php include("$root/discussion/notification.php")?>
|
||||
</a>
|
||||
<a href="/explore/mysteries">
|
||||
<li>mysteries</li>
|
||||
</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;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
@ -278,9 +279,8 @@ table a:hover {
|
||||
}
|
||||
|
||||
#searchbar {
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-self: right;
|
||||
}
|
||||
|
||||
ul.breadcrumb {
|
||||
@ -631,3 +631,25 @@ i, .fa {
|
||||
background-color: lightgreen;
|
||||
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;
|
||||
}
|
||||
|