Making of “White Stars” Part #2

А теперь, я бы хотел дать несколько практических советов и доставить то, что не вошло в первую часть.

Чтобы дема не была набором эффектов, вот как у меня, например, то…

Начинайте с демоплана. (а не просто прикручивайте историю на то, что получилось)

Распланируйте, сколько и какой графики вам понадобится. По правилам компо нельзя использовать процедуры в машинных кодах, значит нам недоступна также и паковка графики и данных. И если мы будем заранее знать сколько нам нужно будет памяти для данных, сможем спланировать и программный код бейсика. Демоплан, как оказалось — вообще самая важная часть всей вашей затеи, как бы странно это не было.

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

Если у вас есть время — отполируйте всё как надо (мне очень стыдно за строчки, дальше середины листинга). По ходу листинга оставляйте комментарии за REM — потом будет проще ориентироваться в “простыне” вашего кода, убрать их вы всегда сможете потом. Параллельно записывайте всё в текстовый файл. В первой части я уже показывал его в процессе, ближе к окончательной сборке он много раз меняется:



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

Планирование также поможет при сборке, чего, к сожалению, не удалось мне, т.к. слишком поздно начал делать записи. Это я намекаю на то, что самые ресурсоёмкие процедуры/части нужно размещать в самом начале программы, будет быстрее.

Чего следует избегать? Естественно, всех вычислений, а особенно всей тригонометрии, вычислений с плавающей запятой, умножений, делений и проч. Из не очевидных вещей: генерация случайных чисел. RND — очень медленная процедура, старайтесь использовать или уже вычисленные заранее данные или берите из ПЗУ (это мне подсказал diver4d ). Сам я что-то не удосужился измерить сколько RND пожирает драгоценных тактов. Но вот иногда чтение из ПЗУ не помогает, да и на исследование его содержимого не очень хочется тратить время. Поэтому, рекомендую все таки сделать прекалк и просто читать данные из памяти.

Используйте весь потенциал Basin — перенумерацию строк, копирование и вставку текста, встроенный дебагер — точки останова и пошаговое выполнение, редактор UDG, редактор графики, таблицы переменных, таблицу системных переменных, карту памяти. Поверьте — это очень удобно, наглядно и много раз спасёт вас в ситуациях: “ДА ЧТО ЖЕ ЭТО ТАКОЕ, ПОЧЕМУ ТАК?”

Очень удобно считать фреймы. В начале вашей программы обнуляете 3 байта системной переменной FRAMES. По ходу программы выставляете точки останова и смотрите в Basin Tools > System Variables количество фреймов от обнуления и до точки останова.

В конце концов, вам потребуется примерно такая табличка с рассчитаными фреймами\паттернами для работы с музыкантом. Понадобится она для фикса демы.



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

Собственно, есть еще один момент. На разных машинах времянка будет плавать и точная синхронизация в Basic, дело очень непростое. Как вариант, синхронизировать под самую медленную машину и корректировать паузы по ходу дела. Синхронизировал я самым простым и топорным способом — выставлял подходящие задержки в PAUSE и добавлял или удалял паттерны в музыкальном модуле. А по идее, нужно было бы по конкретным значениям FRAMES и чтением из памяти значения играющей в данный момент позиции в музыкальном модуле. Тестировал и фиксил свою дему я под спектакулятором в режиме Spectrum 48K, что дало мне неплохую совместимость с оригинальным спектрумом, но в итоге получил полный рассинхрон под Unreal и все клоны. Буду ли выпускать фикс под Unreal и Pentagon, не знаю, скорее всего нет. Тема синхронизации AY-музыки на прерываниях и BASIC демы еще мало изучена и, может быть, diver4d поделится своими наблюдениями и мыслями по этому поводу. Но мне стало интересно сделать удобную систему для фикса и на вскидку, можно определить для этого функцию через DEF FN или просто написать подпрограмму с выделением переменной, а уже по её значениям делать ветвление на дальнейшее ожидание или на продолжение…

Теперь немного о музыке. Плеер для 128 и 48 режима бейсика с удобным сборщиком любезно предоставил introspec , за что ему бесконечное спасибо. Линковать музыку было очень просто и удобно!

И вот такое наблюдение — начинайте сборку тогда, когда у вас есть план по эффектам и есть или готовый трек или хотя бы наброски. Фиксить уже собранную дему будет сложновато, особенно, когда вы уже подвинули и распределили в памяти все данные и графику. Бейсик не код, программа распухает в памяти и если ваши данные требуют пересчёта адресов  — это мучение. Тут простая перекомпиляция, как в случае с ассемблером, не поможет.

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

Если ли сейчас желание делать новое демо на бейсике? Нет.
Есть ли желание что-то попробовать еще на бейсике? Да.
Появится ли желание сделать демо на бейсике? Да, наверняка.

Вот теперь, пожалуй, точно всё, что вспомнилось про дему =)

11 комментариев

avatar
(мне очень стыдно за строчки, дальше середины листинга)
Мне вообще стыдно за весь свой листинг :-D
Но, поскольку я ни разу не уперся в ограничения по памяти для бейсика, то я не тратил время на оптимизацию кода.
Раскрытие циклов, отсутствие, вызываемых по GO SUB, процедур, многократное переопределение переменных с CLEAR в начале каждого эффекта позволяют не терять скорость. Сдается мне, что бейсик при каждом GO TO/GO SUB/RESTORE ищет адресуемые строки перебором, и так с переменными — перебор, пока не будет найдено соответствующее имя. Соответственно, чем дальше адресуемая строка или больше переменных — тем больше тормоза.
avatar
Именно так. Старался чистить переменные, но есть один не очень приятный момент с CLEAR — он чистит не только переменные, но и экран, что не всегда нам на руку.
avatar
Уже в процессе составления таймлайна для написания музыки и фикса, я вдруг осознал, что некоторые эффекты у меня могут сильно отличаться по времени выполнения, что накладывало некоторые проблемы на фикс
То же самое у меня было в Back 2 Basics. Есть какие-то эффекты можно прерывать в любой момент, но есть и части типа Greetings, части с выводом текста, части с пошаговым выводом графики, которые требуют конкретного времени на вывод всего контента, сами собой такие вещи с музыкой не состыкуются, нужны расчеты.
avatar
А по идее, нужно было бы по конкретным значениям FRAMES и чтением из памяти значения играющей в данный момент позиции в музыкальном модуле.
Тема синхронизации AY-музыки на прерываниях и BASIC демы еще мало изучена и, может быть, diver4d поделится своими наблюдениями и мыслями по этому поводу.
Я фиксился как раз через переменную FRAMES. После загрузки и небольшого прекалка я обнулял её и затем считывал в цикле эффекта либо в холостом цикле при ожидании следующего эффекта. Вызов сделал через GO SUB 1. Но всё равно эффекты этим тормозились. Если считывать напрямую номер играемой позиции, то, по идее это должно снизить тормоза, т.к. нам нужна всего лишь одна связка «IF PEEK N<POS THEN GO TO».

Фикс через FRAMES (или через номер позиции в плеере) упрощает работу, т.к. не надо думать о задержках внутри эффекта и скорости выполнения эффекта. Мы просто ловим нужную позицию в таймлайне и начинаем следующий эффект. Это должно корректно работать на всех клонах.

Внутри intro в YSKB фикс сделан как через задержки через PAUSE, так и через FRAMES, в принципе и то и другое работает вполне корректно на разных клонах.
avatar
Да, думаю FRAMES — самый правильный способ. Без этого моя дема на пентагонах идет быстрее и уже на втором эффекте не попадает в «нужных местах» под музыкальный трек.
avatar
Я попробую в финальной версии YSKB сделать через позицию в треке. Это должно быть все же быстрее. Там каждый фрейм ценен.
avatar
Прямо сейчас я тоже не готов делать новое демо :) Возможно зимой/к весне или к лету :)
Остались еще не реализованные идеи и хочется плотнее поработать с фиксом.
Плотнее с фиксом я поработаю в финальной версии YSKB и в следующем демо на бейсике.
avatar
nodeus , нет слов, прекрасный makingof!
Дема очень впечатлила, особенно понравился твистер, да и графика с музыкой не отстают :)

P.S так все вкусно расписано, что даже самому захотелось написать подобное про blash, да и не только :)
avatar
Ох, думаю, будет очень вкусное чтиво! Ждём!
avatar
Напиши! Интересно прочесть про алгоритмы некоторых эффектов! И напиши, чем вдохновлялся в музыке :)
avatar
Исходники «White stars» + ещё кое что теперь доступны на гитлабе.

gitlab.com/zxbasic/white-stars-demo.git
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.