Загрузка данных


<!DOCTYPE html>
<html lang="ru">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Почасовая мелодия</title>
	<style>
	body {
		font-family: Arial, sans-serif;
		background: #f2f2f2;
		text-align: center;
		padding-top: 80px;
	}
	
	button {
		font-size: 18px;
		padding: 14px 24px;
		margin: 10px;
		border: none;
		border-radius: 8px;
		cursor: pointer;
		color: white;
	}
	
	#start {
		background: #2196f3;
	}
	
	#test {
		background: #4caf50;
	}
	
	#status {
		margin-top: 25px;
		font-size: 18px;
	}
	</style>
</head>

<body>
	<h1>&#128276; Почасовая мелодия</h1>
	<button id="start"> &#9654; Включить расписание </button>
	<button id="test"> &#128266; Тест — сыграть сейчас </button>
	<div id="status"> Расписание не запущено </div>
	<script>
	let audioContext = null;
	let timer = null;
	// ========================================
	// Создаём AudioContext после нажатия
	// ========================================
	function initAudio() {
		if(!audioContext) {
			audioContext = new(window.AudioContext || window.webkitAudioContext)();
		}
		if(audioContext.state === "suspended") {
			audioContext.resume();
		}
	}
	// ========================================
	// Проигрывание мелодии
	// ========================================
	function playMelody() {
		initAudio();
		const ctx = audioContext;
		let time = ctx.currentTime;
		// Частота + длительность
		const melody = [
			[523.25, 0.25], // До
			[659.25, 0.25], // Ми
			[783.99, 0.25], // Соль
			[1046.50, 0.50], // До
			[783.99, 0.25], // Соль
			[659.25, 0.25], // Ми
			[523.25, 0.50] // До
		];
		for(const [frequency, duration] of melody) {
			const oscillator = ctx.createOscillator();
			const gain = ctx.createGain();
			oscillator.type = "sine";
			oscillator.frequency.value = frequency;
			// Плавное включение
			gain.gain.setValueAtTime(0, time);
			gain.gain.linearRampToValueAtTime(0.3, time + 0.02);
			// Плавное выключение
			gain.gain.linearRampToValueAtTime(0, time + duration - 0.02);
			oscillator.connect(gain);
			gain.connect(ctx.destination);
			oscillator.start(time);
			oscillator.stop(time + duration);
			time += duration;
		}
	}
	// ========================================
	// Кнопка "Тест"
	// ========================================
	document.getElementById("test").addEventListener("click", () => {
		playMelody();
		document.getElementById("status").innerHTML = "&#128266; Тестовая мелодия играет";
	});
	// ========================================
	// Кнопка "Запустить расписание"
	// ========================================
	document.getElementById("start").addEventListener("click", () => {
		initAudio();
		// Если расписание уже запущено,
		// второй таймер не создаём
		if(timer !== null) {
			return;
		}
		timer = setInterval(checkTime, 1000);
		document.getElementById("status").innerHTML = "&#9989; Расписание запущено. Мелодия прозвучит за 10 и 2 минуты до каждого часа.";
		// Проверяем время сразу
		checkTime();
	});
	// ========================================
	// Проверяем время
	// ========================================
	function checkTime() {
		const now = new Date();
		/*
		    Например:

		    15:50 → играем
		    15:58 → играем
		    16:50 → играем
		    16:58 → играем
		    ...
		*/
		if((now.getMinutes() === 50 || now.getMinutes() === 58) && now.getSeconds() < 2) {
			playMelody();
			document.getElementById("status").innerHTML = "&#128276; Мелодия! Следующая — через час.";
		}
	}
	</script>
</body>

</html>