Русский
Русский
English
Статистика
Реклама

Музыкальные сервисы

Лабаем на MIDI клавиатуре в Angular

30.06.2020 14:13:12 | Автор: admin

Web MIDI API интересный зверь. Хоть он и существует уже почти пять лет, его все еще поддерживает только Chromium. Но это не помешает нам создать полноценный синтезатор в Angular. Пора поднять Web Audio API на новый уровень!



Ранее я рассказывал про декларативную работу с Web Audio API в Angular.


Программировать музыку, конечно, весело, но что если мы хотим ее играть? В 80-е годы появился стандарт обмена сообщениями между электронными инструментами MIDI. Он активно используется и по сей день, и Chrome поддерживает его на нативном уровне. Это значит, что, если у вас есть синтезатор или MIDI-клавиатура, вы можете подключить их к компьютеру и считывать то, что вы играете. Можно даже управлять устройствами с компьютера, посылая исходящие сообщения. Давайте разберемся, как это сделать по-хорошему в Angular.


Web MIDI API


В интернете не так много документации на тему этого API, не считая спецификации. Вы запрашиваете доступ к MIDI-устройствам через navigator и получаете Promise со всеми входами и выходами. Эти входы и выходы еще их называют портами являются нативными EventTargetами. Обмен данными осуществляется через MIDIMessageEventы, которые содержат Uint8Array сообщения. В каждом сообщении не более 3 байт. Первый элемент массива называется status byte. Каждое число означает конкретную роль сообщения, например нажатие клавиши или движение ползунка параметра. В случае нажатой клавиши второй байт отвечает за то, какая клавиша нажата, а третий как громко нота была сыграна. Полное описание сообщений можно подсмотреть на официальном сайте MIDI. В Angular мы работаем с событиями через Observable, так что первым шагом станет приведение Web MIDI API к RxJs.


Dependency Injection


Чтобы подписаться на события, мы сначала должны получить MIDIAccess-объект, чтобы добраться до портов. navigator вернет нам Promise, а RxJs превратит его для нас в Observable. Мы можем создать для этого InjectionToken, используя NAVIGATOR из @ng-web-apis/common. Так мы не обращается к глобальному объекту напрямую:


export const MIDI_ACCESS = new InjectionToken<Promise<MIDIAccess>>(   'Promise for MIDIAccess object',   {       factory: () => {           const navigatorRef = inject(NAVIGATOR);           return navigatorRef.requestMIDIAccess               ? navigatorRef.requestMIDIAccess()               : Promise.reject(new Error('Web MIDI API is not supported'));       },   },);

Теперь мы можем подписаться на все MIDI-события. Можно создать Observable одним из двух способов:


  1. Создать сервис, который наследуется от Observable, как мы делали в Geolocation API
  2. Создать токен с фабрикой, который будет транслировать этот Promise в Observable событий

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


export const MIDI_MESSAGES = new InjectionToken<Observable<MIDIMessageEvent>>(   'All incoming MIDI messages stream',   {       factory: () =>           from(inject(MIDI_ACCESS).catch((e: Error) => e)).pipe(               switchMap(access =>                   access instanceof Error                       ? throwError(access)                       : merge(                             ...Array.from(access.inputs).map(([_, input]) =>                                 fromEvent(                                     input as FromEventTarget<MIDIMessageEvent>,                                     'midimessage',                                 ),                             ),                         ),               ),               share(),           ),   },);

Если нам нужен какой-то конкретный порт, например если мы хотим отправить исходящее сообщение, достанем его из MIDIAccess. Для этого добавим еще один токен и подготовим фабрику для удобного использования:


export function outputById(id: string): Provider[] {   return [       {           provide: MIDI_OUTPUT_QUERY,           useValue: id,       },       {           provide: MIDI_OUTPUT,           deps: [MIDI_ACCESS, MIDI_OUTPUT_QUERY],           useFactory: outputByIdFactory,       },   ];}export function outputByIdFactory(   midiAccess: Promise<MIDIAccess>,   id: string,): Promise<MIDIOutput | undefined> {   return midiAccess.then(access => access.outputs.get(id));}

Кстати, вы знали, что нет необходимости спрэдить массив Provider[], когда добавляете его в метаданные? Поле providers декоратора @Directive поддерживает многомерные массивы, так что можно писать просто:

providers: [  outputById(someId),  ANOTHER_TOKEN,  SomeService,]

Если вам интересны подобные практичные мелочи про Angular приглашаю почитать нашу серию твитов с полезными советами.

Аналогичным образом можно добывать и входные порты, а также запрашивать их по имени.


Операторы


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


  • Фильтрующие. Они отсеивает события, которые нас не интересуют. Например, если мы хотим слушать только сыгранные клавиши или ползунок громкости.
  • Преобразующие. Они будут преобразовывать значения для нас. Например, оставлять только массив данных сообщения, отбрасывая остальные поля события.

Вот так мы можем слушать события с определенного канала:


export function filterByChannel(   channel: MidiChannel,): MonoTypeOperatorFunction<MIDIMessageEvent> {   return source => source.pipe(filter(({data}) => data[0] % 16 === channel));}

Status byte организован группами по 16: 128143 отвечают за нажатые клавиши (noteOn) на каждом из 16 каналов. 144159 за отпускание зажатых клавиш (noteOff). Таким образом, если мы возьмем остаток от деления этого байта на 16 получим номер канала.


Если нас интересуют только сыгранные ноты, поможет такой оператор:


export function notes(): MonoTypeOperatorFunction<MIDIMessageEvent> {   return source =>       source.pipe(           filter(({data}) => between(data[0], 128, 159)),           map(event => {               if (between(event.data[0], 128, 143)) {                   event.data[0] += 16;                   event.data[2] = 0;               }               return event;           }),       );}

Некоторые MIDI-устройства отправляют явные noteOff-сообщения, когда вы отпускаете клавишу. Но некоторые вместо этого отправляют noteOn сообщение с нулевой громкостью. Этот оператор нормализует такое поведение, приводя все сообщения к noteOn. Мы просто смещаем status byte на 16, чтобы noteOff-сообщения перешли на территорию noteOn, и задаем нулевую громкость.

Теперь можно строить цепочки операторов, чтобы получить стрим, который нам нужен:


readonly notes$ = this.messages$.pipe(  catchError(() => EMPTY),  notes(),  toData(),);constructor(  @Inject(MIDI_MESSAGES)  private readonly messages$: Observable<MIDIMessageEvent>,) {}

Пора применить все это на практике!


Создаем синтезатор


С небольшой помощью библиотеки для Web Audio API, которую мы обсуждали ранеесоздадим приятно звучащий синтезатор всего за пару директив. Затем мы скормим ему ноты, которые играем через описанный выше стрим.


В качестве отправной точки используем последний кусок кода. Чтобы синтезатор был полифоническим, нужно отслеживать все сыгранные ноты. Для этого воспользуемся оператором scan:


readonly notes$ = this.messages$.pipe(  catchError(() => EMPTY),  notes(),  toData(),  scan(    (map, [_, note, volume]) => map.set(note, volume), new Map()  ),);

Чтобы звук не прерывался резко и не звучал всегда на одной громкости, создадим полноценный ADSR-пайп. В прошлой статье была его упрощенная версия. Напомню, идея ADSR менять громкость звука следующим образом:



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


@Pipe({    name: 'adsr',})export class AdsrPipe implements PipeTransform {    transform(        value: number,        attack: number,        decay: number,        sustain: number,        release: number,    ): AudioParamInput {        return value            ? [                  {                      value: 0,                      duration: 0,                      mode: 'instant',                  },                  {                      value,                      duration: attack,                      mode: 'linear',                  },                  {                      value: sustain,                      duration: decay,                      mode: 'linear',                  },              ]            : {                  value: 0,                  duration: release,                  mode: 'linear',              };    }}

Теперь, когда мы нажимаем клавишу, громкость будет линейно нарастать за время attack. Затем она убавится до уровня sustain за время decay. А когда мы отпустим клавишу, громкость упадет до нуля за время release.

С таким пайпом мы можем набросать синтезатор в шаблоне:


<ng-container  *ngFor="let note of notes | keyvalue; trackBy: noteKey">  <ng-container    waOscillatorNode    detune="5"    autoplay    [frequency]="toFrequency(note.key)"   >    <ng-container       waGainNode       gain="0"      [gain]="note.value | adsr: 0:0.1:0.02:1"    >      <ng-container waAudioDestinationNode></ng-container>    </ng-container>  </ng-container>   <ng-container    waOscillatorNode    type="sawtooth"    autoplay     [frequency]="toFrequency(note.key)"  >    <ng-container       waGainNode      gain="0"      [gain]="note.value | adsr: 0:0.1:0.02:1"    >      <ng-container waAudioDestinationNode></ng-container>      <ng-container [waOutput]="convolver"></ng-container>    </ng-container>  </ng-container></ng-container><ng-container  #convolver="AudioNode"  waConvolverNode  buffer="assets/audio/response.wav">  <ng-container waAudioDestinationNode></ng-container></ng-container>

Мы перебираем собранные ноты с помощью встроенного keyvalue пайпа, отслеживая их по номеру сыгранной клавиши. Затем у нас есть два осциллятора, играющих нужные частоты. А в конце эффект реверберации с помощью ConvolverNode. Довольно нехитрая конструкция и совсем немного кода, но мы получим хорошо звучащий, готовый к использованию инструмент. Попробуйте демо в Chrome:


https://ng-web-apis.github.io/midi


Если у вас нет MIDI клавиатуры можете понажимать на ноты мышкой.


Живое демо доступно тут, однако браузер не позволит получить доступ к MIDI в iframe: https://stackblitz.com/edit/angular-midi

Заключение


В Angular мы привыкли работать с событиями с помощью RxJs. И Web MIDI API не сильно отличается от привычных DOM событий. С помощью пары токенов и архитектурных решений мы смогли с легкостью добавить поддержку MIDI в наше Angular приложение. Описанное решение доступно в виде open-source библиотеки @ng-web-apis/midi. Она является частью большого проекта, под названием Web APIs for Angular. Наша цель создание легковесных качественных оберток для использования нативного API в Angular приложениях. Так что если вам нужен, к примеру, Payment Request API или Intersection Observer посмотрите все наши релизы.


Если вам любопытно, что же такого интересного можно сделать на Angular при помощи Web MIDI API приглашаю вас научиться играть на клавишах в личном проекте Jamigo.app

Подробнее..

Непрошеные рекомендации зачем учиться искать музыку без помощи стриминговых сервисов

18.10.2020 12:20:24 | Автор: admin

После обзора альтернатив для фона мы рассказали, где искать и как подбирать новые треки. Сегодня посмотрим, за что критикуют стриминговые платформы (помимо низкого качества рекомендаций), и почему их советы полезно разбавлятьсамостоятельным и осознанным поиском музыки.

Фотография: John Hult. Источник: Unsplash.comФотография: John Hult. Источник: Unsplash.com

Что-то пошло не так

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

На этом дело не ограничивается. Месяц назад в колонке для The New Yorker Алекс Росс (Alex Ross), известный критик и лауреат многочисленных премий в области музыкальной журналистики, сделал отсылку к книге Кайла Дивайна (Kyle Devine) под названием Decomposed. Она рассказывает о влиянии музыкальной индустрии, в том числе и стриминговых сервисов, на экологию и объясняет, как онлайн дистрибуция и многократное (повторное) скачивание треков наносит все более существенный ущерб окружающей среде, несравнимый даже с отходами от изданий на виниле и других носителях.

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

Фотография: Annie Spratt. Источник: Unsplash.comФотография: Annie Spratt. Источник: Unsplash.com

В качестве весомого аргумента он приводит статью, где в гуманитарном, но достаточно подробном ключе разобраны риски стриминга и с точки зрения информационной безопасности. Согласно аналитическому обзору автора, представляющего Техасский университет в Остине, руководители отделов по работе с алгоритмами и рекомендательными системами ряда крупных музыкальных сервисов часто хвастаются, что знают не только, что слушает, но и чем занимается их аудитория.

Старый, но хрестоматийный пример не самого удачного PRа в контексте этой статьи рассказ директора одной из таких компаний о наиболее востребованных треках в ванной комнате.

Даже если не брать в расчет такие высказывания и скандальные истории об автоматической установке вредоносов в бесплатных версиях стриминговых учеток, у разработчиков музыкальных сервисов хватает проблем как с заработком музыкантов, так и с пользовательским опытом слушателей.

Последние зачастую не видят новые треки только потому, что те не попадают в нужную категорию. Известные примеры таких ситуаций кейсы легендарной Old Town Road и музыки Нью-Мексико.

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

Фотография: Brett Jordan. Источник: Unsplash.comФотография: Brett Jordan. Источник: Unsplash.com

Сам себе куратор

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

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

Нельзя исключать, что вы решите взять что-то из таких находок на виниле или другом носителе. Если коллекция пластинок уже есть, анализ любимых треков может вылиться в оцифровку всего архива, что тоже вполне достойная затея.Но не стоит забывать и об одном из самых недооцениваемых способов поиска новой музыки советах друзей, коллег и приятелей по тому или иному хобби.

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

Фотография: Artificial Photography. Источник: Unsplash.comФотография: Artificial Photography. Источник: Unsplash.com

Почему это важно

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

Осознанное отношение к тому, что слушать, несет больше практического смысла, чем может показаться на первый взгляд. Даже три круга по игровой гоночной трассе показывают, что это так. Согласно именно такому исследованию, проведенному специалистами из Каледонского университета Глазго при участии 125 добровольцев, самостоятельно выбранное музыкальное сопровождение способствует повышению эффективности и получению положительных эмоций от своей деятельности, плюс снижению напряжения и влияния на процесс различных отвлекающих факторов.

P.S.В следующий раз мы продолжим изучать эту тему и обсудим, что из себя сейчас представляет рынок веб-радиостанций, и какие из них можно было бы порекомендовать для прослушивания.


Что еще мы разбираем на Хабре:


Подробнее..

За счет чего муз. сервис крупнейшего видеохостера собирается конкурировать на рынке стриминга

25.04.2021 00:12:13 | Автор: admin

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

Фотография: Mick Haupt. Источник: Unsplash.comФотография: Mick Haupt. Источник: Unsplash.com

Что происходит

Необходимость эпидемиологических ограничений не обсуждается, но они так или иначе доставили немало неудобств не только обывателям, но и музыкантам. Последние были вынуждены отказаться от туров и точечных выступлений в клубах и экспериментировать с онлайн-концертами. Однако такого опыта у основной массы авторов и исполнителей, конечно же, не было. Поэтому в итоге лишь избранным удавалось проводить стримы и лайвшоу в сети.

Одной из центральных площадок для выступлений таких артистов стал Ютуб, чья команда всеми силами помогала музыкантам организовывать онлайн-перфомансы. Интерес платформы состоял не только в заработке на рекламе, но и в привлечении внимания к собственному музыкальному сервису. Сегодня у руководства корпорации на него большие планы его не устраивает ситуация, когда слушатели находят новую музыку на Ютубе, а потом идут на другие платформы и платят им на регулярной основе за возможность ее слушать.

Опоздали или нет

Кажется, ответ очевиден. Отсутствие постоянства в развитии собственного музыкального продукта сильно бьет по позициям менеджеров платформы. Сперва они занимались сервисом Music Key, параллельно развивали Play Music All Access, а потом запустили YouTube Red, после этого объединили все в YouTube Premium, но вместе с этим развивали YouTube Music.

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

Фотография: Joshua O. Источник: Unsplash.comФотография: Joshua O. Источник: Unsplash.com

Все эти сложности хорошо знакомы специалистам, и о них много где пишут. Однако эксперты высказывают и аргументы в защиту Ютуб мьюзик. Так, Марк Маллиган, анализирующий развитие муз. индустрии, считает, что платформа обладает уникальными возможностями для работы с представителями поколения Z. По его мнению, этот срез аудитории не представляет свою жизнь без видеоконтента, да и с точки зрения наличия ремиксов, каверов и ремастеров популярных треков Ютуб является безусловным лидером. Многообразие библиотеки платформы в этом отношении превосходит то, что можно найти на Спотифай и сервисе Эппл мьюзик.

Вопрос в алгоритмах

Обширная библиотека существенное преимущество. Но контент еще необходимо доставить до слушателя и точно определить, что он желает получить здесь и сейчас. С этим у площадки есть некоторые сложности. Взять хотя бы систему рекомендаций не критикует ее только ленивый, хотя Ютуб неплохо отражает удары, не пытается спорить с аудиторией и в определенной степени берет инициативу в свои руки, запуская новый функционал для основного видеосервиса.

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


Что еще почитать по теме в нашем Мире Hi-Fi:


У нас на Хабре:


Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru