/
rnagimov
/
git
Обзор
Документация
Войти
/
rnagimov
/
git
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
479 строк
17 KB
rnagimov
Update: index.html
06 июл 2026, 19:11
Верифицирован
06 июл 2026, 19:11
f1ce7b2
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Синтезатор</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: white; } .synthesizer { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); border-radius: 20px; padding: 40px; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.1); } .header { text-align: center; margin-bottom: 30px; } .header h1 { font-size: 2.5em; background: linear-gradient(45deg, #00d4ff, #7b2cbf); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 10px; } .controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; } .control-group { background: rgba(255, 255, 255, 0.05); padding: 15px; border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.1); } .control-group label { display: block; margin-bottom: 8px; font-weight: 600; color: #00d4ff; } .wave-buttons { display: flex; gap: 10px; flex-wrap: wrap; } .wave-btn { padding: 8px 16px; border: none; border-radius: 5px; background: rgba(255, 255, 255, 0.1); color: white; cursor: pointer; transition: all 0.3s ease; font-size: 14px; } .wave-btn:hover { background: rgba(255, 255, 255, 0.2); } .wave-btn.active { background: #00d4ff; color: #1a1a2e; } input[type="range"] { width: 100%; height: 6px; border-radius: 3px; background: rgba(255, 255, 255, 0.2); outline: none; -webkit-appearance: none; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%; background: #00d4ff; cursor: pointer; } .keyboard { display: flex; justify-content: center; position: relative; margin-top: 20px; } .key { position: relative; cursor: pointer; transition: all 0.1s ease; user-select: none; } .white-key { width: 60px; height: 200px; background: linear-gradient(to bottom, #ffffff 0%, #e8e8e8 100%); border: 1px solid #ccc; border-radius: 0 0 5px 5px; margin-right: 2px; z-index: 1; } .white-key:hover { background: linear-gradient(to bottom, #f0f0f0 0%, #d8d8d8 100%); } .white-key.active { background: linear-gradient(to bottom, #00d4ff 0%, #0099cc 100%); transform: translateY(2px); } .black-key { width: 40px; height: 120px; background: linear-gradient(to bottom, #333 0%, #111 100%); border-radius: 0 0 3px 3px; position: absolute; z-index: 2; margin-left: -20px; } .black-key:hover { background: linear-gradient(to bottom, #444 0%, #222 100%); } .black-key.active { background: linear-gradient(to bottom, #7b2cbf 0%, #5a1a8a 100%); transform: translateY(2px); } .power-btn { background: linear-gradient(45deg, #ff6b6b, #ee5a24); border: none; color: white; padding: 12px 24px; border-radius: 25px; font-size: 16px; font-weight: bold; cursor: pointer; transition: all 0.3s ease; margin-bottom: 20px; } .power-btn:hover { transform: scale(1.05); box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4); } .power-btn.on { background: linear-gradient(45deg, #00d4ff, #0099cc); } .value-display { text-align: center; margin-top: 5px; font-size: 14px; color: #00d4ff; } @media (max-width: 768px) { .synthesizer { padding: 20px; margin: 10px; } .controls { grid-template-columns: 1fr; } .white-key { width: 40px; height: 150px; } .black-key { width: 30px; height: 90px; margin-left: -15px; } } </style> </head> <body> <div class="synthesizer"> <div class="header"> <h1>🎹 Синтезатор</h1> <p>Виртуальный музыкальный инструмент</p> </div> <button class="power-btn" id="powerBtn">Включить синтезатор</button> <div class="controls"> <div class="control-group"> <label>Тип волны</label> <div class="wave-buttons"> <button class="wave-btn active" data-wave="sine">Синус</button> <button class="wave-btn" data-wave="square">Квадрат</button> <button class="wave-btn" data-wave="sawtooth">Пила</button> <button class="wave-btn" data-wave="triangle">Треугольник</button> </div> </div> <div class="control-group"> <label>Громкость</label> <input type="range" id="volume" min="0" max="100" value="50"> <div class="value-display" id="volumeValue">50%</div> </div> <div class="control-group"> <label>Октава</label> <input type="range" id="octave" min="2" max="6" value="4"> <div class="value-display" id="octaveValue">4</div> </div> <div class="control-group"> <label>Атака</label> <input type="range" id="attack" min="0" max="100" value="10"> <div class="value-display" id="attackValue">0.1с</div> </div> <div class="control-group"> <label>Затухание</label> <input type="range" id="release" min="0" max="100" value="30"> <div class="value-display" id="releaseValue">0.3с</div> </div> </div> <div class="keyboard" id="keyboard"> <!-- Белые клавиши --> <div class="key white-key" data-note="C" data-key="a"></div> <div class="key white-key" data-note="D" data-key="s"></div> <div class="key white-key" data-note="E" data-key="d"></div> <div class="key white-key" data-note="F" data-key="f"></div> <div class="key white-key" data-note="G" data-key="g"></div> <div class="key white-key" data-note="A" data-key="h"></div> <div class="key white-key" data-note="B" data-key="j"></div> <div class="key white-key" data-note="C2" data-key="k"></div> <!-- Черные клавиши --> <div class="key black-key" data-note="C#" data-key="w" style="left: 45px;"></div> <div class="key black-key" data-note="D#" data-key="e" style="left: 107px;"></div> <div class="key black-key" data-note="F#" data-key="t" style="left: 229px;"></div> <div class="key black-key" data-note="G#" data-key="y" style="left: 291px;"></div> <div class="key black-key" data-note="A#" data-key="u" style="left: 353px;"></div> </div> </div> <script> class Synthesizer { constructor() { this.audioContext = null; this.isPlaying = false; this.currentWave = 'sine'; this.volume = 0.5; this.octave = 4; this.attack = 0.1; this.release = 0.3; this.activeOscillators = new Map(); this.noteFrequencies = { 'C': 261.63, 'C#': 277.18, 'D': 293.66, 'D#': 311.13, 'E': 329.63, 'F': 349.23, 'F#': 369.99, 'G': 392.00, 'G#': 415.30, 'A': 440.00, 'A#': 466.16, 'B': 493.88, 'C2': 523.25 }; this.init(); } init() { this.setupEventListeners(); this.setupKeyboard(); } setupEventListeners() { // Кнопка включения document.getElementById('powerBtn').addEventListener('click', () => { this.togglePower(); }); // Кнопки типа волны document.querySelectorAll('.wave-btn').forEach(btn => { btn.addEventListener('click', (e) => { document.querySelectorAll('.wave-btn').forEach(b => b.classList.remove('active')); e.target.classList.add('active'); this.currentWave = e.target.dataset.wave; }); }); // Ползунки document.getElementById('volume').addEventListener('input', (e) => { this.volume = e.target.value / 100; document.getElementById('volumeValue').textContent = e.target.value + '%'; }); document.getElementById('octave').addEventListener('input', (e) => { this.octave = parseInt(e.target.value); document.getElementById('octaveValue').textContent = e.target.value; }); document.getElementById('attack').addEventListener('input', (e) => { this.attack = e.target.value / 100; document.getElementById('attackValue').textContent = (e.target.value / 100).toFixed(1) + 'с'; }); document.getElementById('release').addEventListener('input', (e) => { this.release = e.target.value / 100; document.getElementById('releaseValue').textContent = (e.target.value / 100).toFixed(1) + 'с'; }); // Клавиши синтезатора document.querySelectorAll('.key').forEach(key => { key.addEventListener('mousedown', () => this.playNote(key)); key.addEventListener('mouseup', () => this.stopNote(key)); key.addEventListener('mouseleave', () => this.stopNote(key)); // Для мобильных устройств key.addEventListener('touchstart', (e) => { e.preventDefault(); this.playNote(key); }); key.addEventListener('touchend', (e) => { e.preventDefault(); this.stopNote(key); }); }); } setupKeyboard() { const keyMap = { 'a': 'C', 'w': 'C#', 's': 'D', 'e': 'D#', 'd': 'E', 'f': 'F', 't': 'F#', 'g': 'G', 'y': 'G#', 'h': 'A', 'u': 'A#', 'j': 'B', 'k': 'C2' }; document.addEventListener('keydown', (e) => { if (e.repeat) return; const note = keyMap[e.key.toLowerCase()]; if (note) { const keyElement = document.querySelector(`[data-note="${note}"]`); if (keyElement) this.playNote(keyElement); } }); document.addEventListener('keyup', (e) => { const note = keyMap[e.key.toLowerCase()]; if (note) { const keyElement = document.querySelector(`[data-note="${note}"]`); if (keyElement) this.stopNote(keyElement); } }); } togglePower() { const powerBtn = document.getElementById('powerBtn'); if (!this.isPlaying) { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.isPlaying = true; powerBtn.textContent = 'Выключить синтезатор'; powerBtn.classList.add('on'); } else { this.stopAllNotes(); this.audioContext.close(); this.isPlaying = false; powerBtn.textContent = 'Включить синтезатор'; powerBtn.classList.remove('on'); } } playNote(keyElement) { if (!this.isPlaying) return; const note = keyElement.dataset.note; const baseFrequency = this.noteFrequencies[note]; const frequency = baseFrequency * Math.pow(2, this.octave - 4); // Визуальная обратная связь keyElement.classList.add('active'); // Создаем осциллятор const oscillator = this.audioContext.createOscillator(); const gainNode = this.audioContext.createGain(); oscillator.type = this.currentWave; oscillator.frequency.setValueAtTime(frequency, this.audioContext.currentTime); // Настройка громкости с атакой gainNode.gain.setValueAtTime(0, this.audioContext.currentTime); gainNode.gain.linearRampToValueAtTime(this.volume, this.audioContext.currentTime + this.attack); oscillator.connect(gainNode); gainNode.connect(this.audioContext.destination); oscillator.start(); // Сохраняем активные осцилляторы this.activeOscillators.set(note, { oscillator, gainNode }); } stopNote(keyElement) { const note = keyElement.dataset.note; const activeNote = this.activeOscillators.get(note); if (activeNote) { const { oscillator, gainNode } = activeNote; // Плавное затухание gainNode.gain.setValueAtTime(gainNode.gain.value, this.audioContext.currentTime); gainNode.gain.linearRampToValueAtTime(0, this.audioContext.currentTime + this.release); // Останавливаем осциллятор после затухания setTimeout(() => { oscillator.stop(); oscillator.disconnect(); gainNode.disconnect(); }, this.release * 1000); this.activeOscillators.delete(note); } // Убираем визуальную обратную связь keyElement.classList.remove('active'); } stopAllNotes() { this.activeOscillators.forEach(({ oscillator, gainNode }) => { oscillator.stop(); oscillator.disconnect(); gainNode.disconnect(); }); this.activeOscillators.clear(); // Убираем активный класс со всех клавиш document.querySelectorAll('.key').forEach(key => { key.classList.remove('active'); }); } } // Инициализация синтезатора const synth = new Synthesizer(); </script> </body> </html>