Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ryan778
GitHub Repository: Ryan778/Ryan778.github.io
Path: blob/master/adaptive-music/script.js
574 views
1
var audio = document.getElementById('audio');
2
var micContext = null;
3
var meter = null;
4
var rafID = null;
5
var volbar_width = 200;
6
var player = {
7
vol: 0
8
}
9
var config = {
10
ver: 1,
11
pauseWhenQuiet: true, // pause the music when it goes below a threshold
12
invertVolume: true, // if true, louder mic = quieter music
13
curveUp: true, // apply secondary square root curve to increase overall volume
14
slowFade: true, // volume fades slower
15
active: true
16
}
17
18
function saveConfig(){
19
localStorage.adaptiveMusic = btoa(JSON.stringify(config))}
20
if(localStorage.adaptiveMusic){
21
try {
22
let newConfig = JSON.parse(atob(localStorage.adaptiveMusic));
23
if(newConfig.ver == config.ver) {
24
config = newConfig;
25
}
26
}
27
catch (e) {
28
M.toast({html: 'Your saved settings are corrupted, and have been reset.', classes: 'red darken-1'});
29
localStorage.removeItem(adaptiveMusic);
30
}
31
}
32
33
function reqMicPermission(){
34
try {
35
// borrowed from https://github.com/cwilso/volume-meter/blob/master/main.js under the MIT license
36
// monkeypatch getUserMedia
37
navigator.getUserMedia =
38
navigator.getUserMedia ||
39
navigator.webkitGetUserMedia ||
40
navigator.mozGetUserMedia;
41
42
// ask for an audio input
43
navigator.getUserMedia(
44
{
45
"audio": {
46
"mandatory": {
47
"googEchoCancellation": "false",
48
"googAutoGainControl": "false",
49
"googNoiseSuppression": "false",
50
"googHighpassFilter": "false"
51
},
52
"optional": []
53
},
54
}, gotStream, didntGetStream);
55
} catch (e) {
56
alert('getUserMedia threw exception :' + e);
57
}
58
}
59
60
var mediaStreamSource = null;
61
62
function didntGetStream() {
63
M.Modal.getInstance($('#m_permDenied')[0]).open();
64
}
65
66
function gotStream(stream) {
67
M.toast({html: 'Success! Starting Up...', classes: 'green darken-2'});
68
$('#btn_reqMic').prop('disabled', true);
69
$('#btn_reqMic').html(`<span class='green-text'><i class='fas fa-check'></i> </span><span class='black-text'>Success!</span>`)
70
71
// Create an AudioNode from the stream.
72
mediaStreamSource = micContext.createMediaStreamSource(stream);
73
74
// Create a new volume meter and connect it.
75
meter = createAudioMeter(micContext);
76
mediaStreamSource.connect(meter);
77
}
78
79
let volPeak = [0, 0] //[value, timestamp]
80
function updateMicInputValue(){
81
if(meter){
82
let w = volbar_width;
83
let rmv = meter.volume * 1.5;
84
let mv = Math.sqrt(rmv);
85
if(mv > 1.2){mv = 1.2} //Peak at 120% curved, 144% raw
86
let tval = mv;
87
if(tval < 0.01){tval = 0}
88
if(tval >= 0.1){tval = (tval*100).toFixed(1)}
89
else if(tval < 0.1){tval = (tval*100).toFixed(2)}
90
else{tval = '100'}
91
$('#vol-val').text(tval);
92
$('#vol-cur').css('width', (mv*w)+'px');
93
// }
94
if(volPeak[0] < mv && mv > 0.10){
95
volPeak[0] = mv;
96
volPeak[1] = Date.now();
97
$('#vol-peak').css('width', (mv*w)+'px');
98
$('#vp-val').text((mv*100).toFixed(1)+'%');
99
$('#vp-val').css('opacity', '1');
100
}
101
else if(Date.now() > volPeak[1] + 800){
102
if(volPeak < 0.15){
103
volPeak = 0;
104
$('#vol-peak').css('width', '0px');
105
$('#vp-val').css('opacity', '0');
106
}
107
else{
108
volPeak[0] *= (config.slowFade ? 0.9:0.8);
109
$('#vp-val').css('opacity', '0');
110
$('#vol-peak').css('width', (volPeak[0]*w)+'px');
111
}
112
}
113
player.vol = (volPeak[0] < 1 ? volPeak[0] : 1);
114
updateAudio();
115
}
116
}
117
118
function updateAudio(){
119
let rvol = player.vol; // resulting volume
120
if(config.curveUp){
121
rvol = Math.sqrt(rvol);
122
}
123
if(config.invertVolume){
124
rvol = 1 - rvol;
125
}
126
if(config.pauseWhenQuiet) {
127
rvol = (rvol - 0.1) * (10/9);
128
if(rvol < 0){
129
audio.volume = 0;
130
if(!audio.paused) audio.pause();
131
return;
132
}
133
if(audio.paused && config.active){
134
audio.play();
135
}
136
}
137
audio.volume = rvol;
138
}
139
140
function addFile(ele) {
141
let file = ele.files[0];
142
jsmediatags.read(file, {
143
onSuccess: tag => {
144
$('#audio_name').text(tag.tags.title + ' by ' + tag.tags.artist);
145
},
146
onError: e => {
147
// no ID3 tag
148
return;
149
}
150
});
151
let url = URL.createObjectURL(file);
152
$('#audio_name').text(file.name)
153
audio.src = url;
154
}
155
156
setInterval(updateMicInputValue, 50);
157
158
// On load stuff
159
window.onload = function() {
160
M.AutoInit();
161
162
// monkeypatch Web Audio
163
window.AudioContext = window.AudioContext || window.webkitAudioContext;
164
165
// grab an audio context
166
micContext = new AudioContext();
167
168
// initialize setting switches
169
$('.inp-setting').forEach((ele) => {
170
ele.checked = config[ele.dataset.for];
171
$(ele).on('change', (e) => {
172
let ele = e.target;
173
config[ele.dataset.for] = ele.checked;
174
saveConfig();
175
});
176
})
177
}
178