Первые попытки внедрения звуковой системы в движок

Категория: Дневник разработки | Скилл: SkyXEngine , C++ , ООП | Дата: 23.05.2020
Эти 6 дней были одними из трудных в технической плане (зато + к скиллу). Интеграция звуковой системы с движком начата. Кодеки уже более-менее стандартизированы. Работу с демкой было решено отложить до окончания интеграции звуковой системы.

45 46 дни собирал кодеки, пусть не по всем канонам, но они уже должны работать и выполнять свои основные функции (позже было протестировано - выполняют). Ничего необычного. Это был последний подготовительный этап перед внедрением звуковой системы в движок.

47, 48 и 49 дни провел за интеграцией звуковой системы в движок. Это было нечто ...

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

Другая проблема заключалась в неясности где и как проводить обновление звуковой системы (run-time), потому что некоторые обьекты внутри системы требуют обновления (3d звуки, потоковое воспроизведение). Очень быстро получил ответ что надо заюзать IXUpdatable ... но откуда же я знал что наследоваться классу плагина от IXUpdatable не надо, а надо именно экспортировать? Да, можно было посмотреть примеры, но к тому моменту физическая структура директорий и логическая структура проектов в visual studio была мягко сказать беспорядочной, а про поиск по solution я позабыл. Но это мелочи по сравнению с тем что было дальше.

Третья проблема сгенерировала взрыв мозга. Самый первый обьект IAudio, из проекта MitAL, при обращении к какому-либо методу вызывал FinalRelease , а тот делал delete this. Обзор данных обьекта показывал методы от CAudio, в которых были только методы из реализации IXUnknown, и не было методов из IAudio (но реализация естественно была). А с другими интерфейсами проблем не возникло лишь потому что IAudio являлся первым этапом начала работы с аудио.

Обзор данных обьекта в отладчике от visual studio

Не долго думая и вспоминая свой предыдущий печальный опыт использования глобальных переменных в dll (хоть в данном случае их и не было), я решил протестировать в изолированной от движка среде - сделал проект для компиляции MitAL в dll и в тестовом проекте (proj/test) подключал эту библиотеку. Проблем не возникло, однако обьект IAudio все так же показывал в списке методов от CAudio только методы реализации IXUnknown. Это дало понять что отладчику, в данном случае, нельзя верить и что проблема не в звуковой библиотеке, а в интеграции в движок. Проблема локализована.

Затем я решил сузить круг анализируемого кода. Попробовал вызывать методы обьекта CAudio из конструктора CAudio и сразу за пределом библиотки MitAL (там где MitAl_InitAudio возвращает обьект с реализацией интерфейса IAudio). В первом случае проблем не возникло, а во втором как и следовало ожидать были проблемы. Это было похоже на неправильную интерпретацию таблицы виртуальных функций. Потому что вызовы одних и тех же виртуальных функций имели одно и то же неправильное смещение. На самом деле попыток локализации проблемы было много, но описывать их не стоит, так как проблему можно было понять уже на этом этапе.

49 день (на третий день интеграции звуковой системы в движок) я решил делиться своими исследованиями с архитектором (но давать ему ошибочный код отказался, так как хотел сам разобраться в проблеме), и в один момент он подсказал что реализация базового интерфейса IXUnknown может быть разной. Так оно и оказалось. MitAL использовал библиотеку common с этим коммитом (с первой имплементацией IXUnknown), а в движке был последний коммит (с улучшенной имплементацией IXUnwnown) common на тот момент.

Как видно из изменений коммитов, последний комми вносил в интерфейс IXUnwnown еще одну виртуальную функцию, это и послужило причиной неверной интерпретации виртуальной таблицы. Проект MitAL (lib) создавал обьект с реализацией интерфейса с 4 виртуальными функциями IXUnwnown, а движок воспронимал этот обьект как обьект имеющий 5 виртуальных функций IXUnwnown. Если просто (очень просто) то MitAL и движок это разные единицы компиляции, именно поэтому на стороне библиотеки MitAL все было нормально.

dynamic_cast не помог в данном случае. Мое представление о реализации этого оператора на основании сравнения таблицы виртуальных функций оказалось не совсем верным (точнее реализации зависит от конкретного компилятора), иначе в данном случае dynamic_cast выдал бы NULL. Недолго поискав в интернетах нашел ссылки вот и вот, а в этой доке даже описан алгоритм, в котором увы нет сравнения таблиц виртуальных функций, хотя в описании обосновано ее отсутствие рациональностью. Вывод: dynamic_cast зависит от конкретной реализации и полагаться (смещать ответственность) на это не стоит.

На 50 день было исправлено обновление плагина звуковой системы, и наконец-то аудио кодеки были переведены с FILE на IFile, теперь они почти стандартизированы :)

При правке ogg кодека возник баг с переполнением стека на 64 битной сборке, в том время как 32 битная сборка работала без проблем. Про расход размера стека на 64 битных сборка можно прочитать здесь. Гуляя по стеку было обнаружено, что ogg кодер внутри, при обработке загруженных данных, выделяет память на стеке размером с количество установленных блоков (количество сэмплов / количество каналов), и как показано в здесь, все данные заливались за раз. Ошибка была исправлена путем порционной цикличной заливки.

Коммит правленных кодеков поступил в репозиторий, однако звуковая система еще нет, так как требуется ее небольшая доработка, прежде чем она станет доступна на обозрение всему миру. Движок в локальном репозитории уже умеет воспроизводить звук :)
Я Виталий, ник в сети Byurrer.
Увлекаюсь программированием, веду интересные проекты, пишу здесь об интересующих меня вещах: о работе, проектах, увлечениях и проффесиональном развитии.

Скилы
php, c++, javascript, sql, hlsl, html, css
Проекты
SkyXEngine, PHP-API, S4G
Категории
В разработке :)
Популярное
В разработке :)