This commit is contained in:
Dooho Yi 2024-10-12 15:28:34 +09:00
commit 6d65616f6b
42 changed files with 12803 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.ftpconfig
.jshintrc

138
archive/compass1.html Normal file
View file

@ -0,0 +1,138 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<script src="js/p5.min.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
</style>
</head>
<body>
<h1 id="lat">lat: </h1>
<h1 id="long">long: </h1>
<h1 id="heading">heading: </h1>
<button onclick='requestOrientationPermission();'>Request orientation permission</button>
<script>
//
//gps, heading
const options = {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000,
};
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/) || navigator.userAgent.match(/AppleWebKit/)) {
function requestOrientationPermission() {
DeviceOrientationEvent.requestPermission()
.then(response => {
if (response == 'granted') {
// window.addEventListener('deviceorientation', function(eventData) {
window.addEventListener("deviceorientation", (event) => {
var compassdir;
if (event.webkitCompassHeading) {
// Apple works only with this, alpha doesn't work
compassdir = event.webkitCompassHeading;
} else compassdir = event.alpha;
let heading = document.getElementById('heading');
heading.innerText = 'heading: ' + compassdir;
compass1.heading = -compassdir;
}, true);
}
})
.catch(console.error)
}
} else {
window.addEventListener("deviceorientationabsolute", (event) => {
let heading = document.getElementById('heading');
heading.innerText = 'heading: ' + event.alpha;
compass1.heading = event.alpha;
}, true);
}
const watchID = navigator.geolocation.watchPosition((position) => {
let lat = document.getElementById('lat');
lat.innerText = 'lat: ' + position.coords.latitude;
let long = document.getElementById('long');
long.innerText = 'long: ' + position.coords.longitude;
},
(error) => {},
options);
//p5
class Compass {
constructor(cx, cy, size, colors) {
this.cx = cx;
this.cy = cy;
this.size = size;
this.colors = colors;
this.heading = 0;
}
draw() {
push();
//
translate(this.cx, this.cy);
scale(this.size);
//
translate(0.5, 0.5);
//
noStroke();
//
fill(this.colors[0]);
circle(0, 0, 1);
//
fill(this.colors[1]);
rotate(this.heading);
quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
//
fill(this.colors[2]);
circle(0, 0, 0.1);
//
pop();
}
}
let compass1;
let compass_reading = 0;
function setup() {
createCanvas(windowWidth, windowHeight);
compass1 = new Compass(100, 100, 200, ['red', 'limegreen', 'yellow']);
compass2 = new Compass(300, 300, 20, ['yellow', 'navy', 'white']);
angleMode(DEGREES);
}
function draw() {
//
background(100);
//compass
fill(200);
noStroke();
// compass1.heading = compass_reading;
// compass1.heading = 5;
compass1.draw();
// compass2.draw();
}
</script>
</body>
</html>

View file

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
<meta charset="utf-8">
<!-- <script src="/js/p5.min.js"></script> -->
</head>
<body>
<h1 id="lat">lat: </h1>
<h1 id="long">long: </h1>
<h1 id="heading">heading: </h1>
<button onclick='requestOrientationPermission();'>Request orientation permission</button>
<script>
const options = {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000,
};
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/) || navigator.userAgent.match(/AppleWebKit/)) {
function requestOrientationPermission(){
DeviceOrientationEvent.requestPermission()
.then(response => {
if (response == 'granted') {
// window.addEventListener('deviceorientation', function(eventData) {
window.addEventListener("deviceorientation", (event) => {
var compassdir;
if(event.webkitCompassHeading) {
// Apple works only with this, alpha doesn't work
compassdir = event.webkitCompassHeading;
}
else compassdir = event.alpha;
let heading = document.getElementById('heading');
heading.innerText = 'heading: ' + compassdir;
}, true);
}
})
.catch(console.error)
}
} else {
window.addEventListener("deviceorientationabsolute", (event) => {
let heading = document.getElementById('heading');
heading.innerText = 'heading: ' + event.alpha;
}, true);
}
const watchID = navigator.geolocation.watchPosition((position) => {
let lat = document.getElementById('lat');
lat.innerText = 'lat: ' + position.coords.latitude;
let long = document.getElementById('long');
long.innerText = 'long: ' + position.coords.longitude;
},
(error) => {},
options);
</script>
</body>
</html>

215
archive/index_alt.html Normal file
View file

@ -0,0 +1,215 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<!-- lib -->
<script src="js/p5.min.js"></script>
<script src="js/Tone.min.js"></script>
<!-- css -->
<link rel="stylesheet" href="css/default.css">
<!-- script -->
<script>
const AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx;
</script>
<script src="js/util.js"></script>
<script src="js/classes.js"></script>
</head>
<body>
<button class='overlay-userinput' onclick='initialize();'>
<div>터치하고-시작하기!</div>
</button>
<audio controls crossorigin="anonymous" style="display:none;">
<!-- <source src="https://radio.dianaband.in:8000/stream" type="audio/aac" /> -->
</audio>
<script>
//shared
//device location & motion
let heading = 0;
let latitude = 37.574973;
let longitude = 126.925708;
// let latitude = 37.576774;
// let longitude = 126.931232;
// 맞는 결과 (예) : 작업실 -> 베지스
// p1 = [37.574973, 126.925708]
// p2 = [37.576774, 126.931232]
// getBearing(p1[0], p1[1], p2[0], p2[1])
// 67.6373956496954 (deg)
// getDistance(p1[0], p1[1], p2[0], p2[1])
// 0.5263963610554471 (km)
//audio playback permission checker
let silence;
let clap;
let radio;
//all ready flag (not used)
let ready = false;
//clear all permissions
async function initialize() {
// device orientation data permission
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
requestOrientationPermission();
}
// start audiocontext
audioCtx = new AudioContext;
// some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
// start loading for all sounds
sounds.forEach(async item => await item.load());
// unfreeze audio playback for Tone.js
silence.start();
// remove the veil
let veil = document.querySelector(".overlay-userinput");
veil.style.display = 'none';
// activate radio by adding source tag
const audiotag = document.querySelector('audio'); // N.B. assuming there's only 1 audio tag for streaming...
const sourcetag = document.createElement('source');
sourcetag.setAttribute('src', 'https://radio.dianaband.in:8000/stream');
sourcetag.setAttribute('type', 'audio/aac');
audiotag.appendChild(sourcetag);
audiotag.play();
// //link a sounder object to radio streaming..
// radio = new Sounder({
// // location: [37.576013, 126.927912],
// location: [37.574973, 126.935708],
// soundfile: "./audio/clap01.mp3",
// gain: 6,
// spread: 15,
// distmap: [0.005, 0.05, 0, -10],
// //testing
// volmin: -30,
// });
// // radio.radiolink(audiotag);
// radio.load();
//
ready = true;
}
let compass_target;
let compass_north;
let sounds = [];
function setup() {
createCanvas(windowWidth, windowHeight);
compass_target = new Compass(200, ['#97FFFF', '#33A1DE', 'white']);
compass_north = new Compass(40, ['yellow', 'navy', 'white']);
angleMode(DEGREES);
// register sounders to the list
sounds.push(new Sounder({
location: [37.576774, 126.931232],
soundfile: "./audio/01.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
}
function draw() {
//
background('#202325');
//all data is ready to be used.
if (ready) {
//update sounders
sounds.forEach(async item => await item.update());
// radio.update();
//
let target = sounds[0];
////main group
//(push)
push();
//compass (the North)
translate(20, 20, 0);
compass_target.heading = target.angerr; //target #0
compass_target.draw();
//(pop)
pop();
//(push)
push();
//debug
fill('white');
translate(30, 200, 0);
Textline.restart();
Textline.put('ang');
Textline.put(target.ang);
Textline.put('angerr');
Textline.put(target.angerr);
Textline.put('distance');
Textline.put(target.dist);
// Textline.put('pan');
// Textline.put(target.pv.pan.value);
// Textline.put('distvol');
// Textline.put(target.distvol);
// Textline.put('vol');
// Textline.put(target.pv.volume.value);
Textline.put('target_lat');
Textline.put(target.latitude);
Textline.put('target_lon');
Textline.put(target.longitude);
//(pop)
pop();
////status-left group
//(push)
push();
//
translate(20, windowHeight - 100, 0);
fill('white');
Textline.restart();
Textline.put('current location');
Textline.put(latitude);
Textline.put(longitude);
//(pop)
pop();
////status-right group
//(push)
push();
//
translate(windowWidth - 50, windowHeight - 50, 0);
compass_north.heading = heading;
compass_north.draw();
//(pop)
pop();
}
}
</script>
</body>
</html>

479
archive/index_old.html Executable file
View file

@ -0,0 +1,479 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<script src="js/p5.min.js"></script>
<script src="js/Tone.min.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
.overlay-userinput {
display: grid;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
color: white;
z-index: 2;
/* display: none; */
}
</style>
</head>
<body>
<button class='overlay-userinput' onclick='requestPermissions();'>
<div>터치하고-시작하기!</div>
</button>
<audio controls crossorigin="anonymous">
<!-- <source src="https://radio.dianaband.in:8000/stream" type="audio/aac" /> -->
</audio>
<script>
// //
// Tone.setContext(new Tone.Context());
// // Tone.js is using 'standardized-audio-context' internally. and 'standardized-audio-context' only connects to 'standardized-audio-context' nodes... so, we want to change 'standardized-audio-context' ==> window.AudioContext || window.webkitAudioContext... irony.. standardized doesn't guarantee.. basic audio tag...
//shared
//device location & motion
let heading = 0;
let latitude = 38.57451;
let longitude = 126.92612;
// let latitude = 0;
// let longitude = 0;
//audio playback permission checker
let silence;
let clap;
let radio;
//all ready flag (not used)
let ready = false;
//promisify -> new Tone.Player
function AudioImport(url) {
return new Promise((resolve, reject) => {
var audio = new Tone.Player(url, () => resolve(audio));
});
}
//clear all permissions
function requestPermissions() {
// device orientation data permission
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
requestOrientationPermission();
}
// sound playback permission
silence.start();
//
let veil = document.querySelector(".overlay-userinput");
veil.style.display = 'none';
//activate radio by adding source tag
const audiotag = document.querySelector('audio'); // N.B. assuming there's only 1 audio tag for streaming...
const sourcetag = document.createElement('source');
sourcetag.setAttribute('src', 'https://radio.dianaband.in:8000/stream');
sourcetag.setAttribute('type', 'audio/aac');
audiotag.appendChild(sourcetag);
//link a sounder object to radio streaming..
radio = new Sounder({
location: [37.576013, 126.927912],
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
});
radio.radiolink(audiotag);
//
ready = true;
}
//gps, heading
//get permissions
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
function requestOrientationPermission() {
DeviceOrientationEvent
.requestPermission()
.then(response => {
if (response == 'granted') {
window.addEventListener("deviceorientation", (event) => {
if (event.webkitCompassHeading) {
heading = event.webkitCompassHeading * -1;
}
}, true);
}
})
.catch(console.error)
}
} else {
window.addEventListener("deviceorientationabsolute", (event) => {
heading = event.alpha;
}, true);
}
const watchID = navigator.geolocation.watchPosition(
(position) => {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
},
(error) => {}, {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000,
}
);
//distance between 2 locations (lat/lon)
function getDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
//bearing between 2 locations (lat/lon)
// Converts from degrees to radians.
function toRadians(degrees) {
return degrees * Math.PI / 180;
};
// Converts from radians to degrees.
function toDegrees(radians) {
return radians * 180 / Math.PI;
}
// const y = Math.sin(λ2-λ1) * Math.cos(φ2);
// const x = Math.cos(φ1)*Math.sin(φ2) -
// Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
// const θ = Math.atan2(y, x);
// const brng = (θ*180/Math.PI + 360) % 360; // in degrees
function getBearing(startLat, startLng, destLat, destLng) {
startLat = toRadians(startLat);
startLng = toRadians(startLng);
destLat = toRadians(destLat);
destLng = toRadians(destLng);
y = Math.sin(destLng - startLng) * Math.cos(destLat);
x = Math.cos(startLat) * Math.sin(destLat) -
Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
brng = Math.atan2(y, x);
brng = toDegrees(brng);
return (brng + 360) % 360;
}
// sounds
class Sounder {
constructor(args) {
this.soundfile = args.soundfile;
this.gain = args.gain; // (dB)
this.latitude = args.location[0];
this.longitude = args.location[1];
this.spread = args.spread; // (deg)
this.distmap = args.distmap;
this.volmin = args.volmin; // (dB)
this.ramptime = args.ramptime; // (seconds)
}
async load() {
//start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination();
this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here.
// this.snd.connect(this.pv).start();
this.snd.connect(this.pv);
this.snd.loop = true;
}
radiolink(audiotag) {
//start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination();
let stream = Tone.context.createMediaElementSource(audiotag);
this.snd = Tone.context.createGain();
stream.connect(this.snd);
console.log(stream);
console.log(this.snd);
console.log(this.pv);
// this.snd.connect(this.pv.input.input); // a hack ...
this.snd.gain.value = 1;
this.snd.connect(Tone.context.destination);
}
update() {
//
//update sound pan/volume
//
this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); // (deg)
this.angerr = (((heading - this.ang + 360) % 360) + 180) % 360 - 180;
this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); // (km)
//
this.distvol = map(this.dist, this.distmap[0], this.distmap[1], this.distmap[2], this.distmap[3], true); //(dB)
// (from Pure Data patch "iamyou", [eqpan2~])
// arg #1 (inlet #3): width:
// -width*(1.5) ~ -width/2 -> left fade-in
// -width/2 ~ width/2 -> cross fading
// +width/2 ~ width*(1.5) -> right fade-out
let panleft_start = this.spread * (-1.5);
let panleft_end = this.spread * (-0.5);
let panright_start = this.spread * (0.5);
let panright_end = this.spread * (1.5);
//left fade-in
if (this.angerr > panleft_start && this.angerr < panleft_end) {
this.pv.pan.value = -1; //left-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panleft_start, panleft_end, this.volmin, 0), this.ramptime); //(dB)
}
//cross fading
else if (this.angerr > panleft_end && this.angerr < panright_start) {
this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1); // crossfade
this.pv.volume.rampTo(this.distvol + this.gain, this.ramptime); //(dB)
}
//right fade-out
else if (this.angerr > panright_start && this.angerr < panright_end) {
this.pv.pan.value = 1; //right-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panright_start, panright_end, 0, this.volmin), this.ramptime); //(dB)
}
//slience
else {
this.pv.volume.rampTo(-99, 10); //(dB)
}
}
draw() {
//draw sound location
}
}
//p5
class Compass {
constructor(size, colors) {
this.size = size;
this.colors = colors;
this.heading = 0;
}
draw() {
push();
//
scale(this.size);
//
translate(0.5, 0.5);
//
noStroke();
//
fill(this.colors[0]);
circle(0, 0, 0.9);
//
fill(this.colors[1]);
rotate(this.heading);
quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
//
fill(this.colors[2]);
circle(0, 0, 0.1);
//
pop();
}
}
let compass_target;
let compass_north;
let sounds = [];
async function preload() {
//some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
//register sounders to the list
sounds.push(new Sounder({
location: [37.576013, 126.927912],
soundfile: "./audio/01.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [37.574409, 126.925210],
soundfile: "./audio/02.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [37.573149, 126.922870],
soundfile: "./audio/03.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [37.577172, 126.922993],
soundfile: "./audio/04.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
//preload all sounds
sounds.forEach(async item => await item.load());
}
function setup() {
createCanvas(windowWidth, windowHeight);
compass_target1 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_target2 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_target3 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_target4 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_north = new Compass(40, ['yellow', 'navy', 'white']);
angleMode(DEGREES);
}
let lines = 0;
let linestep = 20;
function textline(t, restart) {
if (restart) lines = 0;
else lines = lines + 1;
text(t, 0, linestep * lines);
}
function draw() {
//
background('olive');
//all data is ready to be used.
if (ready) {
//update sounders
sounds.forEach(async item => await item.update());
radio.update();
//
let target = sounds[0];
////main group
//(push)
push();
//compass (the North)
translate(20, 20, 0);
compass_target1.heading = radio.angerr; //target #0
compass_target1.draw();
translate(100, 0, 0);
compass_target2.heading = sounds[1].angerr; //target #0
compass_target2.draw();
translate(-100, 100, 0);
compass_target3.heading = sounds[2].angerr; //target #0
compass_target3.draw();
translate(100, 0, 0);
compass_target4.heading = sounds[3].angerr; //target #0
compass_target4.draw();
//(pop)
pop();
//(push)
push();
//debug
fill('white');
translate(30, 200, 0);
textline('angerr', true);
textline(target.angerr);
textline('distance');
textline(target.dist);
textline('pan');
textline(target.pv.pan.value);
textline('distvol');
textline(target.distvol);
textline('vol');
textline(target.pv.volume.value);
textline('target_lat');
textline(target.latitude);
textline('target_lon');
textline(target.longitude);
//(pop)
pop();
////status-left group
//(push)
push();
//
translate(20, windowHeight - 100, 0);
fill('white');
textline('current location', true);
textline(latitude);
textline(longitude);
//(pop)
pop();
////status-right group
//(push)
push();
//
translate(windowWidth - 50, windowHeight - 50, 0);
compass_north.heading = heading;
compass_north.draw();
//(pop)
pop();
}
}
</script>
</body>
</html>

44
archive/radio_heeju.html Normal file
View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="js//hls.min.js" crossorigin="anonymous"></script>
<title>Radio</title>
</head>
<body>
<video id="video" controls></video>
<script>
var video = document.getElementById('video');
if (Hls.isSupported()) {
var hls = new Hls({
debug: true,
// html5: { nativeAudioTracks: false }
});
hls.loadSource('https://radio.ururu.cloud/hls/live.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
video.muted = true;
video.play();
});
}
// hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled.
// When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element through the `src` property.
// This is using the built-in support of the plain video element, without using hls.js.
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = 'https://radio.ururu.cloud/hls/live.m3u8';
video.addEventListener('canplay', function () {
video.play();
});
}
</script>
</body>
</html>

54
archive/radio_test_heeju.html Executable file
View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="js/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.4/howler.min.js"></script>
<title>Sketch</title>
</head>
<body>
<audio controls>
<source src="https://radio.dianaband.in:8000/stream" type="audio/aac" />
</audio>
<audio controls loop>
<source src="audio/102.mp3" type="audio/mpeg" />
</audio>
<script>
function setup() {
createCanvas(600, 400);
}
function draw() {
//sky blue background
background(135, 206, 235);
//sun in top right
fill("yellow"); //yellow
stroke("orange"); //orange outline
strokeWeight(20); //large outline
circle(550, 50, 100);
//grass on bottom half
stroke(0); //black outline
strokeWeight(1); //outline thickness
fill("green");
rect(0, 200, 600, 200);
}
</script>
</body>
</html>

View file

@ -0,0 +1,375 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<script src="js/p5.min.js"></script>
<script src="js/Tone-14.8.36.min.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
.overlay-userinput {
display: grid;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
color: white;
z-index: 2;
/* display: none; */
}
</style>
</head>
<body>
<button class='overlay-userinput' onclick='requestPermissions();'>
<div>터치하고-시작하기!</div>
</button>
<script>
//
//shared
//device location & motion
let heading = 0;
let latitude = 37;
let longitude = 126;
// let latitude = 0;
// let longitude = 0;
//audio playback permission checker
let silence;
let clap;
//all ready flag (not used)
let ready = false;
//promisify -> new Tone.Player
function AudioImport(url) {
return new Promise((resolve, reject) => {
var audio = new Tone.Player(url, () => resolve(audio));
});
}
//clear all permissions
function requestPermissions() {
// device orientation data permission
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
requestOrientationPermission();
}
// sound playback permission
silence.start();
//
let veil = document.querySelector(".overlay-userinput");
veil.style.display = 'none';
//
ready = true;
}
//gps, heading
//get permissions
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
function requestOrientationPermission() {
DeviceOrientationEvent
.requestPermission()
.then(response => {
if (response == 'granted') {
window.addEventListener("deviceorientation", (event) => {
if (event.webkitCompassHeading) {
heading = event.webkitCompassHeading * -1;
}
}, true);
}
})
.catch(console.error)
}
} else {
window.addEventListener("deviceorientationabsolute", (event) => {
heading = event.alpha;
}, true);
}
const watchID = navigator.geolocation.watchPosition(
(position) => {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
},
(error) => {}, {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000,
}
);
//distance between 2 locations (lat/lon)
function getDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
//bearing between 2 locations (lat/lon)
// Converts from degrees to radians.
function toRadians(degrees) {
return degrees * Math.PI / 180;
};
// Converts from radians to degrees.
function toDegrees(radians) {
return radians * 180 / Math.PI;
}
// const y = Math.sin(λ2-λ1) * Math.cos(φ2);
// const x = Math.cos(φ1)*Math.sin(φ2) -
// Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
// const θ = Math.atan2(y, x);
// const brng = (θ*180/Math.PI + 360) % 360; // in degrees
function getBearing(startLat, startLng, destLat, destLng) {
startLat = toRadians(startLat);
startLng = toRadians(startLng);
destLat = toRadians(destLat);
destLng = toRadians(destLng);
y = Math.sin(destLng - startLng) * Math.cos(destLat);
x = Math.cos(startLat) * Math.sin(destLat) -
Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
brng = Math.atan2(y, x);
brng = toDegrees(brng);
return (brng + 360) % 360;
}
// sounds
class Sounder {
constructor(soundfile, latitude, longitude, spread) {
this.soundfile = soundfile;
this.latitude = latitude;
this.longitude = longitude;
this.spread = spread; //deg
}
async load() {
//start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination();
this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here.
this.snd.connect(this.pv).start();
this.snd.loop = true;
}
update() {
//
//update sound pan/volume
//
this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); //deg
this.angerr = (((heading - this.ang + 360) % 360) + 180) % 360 - 180;
this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); //km
//
this.distvol = map(this.dist, 0.005, 0.05, 0, -10, true); //(dB)
// (from Pure Data patch "iamyou", [eqpan2~])
// arg #1 (inlet #3): width:
// -width*(1.5) ~ -width/2 -> left fade-in
// -width/2 ~ width/2 -> cross fading
// +width/2 ~ width*(1.5) -> right fade-out
let panleft_start = this.spread * (-1.5);
let panleft_end = this.spread * (-0.5);
let panright_start = this.spread * (0.5);
let panright_end = this.spread * (1.5);
//left fade-in
if (this.angerr > panleft_start && this.angerr < panleft_end) {
this.pv.pan.value = -1; //left-full
this.pv.volume.exponentialRampTo(this.distvol + map(this.angerr, panleft_start, panleft_end, -50, 0), 3); //(dB)
}
//cross fading
else if (this.angerr > panleft_end && this.angerr < panright_start) {
this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1); // crossfade
this.pv.volume.exponentialRampTo(this.distvol, 3); //(dB)
}
//right fade-out
else if (this.angerr > panright_start && this.angerr < panright_end) {
this.pv.pan.value = 1; //right-full
this.pv.volume.exponentialRampTo(this.distvol + map(this.angerr, panright_start, panright_end, 0, -50), 3); //(dB)
}
//slience
else {
this.pv.pan.value = 0; //silent
this.pv.volume.exponentialRampTo(-99, 10); //(dB)
}
}
draw() {
//draw sound location
}
}
//p5
class Compass {
constructor(size, colors) {
this.size = size;
this.colors = colors;
this.heading = 0;
}
draw() {
push();
//
scale(this.size);
//
translate(0.5, 0.5);
//
noStroke();
//
fill(this.colors[0]);
circle(0, 0, 0.9);
//
fill(this.colors[1]);
rotate(this.heading);
quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
//
fill(this.colors[2]);
circle(0, 0, 0.1);
//
pop();
}
}
let compass_target;
let compass_north;
let sounds = [];
async function preload() {
//some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
//register sounders to the list
sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
//preload all sounds
sounds.forEach(async item => await item.load());
}
function setup() {
createCanvas(windowWidth, windowHeight);
compass_target = new Compass(windowWidth - 100, ['springgreen', 'navy', 'white']);
compass_north = new Compass(40, ['yellow', 'navy', 'white']);
angleMode(DEGREES);
}
let lines = 0;
let linestep = 20;
function textline(t, restart) {
if (restart) lines = 0;
else lines = lines + 1;
text(t, 0, linestep * lines);
}
function draw() {
//
background('olive');
//all data is ready to be used.
if (ready) {
//update sounders
sounds.forEach(async item => await item.update());
//
let target = sounds[0];
////main group
//(push)
push();
//compass (the North)
translate((windowWidth - compass_target.size) / 2, (windowWidth - compass_target.size) / 2, 0);
compass_target.heading = target.angerr; //target #0
compass_target.draw();
//debug
fill('white');
translate(-30, 0, 0);
textline('angerr', true);
textline(target.angerr);
textline('distance');
textline(target.dist);
textline('pan');
textline(target.pv.pan.value);
textline('distvol');
textline(target.distvol);
textline('vol');
textline(target.pv.volume.value);
textline('target_lat');
textline(target.latitude);
textline('target_lon');
textline(target.longitude);
//(gap)
translate(0, compass_target.size, 0);
//gps
translate(0, 20, 0);
fill('white');
textline('current location', true);
textline(latitude);
textline(longitude);
//
//(pop)
pop();
////status group
//(push)
push();
//
translate(windowWidth - 50, windowHeight - 50, 0);
compass_north.heading = heading;
compass_north.draw();
//(pop)
pop();
}
}
</script>
</body>
</html>

99
archive/stream_ios.html Normal file
View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="js/p5.min.js"></script>
<script src="js/Tone.min.js"></script>
<title>Sketch</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
.overlay-userinput {
display: grid;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 255, 255, 0.5);
color: black;
z-index: 2;
/* display: none; */
}
</style>
</head>
<body>
<button class='overlay-userinput' onclick='requestPermissions();'>
<div>터치하고-시작하기!</div>
</button>
<!-- <audio controls>
<source src="https://radio.dianaband.in:8000/stream" type="audio/aac" />
<source src="audio/delayecho.mp3" type="audio/mpeg" />
</audio> -->
<script>
// const audioCtx = new AudioContext();
// const myAudio = document.querySelector("audio");
// const source = audioCtx.createMediaElementSource(myAudio);
// const gainNode = audioCtx.createGain();
// gainNode.gain.value = 1;
// // source.connect(gainNode);
// gainNode.connect(audioCtx.destination);
// https://radio.dianaband.in:8000/stream
let silence;
let clap;
//clear all permissions
function requestPermissions() {
// sound playback permission
silence.start();
clap.start();
//
let veil = document.querySelector(".overlay-userinput");
veil.style.display = 'none';
//
ready = true;
}
//promisify -> new Tone.Player
function AudioImport(url) {
return new Promise((resolve, reject) => {
var audio = new Tone.Player(url, () => resolve(audio));
});
}
async function preload() {
//some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
}
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
}
</script>
</body>
</html>

72
archive/webaudio_ios.html Normal file
View file

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="js/p5.min.js"></script>
<script src="js/Tone.min.js"></script>
<title>Sketch</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
.overlay-userinput {
display: grid;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 255, 255, 0.5);
color: black;
z-index: 2;
/* display: none; */
}
</style>
</head>
<body>
<button id='btn' class='overlay-userinput' onclick='requestPermissions();'>
<div>터치하고-시작하기!</div>
</button>
<!-- <audio controls>
<source src="https://radio.dianaband.in:8000/stream" type="audio/aac" />
<source src="audio/delayecho.mp3" type="audio/mpeg" />
</audio> -->
<script>
function requestPermissions() {
const audio = new Audio();
audio.crossOrigin = "anonymous";
const AudioContext = window.AudioContext || window.webkitAudioContext,
audioCtx = new AudioContext(),
audioSrc = audioCtx.createMediaElementSource(audio);
audioSrc.connect(audioCtx.destination);
audio.addEventListener('canplaythrough', () => {
audio.play();
audio.src = 'https://radio.dianaband.in:8000/stream';
audio.type = 'audio/aac'
audio.load();
};
</script>
</body>
</html>

447
archive/wonjung.html Normal file
View file

@ -0,0 +1,447 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<script src="js/p5.min.js"></script>
<script src="js/Tone-14.8.36.min.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
.overlay-userinput {
display: grid;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
color: white;
z-index: 2;
/* display: none; */
}
</style>
</head>
<body>
<button class='overlay-userinput' onclick='requestPermissions();'>
<div>터치하고-시작하기!</div>
</button>
<script>
//
//shared
//device location & motion
let heading = 0;
let latitude = 37.576762;
let longitude = 126.931267;
// let latitude = 0;
// let longitude = 0;
//audio playback permission checker
let silence;
let clap;
//all ready flag (not used)
let ready = false;
//promisify -> new Tone.Player
function AudioImport(url) {
return new Promise((resolve, reject) => {
var audio = new Tone.Player(url, () => resolve(audio));
});
}
//clear all permissions
function requestPermissions() {
// device orientation data permission
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
requestOrientationPermission();
}
// sound playback permission
silence.start();
//
let veil = document.querySelector(".overlay-userinput");
veil.style.display = 'none';
//
ready = true;
}
//gps, heading
//get permissions
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
function requestOrientationPermission() {
DeviceOrientationEvent
.requestPermission()
.then(response => {
if (response == 'granted') {
window.addEventListener("deviceorientation", (event) => {
if (event.webkitCompassHeading) {
heading = event.webkitCompassHeading * -1;
}
}, true);
}
})
.catch(console.error)
}
} else {
window.addEventListener("deviceorientationabsolute", (event) => {
heading = event.alpha;
}, true);
}
const watchID = navigator.geolocation.watchPosition(
(position) => {
//latitude = position.coords.latitude;
//longitude = position.coords.longitude;
},
(error) => {}, {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000,
}
);
//distance between 2 locations (lat/lon)
function getDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
//bearing between 2 locations (lat/lon)
// Converts from degrees to radians.
function toRadians(degrees) {
return degrees * Math.PI / 180;
};
// Converts from radians to degrees.
function toDegrees(radians) {
return radians * 180 / Math.PI;
}
// const y = Math.sin(λ2-λ1) * Math.cos(φ2);
// const x = Math.cos(φ1)*Math.sin(φ2) -
// Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
// const θ = Math.atan2(y, x);
// const brng = (θ*180/Math.PI + 360) % 360; // in degrees
function getBearing(startLat, startLng, destLat, destLng) {
startLat = toRadians(startLat);
startLng = toRadians(startLng);
destLat = toRadians(destLat);
destLng = toRadians(destLng);
y = Math.sin(destLng - startLng) * Math.cos(destLat);
x = Math.cos(startLat) * Math.sin(destLat) -
Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
brng = Math.atan2(y, x);
brng = toDegrees(brng);
return (brng + 360) % 360;
}
// sounds
class Sounder {
constructor(args) {
this.soundfile = args.soundfile;
this.gain = args.gain; // (dB)
this.latitude = args.location[0];
this.longitude = args.location[1];
this.spread = args.spread; // (deg)
this.distmap = args.distmap;
this.volmin = args.volmin; // (dB)
this.ramptime = args.ramptime; // (seconds)
}
async load() {
//start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination();
this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here.
this.snd.connect(this.pv).start();
this.snd.loop = true;
}
update() {
//
//update sound pan/volume
//
this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); // (deg)
this.angerr = (((heading - this.ang + 360) % 360) + 180) % 360 - 180;
this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); // (km)
//
this.distvol = map(this.dist, this.distmap[0], this.distmap[1], this.distmap[2], this.distmap[3], true); //(dB)
// (from Pure Data patch "iamyou", [eqpan2~])
// arg #1 (inlet #3): width:
// -width*(1.5) ~ -width/2 -> left fade-in
// -width/2 ~ width/2 -> cross fading
// +width/2 ~ width*(1.5) -> right fade-out
let panleft_start = this.spread * (-1.5);
let panleft_end = this.spread * (-0.5);
let panright_start = this.spread * (0.5);
let panright_end = this.spread * (1.5);
//left fade-in
if (this.angerr > panleft_start && this.angerr < panleft_end) {
this.pv.pan.value = -1; //left-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panleft_start, panleft_end, this.volmin, 0), this.ramptime); //(dB)
}
//cross fading
else if (this.angerr > panleft_end && this.angerr < panright_start) {
this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1); // crossfade
this.pv.volume.rampTo(this.distvol + this.gain, this.ramptime); //(dB)
}
//right fade-out
else if (this.angerr > panright_start && this.angerr < panright_end) {
this.pv.pan.value = 1; //right-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panright_start, panright_end, 0, this.volmin), this.ramptime); //(dB)
}
//slience
else {
this.pv.volume.rampTo(-99, 10); //(dB)
}
}
draw() {
//draw sound location
}
}
//p5
class Compass {
constructor(size, colors) {
this.size = size;
this.colors = colors;
this.heading = 0;
}
draw() {
push();
//
scale(this.size);
//
translate(0.5, 0.5);
//
noStroke();
//
fill(this.colors[0]);
circle(0, 0, 0.9);
//
fill(this.colors[1]);
rotate(this.heading);
quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
//
fill(this.colors[2]);
circle(0, 0, 0.1);
//
pop();
}
}
let compass_target;
let compass_north;
let sounds = [];
async function preload() {
//some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
//register sounders to the list
sounds.push(new Sounder({
location: [35.574593, 126.925577],
soundfile: "./audio/minok01.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [35.574411, 126.925311],
soundfile: "./audio/minok02.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [37.573811, 126.924411],
soundfile: "./audio/minok03.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [37.572811, 126.923511],
soundfile: "./audio/minok04.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
sounds.push(new Sounder({
location: [37.571711, 126.922311],
soundfile: "./audio/minok05.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
// sounds.push(new Sounder("./audio/delayecho.mp3", 37.57451, 126.92612, 30));
//preload all sounds
sounds.forEach(async item => await item.load());
}
function setup() {
createCanvas(windowWidth, windowHeight);
compass_target1 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_target2 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_target3 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_target4 = new Compass(100, ['springgreen', 'navy', 'white']);
compass_north = new Compass(40, ['yellow', 'navy', 'white']);
angleMode(DEGREES);
}
let lines = 0;
let linestep = 20;
function textline(t, restart) {
if (restart) lines = 0;
else lines = lines + 1;
text(t, 0, linestep * lines);
}
function draw() {
//
background('olive');
//all data is ready to be used.
if (ready) {
//update sounders
sounds.forEach(async item => await item.update());
//
let target = sounds[0];
////main group
//(push)
push();
//compass (the North)
translate(20, 20, 0);
compass_target1.heading = sounds[0].angerr; //target #0
compass_target1.draw();
translate(100, 0, 0);
compass_target2.heading = sounds[1].angerr; //target #0
compass_target2.draw();
translate(-100, 100, 0);
compass_target3.heading = sounds[2].angerr; //target #0
compass_target3.draw();
translate(100, 0, 0);
compass_target4.heading = sounds[3].angerr; //target #0
compass_target4.draw();
//(pop)
pop();
//(push)
push();
//debug
fill('white');
translate(30, 200, 0);
textline('angerr', true);
textline(target.angerr);
textline('distance');
textline(target.dist);
textline('pan');
textline(target.pv.pan.value);
textline('distvol');
textline(target.distvol);
textline('vol');
textline(target.pv.volume.value);
textline('target_lat');
textline(target.latitude);
textline('target_lon');
textline(target.longitude);
//(pop)
pop();
////status-left group
//(push)
push();
//
translate(20, windowHeight - 100, 0);
fill('white');
textline('current location', true);
textline(latitude);
textline(longitude);
//(pop)
pop();
////status-right group
//(push)
push();
//
translate(windowWidth - 50, windowHeight - 50, 0);
compass_north.heading = heading;
compass_north.draw();
//(pop)
pop();
}
}
</script>
</body>
</html>

BIN
audio/01.mp3 Normal file

Binary file not shown.

BIN
audio/02.mp3 Normal file

Binary file not shown.

BIN
audio/03.mp3 Normal file

Binary file not shown.

BIN
audio/04.mp3 Normal file

Binary file not shown.

BIN
audio/102.mp3 Normal file

Binary file not shown.

BIN
audio/_silence.wav Normal file

Binary file not shown.

BIN
audio/clap01.mp3 Normal file

Binary file not shown.

BIN
audio/delayecho.mp3 Normal file

Binary file not shown.

BIN
audio/minok01.mp3 Normal file

Binary file not shown.

BIN
audio/minok02.mp3 Normal file

Binary file not shown.

BIN
audio/minok03.mp3 Normal file

Binary file not shown.

BIN
audio/minok04.mp3 Normal file

Binary file not shown.

BIN
audio/minok05.mp3 Normal file

Binary file not shown.

BIN
audio/minok1frequency.mp3 Normal file

Binary file not shown.

BIN
audio/minok2transpose.mp3 Normal file

Binary file not shown.

BIN
audio/minok3delay.mp3 Normal file

Binary file not shown.

BIN
audio/minok4eq.mp3 Normal file

Binary file not shown.

24
css/default.css Normal file
View file

@ -0,0 +1,24 @@
html,
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
.overlay-userinput {
display: grid;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
color: white;
z-index: 2;
/* display: none; */
}

215
index.html Normal file
View file

@ -0,0 +1,215 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<!-- lib -->
<script src="js/p5.min.js"></script>
<script src="js/Tone.min.js"></script>
<!-- css -->
<link rel="stylesheet" href="css/default.css">
<!-- script -->
<script>
const AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx;
</script>
<script src="js/util.js"></script>
<script src="js/classes.js"></script>
</head>
<body>
<button class='overlay-userinput' onclick='initialize();'>
<div>터치하고-시작하기!</div>
</button>
<audio controls crossorigin="anonymous" style="display:none;">
<!-- <source src="https://radio.dianaband.in:8000/stream" type="audio/aac" /> -->
</audio>
<script>
//shared
//device location & motion
let heading = 0;
let latitude = 37.574973;
let longitude = 126.925708;
// let latitude = 37.576774;
// let longitude = 126.931232;
// 맞는 결과 (예) : 작업실 -> 베지스
// p1 = [37.574973, 126.925708]
// p2 = [37.576774, 126.931232]
// getBearing(p1[0], p1[1], p2[0], p2[1])
// 67.6373956496954 (deg)
// getDistance(p1[0], p1[1], p2[0], p2[1])
// 0.5263963610554471 (km)
//audio playback permission checker
let silence;
let clap;
let radio;
//all ready flag (not used)
let ready = false;
//clear all permissions
async function initialize() {
// device orientation data permission
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
requestOrientationPermission();
}
// start audiocontext
audioCtx = new AudioContext;
// some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
// start loading for all sounds
sounds.forEach(async item => await item.load());
// unfreeze audio playback for Tone.js
silence.start();
// remove the veil
let veil = document.querySelector(".overlay-userinput");
veil.style.display = 'none';
// activate radio by adding source tag
const audiotag = document.querySelector('audio'); // N.B. assuming there's only 1 audio tag for streaming...
const sourcetag = document.createElement('source');
sourcetag.setAttribute('src', 'https://radio.dianaband.in:8000/stream');
sourcetag.setAttribute('type', 'audio/aac');
audiotag.appendChild(sourcetag);
audiotag.play();
// //link a sounder object to radio streaming..
// radio = new Sounder({
// // location: [37.576013, 126.927912],
// location: [37.574973, 126.935708],
// soundfile: "./audio/clap01.mp3",
// gain: 6,
// spread: 15,
// distmap: [0.005, 0.05, 0, -10],
// //testing
// volmin: -30,
// });
// // radio.radiolink(audiotag);
// radio.load();
//
ready = true;
}
let compass_target;
let compass_north;
let sounds = [];
function setup() {
createCanvas(windowWidth, windowHeight);
compass_target = new Compass(200, ['#97FFFF', '#33A1DE', 'white']);
compass_north = new Compass(40, ['yellow', 'navy', 'white']);
angleMode(DEGREES);
// register sounders to the list
sounds.push(new Sounder({
location: [37.576774, 126.931232],
soundfile: "./audio/01.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
}
function draw() {
//
background('#202325');
//all data is ready to be used.
if (ready) {
//update sounders
sounds.forEach(async item => await item.update());
// radio.update();
//
let target = sounds[0];
////main group
//(push)
push();
//compass (the North)
translate(20, 20, 0);
compass_target.heading = target.angerr; //target #0
compass_target.draw();
//(pop)
pop();
//(push)
push();
//debug
fill('white');
translate(30, 200, 0);
Textline.restart();
Textline.put('ang');
Textline.put(target.ang);
Textline.put('angerr');
Textline.put(target.angerr);
Textline.put('distance');
Textline.put(target.dist);
// Textline.put('pan');
// Textline.put(target.pv.pan.value);
// Textline.put('distvol');
// Textline.put(target.distvol);
// Textline.put('vol');
// Textline.put(target.pv.volume.value);
Textline.put('target_lat');
Textline.put(target.latitude);
Textline.put('target_lon');
Textline.put(target.longitude);
//(pop)
pop();
////status-left group
//(push)
push();
//
translate(20, windowHeight - 100, 0);
fill('white');
Textline.restart();
Textline.put('current location');
Textline.put(latitude);
Textline.put(longitude);
//(pop)
pop();
////status-right group
//(push)
push();
//
translate(windowWidth - 50, windowHeight - 50, 0);
compass_north.heading = heading;
compass_north.draw();
//(pop)
pop();
}
}
</script>
</body>
</html>

1
js/Tone-14.8.36.min.js vendored Normal file

File diff suppressed because one or more lines are too long

17
js/Tone.min.js vendored Normal file

File diff suppressed because one or more lines are too long

117
js/classes.js Normal file
View file

@ -0,0 +1,117 @@
// sounds
class Sounder {
constructor(args) {
this.soundfile = args.soundfile;
this.gain = args.gain; // (dB)
this.latitude = args.location[0];
this.longitude = args.location[1];
this.spread = args.spread; // (deg)
this.distmap = args.distmap;
this.volmin = args.volmin; // (dB)
this.ramptime = args.ramptime; // (seconds)
}
async load() {
//start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination();
this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here.
// this.snd.connect(this.pv).start();
this.snd.connect(this.pv);
this.snd.loop = true;
}
update() {
//
//update sound pan/volume
//
// this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); (deg)
this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); // (deg)
this.angerr = (((this.ang - heading + 360) % 360) + 180) % 360 - 180;
this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); // (km)
//
this.distvol = map(this.dist, this.distmap[0], this.distmap[1], this.distmap[2], this.distmap[3], true); //(dB)
// (from Pure Data patch "iamyou", [eqpan2~])
// arg #1 (inlet #3): width:
// -width*(1.5) ~ -width/2 -> left fade-in
// -width/2 ~ width/2 -> cross fading
// +width/2 ~ width*(1.5) -> right fade-out
let panleft_start = this.spread * (-1.5);
let panleft_end = this.spread * (-0.5);
let panright_start = this.spread * (0.5);
let panright_end = this.spread * (1.5);
//left fade-in
if (this.angerr > panleft_start && this.angerr < panleft_end) {
this.pv.pan.value = -1; //left-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panleft_start, panleft_end, this.volmin, 0), this.ramptime)//cross fading; //(dB)
} else if (this.angerr > panleft_end && this.angerr < panright_start) {
this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1); // crossfade
this.pv.volume.rampTo(this.distvol + this.gain, this.ramptime)//right fade-out; //(dB)
} else if (this.angerr > panright_start && this.angerr < panright_end) {
this.pv.pan.value = 1; //right-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panright_start, panright_end, 0, this.volmin), this.ramptime)//slience; //(dB)
} else {
this.pv.volume.rampTo(-99, 10); //(dB)
}
}
draw() {
//draw sound location
}
}
//
class RadioSounder extends Sounder {
//do nothing
async load() {
;
}
link(audiotag) {
//start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination();
let stream = Tone.context.createMediaElementSource(audiotag);
this.snd = Tone.context.createGain();
stream.connect(this.snd);
console.log(stream);
console.log(this.snd);
console.log(this.pv);
// this.snd.connect(this.pv.input.input); a hack ...
this.snd.gain.value = 1;
this.snd.connect(Tone.context.destination);
}
}
//p5
class Compass {
constructor(size, colors) {
this.size = size;
this.colors = colors;
this.heading = 0;
}
draw() {
push();
//
scale(this.size);
//
translate(0.5, 0.5);
//
noStroke();
//
fill(this.colors[0]);
circle(0, 0, 0.9);
//
fill(this.colors[1]);
rotate(this.heading);
quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
//
fill(this.colors[2]);
circle(0, 0, 0.05);
//
pop();
}
}

4
js/hls.min.js vendored Normal file

File diff suppressed because one or more lines are too long

28
js/p5-v0.3.11.sound.min.js vendored Normal file

File diff suppressed because one or more lines are too long

3
js/p5-v1.1.9.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
js/p5.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

87
js/two-v0.8.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

100
js/util.js Normal file
View file

@ -0,0 +1,100 @@
//gps, heading
//get permissions
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
function requestOrientationPermission() {
DeviceOrientationEvent
.requestPermission()
.then(response => {
if (response == 'granted') {
window.addEventListener("deviceorientation", (event) => {
if (event.webkitCompassHeading) {
heading = event.webkitCompassHeading;
}
}, true);
}
})
.catch(console.error)
}
} else {
window.addEventListener("deviceorientationabsolute", (event) => {
heading = event.alpha * -1;
}, true);
}
const watchID = navigator.geolocation.watchPosition(
(position) => {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
},
(error) => {}, {
enableHighAccuracy: true,
maximumAge: 30000,
timeout: 27000,
}
);
//distance between 2 locations (lat/lon)
function getDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
//bearing between 2 locations (lat/lon)
// Converts from degrees to radians.
function toRadians(degrees) {
return degrees * Math.PI / 180;
};
// Converts from radians to degrees.
function toDegrees(radians) {
return radians * 180 / Math.PI;
}
// const y = Math.sin(λ2-λ1) * Math.cos(φ2);
// const x = Math.cos(φ1)*Math.sin(φ2) -
// Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
// const θ = Math.atan2(y, x);
// const brng = (θ*180/Math.PI + 360) % 360; in degrees
function getBearing(startLat, startLng, destLat, destLng) {
startLat = toRadians(startLat);
startLng = toRadians(startLng);
destLat = toRadians(destLat);
destLng = toRadians(destLng);
y = Math.sin(destLng - startLng) * Math.cos(destLat);
x = Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
brng = Math.atan2(y, x);
brng = toDegrees(brng);
return (brng + 360) % 360;
}
//promisify -> new Tone.Player
function AudioImport(url) {
return new Promise((resolve, reject) => {
var audio = new Tone.Player(url, () => resolve(audio));
});
}
// some p5 tools
class Textline {
static #lines = 0;
static #linestep = 20;
static restart() {
Textline.#lines = 0;
}
static put(t) {
Textline.#lines = Textline.#lines + 1;
text(t, 0, Textline.#linestep * Textline.#lines);
}
}