Comments 10
Я бы добавил что группирование по немспейсам также облегчает чтение конечным потребителем. Гораздо удобней ткнуть список классов и интерфейсов в IDE, чем каждый раз лезть в документацию чтобы вспомнить название нужного. В этом плане слишком подробный неймспейс действительно может быть минусом и стоит сократить до какого-то уровня.
Но в стандарте MIDI нет понятия “нота”.
Да, потому что в стандарте MIDI есть понятие "событие". Поэтому правильные (и логичные) нэймспейсы будут Midi.Event.NoteOn, Midi.Event.NoteOff, Midi.Event.AllNoteOff и т.д. И сам MIDI - это прежде всего протокол передачи данных, поэтому строить над ним высокоуровневые абстракции возможно не самая лучшая идея. Возможно, более лучшей идеей будет строить высокоуровневые абстракции над более понятными музыканту вещами, такими как классическая нотная запись, пиано-ролл, гитарные табы/аккорды и пр., а MIDI оставить как вариант импорта/экспорта.
Да, потому что в стандарте MIDI есть понятие "событие".
Да, об этом сказано в статье:
В MIDI есть события. При этом у каждого задано смещение во времени (в неких тиках) относительно предыдущего. Но в музыке, разумеется, никто не оперирует MIDI-событиями
По поводу
Поэтому правильные (и логичные) нэймспейсы будут Midi.Event.NoteOn, Midi.Event.NoteOff, Midi.Event.AllNoteOff и т.д.
не согласен категорически. Мало того, что я вообще в первый раз вижу отдельные пространства имён под каждый класс (пользователи за это будут вам очень "благодарны"), так ещё и логичного в этом ничего не вижу (AllNoteOff это так-то событие Control Change с определёнными параметрами).
И сам MIDI - это прежде всего протокол передачи данных, поэтому строить над ним высокоуровневые абстракции возможно не самая лучшая идея.
Опять же, не могу согласиться. Да, это протокол передачи данных. Но его активно используют музыканты, например, вставляя в DAW. К слову, DAW пары Note On/Off объединяют, внезапно, в ноты в пиано ролле, потому что, как я и говорил, музыканты не работают в терминах MIDI.
Да и большое число пользователей, вопросов и обращений подтверждают, что API библиотеки сделан более или менее правильно. Библиотека ведь не запрещает вам использовать и "сырые" MIDI-события. Архитектура DryWetMIDI слоистая, есть и слой с абстракциями в терминах MIDI, можно и ими пользоваться. А можно и более высокоуровневыми.
Возможно, более лучшей идеей будет строить высокоуровневые абстракции над более понятными музыканту вещами, такими как классическая нотная запись, пиано-ролл, гитарные табы/аккорды и пр., а MIDI оставить как вариант импорта/экспорта.
Ну так чтобы сделать импорт, понадобится вся та кухня, что есть сейчас по работе с MIDI. Мне кажется, вы полагаете, что библиотека предоставляет только абстракции высокого уровня. Это не так. Даже в README проекта я об этом явно говорю:
DryWetMIDI is the .NET library to work with MIDI data and MIDI devices. It allows:
...
Manage content of a MIDI file either with low-level objects, like event, or high-level ones, like note (read the High-level data managing section of the library docs).
пользователи за это будут вам очень "благодарны"
Так я и есть тот самый "благодарный пользователь" Sanford и MidiSharp. Там конечно тоже не всё идеально и есть что улучшить, но зато вполне ложится на мою логику.
Да и большое число пользователей, вопросов и обращений подтверждают, что API библиотеки сделан более или менее правильно
Конечно, ведь те, кто считает иначе - просто проходят мимо. Если бы не ваши статьи на хабре и мой интерес в этой теме - вы бы так и не узнали, что ненулевое количество людей считают вашу библиотеку излишне переусложнённой, не воспримите за критику пожалуйста. Своё видение высокоуровневой абстракции я вам ещё в прошлой статье показывал, если помните. Заодно и ошибку в низкоуровневых алгоритмах нашёл, которую вы не захотели принимать, что тоже мне не совсем понятно.
Мне кажется, вы полагаете, что библиотека предоставляет только абстракции высокого уровня.
Конечно я ознакомился с кодом вашей библиотеки, причём не раз. Не нашёл, например, никакого упоминания про VSTi и устройства вывода звука, ни на каком уровне абстракции. Что заодно решило бы проблему с таймером в 1мс. Значит, это нужно делать самому, и вникать в низкоуровневую реализацию тоже самому, а тогда зачем вот это вот всё.
Заодно и ошибку в низкоуровневых алгоритмах нашёл, которую вы не захотели принимать
Принимаю. Но для пользователей функция, от того алгоритма зависящаая, работает верно.
Не нашёл, например, никакого упоминания про VSTi и устройства вывода звука, ни на каком уровне абстракции. Что заодно решило бы проблему с таймером в 1мс.
Вы путаете MIDI и Audio. MIDI playback никогда не будет без таймера. Audio будет, звук выводится на аудио-устройства посредством буфера.
Любой VSTi имеет параметр MIDI input. Это MIDI-устройство, откуда принимать даные. Стандартная практика вывода программного MIDI в VST-инструмент — виртуальные устройства (aka virtual cables). DryWetMIDI предоставляет возможность выводить MIDI.
Значит, это нужно делать самому, и вникать в низкоуровневую реализацию тоже самому, а тогда зачем вот это вот всё.
Процент задач, в которых нужно вникать в низкоуровневую реализацию намного меньше прикладных задач, в которых получить ноты или выполнить их квантизацию есть насущные проблемы.
Так я и есть тот самый "благодарный пользователь" Sanford и MidiSharp.
Разумеется, каждый сам выбирает себе инструмент, который ему больше нравится.
Возвращаясь в русло статьи: в обеих этих библиотеках нет предлагаемого вами подхода — каждый класс класть в отдельное пространство имён. Повторюсь, вы первый, кто такое практикует. Это любопытно, и в любом случае спасибо за комментарий.
Я за критику, но конструктивную. В прошлой статье были комментарии, указывающие на минусы подхода с кастомными структурами. Очень благодарен этим замечаниям, я их добавил в статью даже.
предлагаемого вами подхода — каждый класс класть в отдельное пространство имён
Я не кладу каждый класс в отдельное пространство имён конечно же, приводил полное имя класса. Привычка такая сформировалась после работы с рефлексией.
Вы путаете MIDI и Audio.
Не путаю. 99.99% задач связанных с MIDI - это воспроизведение MIDI. Когда-то давно этим занималась звуковая карта, а типичный процессор тех лет синтез звука в реальном времени никак не тянул. Для этого и нужен был вывод в миди-устройство. Но сейчас ситуация изменилась и мощности обычного домашнего компьютера более чем хватает для роли студии звукозаписи, синтезом звука занимаются VSTi и прочие программные продукты, а аудио-карты занимаются только вводом/выводом звука.
Ну вот подключил я недавно синтезатор к компьютеру и захотел с него получить квадро-звук с реверберацией из органного зала. Но стандартный миди-девайс Microsoft GS Wavetable Synth не даёт такой возможности, поэтому никак тут без низкоуровневого звука не обойтись.
99.99% задач связанных с MIDI - это воспроизведение MIDI.
Слишком категоричное заявление. Из моего опыта обращений пользователей это не так. Хотя, подтверждаю, задача одна из популярных.
синтезом звука занимаются VSTi и прочие программные продукты
Совершенно верно, и VSTi это уже про генерацию аудио (собственно, звука). VSTi забирает данные из MIDI Input и генерирует звук. MIDI это только про команды для синтезатора (аппратного, программного, VSTi и иже с ними), MIDI абсолютно никак с генерацией звука не связан сам по себе.
Ну вот подключил я недавно синтезатор к компьютеру и захотел с него получить квадро-звук с реверберацией из органного зала. Но стандартный миди-девайс Microsoft GS Wavetable Synth не даёт такой возможности, поэтому никак тут без низкоуровневого звука не обойтись.
Думаю, ваша проблема была какой-то иной или я чего-то не понял. Что мешает озвучивать ваш синтезатор (аппаратный, как я понимаю, речь не про генерацию MIDI из программы) любым VSTi? Зачем тут какой-то "низкоуровневый звук"?
Если же речь про озвучивание генерируемого программой MIDI, то ситуация стандартная и решается не менее стандартно через виртуальные устройства. Как я и писал выше, virtual cables это называется. Из наиболее популярных и бесплатных, наверное, loopMIDI:
создаёте в loopMIDI устройство с именем X;
выводите MIDI плейбек на этот X;
забираете данные из X в любом нужном вам VSTi (т.е. у инструмента указываете MIDI Input = X).
Что мешает озвучивать ваш синтезатор (аппаратный, как я понимаю, речь не про генерацию MIDI из программы) любым VSTi? Зачем тут какой-то "низкоуровневый звук"?
Что мешает загрузить MIDI в любой из миллионов редакторов/секвенсоров? Зачем для этого нужна ваша библиотека?
Если же речь про озвучивание генерируемого программой MIDI, то ситуация стандартная и решается не менее стандартно через виртуальные устройства. Как я и писал выше, virtual cables это называется.
Зачем использовать виртуальные миди-кабеля, если здесь можно прекрасно обойтись без них? Получить миди-событие, отправить его в VSTi, из VSTi получить аудио-семпл, отправить его в 4-канальный конвольвер, затем отправить его в аудио-выход. Зачем плодить сущности и усложнять реализацию?
Все верно и подход в общим правильный, но... пишет библиотеки для внешнего использования абсолютное меньшинство программистов. Остальные пилят какие-то проекты внутри одного солюшена. Редко, если для пары-тройки соседних солюшенов. И уж наверняка при каждом релизе вся эта батага билдится заново с нуля. Так что проблемы переместить класс нет.
Заметки по архитектуре .NET библиотеки: пространства имён