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 , за что ему бесконечное спасибо. Линковать музыку было очень просто и удобно!
И вот такое наблюдение — начинайте сборку тогда, когда у вас есть план по эффектам и есть или готовый трек или хотя бы наброски. Фиксить уже собранную дему будет сложновато, особенно, когда вы уже подвинули и распределили в памяти все данные и графику. Бейсик не код, программа распухает в памяти и если ваши данные требуют пересчёта адресов — это мучение. Тут простая перекомпиляция, как в случае с ассемблером, не поможет.
И да, я сторонник той тёмной (или светлой) стороны и считаю, что дему нужно писать по уже готовой музыке, да простят меня те, кто считает наоборот. Мне намного проще представить и вдохновиться, прослушав трек, а вот объяснить музыканту, что творится в моём воображаемом мире конкретной демы очень сложно. Но это не значит, что готовый трек не нужно будет также фиксить\менять. В музыке обязательно будут изменения, в любом случае.
Если ли сейчас желание делать новое демо на бейсике? Нет.
Есть ли желание что-то попробовать еще на бейсике? Да.
Появится ли желание сделать демо на бейсике? Да, наверняка.
Вот теперь, пожалуй, точно всё, что вспомнилось про дему =)
Чтобы дема не была набором эффектов, вот как у меня, например, то…
Начинайте с демоплана. (а не просто прикручивайте историю на то, что получилось)
Распланируйте, сколько и какой графики вам понадобится. По правилам компо нельзя использовать процедуры в машинных кодах, значит нам недоступна также и паковка графики и данных. И если мы будем заранее знать сколько нам нужно будет памяти для данных, сможем спланировать и программный код бейсика. Демоплан, как оказалось — вообще самая важная часть всей вашей затеи, как бы странно это не было.
Часто вызываемые и критичные по быстродействию подпрограммы и функции выносите в самое начало программы — этим вы ускорите свой бейсик в несколько раз или даже в десятки раз, если процедуры и функции будут вызываться в цикле.
Если у вас есть время — отполируйте всё как надо (мне очень стыдно за строчки, дальше середины листинга). По ходу листинга оставляйте комментарии за 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 , за что ему бесконечное спасибо. Линковать музыку было очень просто и удобно!
И вот такое наблюдение — начинайте сборку тогда, когда у вас есть план по эффектам и есть или готовый трек или хотя бы наброски. Фиксить уже собранную дему будет сложновато, особенно, когда вы уже подвинули и распределили в памяти все данные и графику. Бейсик не код, программа распухает в памяти и если ваши данные требуют пересчёта адресов — это мучение. Тут простая перекомпиляция, как в случае с ассемблером, не поможет.
И да, я сторонник той тёмной (или светлой) стороны и считаю, что дему нужно писать по уже готовой музыке, да простят меня те, кто считает наоборот. Мне намного проще представить и вдохновиться, прослушав трек, а вот объяснить музыканту, что творится в моём воображаемом мире конкретной демы очень сложно. Но это не значит, что готовый трек не нужно будет также фиксить\менять. В музыке обязательно будут изменения, в любом случае.
Если ли сейчас желание делать новое демо на бейсике? Нет.
Есть ли желание что-то попробовать еще на бейсике? Да.
Появится ли желание сделать демо на бейсике? Да, наверняка.
Вот теперь, пожалуй, точно всё, что вспомнилось про дему =)
12 комментариев
Но, поскольку я ни разу не уперся в ограничения по памяти для бейсика, то я не тратил время на оптимизацию кода.
Раскрытие циклов, отсутствие, вызываемых по GO SUB, процедур, многократное переопределение переменных с CLEAR в начале каждого эффекта позволяют не терять скорость. Сдается мне, что бейсик при каждом GO TO/GO SUB/RESTORE ищет адресуемые строки перебором, и так с переменными — перебор, пока не будет найдено соответствующее имя. Соответственно, чем дальше адресуемая строка или больше переменных — тем больше тормоза.
Фикс через FRAMES (или через номер позиции в плеере) упрощает работу, т.к. не надо думать о задержках внутри эффекта и скорости выполнения эффекта. Мы просто ловим нужную позицию в таймлайне и начинаем следующий эффект. Это должно корректно работать на всех клонах.
Внутри intro в YSKB фикс сделан как через задержки через PAUSE, так и через FRAMES, в принципе и то и другое работает вполне корректно на разных клонах.
Остались еще не реализованные идеи и хочется плотнее поработать с фиксом.
Плотнее с фиксом я поработаю в финальной версии YSKB и в следующем демо на бейсике.
Дема очень впечатлила, особенно понравился твистер, да и графика с музыкой не отстают :)
P.S так все вкусно расписано, что даже самому захотелось написать подобное про blash, да и не только :)
gitlab.com/zxbasic/white-stars-demo.git