Skip to content

Commit bd523bd

Browse files
committed
[feat] Add song progress / random access bar.
1 parent 999ee19 commit bd523bd

File tree

3 files changed

+110
-23
lines changed

3 files changed

+110
-23
lines changed

public/index.html

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ <h1>audioMotion</h1>
100100
</ul>
101101
</header>
102102

103-
<div class="player-panel grid align-center center">
103+
<div class="player-panel grid center">
104104
<div class="controls-left">
105105
<div>
106106
<div class="config-label">SOURCE</div>
@@ -148,6 +148,12 @@ <h1>audioMotion</h1>
148148
<div class="marker"></div>
149149
</div>
150150
</div>
151+
152+
<div class="progress-bar abs-center flex">
153+
<div id="current_time" class="small-display"></div>
154+
<input id="progress" class="custom-slider song-progress" type="range">
155+
<div id="song_duration" class="small-display"></div>
156+
</div>
151157
</div>
152158

153159
</div> <!-- .player-area -->
@@ -194,7 +200,7 @@ <h1>audioMotion</h1>
194200
</span>
195201
</span>
196202
<div class="value"></div>
197-
<input id="line_width" data-prop="lineWidth" type="range">
203+
<input id="line_width" data-prop="lineWidth" type="range" class="custom-slider">
198204
</div>
199205

200206
<div>
@@ -204,7 +210,7 @@ <h1>audioMotion</h1>
204210
</span>
205211
</span>
206212
<div class="value"></div>
207-
<input id="fill_alpha" data-prop="fillAlpha" type="range">
213+
<input id="fill_alpha" data-prop="fillAlpha" type="range" class="custom-slider">
208214
</div>
209215

210216
<!-- COLUMN 2 -->
@@ -253,7 +259,7 @@ <h1>audioMotion</h1>
253259
</span>
254260
</span>
255261
<div class="value"></div>
256-
<input id="spin" data-prop="spin" type="range">
262+
<input id="spin" data-prop="spin" type="range" class="custom-slider">
257263
</div>
258264

259265
<!-- COLUMN 3 -->
@@ -282,7 +288,7 @@ <h1>audioMotion</h1>
282288
</span>
283289
</span>
284290
<div class="value"></div>
285-
<input id="bg_img_dim" type="range" data-prop="bgImageDim">
291+
<input id="bg_img_dim" type="range" data-prop="bgImageDim" class="custom-slider">
286292
</div>
287293

288294
<div>
@@ -310,7 +316,7 @@ <h1>audioMotion</h1>
310316
</span>
311317
<div class="flex align-center">
312318
<select id="freq_min" data-prop="freqMin"></select>
313-
&nbsp;-&nbsp;
319+
&ndash;
314320
<select id="freq_max" data-prop="freqMax"></select>
315321
</div>
316322
</div>

src/index.js

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ const elAlphaBars = $('#alpha_bars'),
310310
elShowSong = $('#show_song'),
311311
elShowSubtitles = $('#show_subs'),
312312
elSmoothing = $('#smoothing'),
313+
elSongDuration = $('#song_duration'),
314+
elSongPosition = $('#current_time'),
315+
elSongProgress = $('#progress'),
313316
elSource = $('#source'),
314317
elSpin = $('#spin'),
315318
elSplitGrad = $('#split_grad'),
@@ -1048,22 +1051,28 @@ const saveLastDir = path => {
10481051
}
10491052

10501053
// format a value in seconds to a string in the format 'hh:mm:ss'
1051-
const secondsToTime = secs => {
1052-
if ( secs == Infinity || secs == -1 )
1054+
const secondsToTime = ( secs, forceHours ) => {
1055+
if ( Math.abs( secs ) == Infinity || secs === '-1' )
10531056
return 'LIVE';
10541057

1055-
let str = '',
1056-
lead = '';
1058+
let lead = '',
1059+
sign = '',
1060+
str = '';
10571061

1058-
if ( secs >= 3600 ) {
1062+
if ( secs < 0 ) {
1063+
secs = -secs;
1064+
sign = '-';
1065+
}
1066+
1067+
if ( secs >= 3600 || forceHours ) {
10591068
str = ( secs / 3600 | 0 ) + ':';
10601069
secs %= 3600;
10611070
lead = '0';
10621071
}
10631072

10641073
str += ( lead + ( secs / 60 | 0 ) ).slice(-2) + ':' + ( '0' + ( secs % 60 | 0 ) ).slice(-2);
10651074

1066-
return str;
1075+
return sign + str;
10671076
}
10681077

10691078
// update configuration options from an existing preset
@@ -4238,6 +4247,17 @@ function setUIEventListeners() {
42384247
skipTrack();
42394248
});
42404249

4250+
// song progress
4251+
elSongProgress.addEventListener( 'input', () => {
4252+
const audioEl = audioElement[ currAudio ],
4253+
{ duration } = audioEl;
4254+
if ( ! duration || duration == Infinity ) {
4255+
elSongProgress.value = 0;
4256+
return;
4257+
}
4258+
audioEl.currentTime = duration * elSongProgress.value;
4259+
});
4260+
42414261
// action buttons
42424262
$('#load_preset').addEventListener( 'click', () => {
42434263
const choices = [];
@@ -4910,6 +4930,17 @@ function updateRangeValue( el ) {
49104930
}
49114931
}
49124932

4933+
const audioOnTimeUpdate = e => {
4934+
if ( e.target != audioElement[ currAudio ] )
4935+
return;
4936+
4937+
const { currentTime, duration } = audioElement[ currAudio ];
4938+
4939+
elSongProgress.value = ! duration || duration == Infinity ? 0 : currentTime / duration;
4940+
elSongPosition.innerText = secondsToTime( currentTime, true );
4941+
elSongDuration.innerHTML = secondsToTime( ! duration ? 0 : currentTime - duration, true ).padEnd(6).replaceAll(' ','&nbsp;'); // make sure 'LIVE' is centered
4942+
}
4943+
49134944
// BEGIN INITIALIZATION -----------------------------------------------------------------------
49144945

49154946
// Log all JS errors to our UI console
@@ -5040,6 +5071,7 @@ function updateRangeValue( el ) {
50405071
audioElement[ i ].addEventListener( 'play', audioOnPlay );
50415072
audioElement[ i ].addEventListener( 'ended', audioOnEnded );
50425073
audioElement[ i ].addEventListener( 'error', audioOnError );
5074+
audioElement[ i ].addEventListener( 'timeupdate', audioOnTimeUpdate );
50435075
audioElement[ i ].querySelector('track').addEventListener( 'load', setSubtitlesPosition );
50445076

50455077
if ( panNode )
@@ -5048,6 +5080,10 @@ function updateRangeValue( el ) {
50485080
audioMotion.connectInput( audioElement[ i ] );
50495081
}
50505082

5083+
setRangeAtts( elSongProgress, 0, 1, .001 );
5084+
elSongProgress.value = 0;
5085+
elSongPosition.innerText = elSongDuration.innerText = secondsToTime( 0, true );
5086+
50515087
// Setup configuration panel
50525088
doConfigPanel();
50535089

src/styles.css

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
--audioMotion-gradient: linear-gradient( -45deg, #ffdf43, #fa5476, #c63bf3, #8550ff, #4a68f7, #23d2ff );
44
--audioMotion-gradient-transparent: linear-gradient( -45deg, #ffdf43cc, #fa5476cc, #c63bf3cc, #8550ffcc, #4a68f7cc, #23d2ffcc );
55
--background-image: none;
6+
--display-background: #1c231a;
67
--glass-gradient: linear-gradient( to bottom, #ffffff 0%, #f1f1f1 50%, #e1e1e1 51%, #f6f6f6 100% );
78
--glass-gradient-hover: linear-gradient( to bottom, #f2ffd3 0%, #e4f1c5 50%, #d4e1b5 51%, #e9f6ca 100% );
89
--glass-gradient-active: linear-gradient( to bottom, #bfd255 0%, #8eb92a 50%, #72aa00 51%, #9ecb2d 100% );
910
--light-color: #b2ff00;
1011
--metal-gradient: linear-gradient( to right, #7a7a7a, #ededed, #7a7a7a );
12+
--mono-font: 'JetBrains Mono', monospace;
1113
}
1214

1315
* {
@@ -222,37 +224,41 @@ a.button:visited {
222224
grid-template-rows: repeat(5, 1fr);
223225
padding: 0 5px;
224226
}
225-
.controls input,
227+
.controls input[type="number"],
226228
.controls form,
227229
.controls select {
228230
margin: 3px 0;
229231
padding-left: 0;
230232
padding-right: 0;
231233
width: 100%;
232234
}
235+
.controls select {
236+
height: 25px; /* mostly for Firefox, because emojis in the Background selection increase line height */
237+
}
238+
233239
/* custom range inputs - thanks https://www.smashingmagazine.com/2021/12/create-custom-range-input-consistent-browsers/ */
234-
.controls input[type="range"] {
240+
.custom-slider {
235241
-webkit-appearance: none;
236242
appearance: none;
237243
background: transparent;
238244
cursor: pointer;
239245
margin-top: 8px;
240246
width: 100%;
241247
}
242-
.controls input[type="range"]::-webkit-slider-runnable-track {
248+
.custom-slider::-webkit-slider-runnable-track {
243249
background: linear-gradient(rgba(0,0,0,.5),transparent),rgba(0,0,0,.2);
244250
border-radius: 999px;
245251
box-shadow: inset 1px 1px 0 rgba(0,0,0,.4), inset -1px -1px 0 rgba(0,0,0,.2);
246252
height: 4px;
247253
margin-top: 6px;
248254
}
249-
.controls input[type="range"]::-moz-range-track {
255+
.custom-slider::-moz-range-track {
250256
background: linear-gradient(rgba(0,0,0,.5),transparent),rgba(0,0,0,.2);
251257
border-radius: 999px;
252258
box-shadow: inset 1px 1px 0 rgba(0,0,0,.4), inset -1px -1px 0 rgba(0,0,0,.2);
253259
height: 4px;
254260
}
255-
.controls input[type="range"]::-webkit-slider-thumb {
261+
.custom-slider::-webkit-slider-thumb {
256262
-webkit-appearance: none;
257263
appearance: none;
258264
background: url(img/brushed-knob.png);
@@ -263,7 +269,7 @@ a.button:visited {
263269
margin-top: -7px;
264270
width: 16px;
265271
}
266-
.controls input[type="range"]::-moz-range-thumb {
272+
.custom-slider::-moz-range-thumb {
267273
background: url(img/brushed-knob.png);
268274
background-size: 100%;
269275
border: none;
@@ -603,6 +609,7 @@ div.value {
603609
grid-template-columns: 1fr minmax(350px,1fr) 1fr;
604610
margin: 10px auto 15px;
605611
max-width: 1400px;
612+
position: relative;
606613
}
607614

608615
.controls-left {
@@ -622,7 +629,6 @@ div.value {
622629
background: var(--glass-gradient);
623630
border-radius: 0;
624631
display: inline-block;
625-
margin: 5px 0;
626632
padding: 4px 10px 0;
627633
font-size: 30px;
628634
}
@@ -661,6 +667,45 @@ div.value {
661667
display: block;
662668
}
663669

670+
.progress-bar {
671+
align-items: flex-end;
672+
bottom: -10px;
673+
position: absolute;
674+
width: 45%;
675+
}
676+
.small-display {
677+
background: var(--display-background);
678+
border-radius: 3px;
679+
color: var(--light-color);
680+
font-family: var(--mono-font);
681+
font-size: 11px;
682+
margin: 0 10px;
683+
min-width: 63px;
684+
padding: 3px 5px;
685+
text-align: right;
686+
}
687+
.song-progress {
688+
height: 2px;
689+
margin: 0;
690+
padding: 6px 0 10px;
691+
}
692+
.song-progress::-webkit-slider-runnable-track {
693+
height: 2px;
694+
margin-top: 3px;
695+
}
696+
.song-progress::-moz-range-track {
697+
height: 2px;
698+
}
699+
.song-progress::-webkit-slider-thumb {
700+
height: 13px;
701+
margin-top: -6px;
702+
width: 13px;
703+
}
704+
.song-progress::-moz-range-thumb {
705+
height: 13px;
706+
width: 13px;
707+
}
708+
664709
.switch input {
665710
display: none;
666711
}
@@ -849,7 +894,7 @@ kbd {
849894
box-shadow: 0 1px 1px rgba(0,0,0,.2),0 2px 0 0 rgba(255,255,255,.7) inset;
850895
color: #333;
851896
display: inline-block;
852-
font-family: 'JetBrains Mono', monospace;
897+
font-family: var(--mono-font);
853898
font-size: .85em;
854899
font-weight: 600;
855900
height: 1.6em;
@@ -1063,10 +1108,10 @@ kbd.wide {
10631108
}
10641109

10651110
#console {
1066-
background: #1c231a;
1111+
background: var(--display-background);
10671112
bottom: -250px;
10681113
color: #0b0;
1069-
font-family: 'JetBrains Mono', monospace;
1114+
font-family: var(--mono-font);
10701115
font-size: 12.5px;
10711116
height: 250px;
10721117
left: 0;
@@ -1107,7 +1152,7 @@ kbd.wide {
11071152

11081153
#console-clear,
11091154
#console-close {
1110-
background: #1c231a;
1155+
background: var(--display-background);
11111156
border: 1px solid #0c0;
11121157
bottom: 220px;
11131158
color: #0c0;

0 commit comments

Comments
 (0)