На написание данной статьи меня вдохновила другая – Как делается OpenSource: личный опыт. Мой проект DryWetMIDI менее масштабный, но тем не менее весьма популярен в своей нише. В статье я вспомню, как он создавался, развивался, что дал (и продолжает давать) и какие были любопытные моменты по пути. Надеюсь, сии мемуары будут вам интересны и полезны. MIDI – формат, широко используемый для передачи музыкальных данных (например, нот, событий изменения контроллеров и т.д.). Подробные спецификации доступны на официальном сайте. Немного о том, что умеет делать DryWetMIDI: Читать, писать и создавать MIDI-файлы. Библиотека предоставляет для этого структуры данных, позволяющие манипулировать содержимым файлов. Отсылать MIDI-события на MIDI-устройства и принимать их с устройств. Кроме того, есть функционал воспроизведения MIDI-данных и их записи. Работать с MIDI как на низком уровне (например, с событиями и блоками (chunks)), так и на высоком (ноты, аккорды). Быстро создавать музыкальные композиции. Выполнять сложные задачи, например, квантизацию музыкальных объектов или же разбиение файлов. Если в двух словах – DryWetMIDI пригодится при подготовке и обработке музыкальных партий, их записи и воспроизведения, с полным контролем над происходящим. Сложно и долго приводить список всего того, в чём может помочь библиотека. Одним из примеров является создание игр наподобие Guitar Hero. Также используется для разработки обучающих программ, например, для тренировки слуха и чувства ритма. Разумеется, широкое применение имеет у людей, занимающихся созданием музыки (например, можно программно подготовить MIDI-файл и вставить его в DAW). А почему бы... Второй заход Ещё одна библиотека Узрите же её Эволюция История версий Идеи и где они обитают Про деньги Пользователи Плоды Связь с миром Радость созидания Профессиональная прокачка Заключение Как обычно создаётся проект с открытым исходным кодом? Человек сталкивается с какой-то задачей, не находит готовых вариантов её решения, пишет инструмент для своих нужд и выкладывает его код в открытый доступ (а потом нередко теряет интерес к теме и проект умирает, но не будем об этом). А почему бы не сделать что-то крутое? С таким вопросом рождается подобный проект у автора данной статьи. И не говорите, что аналогичные мысли никогда у вас не возникали. Невозможно сосчитать, сколько “невиданных доселе” калькуляторов было написано в этих порывах по всему миру. Я, например, наваял такой в 2008-ом на Delphi (к слову, он-таки пригождался иногда). Нужно было понять, что именно сделать крутого. Загибаем пальцы: я программист, иногда создаю музыку (Melanchall, 12 o’clock), в музыке активно применяю MIDI. Вот и ответ – напишу библиотеку для работы с MIDI-файлами. К тому же, я считаю парсинг достаточно сложного формата отдельным видом земных удовольствий. Но “сделать что-то крутое” – спорная причина начать проект. Кому-то она может стать стимулом для создания настоящего шедевра, а кого-то погрузить в вялотекущее написание кода ради написания кода. Я из второго лагеря. Разработка была начата в 2013-ом году на C#. Я даже нашёл свой полный энтузиазма пост на музыкальном форуме Underground Exhibitions (сам пост в закрытом разделе, оригинальная орфография сохранена): И хотя сам по себе протокол MIDI и формат SMF (Standard MIDI File) достаточно мудрёные ввиду своей старины, вряд ли кто-то из вас скажет, что на создание подобной библиотеки нужно больше нескольких месяцев. Однако шёл 2014-ый год, затем 2015-ый, затем (внезапно) 2016-ый, а воз был и ныне там. Какой-то код я, конечно, писал, но это не было чем-то завершённым. Да и вопросов вроде “Зачем я делаю проект?” или “Что должно быть в итоге?” я себе не задавал. В почте у меня сохранились письма тех лет самому себе с архивами исходников библиотеки (система контроля версий, говорите?). Если заглянуть в самый ранний код, можно немного испугаться. Но оно и неудивительно, зная мой опыт на момент начала разработки: Разного рода лабораторные задачи в университете и поделия для себя. Неполных 2 года в компании разработчиком на задачах, требующих минимального профессионального развития. К слову, как раз в 2013-ом ситуация изменилась в положительную сторону с переходом в другой проект внутри той же компании. Разработка графики для мобильного приложения одной из сети кофеен. Не удивляйтесь. В начале 2011-го года наш преподаватель курса “Программирование на языке высокого уровня” предложил мне такую подработку. Забавно было найти письмо ему, когда он озвучил оплату моих трудов: Если что, мой вопрос был касательно лишнего нуля, а не забытого. И всё-таки именно в эту пору появилось кое-что, дошедшее в неизменном виде до наших дней. А именно название библиотеки. Придумано оно было быстро. Хотелось что-то связанное с MIDI, но не такое банальное для мира .NET-разработки, как добавление префикса N или суффикса .NET. Те, кто работает с музыкой, хорошо знают понятия dry/wet signal в обработке аудио – в большинстве эффектов вы найдёте элементы управления для настройки баланса исходного (dry) и обработанного (wet) сигналов. Так что я взял и соединил эти термины со словом MIDI и получил DryWetMIDI. Да и аббревиатура получается удобная – DWM. В начале 2017-го я задумался о смене места работы, хотелось двигаться дальше как профессионально, так и карьерно. Я не из тех, кто легко выходит из зоны комфорта, поэтому сиё решение было тяжёлым. Но вот так сразу взять и искать работу я не мог, в моей профессиональной биографии не было ничего интересного, среднестатистический мидл-разработчик. Шансы найти классного работодателя с таким резюме не особо большие, да и мыкаться по куче собеседований не хотелось. Резюме должно было сверкать, как бы крича “Вам нужен этот парень!”. Я моментально достал с пыльной полки DryWetMIDI, намереваясь в этот раз сделать законченный продукт, упомянуть который будет не стыдно при случае. Появилась ясная цель работы над проектом. У меня даже был критерий того, готов ли я включать упоминание библиотеки в обновлённое резюме: проект должен иметь на GitHub как минимум 10 звёзд. Кроме того, я обозначил для себя ряд принципов, которым собирался следовать: Максимально разрешительная лицензия. Пусть пользователи делают с библиотекой, что захотят. Не хочу чинить никаких препятствий для экспериментов, коммерческих продуктов и в целом изучения моего продукта. Я выбрал лицензию MIT. И хотя согласно этой лицензии её текст должен быть включён в программное обеспечение, зависящее от моей библиотеки, я не требую и этого. На вопросы касательно упоминания DryWetMIDI в пользовательских проектах, я отвечаю, что буду этому рад, но решение за авторами этих проектов. Польза как реклама. Никакого выклянчивания звёзд и отзывов у друзей, знакомых и сообществ в Интернете. Популярность библиотеки должна возникнуть вследствие её пользы для людей. Конечно, миру нужно донести слово о своём изделии, но реклама должна представлять из себя демонстрацию решения реальных задач. Спам – зло. Публичный баг-трекер только для обращений пользователей. Раздел Issues (а позже и Discussions) в проекте на GitHub будет содержать только обращения пользователей. Возможно, это мои тараканы в голове, но для меня присутствие в публичном баг-трекере задач и проблем автора проекта выглядит, как искусственное создание активности. При этом я понимаю, что нет ничего плохого в использовании его для ведения своего бэклога. Тем не менее, все свои планы и замеченные мной баги я решил убрать за кулисы, в публичном же поле должна быть видна активность только пользователей DryWetMIDI. Эти правила были для меня своего рода делом чести. Сделать безвозмездно продукт, который полюбят за его пользу, видимую на живых примерах. Для полноты картины замечу, что разработка DryWetMIDI не была единственным пунктом в моих требованиях к новому облику меня, как ценного кадра. Я также стал активно отвечать на вопросы на Code Review Stack Exchange и Stack Overflow в меру своих познаний. Ценность этой активности, к слову, не только в помощи людям, но также в подготовке к будущему общению с пользователями. Ну и английский язык немного подтягивается, всё-таки вести дискуссии вы будете именно на нём. Первый релиз DryWetMIDI состоялся 26 мая 2017-го. Первое обращение пользователя 27 июля того же года (уже после второго релиза). Тут я должен был показать, что к октябрю я набрал 10 звёзд, выполнив обозначенную выше цель, но что-то пошло не так. Вызвав при подготовке статьи соответствующий метод GitHub API, я обнаружил, что 10-я звезда была получена 7 ноября, а на тот момент я уже работал в другой компании и даже в другом городе (спустя четыре собеседования с разными работодателями). Оффер был получен 9 октября с 6 звёздами на руках. Видимо, я посчитал, что тянуть уже больше некуда. Раз подход в этот раз был таким серьёзным, то сделать просто ещё одну библиотеку для работы с MIDI меня не устраивало. Должны быть функции, отсутствующие у подобных проектов, киллер-фичи. Если сейчас сделать поиск в GitHub по тегу midi и языку C#, то DryWetMIDI вы увидите на третьем месте в рейтинге. На первом месте проект для управления видео посредством MIDI, на втором – плагин для Unity, добавляющий поддержку MIDI-устройств ввода. То есть оба проекта являются специализированными применениями MIDI. DryWetMIDI же, будучи библиотекой общего назначения, предоставляет самые разные функции. Далее в списке можно увидеть проекты, которые в разные годы оставались позади. Наиболее значимые из них: Sanford.Multimedia.Midi. Была своего рода стандартом по работе с MIDI в мире .NET. К сожалению, давно не развивается. MIDI.NET. Ещё одна из некогда популярных, а теперь заброшенных, библиотек. Кстати, если ознакомиться с файлом README.md, можно заметить, что автор очень любит разные паттерны проектирования (я про flyweight не слышал со времён чтения знаменитой книги банды четырёх). managed-midi. Перспективный проект, основной упор в котором сделан на кросс-платформенность. Это действительно важная особенность, выделяющая данную библиотеку на фоне остальных, в том числе и DryWetMIDI (API для работы с MIDI-устройствами реализован пока только для Windows и macOS). Аналогично – проект позабыт, и развитие не планируется, автор честно об этом пишет. При поиске библиотеки для работы с MIDI под .NET вы также можете наткнуться на замечательный проект NAudio, крупный и живой. Но хотя эта библиотека и предоставляет некоторые возможности по взаимодействию с MIDI, этот API крайне низкоуровневый; автор принимает PRы, но сам функционал не модифицирует; более того, некоторые функции существуют в примитивном виде; библиотека про аудио, а MIDI ≠ аудио (к сожалению есть те, кто этого не понимает). Взглянув пристальнее на все эти проекты, я с удивлением обнаружил, что ни один из них не рассчитан на то, что с ним будет работать музыкант. То есть они предоставляют сухой API для чтения/записи MIDI-файлов и манипуляций с MIDI-устройствами, просто согласно спецификациям. Мне же хотелось, чтобы библиотека умела оперировать терминами, понятными занятыми в музыке людьми (не в ущерб согласованности с MIDI-протоколом, конечно же). Цель была соединить миры программирования и музыки. Первой киллер-фичей в DryWetMIDI, задуманной ещё перед релизом, стала система работы со временем и длиной (например, нот). Тут важно понимать, как представляется время в MIDI. Дабы не дублировать информацию, прошу прочесть соответствующий раздел моей прошлой статьи Конвертация MIDI-времени в такты и доли. Ну и кто, скажите, при создании музыки оперирует MIDI-тиками? Вопрос риторический. DryWetMIDI же с версии 1.1.0 предоставляет различные классы для работы с временными диапазонами в музыкальных терминах, корректно обрабатывая события смены темпа и размера (time signature). Подробнее о развитии библиотеки и больших пластах полезного функционала читайте в разделе Эволюция. Сколь полезным бы ни был ваш инструмент, им никто не будет пользоваться, если про него никто не знает. Способ для продвижения своего проекта я выбрал такой: искать вопросы по теме MIDI + .NET/C# и отвечать на них, показывая решение проблемы с использованием DryWetMIDI. Например, на Stack Overflow: Parsing a MIDI file for Note On only Convert MIDI file to list of notes with length and starting time Сразу после первого релиза библиотеки пришлось обработать все интересные мне проблемы. Далее я создал фильтр по тегу midi и теперь, если кто-то задаёт вопрос с таким тегом на Stack Overflow, Sound Design Stack Exchange или Music Stack Exchange, мне приходит уведомление на почту. Конечно, не все из этих вопросов мне интересны, многие из них даже не про .NET. Но это лучше, чем руками мониторить новые посты. Под конец 2017-го ко мне обратился пользователь с вопросом об использовании DryWetMIDI в проектах на игровом движке Unity. Это побудило меня зайти на сайт Unity Answers (был отключен 23 июня 2022-го года, все темы перенесены на новый ресурс Unity Discussions), и найти интересные темы и там. Сильно позже в одной из статей (не смог найти, где) я узнал про сервис F5Bot, который может присылать уведомления на почту в случае обнаружения заданных ключевых слов на Reddit. Я отслеживаю слова melanchall и drywetmidi. Ещё одним инструментом продвижения DryWetMIDI стали статьи на CodeProject. Я искал сайт сродни Хабру и на момент написания первой статьи (24 августа 2017-го) данный ресурс показался мне единственно подходящим на англоязычной сцене. Всего я выложил там три статьи: DryWetMIDI: High-Level Processing of MIDI Files DryWetMIDI: Notes Quantization DryWetMIDI: Working with MIDI Devices Я периодически обновляю их, дабы с выходом новых версий библиотеки они не теряли актуальность. Выше я писал, что важный API для работы со временем и длиной был реализован в версии 1.1.0. У кого-то может возникнуть вопрос “А почему не в версии 1.0.0?”. Дело в том, что я хотел поскорее опубликовать библиотеку, при этом не поступившись качеством. При таком раскладе я видел (и до сих пор вижу) только один вариант – отсечь некоторые фичи, не затягивая релиз. Поэтому первая версия DryWetMIDI не имела значительных преимуществ перед похожими проектами. Следующая же вышла полтора месяца спустя (7 июля 2017-го) и уже включала в себя указанный выше функционал. Немаловажным элементом, влияющим на доверие к продукту и его серьёзность, на мой взгляд является наличие документации. Поэтому ещё до выхода первой версии библиотеки я включил раздел Wiki на странице проекта в GitHub и наполнял его локально. Вероятно, вы знаете, что раздел Wiki это обычный Git-репозиторий, с которым вы можете работать привычным образом. Позже я ушёл с Wiki на GitHub Pages (подробнее см. в разделе Документация моей прошлой статьи Создание .NET библиотеки от А до Я), но у меня сохранился локальный репозиторий, и через git log я вижу, что первый коммит был сделан 13 апреля 2017-го, за полтора месяца до первого релиза. Часто ли вы опираетесь на чужое мнение, дабы сделать выбор? Смотрите фильмы с высоким рейтингом или же покупаете товары с оценкой не ниже 4 звёзд? Активность людей относительного проекта будет побуждать других попробовать его. Поэтому я очень благодарен тем первым пользователям, кто в 2017-ом обратил свой взор на DryWetMIDI для решения своих задач. Довольный пользователь приведёт за собой других, и вместе вы будете делать библиотеку ещё лучше. Без лишней скромности могу сказать, что на сегодняшний день DryWetMIDI для большинства людей будет первым вариантом, если им нужно сделать что-то с MIDI на платформе .NET. Разумеется, с 2017-го года проект сильно вырос, но, мне кажется, ему изначально был задан правильный импульс. Первая версия библиотеки просто предоставляла работу с MIDI-файлами. Две последующие (1.1.0 и 1.2.0) были сконцентрированы на управлении объектами (события, ноты, аккорды) и их временами и длинами. То, что реализуемый этими версиями функционал был задуман заранее, хорошо демонстрирует скорость выпуска релизов – три штуки за почти два месяца. Версия 1.3.0 в конце августа 2017-го привнесла важный API – Pattern – позволяющий создавать музыкальные композиции быстрее. Идею подал проект JFugue, который предоставляет собственный язык написания музыки. Мне же хотелось описывать композиции без кучи строк кода, но при этом не реализуя свой синтаксис (да, я знаю про инструменты вроде ANTLR), что усложнило бы библиотеку. В итоге я пришёл ко вполне простому fluent API, который хоть и массивнее языка Staccato, используемого в JFugue, но всё же проще ручного конструирования объектов и управления их временем, оставаясь при этом в рамках .NET. Релиз за номером 2.0.0 важен не только потому, что сделал концепцию управления временем в библиотеке действительно стройной, но и выявил первую серьёзную архитектурную ошибку. До выхода этой версии существовали отдельные классы для времени и длины (например, MetricTime и MetricLength). Это значит, что при изменениях в коде управления временем в каком-то из форматов необходимо заботиться о двух классах (например, создавать или обновлять тесты), а при поддержке нового формата создавать те самые два класса. Более того, время ничем технически не отличается от длины. Результатом этих рассуждений стало объединение этих пар классов в единую абстракцию ITimeSpan. Реализации этого интерфейса (например, MetricTimeSpan) используются для работы как со временем, так и с длиной. С версией 3.0.0 в DryWetMIDI появились инструменты для выполнения сложных задач. Сначала они предлагали встроенные алгоритмы для квантизации (или квантования, кому как больше нравится) и рандомизации объектов, а также разбиения нот и аккордов множеством способов. Позже к ним добавлялись другие инструменты, например, для разбиения файлов или слияния нот. Этот пласт функциональности также претерпел архитектурные изменения, уйдя от алгоритмов под конкретные типы объектов к обобщённым вариантам. Текущий набор инструментов можно увидеть здесь. В разработке библиотеки с первого же релиза я опирался на два главных принципа: Слои абстракции. Стандартный приём в архитектуре, и тем не менее DryWetMIDI был первым опытом, где я стал осознанно его применять. Сначала в библиотеке был API для чтения и записи MIDI файлов просто согласно спецификации SMF. Далее я добавил функционал по более высокоуровневому взаимодействию с MIDI-данными, который опирался на тот первый. А инструменты, про которые я рассказывал в предыдущем абзаце, образуют слой ещё выше, используя концепции из первых двух. Итеративность. Изначально библиотека предоставляла методы вроде GetNotes и GetChords, которые можно вызвать на MIDI-файле и получить коллекцию объектов указанного типа. Версия 5.2.0 в марте 2021-го представила миру возможность получать одновременно объекты разных типов, унифицируя (но не удаляя) и указанные выше методы и другие утилиты. Именно это позволило провести пошаговую генерализацию инструментов, сделав API лаконичнее и гибче. Как я и писал, изначально библиотека должна была предоставлять только возможности для работы с MIDI-файлами. Более того, я ревностно отстаивал эту концепцию в обращениях пользователей. Но быть упрямым вечно не есть хорошо, если хочется завоевать сердца большего количества пользователей. Запросы на воспроизведение MIDI-файлов поступали время от времени, да и на публичных площадках эта потребность была видна. Поэтому через почти два года версия 4.0.0 добавила в библиотеку API для работы с MIDI-устройствами наряду с возможностью воспроизведения и записи данных. С этим релизом связана поучительная история. Я не выпускаю новый функционал без написания юнит-тестов к нему. Работа с устройствами не должна быть исключением. Для автоматического прогона тестов на соответствующий API нужно было научиться создавать виртуальные MIDI-устройства. На macOS такая возможность есть из коробки (об этом я рассказывал в разделе Виртуальные устройства в статье Введение в CoreMIDI), а вот на Windows вам нужно засучить рукава и написать драйвер под это дело. К счастью, мир не без добрых людей и такие инструменты уже существуют. Сделав свой выбор, довольный я положил инсталлятор утилиты к себе в репозиторий, дабы вызывать его из CI-конвейеров, и был таков. И как-то раз я решил написать автору, дабы выяснить, как создавать виртуальные MIDI-порты во время тихой установки. На что помимо ответа на вопрос получил в мягкой форме по шапке за распространение его программного обеспечения у себя в репозитории. В итоге я перешёл на другой способ, переписав с помощью BFG всю историю репозитория и удалив тот инсталлятор. Так что при работе со сторонними инструментами нужно быть аккуратным. Релиз 5.0.0 устранил ещё одно следствие моей недальновидности – названия некоторых пространств имён содержали в себе .Smf, отсылая к былым временам, когда работа с MIDI-файлами (SMF = Standard MIDI File) виделась ядром проекта. Кроме того, я ушёл с GitHub Wiki на GitHub Pages, настроив выкладку туда сайта, сгенерированного DocFX. Кроме того, были расширены примитивы работы с музыкальной теорией. Важно заметить, что всё это время библиотека оставалась привязанной к Windows. Нет, сама она, конечно, давно переехала на .NET Standard и весь базовый функционал работал на системах, поддерживаемых .NET Core, а затем и просто .NET. Но делать что-то с MIDI-устройствами можно только посредством задействования системного API напрямую (я намеренно не тяну никакие зависимости, так что всякие Xamarin не предлагать). Для этого в DryWetMIDI была создана нативная прослойка, обращения к которой через обвешивание атрибутами DllImport позволяли общаться с MIDI-подсистемой Windows (свои исследования по теме я изложил в статье Создание пакета NuGet для библиотеки с платформозависимым API). При этом в мире создания музыки macOS является сравнимо популярной платформой, да и вопросы касательно работы с устройствами на этой системе стали поступать всё чаще. Спустя почти 4 года с запуска проекта версия 6.0.0 ознаменовала собой кросс-платформенность DryWetMIDI, хоть и в отношении только двух операционных систем. Не обошлось и в этот раз без переделывания пространств имён, ибо снова они стали рассогласованными с API. Последний на момент написания этих строк релиз – 7.0.0– не привнёс значительных улучшений, зато позволил избавиться от большого количества устаревшего функционала (см. пункт Устаревший API в разделе Работа с кодом статьи Создание .NET библиотеки от А до Я). Главным источником наполнения бэклога проекта на первых порах были, конечно, собственные хотелки и вопросы на Stack Overflow. Однако, как только DryWetMIDI приобрёл какую-никакую популярность, доля пользовательских запросов стала весьма ощутимой. Уверен, без них библиотека до сих пор умела бы работать только с MIDI-файлами, да ещё и на Windows. Говоря о развитии или движении проекта, я имею в виду не только реализацию нового функционала. Исправление ошибок – большой пласт такой эволюции. Большинство проблем находят юнит-тесты во время разработки, но всё учесть невозможно, и какая-то доля непотребства просачивается в публичные релизы библиотеки. Я ещё поговорю про общение с пользователями далее в статье, но уже сейчас хочу сказать огромное спасибо тем, кто не просто находит ошибки и сообщает о них, но и не жалея своего времени помогает понять их причину и пути исправления. Временами это выливается в весьма длинную дискуссию. Прислушиваясь к пользователям, полезно замечать типовые сценарии. Стандартный вариант поставки .NET-библиотеки это NuGet-пакет. Разумеется, его я выпускаю с первой же версии. Но довольно скоро я понял, что игры на Unity являются одним из распространённых сценариев. Существуют варианты добавить NuGet-пакет в проект игры, однако, каноничный путь – установить ассет из Unity Asset Store. Как правило, ассеты это наборы моделей, текстур, звуков и т.д. Но почему бы не завернуть программную библиотеку в ассет и не дать пользователям быстрый способ добавить её в игру? Я считаю интеграции интересным вектором развития проекта, эту тему я затронул в статье Создание .NET библиотеки от А до Я. Искал идеи я и в похожих проектах, не важно на каком языке программирования. У меня есть подписки в GitHub (watch) на некоторые из наиболее заметных в мире MIDI: mido; music21; RtMidi. Это позволяет быть в курсе новых релизов через уведомления в почту, своевременно узнавая об интересных функциях коллег по цеху. Но, по правде говоря, я так сходу и не вспомню, какие из возможностей DryWetMIDI обязаны такому подглядыванию. Зато я прекрасно помню, как форк моей библиотеки на GitHub указал на некоторое упущение. Изначально DryWetMIDI предоставляла метод для чтения файлов только по пути. Но в конце июля 2017-го я заметил, что кто-то сделал форк проекта. Заглянув в него, обнаружился интересный коммит, добавляющий возможность чтения из Stream. Это было так очевидно! Поэтому метод MidiFile.Read с тех пор умеет принимать аргумент и такого типа. Так что в форки я тоже поглядываю. К слову о проактивности. Как-то раз, просматривая результаты поиска по слову “drywetmidi” я наткнулся на заметки к выпуску популярного клона игры Guitar Hero – Clone Hero. В длинном списке значилось: Не дожидаясь, пока мне заведут баг, я решил связаться с разработчиками Clone Hero и узнать, что там за проблема и как я могу помочь решить её. В процессе выяснилось, что конкретно к этой ситуации DryWetMIDI не причастна, зато один из разработчиков поделился большим количеством найденных в библиотеке проблем с производительностью чтения MIDI-файлов. Присовокупив к этому списку обращение другого пользователя, я добился значительного прироста в скорости операции: Невозможно обойти стороной денежную сторону. В сети вы можете найти разные варианты конвертации сил и времени, вложенных в ваш проект с открытым исходным кодом, во что-то материальное: Платная поддержка. Самый очевидный вариант. Нужна помощь с вашей проблемой? За мешочек золотых – пожалуйста. Мне запомнилась статья на Хабре по этому поводу – Нет, Open Source не означает «бесплатная поддержка». Premium-функции. Некий набор базовых методов предоставляется бесплатно, а за продвинутые придётся заплатить. Лицензия. Можно составить лицензию таким образом, что определённые сценарии использования библиотеки будут подразумевать или отчисления в виде процентов или необходимость согласования с автором для обсуждением цены. Вариантов много. Про первый пункт хочу поговорить отдельно, в нём есть здравое зерно. Дело в том, что более или менее популярный проект порождает вопросы к вам от пользователей. А пользователи бывают самые разные. Иногда человек не жалеет ни своё ни ваше время, не предоставляет необходимую для решения вопроса информацию и не изучает документацию, затягивая дискуссию. Лично мне в таких случаях больше жаль не времени, а своих нервов. И, возможно, платная поддержка неплохой фильтр от таких эмоциональных потрясений. В конце концов я создал статью в документации, в которую вежливо предлагаю заглянуть, когда мне не идут навстречу. Стыдно признаться, но однажды я и сам оказался по другую сторону баррикад. Речь снова про переписку с автором утилиты для создания виртуальных MIDI-устройств. Я пытался выяснить у него способ реализации некоторого сценария, а оказалось, что это уже есть в примерах, поставляемых с программой. Так что, спустя несколько сообщений я совершенно по делу получил ответ с предложением перейти на платную консультацию за N монет в час. И всё же, получил ли я какие-то деньги за DryWetMIDI? Только не падайте со стула, увидя эти числа: 93 американских доллара 97 центов; 20 канадских долларов; 15 евро; 3663 рубля 72 копейки. Это всё, что мне добровольно перевели пользователи на мой PayPal-кошелёк в качестве благодарности за 5 лет активной разработки (считаю то время, когда сервис работал с клиентами из России). Но я сразу понимал, что в нишевом проекте (а DryWetMIDI является таковым) можно заработать плюс-минус ничего. На самом деле я не ожидал, что вообще кто-то поддержит меня рублём своей страны, да и не в заработке была цель. Делает ли кто деньги с помощью DryWetMIDI? Наверняка. Как минимум один пример мне известен – CoyoteMIDI. Разработчики сами со мной связались, дав знать, что пользуются моим продуктом. Лицензия MIT избавляет меня от переживаний по этому поводу. Справедливости ради замечу, что про способы монетизации я-таки задумывался. Но не напрямую. Библиотека должна оставаться бесплатной, и делать с ней можно всё, что угодно. Проект долго завоёвывал авторитет, и испортить репутацию деньгами было бы очень неприятно. Моя идея заключалась в создании полноценных инструментов с графическим интерфейсом для решения музыкальных задач. В основе их, разумеется, была бы DryWetMIDI. От сего мероприятия я в итоге отказался по двум причинам: Инструменты были бы в любом случае нишевые. Если бы стоимость разработки и отбилась, то крайне нескоро. Не ясно, как привлекать пользователей. Музыку создают в DAW, в которых есть богатые возможности по работе в том числе с MIDI. Можно было бы создать утилиты, предоставляющие отсутствующий функционал или даже плагины к DAW, но см. п. 1. Взаимодействие с людьми, желающими внедрить вашу разработку в своё программное обеспечение, есть неотъемлемая часть работы с проектом. Поэтому будьте готовы, что вам будут писать по всем каналам связи: почта, GitHub, другие опубликованные вами контакты. Временами эти коммуникации доставляют радость, временами боль. Однако на первых порах мне видится необходимым максимально глубоко вникать в каждое обращение, сколь непонятным и нелепым оно бы ни было. Вы не поверите, насколько заметный процент от всех обращений составляют случаи, когда человек задаёт вопрос и больше не выходит на связь. Несколько примеров: Automatic chords - is it possible? Arduino Play the notes in a 3D keyboard increase buffer size? Часто пользователь открывает issue с парой-тройкой предложений, думая, что я, видимо, умею читать мысли и знаю, что в реальности он хочет. В итоге приходится клещами вытягивать детали: How can I Spawn Objects using MIDI Finalizer of InputDevice can throw an exception Read multiple MIDI files from stream Я уже упоминал ранее в статье о документации, как способе повысить солидность проекта. Но самая главная её роль, конечно, не в этом. Подробная справка помогает избавить вас от большого количества обращений. Человек посмотрит в справочные материалы, найдёт необходимую информацию и пойдёт дальше писать код во благо мира, ведь так? Не всегда: please help a noob HELP !!! Notes in panel to midi file?? Иногда пользователь открывает issue и через несколько минут сам же его закрывает: Read Midi via Stream Using wetdrymidi in C# project causes error CS0009 Simply not working? Однажды мне в почту даже написал человек и крайне странными фразами попросил удалить своё обращение на GitHub, ибо он там предстаёт в неприглядном свете. Бывало, что от библиотеки хотели того, что находится за пределами её предметной области. Пользователь не поленился оставить до кучи отзыв на две звезды под ассетом для Unity, сетуя на то, для чего DryWetMIDI не предназначена (ох уж эта путаница MIDI и аудио). Через какое-то время он его удалил-таки. И всё же большинство пользователей идут навстречу, активно делятся информацией и помогают библиотеке стать лучше. Задаётся вопрос, проясняются детали, проблема решается и все благодарят друг друга. Могу отметить случай с реализацией поддержки чипов Apple Silicon. У меня нет яблочных устройств, тем более на новых процессорах вроде M1 или M2, поэтому всю отладку приходилось делать на пользовательских машинах. В какой-то момент в issue подключился человек, с которым мы спустя уйму сообщений добились поддержки в библиотеке процессоров Apple Silicon. Общаясь с людьми со всей планеты чувствуешь себя частью глобального мира, и я считаю это важным. Известные мне локации пользователей, обращавшихся ко мне: Россия, США, Испания, Германия, Великобритания, Бразилия, Новая Зеландия, Мексика, Австралия, Турция, Египет, Швеция, Ирландия, Грузия, Армения, Бангладеш, Китай, Канада, Франция, Таиланд, Дания, Чили. Я неоднократно отвечал на вопросы студентов разных ВУЗов, помогая им с их курсовыми и дипломными работами. Оказывал поддержку в решении творческих задач участнику Большого симфонического оркестра имени П. И. Чайковского и профессиональному джаз-музыканту из Лондона. На GitHub даже есть обращение от небезызвестного Джона Скита. Сотворить что-то, а не только использовать чужие труды, одна из великих радостей. Масштабы не важны для ощущения этого чувства – сконструировать ракету или же написать статью. На своей основной работе многие из нас причастны к созданию программных (и не только) продуктов. Но одно дело быть винтиком в этом конвейере и другое – полностью ответственным за инструмент, которым пользуются люди по всему земному шару. DryWetMIDI – капля в океане разработки программного обеспечения. Ещё меньше библиотека заметна в целом для мира и его развития. И всё же, создавая какой-никакой популярный в своей области проект, понимаешь, что ты помогаешь кому-то сделать свою жизнь чуточку проще и приятнее. Банальный пункт, но его нужно упомянуть. Из-за того, что разработка находится полностью в ваших руках, вы вольны пробовать различные инструменты, языки программирования и технологии. Приходя же на работу, большинство из нас так или иначе получает инструкции сверху, нужно советоваться и т.д. Сложно переоценить вклад собственного проекта в вас, как профессионала. Возросший уровень компетенции позволяет и на основной работе решать задачи проще и качественнее, вы становитесь более ценным сотрудником и так по нарастающей. Вообще, тут двунаправленный поток. Какие-то моменты из промышленной разработки приходят в хобби-проект, какие-то наоборот. Но я могу сказать честно, самый значимый стартовый импульс на текущем месте работы был дан именно знаниями, полученными в ходе разработки DryWetMIDI. Кроме того, выкладывая код проекта в открытый доступ, начинаешь более трепетно к нему относиться. Перефразируя знаменитую фразу – покажи мне свой код и я скажу, кто ты. Тем более это важно, если вы, как и я изначально, хотите иметь козырь на собеседовании у потенциального работодателя. Также начинаешь задумываться о вещах, на которые раньше не особенно обращал внимание. Яркий тому пример в моей истории – производительность. Я несколько раз получал обращения на эту тему, например: Parsing performance TimeAs and LengthAs slow В статье я опустил разные незначительные детали и истории из жизни, и не стал приводить никаких примеров кода, дабы не превращать сиё чтиво в полотно текста, которое будет сразу же закрыто. Данный текст содержит ссылки на некоторые прошлые мои статьи, приведу их отдельным списком: Конвертация MIDI-времени в такты и доли Создание .NET библиотеки от А до Я Введение в CoreMIDI Создание пакета NuGet для библиотеки с платформозависимым API Спасибо за внимание, надеюсь, вам было интересно. Рассказывайте свои истории тоже.  Desktop software developer