Как стать автором
Обновить

Комментарии 12

Добавлю, что в Chrome и Safari playTrack() можно запустить только синхронно из события, порожденного пользовательским взаимодействием (ondrop, ochange, onclick, ontouch, etc). Другими словами, автопроигрывание запрещено (слава богу?).
Все началось со злоупотребления атрибутом autoplay тегов «audio» и «video» (и методом play сразу после window.onload), это сильно раздражало пользователей. В случае с видео включить автопроигрывание можно только в беззвучном режиме (muted), аудио запускается только «по желанию» пользователя
Впечатляет
// добавляем подсказку
console.log(
" Use Keyboard: \n Space to Play/Pause \n Enter to Stop \n Arrows to Change \n Time and Volume"
);
Подсказку в консоль? Не очень хорошая идея, лучше текстом или при наведении на иконку.

$ = C.getContext(«2d»)
Имя переменной по-моему неудачное. Можно подумать, что используется jQuery.

Но в целом материал очень полезный. Странно, что такие статьи не выходят на главную.
С подсказкой экспериментировал, вариант с console показался оптимальным, но, возможно, Вы правы. Использование $ в качестве ссылки на контекст холста является распространенной практикой (удобно: все методы холста начинаются с контекста)
Давайте попробуем разобраться что происходит тут:
необходимость использования try/catch обусловлена странным поведением Chrome, связанным с вычислением громкости звука. Попробуйте убрать try/catch и выводить в консоль громкость звука (console.log(audio.volume)) после каждого изменения при приближении к 0 и 1 (согласно спецификации значение громкости звука варьируется от 0.1 до 1) получаем странные значения, которые нивелируют проверки типа if(audio.volume>0 && audio.volume<1). Использование в проверках «неточных» значений вроде 0.1 и 0.9 решает проблему исключений, но приводит к некорректному изменению громкости звука. Исключения работе плеера не мешают, но раздражают
Мне стало интересно, я попробовал воспроизвести и не совсем понял в чем заключается «странное поведение»: у меня в Chrome console.log(audio.volume) выдает предсказуемые значения в диапазоне (0;1]. А такое решение у вас работает или тоже падает/ведет себя странно?

согласно спецификации значение громкости звука варьируется от 0.1 до 1
Нет, от 0 до 1.
Смотрите, без try/catch и вашей функции (clampNumber) это выглядит так (уменьшаем громкость):
document.addEventListener("keydown", e => {
    if (e.keyCode == 32) {
        audio.paused ? audio.play() : audio.pause();
    } else if (e.keyCode == 13) {
        audio.load();
    } else if (e.keyCode == 39) {
        audio.currentTime += 10;
    } else if (e.keyCode == 37) {
        audio.currentTime -= 10;
    } else if (e.keyCode == 40) {
        audio.volume -= 0.1;
        console.log(audio.volume)
    } else if (e.keyCode == 38) {
        audio.volume += 0.1;
        console.log(audio.volume)
    }
});



C вашей функцией так:
document.addEventListener("keydown", e => {
    if (e.keyCode == 32) {
        audio.paused ? audio.play() : audio.pause();
    } else if (e.keyCode == 13) {
        audio.load();
    } else if (e.keyCode == 39) {
        audio.currentTime += 10;
    } else if (e.keyCode == 37) {
        audio.currentTime -= 10;
    } else if (e.keyCode == 40) {
        audio.volume = clampNumber(audio.volume - 0.1);
    } else if (e.keyCode == 38) {
        audio.volume = clampNumber(audio.volume + 0.1);
    }
});



Проблема исключений решается, странные значения остаются. Результат такой же, как при использовании try/catch, но пришлось написать целую функцию (которая иногда приводит к громкости = 79, 89 и т.д.). С диапазоном согласен.
Ага, кажется понял о чем вы. «Странные» некруглые значения громкости — это всего лишь артефакт того, что значение храниться во float.

В нормальных (ирония) языках вроде C, где есть отдельно целочисленные и плавающие типы, такое поведение — обычное дело. Там никого не удивишь, что 0.0001 + 0.0002 != 0.0003. А в javascript число представлено одним универсальным типом IEEE 754 binary64. Что позволяет однозначно закодировать (в том числе и) диапазон целых чисел от Number.MIN_SAFE_INTEGER до Number.MAX_SAFE_INTEGER и как будто бы ожидать от number поведение, свойственное для integer в других языках: 123 + 456 == 579 строго. И это ослабляет бдительность. Ведь по-прежнему 0.1 + 0.2 == 0.30000000000000004

А в нашем случае вообще происходит итеративное сложение, которое за каждую операцию накапливает в себе ошибку. Так что это поведение абсолютно нормально. Чтобы видеть красивые ровные проценты в UI — отображаемое значение необходимо округлить. Это стандартная практика.
И ещё один момент по поводу:
Результат такой же, как при использовании try/catch, но пришлось написать целую функцию

Дело в том, что
catch(everyErrorIDontCare) { return; }

это антипаттерн, которого рекомендуют всячески избегать. Ведь вы никогда не узнаете, если что-то другое неожиданно сломается внутри try блока.

Считается, что допустимо использовать try/catch при выполнении трех условий:

  1. без ошибок никак иначе не обойтись
  2. минимально необходимое тело try
  3. выброс необработанной ошибки наружу

try {
  audio.volume = 1.1;
} catch (err) {
  if (err instanceof DOMException && err.name === 'IndexSizeError') {
    return;
  } else {
    throw err; // pass any other unhandled error
  }
}

Но всё это совершенно не оправдано в нашем случае. И не красиво.

А вот функция clampNumber() — вполне self-explaining code. Ведь вам сам API как бы говорит: «программист, позаботься о том, чтобы громкость была в интервале от 0 до 1, иначе я ломаюсь».
Когда занимался подобным проектом, попалась интересная библиотека по определению ритма музыки (BPM): web-audio-beat-detector
Работает с применением Web-воркеров

А можно такое же, но для бесконечного радиопотока? :)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации