-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsound_track_looper_two.js
292 lines (261 loc) · 12.1 KB
/
sound_track_looper_two.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/**
* file: sound_track_looper_two.js
* type: JavaScript
* author: karbytes
* date: 26_JANUARY_2025
* license: PUBLIC_DOMAIN
*/
let track_count = 1; // This global variable is used to keep track how many sound track file menus are added to the application user interface (and is 1 immediately after the page is loaded).
/**
* Dynamically add a new sound track menu to the application web page (and increment the global variable named track_count).
*
* Assume this function is called in response to the add_another_sound_file_menu() button being clicked.
*
* Also append a time-stamped message to the output DIV indicating when this function was called (assumedly by the add button being clicked).
*/
function add_another_sound_file_menu() {
try {
// Generate a time-stamped message string containing the (approximate) number of milliseconds which have elapsed since the Unix Epoch (i.e. 12:00AM Coordinated Universal Time on 01_JANUARY_1970).
const message = "The add_another_sound_file_menu() button was clicked at time: " + generate_time_stamp();
let sound_file_menu_area = document.getElementById("sound_file_menu_area");
// Create a new paragraph (i.e. <p>) element.
let new_paragraph = document.createElement("p");
// Create a new menu (i.e. <select>) element.
let new_select = document.createElement("select");
new_select.id = "sound_file_menu_" + track_count;
// Populate the <select> with menu options.
new_select.innerHTML = get_menu_options();
// Append the <select> to the <p>.
new_paragraph.appendChild(new_select);
// Append the <p> to the menu area.
sound_file_menu_area.appendChild(new_paragraph);
// Increment the track count by one.
track_count += 1;
// Append a new paragraph element to the DIV element on the respective web page whose ID is "console_display".
document.getElementById("console_display").innerHTML += (('<' + 'p' + '>') + message + ('<' + '/' + 'p' + '>'));
}
catch(e) {
console.log("An exception to normal functioning occurred during the runtime of add_another_sound_file_menu(): " + e);
}
}
/**
* Extract the sound file portion from a Uniform Resource Locator (URL).
*
* @param {String} url - The full URL to the sound track file.
*
* @return {String} The sound file portion of the URL.
*/
function extractSoundFileName(url) {
try {
// Use the last index of '/' to find the start of the file name.
const fileName = url.substring(url.lastIndexOf('/') + 1);
return fileName;
}
catch (e) {
console.error("An error occurred in extractSoundFileName:", e);
return "";
}
}
/**
* Get the Number of milliseconds which have elapsed since the Unix Epoch.
*
* The Unix Epoch is 01_JANUARY_1970 at midnight (Coordinated Universal Time (UTC)).
*
* @return {String} message displaying the time at which this function was called.
*/
function generate_time_stamp() {
const milliseconds_elapsed_since_unix_epoch = Date.now();
return milliseconds_elapsed_since_unix_epoch + " milliseconds since midnight on 01_JANUARY_1970.";
}
/**
* Generate an HTML formatted string which represents the list of OPTIONs displayed by a SELECT menu.
*
* By clicking on the SELECT element, a scrollable list of OPTIONs will appear.
*
* @return {String} a sequence of characters representing some natural number of OPTIONs inside of a SELECT menu.
*/
function get_menu_options() {
let file_path_root = 'http://qkbrwfubnh4knc6kkhx6uepccavpwezdf2al7w2quepe3qociegsi3yd.onion/KARBYTES_BLOG_APPS/SOUND_TRACK_LOOP_COUNTER_TWO/';
let HTML_string = '';
// Define the list of sound eleven sound files and their display names.
const sound_files = [
'frogs_croaking_in_castro_valley_california_21_april_2022.mp3',
'coyote_vocalizations_01_july_2023.mp3',
'karbytes_drums_castro_valley_california_12_december_2022.mp3',
'drums_karbytes_10_september_2023_part_0.mp3',
'karbytes_guitar_castro_valley_california_12_december_2022.mp3',
'karbytes_guitar_13_may_2023.mp3',
'karbytes_guitar_07_june_2023.mp3',
'karbytes_guitar_16_october_2023.mp3',
'karbytes_drums_20_october_2023.mp3',
'guitar_karbytes_13july2024.mp3',
'guitar_karbytes_20august2024.mp3'
];
// Build the HTML string for each sound file
sound_files.forEach((file, index) => {
const selected = index === 0 ? ' selected' : ''; // Make the first option selected.
HTML_string += `<option value="${file_path_root + file}"${selected}>${file}</option>`;
});
return HTML_string;
}
/**
* Return the value of the selected menu OPTION of a SELECT menu element.
*
* @param {String} select_menu_identifier is the identifier (id) of a SELECT HTML element.
*
* @return {String} the value of the selected menu OPTION.
*/
function get_selected_menu_option_value(select_menu_identifier) {
try {
let menu_object = {}, options_array = [], selected_option_index = 0, selected_option_object = {}, selected_option_value;
menu_object = document.getElementById(select_menu_identifier);
options_array = menu_object.options;
selected_option_index = menu_object.selectedIndex;
selected_option_object = options_array[selected_option_index];
selected_option_value = selected_option_object.value
return selected_option_value;
}
catch(e) {
console.log("An exception to normal functioning occurred during the runtime of get_selected_menu_option(select_menu_identifier): " + e);
}
}
/**
* Assume that this function is called whenever the web page file is opened or refreshed by a web browser.
*
* Display a time-stamped message which indicates the time at which the web page was opened as GREEN text inside the DIV at the bottom of the web page.
*
* Set the CYAN SPAN text which displays the number of seconds elapsed after the start_sound_track_looper() button is clicked to the value 0.
*
* Set the CYAN SPAN text which displays the number of times the selected audio track is played to the value 0.
*
* Populate the sound file SELECT menu with multiple sound file OPTIONs.
*
* Set the start_sound_track_looper() button to be visible rather than hidden to the application end user.
*
* If a runtime error occurs, use the try-catch block to perform exception handling by displaying a relevant web console message.
*/
/*
function load_web_page() {
try {
const message = "The web page was loaded by the web browser at time: " + generate_time_stamp();
document.getElementById("console_display").innerHTML = message;
document.getElementById("seconds_elapsed_display").innerHTML = "0";
document.getElementById("loops_completed_display").innerHTML = "0";
document.getElementById("sound_file_menu_0").innerHTML = get_menu_options();
document.getElementById("file_selected_display").innerHTML = get_selected_menu_option_value("sound_file_menu_0");
document.getElementById("the_button").style.display = "block";
}
catch(e) {
console.log("An exception to normal functioning occurred during the runtime of load_web_page(): " + e);
}
}
*/
/**
* Assume that this function is called whenever the web page file is opened or refreshed by a web browser.
*
* Display a time-stamped message which indicates the time at which the web page was opened as GREEN text inside the DIV at the bottom of the web page.
*
* Set the CYAN SPAN text which displays the number of seconds elapsed after the start_sound_track_looper() button is clicked to the value 0.
*
* Set the CYAN SPAN text which displays the number of times the selected audio track is played to the value 0.
*
* Populate the sound file SELECT menu with multiple sound file OPTIONs.
*
* Set the start_sound_track_looper() button to be visible rather than hidden to the application end user.
*
* If a runtime error occurs, use the try-catch block to perform exception handling by displaying a relevant web console message.
*/
function load_web_page() {
try {
const message = "The web page was loaded by the web browser at time: " + generate_time_stamp();
const menuElement = document.getElementById("sound_file_menu_0");
if (menuElement) {
menuElement.innerHTML = get_menu_options();
console.log("Menu populated successfully.");
}
else {
console.error("Menu element not found during load_web_page().");
}
document.getElementById("console_display").innerHTML = message;
}
catch (e) {
console.error("An exception occurred in load_web_page():", e);
}
}
/**
* Assume that this function is called by the event of the start_sound_track_looper() button being clicked.
*
* Hide the add_another_sound_file_menu() button from the web page after that button is clicked.
*
* Hide the start_sound_track_looper() button from the web page after that button is clicked.
*
* Append a time-stamped message which indicates the time at which the button was clicked as green text to the DIV content at the bottom of the web page.
*
* Set the CYAN SPAN text which displays the number of times the each of the selected audio track is played to the value 0 (and increment by one each second after that indefinitely).
*
* Start playing the selected sound file(s) for an indefinite number of times and start incrementing the number of seconds elapsed and the number of times each sound track is played.
*
* If a runtime error occurs, use the try-catch block to perform exception handling by displaying a relevant web console message.
*/
function start_sound_track_looper() {
try {
const message = "The start_sound_track_looper() button was clicked at time: " + generate_time_stamp();
let sound_track_array = [];
//let elapsed_seconds_display = document.getElementById("seconds_elapsed_display");
let output_display = document.getElementById("output");
let console_display = document.getElementById("console_display");
let add_button = document.getElementById("add_another_sound_file_menu_button");
let start_button = document.getElementById("the_button");
// Hide the buttons.
add_button.style.display = "none";
start_button.style.display = "none";
// Reset the elapsed seconds display.
//elapsed_seconds_display.innerHTML = "0";
// Clear the content which is initially displayed in the output display element (DIV).
output_display.innerHTML = "";
// Loop through each track and set up the player.
for (let i = 0; i < track_count; i++) {
const menu_id = "sound_file_menu_" + i;
const sound_file_name = extractSoundFileName(get_selected_menu_option_value(menu_id));
// Create an audio object for the track.
const audio_file = new Audio(get_selected_menu_option_value(menu_id));
const loops_display_id = `loops_completed_${i}`;
const elapsed_display_id = `elapsed_seconds_${i}`;
// Add a track object for managing its data.
sound_track_array.push(
{
sound_track_name: sound_file_name,
loops_completed: 0,
elapsed_seconds: 0,
audio: audio_file,
}
);
// Create dynamic loop and elapsed displays for the track.
const track_display_html = `
<p>* * *</p>
<p>Sound Track: ${sound_file_name}</p>
<p>Loops Completed: <span id="${loops_display_id}">0</span></p>
<p>Seconds Elapsed: <span id="${elapsed_display_id}">0</span></p>
`;
// Replace the content which is displayed in the output DIV with the sound track data.
output_display.innerHTML += track_display_html;
if (i == (track_count - 1)) output_display.innerHTML += '<p>* * *</p>';
// Play the sound and start tracking loops and elapsed time
audio_file.play();
setInterval(() => {
const track_data = sound_track_array[i];
track_data.elapsed_seconds += 1;
document.getElementById(elapsed_display_id).textContent = track_data.elapsed_seconds;
if (audio_file.ended) {
track_data.loops_completed += 1;
document.getElementById(loops_display_id).textContent = track_data.loops_completed;
audio_file.play(); // Restart the track
}
}, 1000);
}
console_display.innerHTML += `<p>${message}</p>`;
}
catch(e) {
console.log("An exception to normal functioning occurred during the runtime of start_sound_track_looper(): " + e);
}
}