19 ноября 2013 в 07:03

Пианино в 24 строки на Javascript: если играть, то музыку

Пока производители телефонов меряются, у кого тоньше, программисты продолжают меряться, у кого короче.

Я тоже решил принять участие в этой специальной спонтанной олимпиаде кодерского мастерства, и вспомнил фразу одной моей подруги-музыканта: «Если уж играть, то на пианино». И решил: да будет так. Вместо игры напишу пианино. И написал.

Оговорюсь сразу: я ни разу не музыкант, моё музыкальное образование ограничивается десятком блатных песенок на расстроенной гитаре, так что, с терминологией могу и обязательно буду безбожно врать, но буду чертовски рад, если вы меня будете в этом поправлять.

Итак, начнем.

Клавиатура классического фортепиано состоит из 88 клавиш, покрывающих диапазон от A0 (Ля суб-контр-октавы, частота звучания 27.5 Гц) до C8 (До пятой октавы, частота 4186 Гц). Каждая октава на клавиатуре состоит из двенадцати нот:
До, До-диез, Ре, Ре-диез, Ми, Фа, Фа-диез, Соль, Соль-диез, Ля, Ля-диез/Си-бемоль, Си. Жирным выделены клавиши верхнего ряда, они на клавиатуре обычно бывают черного цвета.

Собственно, вот так выглядит одна октава:

image

Просто взглянув на таблицу частот звучания нот, становится очевидной закономерность: каждая последующая октава ровно вдвое выше предыдущей. Таким образом, можно сказать, что:

Nx = N1 × 2x-1, где:
  • N – название ноты;
  • x — номер октавы (от 0 до 8);
  • Nx, соответственно, частота звука, соответствующая ноте N октавы x;

В формуле фигурирует N1 вместо N0 лишь потому, что часть нот суб-контр-октавы (N0) имеет частоту звучания ниже порога слышимости человеческим ухом (< 20 Hz).

Чтобы ноты получались чистыми, нам нужны достаточно точные значения частот нот контроктавы, от которой мы начинаем считать. Собственно, вот они:

C: 32.703,
С#: 34.648,
D: 36.708,
D#: 38.891,
E: 41.203,
F: 43.654,
F#: 46.249,
G: 48.999,
G#: 51.913,
A: 55,
A#: 58.27,
B: 61.735

Основываясь на этом, пишем функцию, принимающую в качестве аргумента строку с именем клавиши в виде "A4" или "C5#", и возвращающую частоту её звучания:

function play(key) {
	var controctave = {
			'C': 32.703,
			'С#': 34.648,
			'D': 36.708,
			'D#': 38.891,
			'E': 41.203,
			'F': 43.654,
			'F#': 46.249,
			'G': 48.999,
			'G#': 51.913,
			'A': 55,
			'A#': 58.27,
			'B': 61.735,
		},
		note = key[0].toUpperCase(),
		octave = parseInt(key[1]),
		sharp = key[2] == '#' ? true : false;
	if (sharp) {
		return controctave[note + '#'] * Math.pow(2, octave-1);
	} else {
		return controctave[note] * Math.pow(2, octave-1);
	}
}

Ах, да, мы же пишем не красиво, а коротко. Немного подсократим:

function play(key) {
	var controctave = { 'C': 32.703, 'С#': 34.648, 'D': 36.708, 'D#': 38.891, 'E': 41.203, 'F': 43.654, 'F#': 46.249, 'G': 48.999, 'G#': 51.913, 'A': 55, 'A#': 58.27, 'B': 61.735};
	freq = key[2] == '#' ? controctave[key[0].toUpperCase() + '#'] * Math.pow(2, (key[1]|0) - 1) : controctave[key[0].toUpperCase()] * Math.pow(2, (key[1]|0) - 1);
	return freq; }


Уже использовано четыре строчки кода.

Давайте нарисуем клавиатуру

88 клавиш клавиатуры начинаются с ноты Ля (A0).
Соответственно, цикл будет такой: в цикле рисуем по 12 клавиш, и каждую вторую, четвертую, седьмую, девятую и одиннадцатую делаем черной. Каждой клавише присвоим id, соответствующей ноте, которую она должна воспроизводить при нажатии.

В общем, так:

var width = 1000;
var deck = document.createElement('div'), 
	octave = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'], 
	id = "", 
	keynumber = 0,
	whitekeys = 0,
	keys = [];

deck.style.width = width;

parent:
for (var i = 0; i < 8; i++) {
	for (var j = 0; j < 12; j++) {
		keynumber = (i * 12) + j;
		if (keynumber >= 88) break parent;
		keys[keynumber] = document.createElement('div');
		keys[keynumber].style.border = "1px solid black";
		keys[keynumber].style.position = "absolute";
		id = (octave[j][1] == '#') ? octave[j] + i + 's' : octave[j] + i;
		keys[keynumber].id = id;

		switch(j%12) {
			case 1: 
			case 3: 
			case 6: 
			case 8:
			case 10:
				keys[keynumber].style.backgroundColor = 'black';
				keys[keynumber].style.left = ((width / 50 * whitekeys) - (width / 200)) + 'px';
				keys[keynumber].style.width = width/100 + "px";
				keys[keynumber].style.height = "200px";
				keys[keynumber].style.zIndex = 10;
				break;
			default:
				keys[keynumber].style.backgroundColor = 'white';
				keys[keynumber].style.left = (width / 50 * whitekeys) + 'px';
				keys[keynumber].style.width = width/50 + "px";
				keys[keynumber].style.height = "300px";
				whitekeys++;

		}

		deck.appendChild(keys[keynumber]);

	}
}

document.body.appendChild(deck);

И вновь превратим нормальный код в нечитабельное говнище применим небольшую оптимизацию.

var width = 1000, octave = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'], id = "", div, whitekeys=0, keys = [];
parent: for (var i = 0; i < 8; i++) {
	for (var j = 0; j < 12; j++) {
		if ((i * 12) + j >= 88) break parent;
		div = document.createElement('div');
		div.id = (octave[j][1] == '#') ? octave[j][0] + ((((i * 12) + j + 9) / 12)|0) + 's' : octave[j] + ((((i * 12) + j + 9) / 12)|0);
		if (j % 12 == 1 || j % 12 == 4 || j % 12 == 6 || j % 12 == 9 || j % 12 == 11) {
			div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:black; left:' + ((width / 50 * whitekeys) - (width / 200)) + 'px; width:' + width/100 + 'px; height: 200px; z-index:1;');}
		else {
			div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:white; left:' + (width / 50 * whitekeys) + 'px; width:' + width/50 + 'px; height:300px;');
			whitekeys++;
		}
		document.body.appendChild(div);}}


Мы израсходовали ещё 13 строк.

Научим пианино издавать звуки

Для этого нам понадобится Web Audio API, который на сей момент поддерживается только Webkit-based браузерами и Firefox.

Добавим в строку объявления глобальных переменных создание аудиоконтекста:
context = window.AudioContext ? new AudioContext() : new webkitAudioContext();

добавим обработчик нажатий на клавиши:
document.body.addEventListener('click', play);

а саму функцию play изменим следующим образом:
function play(e) {
	var controctave = { 'C': 32.703, 'Cs': 34.648, 'D': 36.708, 'Ds': 38.891, 'E': 41.203, 'F': 43.654, 'Fs': 46.249, 'G': 48.999, 'Gs': 51.913, 'A': 55, 'As': 58.27, 'B': 61.735}, osc = context.createOscillator();
	osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1);
	osc.type = "square";
	osc.connect(context.destination);
	osc.start(0);
	setTimeout(function() {
	    osc.stop(0);
	    osc.disconnect(context.destination);
	}, 1000 / 2);}


Здесь мы создали осциллятор: osc = context.createOscillator();, установили ему необходимую частоту звучания: osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1); (ну, мы же не следим за чистотой и опрятностью кода, не так ли?), установили форму сигнала: osc.type = "square"; (по умолчанию был синусоидальный) соединили его с устройством вывода звука: osc.connect(context.destination);, и дали команду начать воспроизведение: osc.start(0);. После этого нам необходимо заставить клавишу замолчать через некоторое время (500мс), а то она так и будет противно пищать. Для этого используем osc.stop(0), завёрнутый в интервал. Обязательный элемент — osc.disconnect(context.destination); — отключаем осциллятор от устройства вывода.

Резюмируем: у нас получился вот такой нехитрый код:

var width = 1000, octave = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'], id = "", div, whitekeys=0, keys = [],context = window.AudioContext ? new AudioContext() : new webkitAudioContext();
parent: for (var i = 0; i < 8; i++) {
	for (var j = 0; j < 12; j++) {
		if ((i * 12) + j >= 88) break parent;
		div = document.createElement('div');
		div.id = (octave[j][1] == '#') ? octave[j][0] + ((((i * 12) + j + 9) / 12)|0) + 's' : octave[j] + ((((i * 12) + j + 9) / 12)|0);
		if (j % 12 == 1 || j % 12 == 4 || j % 12 == 6 || j % 12 == 9 || j % 12 == 11) {
			div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:black; left:' + ((width / 50 * whitekeys) - (width / 200)) + 'px; width:' + width/100 + 'px; height: 200px; z-index:1;');}
		else {
			div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:white; left:' + (width / 50 * whitekeys) + 'px; width:' + width/50 + 'px; height:300px;');
			whitekeys++;
		}
		document.body.appendChild(div);}}
document.body.addEventListener('click', play);
function play(e) {
	var controctave = { 'C': 32.703, 'Cs': 34.648, 'D': 36.708, 'Ds': 38.891, 'E': 41.203, 'F': 43.654, 'Fs': 46.249, 'G': 48.999, 'Gs': 51.913, 'A': 55, 'As': 58.27, 'B': 61.735}, osc = context.createOscillator();
	osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1);
	osc.type = "square";
	osc.connect(context.destination);
	osc.start(0);
	setTimeout(function() {
	    osc.stop(0);
	    osc.disconnect(context.destination);
	}, 1000 / 2);}


В заключение хочу сказать, что теперь меня надо называть Страдивари XXI века Web Audio API — штука очень классная и интересная. Почитать про него можно, естественно, на MDN, могу посоветовать милый туториал на HTML5Rocks и ещё один забавный эксперимент.

А пианино вышло жутко примитивное, но экспериментом я всё равно доволен. Надеюсь, вам тоже было интересно.

Поиграть

Посмотреть код

P.S. динамики макбука, например, отказываются издавать слышимые звуки вплоть до малой октавы (т.е. до 130 Гц), что неудивительно. В общем, не удивляйтесь, если левая часть клавиатуры будто бы вообще не звучит.
Андрей Озорнин @oshibka404
карма
122,2
рейтинг 0,1
Front-end developer
Похожие публикации
Самое читаемое Разработка

Комментарии (54)

  • +8
    Вызов принят.
  • +12
    Вот почему было все со змейки: якобы сейчас каждый новый пост, это как еда для той же змейки, в итоге хабр растет с постами о играх в 30+ строк.
  • +10
    Можно ещё добавить немного для поддержки игры с клавиатуры:
    document.body.addEventListener('keydown', press);
    function press(e) {
      var map = 'zsxdcvgbhnjmq2w3er5t6y7ui9o0p', key = map.indexOf(String.fromCharCode(e.which).toLowerCase());
      if (key + 1) play({target: document.querySelector('div:nth-child(' + (29 + key)  + ')')});}
    


    jsfiddle.net/c62Pe/3/embedded/result/ (сначала айфрейму надо дать фокус)
    • 0
      Шикарно, спасибо.
  • +6
    А как же кривая громкости ADSR (attack-decay-sustain-release)?
  • +22
    Я всегда балдею, когда читаю что-то вроде «я вообще нуб в этом деле», а потом следует что-то вроде «покрывающих диапазон от A0 (Ля суб-контр-октавы, частота звучания 27.5 Гц) до C8 (До пятой октавы, частота 4186 Гц)».
    Я хоть и играю на настроенной гитаре и значительно больше десятка песен, но для меня большая часть этой фразы — магия, и больше всего мне ясны слова «частота звучания» и «герц» =)
    • +1
      Где же тут магия? Эти страшные слова — по сути всего лишь названия клавиш. Все что нужно знать для написания эмулятора — то, что такие клавиши есть.
      • 0
        Вообще суть многих страшных слов очень часто сводится к простым принципам. Взять хотя бы те же синхрофазотрон и интеграл.
        Но все-таки после слов автора «моё музыкальное образование ограничивается десятком блатных песенок на расстроенной гитаре» как-то не очень ожидалось появление термина «суб-контр-октава» без пояснения, что это заклинание значит =)
    • +5
      Эммм. Ну я уж не знаю какой-то более базовой вещи в теории музыки.

      image
      • 0
        Ну так автор и не упоминал о том, что он знаком с теорией музыки. Я как гитарист-самоучка могу определенно сказать, что для блатных песен под гитару никакие понятия о теории музыки не нужны. А для примитивной настройки гитары достаточно только понимать явление резонанса.
        Еще раз процитирую автора «моё музыкальное образование ограничивается десятком блатных песенок на расстроенной гитаре».
        Именно поэтому я приготовился к некоторому уровню изложения. И тут на тебе — суб-контр-октава! Да еще и Ля суб-контр-октавы! Для меня это было несколько внезапно =)
        И вообще, предлагаю закончить оффтопить =) Мне кажется, я уже достаточно аргументировал свое высказывание. Оставим место для полезных комментариев =)
        • 0
          Не, я удивился что для вас «большая часть этой фразы — магия» при том, что «хоть и играю на настроенной гитаре и значительно больше десятка песен».

          Хотя конечно прекрасно представляю как можно играть на скажем гитаре без теории этой всей. Я-то и сам музыкант-самоучка (барабаны), правда базовое сольфеджио осилил самостоятельно, даже гаммы на фортепиано поиграл пока не надоело.
          • +1
            Да это просто мечта детства была — научиться на гитаре играть.
            Потом гитара появилась, я взял самоучитель… А там чего-то втирают, втирают… А как после этого «Что такое осень» сыграть — непонятно. А вот аппликатуры аккордов и надписи С, D, Аm мне понравились. Так что теория пошла лесом, началась сугубая практика. А потом еще и гитарпро развратил =)
            Поэтому когда при мне начинают говорить словами «сольфеджио», «суб-контр-октава», «сустейн», и т.п., да еще и вроде как со знанием дела, у меня к таким людям сразу уважение просыпается, потому что я это шаманство не осилил =)
        • +9
          Да я это все нагуглил. Ещё вчера я бы не смог так отборно материться.
  • 0
    О! Моя курсовая, правда делал еще на паскале)
    • +3
      Тоже была в 30 строк?
      • +1
        Да разве-ж я помню?) 14 лет прошло…
  • +11
    А зачем забивать частоты нот хардкодом? Насколько я помню, частота ноты равна 440*2^{n/12} Гц, где n — смещение ноты от ля первой октавы в полутонах.
    • +1
      Ну, не каждый лад выражается такой простой формулой… Если мы захотим поиграть в одном оркестре с духовыми инструментами, то придется брать рациональные отношения частот.

      Хотя, с точки зрения минимальности кода, идея использовать формулу здравая.
      • +3
        Для пианино — все клавиши описываются этой формулой. Почему бы и нет, в соревновании то на краткость? ;)
        • 0
          Для пианино — все клавиши звучат так, как их настроят, и формулой описываются только в том случае, если их по этой формуле и настраивали
          • +1
            Вообще-то уже давно принят как стандарт равномерно-темперированный строй ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE_%D1%82%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%81%D1%82%D1%80%D0%BE%D0%B9

            есть конечно споры писал ли Бах ХТК именно под этот строй или под строй Веркмейстера но факт что с 18-го века используется именно этот строй.
            • 0
              На некоторых музыкальных инструментах можно извлечь только звуки натурального звукоряда, cреди них фанфара (и горн), рог (охотничий рог, альпийский рог, почтовый рожок, шофар и т.п.), натуральная труба (особенно её старинные разновидности, например, лур), натуральная валторна, так называемые обертоновые флейты (молдавская тилинка, некоторые разновидности общетюркского шогура) и другие духовые инструменты, а также варган. По отношению к этим и подобным инструментам говорят, что они звучат в «натуральном строе».
              И если такие инструменты нужно добавить в оркестр — то и остальные придется под них подстраивать. А так — да, равномерно-темперированный строй давно уже стандарт…
              • +1
                но мы же про пианино — там натуральный звукоряд не используют
    • +3
      Большое спасибо. Сказывается отсутствие базовых знаний.
  • +7
    Что, на хабре неделя JavaScript?
    • +6
      Прирост 30-ти строчных игр удвоен!
  • +8
    Я вот уже какой пост читаю и не понимаю, честно говоря, в чём смысл. Искаверкать код не невозможности, но вместиться в N строчек?

    То есть как, мне понятно, что всё это — just for fun. Но так же мне понятно, что если сжать этот с помощью ADVANCED_OPTIMIZATIONS в GCC, то вообще 4 строчки получится. И читабельность примерно такая же :). А можно ещё переносы строк убрать! :)

    Тот код, который получился — он уже нечитабелен никому, кроме автора (и автору через два месяца тоже будет нечитабелен). Если это — нечто для конкурса типа js1k, то тут очевидно фиговая оптимизация, есть уже описанные здесь на хабре гораздо более прикольные техники.
  • +1
    У меня звук был на максимуме. А это пианино меня кипричом по ушам!
    1. Можно ли избавиться от задержек?
    2. Пусть строк будет больше, а звук поживее :)
    • +2
      Можно ли избавиться от задержек?

      А это не задержка, а звук на Release, хотя логичнее — на Press.
      • 0
        Да, конечно, mousedown здесь куда уместнее, вы правы.
  • +1
    установили форму сигнала: osc.type = «square»; (по умолчанию был синусоидальный)

    Почему отказались от синуса? Он вроде приятнее звучит. Да и звук пианино всё-же более близок к синусу чем к прямоугольным колебаниям.
    • 0
      Зато получается очень нинтендовско.
    • 0
      Не-не, синус не пойдёт! Без гармоник это очень глухое и невнятное звучание.
      Но квадрат тоже, да, «компьютерный» звук от 8-битных игрушек.
      Вот пила бы очень подошла — звучит ярко, выразительно, похоже на скрипку.
  • +1
    До пианино расти и расти :( Электро-орган, и то примитивный :( Я так понимаю нормального звука в API нет?
  • +2
    Действительно, спонтанный конкурс лучше выдерживать не в стиле «30 строк» а 1024, 4096 и 10кб — хотя такие соревнования уже есть:
    js1k.com
    10k.aneventapart.com
    даже с призами вроде…
    • +1
      А это уже демосцена получается!
  • 0
    Вот, японцы развлекаются: www.g200kg.com/en/webaudio/
    Хотя тут далеко не 30 строк, конечно
  • +6
    Многовато лишнего кода. Можно же и короче, и читабельнее: jsfiddle.net/c62Pe/29/ А с треугольными волнами ещё и ламповее.
    • 0
      Вообще красота.
    • 0
      а сложно сделать так что бы длительность ноты задавалась длительностью нажатия клавиши?
      Или что бы вообще клавиши соответствовали обычной клавиатуре?
      • 0
        Сегодня буду переписывать и дописывать.
        Разумеется, уже не в 30-строчных рамках, и с нормальным читабельным кодом :)
        • 0
          да всё равно сколько кода не мне же его писать:-) самое главное звучание и возможность сыграть на обычной клавиатуре без миди — к примеру было бы очень круто если бы клавиши
          от «y» до "]" — были до ре ми фа соль ля си — первой октавы
          соответственно:
          «7» — до диез
          «8» — ре диез
          «0» — фа диез
          "-" — соль диез
          "=" — ля диез
          ну и от «z» до «m» — до ре ми фа соль ля си малой октавы
          «s» — до диез
          «d» — ре диез
          «g» — фа диез
          «h» — соль диез
          «j» — ля диез
          а если ещё будет возможность задавать октавы (повышать понижать другими клавишами — то вообще жесть:-)

          что-то я размечтался — захотелось сыграть что-то на обычной клавиатуре как на настоящем пианино — наверное надо самому этим занятся
  • +2
    Кто о чём, а я о матмузчасти.
    Нота «си» у пианистов (по крайней мере, у тех, кто меня учил бряцать на клавишах в музыкальной школе 15 лет тому назад) обозначается вовсе не B, как обычно пишут в табах гитаристы, а H. B — это си-бемоль, т.е. на клавиатуре фо-но соответствует A# (ля-диезу). Например, вот тут про это в двух словах сказано. И на жизнерадостной картиночке, приведённой в комментах выше, тоже везде H, если приглядеться.
    Каждая октава на клавиатуре состоит из двенадцати нот:
    До, До-диез, Ре, Ре-диез, Ми, Фа, Фа-диез, Соль, Соль-диез, Ля, Ля-диез/Си-бемоль, Си

    Тогда уж так:
    До, До-диез/Ре-бемоль, Ре, Ре-диез/Ми-бемоль, Фа, Фа-диез/Соль-бемоль, Соль, Соль-диез/Ля-бемоль, Ля, Ля-диез/Си-бемоль.
    А то чего это, си-бемоль есть, а остальных бемолей нету… Непорядок!
    • 0
      А оно по-разному.
      В классике — где всё считается от камертонного «ля» 440 герц — и оттуда обозначается последовательными буквами алфавита (A,B,C,D...). Очень логично и последовательно. Легко запомнить! H при этом обозначает Bb или A#. Но есть и да, другой вариант. Где B и H меняются местами, и звукоряд обозначается уже A,H,C,D..., а B это Hb или A#.
      Я одинаково часто сталкивался с обоими вариантами. Поэтому утверждать, что один из них более «правильный» — не стану. Просто факт в том, что есть оба!
      • 0
        Я вовсе и не утверждаю, что какой-то один вариант правильный. Просто лично мне это «B» в качестве «си» царапает глаз, потому что меня учили по-другому (хотя знакомые гитаристы и используют нотацию, как у автора, но тут речь всё же про фо-но). Я и источники своего знания привожу — это программа муз. школы (т.е. учебники по сольфеджио, которые гуглибельны) и вики. А вы где «одинаково часто сталкивались», если не секрет? :)
        • 0
          Да как раз в песенных сборниках. Там обычно мелодическая линия для голоса + обозначена гармония для аккомпанемента. И вот там порой полная вольность обозначений H и B. Иногда даже в пределах одного сборника! Вполне обычно, когда доминанта к E обозначается как H. А в другом произведении там же субдоминанта к F — всё та же H.
  • +2
    Писал похожее для конкурса JS1K. Вот демо: js1k.com/2012-love/demo/1209 Вроде даже исходник сохранился но он очень подрезанный. Надо поискать или полный исходить есть где-то… У меня там даже есть режим самопроигрывания :)
  • +4
    Как-то оно надоело уже. Ну и не меряется код строками.
    • 0
      Я попытался сделать статью информативной, а не просто «Смотрите, пацаны, чо я написал».
      Если не получилось — извините, над комментами есть кнопочка со стрелочкой вниз.

      И код не меряется строками если вы разрабатываете что-то для реальной жизни. В продакшн бы я в жизни ничего похожего не написал.
      А это — просто развлечение, если хотите, своего рода искусство. Занятие, родственное демосцене. Тут код может меряться и строками, и байтами, и соотношением количеств букв «a» и «b» в коде.
  • 0
    Если добавить немного кода и переписать соединение источников, будет 30 строк, но звучать будет получше благодаря непостоянной огибающей.

    gainNode = context.createGain();
    //<...>
    osc.type = "square";
    osc.connect(gainNode);   //Меняем дестинейшен вот тут
    //ниже - энвелоуп
    gainNode.connect(context.destination);
    gainNode.gain.value = 0.5;
    gainNode.gain.linearRampToValueAtTime(0, context.currentTime);
    gainNode.gain.setTargetAtTime(1,context.currentTime,0.1);
    gainNode.gain.setTargetAtTime(0,context.currentTime+0.1,0.3);
    osc.start(0);
    	setTimeout(function() {
    	    osc.stop(0);
    	    osc.disconnect(gainNode); //Меняем дестинейшен вот тут, заодно делаем звучание подлиннее
    	}, 5000 / 2);}
    
    • 0
      http://jsfiddle.net/MQ8Q7/3/
      Вот, добавил в ваш код огибающую, можно потестить.
  • 0
    Не проверил уровень звука. Открыл демо. Нажал клавишу. Навалил кирпичей. Закрыл демо.
  • 0
    В общем, не удивляйтесь, если левая часть клавиатуры будто бы вообще не звучит.

    Вы так пишите, как-будто бы маковские ноуты у всех, и все как один будут писать почему работает только половина клавы)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.