Вопрос эмуляторописателям
|
|
Romanich | Дата: Понедельник, 2009-04-06, 09:01:35 | Сообщение # 1 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| есть основной цикл программы, подготавливающий буфер аудио-данных: Code while(1) { MakeSoundBuffer(Buf); ... } есть обработчик прерывания звукового устройства (например аудиокодек. Прерывание по высокому уровню ножки DREQ - когда данные нужно зохавоть): Code EXEPTION Handler() { for(i=0;i<32;i++) SPISend(Buf[i]); EOI(); } тоесть Buf - буфер из 32 байт, по прерыванию засылаем 32 байта в mp3 декодер (по даташиту именно столько можно слать без опроса DREQ) проблема в том что функция MakeSoundBuffer или остальная часть в программе в главном цикле - очень медленна - буфер не успевает построиться полностью, когда mp3-кодер его уже требует. в итоге вместо непрерываного звука слышен хрип. что делать? как следует организовать программу по заполнению буфера/чтению из него? 32 байта это ведь мало?
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
|
|
| |
jdigreze | Дата: Понедельник, 2009-04-06, 10:55:41 | Сообщение # 2 |
Креветко
Группа: Человеки
Сообщений: 322
Статус: Offline
| Делай два буфера, с переключением между ними. Т.е. когда заполнем буфер1, то в мп3 кидаем из буфера2, как только буфер1 заполнен, и данные из буфера2 перекинуты в мп3, делаем переглюк местами, начинаем заполнять буфер2, а из буфера1 по требованию мп3 шлем в мп3, потом опять проверка условия и возврат в начальное состояние.
|
|
| |
lvd | Дата: Понедельник, 2009-04-06, 18:50:42 | Сообщение # 3 |
 Retry, Abort, Ignore?
Группа: Человеки
Сообщений: 2528
Статус: Offline
| 1. сделать буфер нормальной длины. Например, 512 байт, или 4 килобайта, или сколько не жалко. 2. научиться параллельно и независимо его заполнять и считывать. Почти то же самое (как уже jdigreze сказал) - сделать 2 буфера, пока один заполняется, другой считывается. Заполненный остаётся заполненным пока до него не доберётся считыватель, как это случится - начинает заполняться другой. 3. ОЧЕНЬ крепко подумать насчёт ДРЕК. В доках на вски говорится, что оно может дёргаться во время пересылки байтов. Не вызывает ли это лишние прерывания? Да и вообще, дёргаться каждые 32 байта в прерывание - ахтунг. Проц зафлуживается. Может, исхитриться и слать бОльшими кусками (глубина того буфера в ВСках около 4 кило, вродеб).
Многого нет здесь: http://lvd.nedopc.com
|
|
| |
deathsoft | Дата: Понедельник, 2009-04-06, 21:09:39 | Сообщение # 4 |
 Retry, Abort, Ignore?
Группа: Человеки
Сообщений: 1587
Статус: Offline
| Сделать 1 кольцевой буфер (программный, либо аппаратный, если ДСП), заполнять буфер данными из основного цикла (большой порцией данных), читать из буфера по прерыванию. ОБЯЗАТЕЛЬНО сделать синхронизацию доступа к буферу между читателем и писателем. Принцип примерно тот же самый что изложено в предыдущих 2х постах, но буфер всего 1.
|
|
| |
Romanich | Дата: Вторник, 2009-04-07, 02:50:43 | Сообщение # 5 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| Quote (lvd) ОЧЕНЬ крепко подумать насчёт ДРЕК. В доках на вски говорится, что оно может дёргаться во время пересылки байтов. Не вызывает ли это лишние прерывания? Да и вообще, дёргаться каждые 32 байта в прерывание - ахтунг. Проц зафлуживается. Может, исхитриться и слать бОльшими кусками (глубина того буфера в ВСках около 4 кило, вродеб). согласно тем же докам - мы можем пропихать без опроса DREQ не более 32 байта. после этого DREQ=0, до тех пор пока часть не отиграет. Затем када снова DREQ=1 - кладем опять 32 байта... итд. Даже если допустить дергание DREQ во время пересылки данных по SPI, ничего левого не будет - так как мы в высокоприоритетном обработчике прерывания с запрещенными вложенностями. Прерывание по высокому уровню. Я так делал - и оно работает в эмуле GBC,NES с офигенной скоростью - тормозов нет. Ибо когда играют 32 байта - предостаточно времени на эмуляцию всего остального. У мну 8 бит моно 22050Гц. 32 байта буфер , итого 22050/32=690 Гц - воспринимаем прерывание DREQ как прерывание таймера 690 Гц. Буфер апдейтился прямо в обработчике прерывания. ---- Сейчас же я переделал по-другому: Code #define RATE 22050 #define SND_BUFSIZE 512 Code EMU: dos_update_input(); //Апдейтим кнопки system_frame(); //Фрейм эмуляции dos_update_video(); //Отрисовка на экран goto EMU; Code int system_frame(void) { //Эмулируем... ... ... ... audio_update(); //Обновляем буфер когда сэмулировался фрейм(весь кадр) } Code extern volatile u32 Ready; //Признак готовности свежих данных extern volatile u32 Part; //Смещение которое устанавливает половинки буфера extern volatile u8 SOUND_BUFFER[SND_BUFSIZE<<1]; //Аудиобуфер из 2-х половинок
void audio_update(void) //Обновляем данные { Ready=0; //Данные ещё не готовы for(i=0;i<SND_BUFSIZE;i++) SOUND_BUFFER[Part+i]=f(i); //Строим волну в одной половинке буфера Ready=1; //Данные готовы } Quote //Макрос посылки 32 байт в VS1003 #define Send32 \ { \ register u32 i0=(u32)SOUND_BUFFER+(Part^SND_BUFSIZE)+(Kusok<<5); \ register u32 i1=i0+32; \ for(;i0<i1;i0++) SPI(*(u8*)i0); \ } EX_INTERRUPT_HANDLER(FlagA_ISR) //Обрабоччег прерывания по DREQ { *pFIO_FLAG_C=0x0080; //Подтверждаем прерывание Send32 //Посылаем 32 байта Kusok++; //Инкрементируем на 32 байта в половинке буфера if(Kusok==(SND_BUFSIZE>>5)) if(Ready) //Если последний кусок и данные новые поступали { Ready=0; //Готовность сбрасываем Kusok=0; //Сначала в половинку Part^=SND_BUFSIZE; //Меняем половинки } else Kusok=(SND_BUFSIZE>>5)-1; //В противном случае данные не поступали но не можем же мы заткнуться просто так - поэтому играем последнее!!!! } В общем у мну данные читаются быстрее, чем они подготавливаются!!! Потому что выборка 22050 буфер 512 байт, это 22050/512=43 Гц - данные обновляются с меньшей частотой. Отключаю отрисовку экрана - звук нормальный. Отрисовка занимает примерно тоже время что и эмуляция цпу+железа Поэтому сделано воспроизведение последнего куска 32 байта пока не прийдут новые данные. В общем такое работает, но в некоторых играх - темп слегка растянут - что и нужно! Но там где где юзается сильно интенсивно звук и эмулируется много и сильно - данный метод работает не очень - много хрипа (особенно когда DAC) Поясните как можно сделать лучше...
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
Сообщение отредактировал Romanich - Вторник, 2009-04-07, 02:55:35 |
|
| |
lvd | Дата: Среда, 2009-04-08, 23:13:55 | Сообщение # 6 |
 Retry, Abort, Ignore?
Группа: Человеки
Сообщений: 2528
Статус: Offline
| Ниасилел. Ты говоришь, что у тебе звук выигрывается из буферов быстре, чем за фрейм эмуляции генериццо? Так сделай, чтоб такого не было, то бишь засинхри эмуль от звука, а не от чего-либо ещё. На амиге, например, можно синхриться и от видео, а частоту звука динамически менять и подгонять. А на пц без вариантов - звук. Подозреваю, что и на твоей бряцалке тоже. Другое дело, что играть пцм через мр3-декодер - извращение. Как раз потому, что жёстко засинхриться нет возможности - всегда есть те самые 32 байта, к тому же вообще байты для синхронизации руками считать нужно, и точности лучше +-32 байт не достичь. Поставь обычный дельто-сигмо-цап, заюзай ДСПшный вывод в него и би хеппи...
Многого нет здесь: http://lvd.nedopc.com
|
|
| |
Romanich | Дата: Четверг, 2009-04-09, 04:36:51 | Сообщение # 7 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| Quote (lvd) то бишь засинхри эмуль от звука, а не от чего-либо ещё. попытаемся Quote (lvd) Другое дело, что играть пцм через мр3-декодер - извращение не я первый так делаю Quote (lvd) Поставь обычный дельто-сигмо-цап, заюзай ДСПшный вывод в него и би хеппи... поздно
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
Сообщение отредактировал Romanich - Четверг, 2009-04-09, 04:37:08 |
|
| |
Romanich | Дата: Четверг, 2009-04-09, 07:50:10 | Сообщение # 8 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| Обдумав, придумал следующее. Так как хочу 8 бит моно 22050, то несложно посчитать длину буфера в байтах: 22050/60=367,5байт. 60 - частота одного фрейма NTSC. Округляем в большую сторону чтоб кратно 32 было: 384 байта - длина половинки буфера. Далее в памяти имеем буфер из двух половинок 2*384=768 байт. Это 24 куска по 32 байта. Присваиваем указателю проигрывания куска Kusok=12. Разрешаем прерывание. Пока будут играться куски 12..23, мы должны проапдейтить другую половинку (куски 0..11). Как только указатель проигрвания проиграл кусок 23, надо закольцевать: Kusok=0. Теперь по синхронизации. Если Kusok=12 или Kusok=0, то разрешаем фрейм эмуляции, свопая естественно половинки буфера. Как я это вижу: Code Kusok=12; //первоначально Part=384;
SPI_Send32Byte(u32 Kusok) { for(i=0;i<32;i++) SPI(Buffer[32*Kusok+i]); }
IRQ_Handler() { if((Kusok==0)||(Kusok==12)) { emuflag=1; //Как только начали играть новый кусок, разрешаем эмуляцию Part^=384; } SPI_Send32Byte(Kusok); //Посылаем кусок Kusok++; //Увеличиваем для следущего раза if(Kusok==24) Kusok=0; //Если конец, то в начало }
while(1) { if(emuflag) //Для синхронизации { emuflag=0; emuM68K(); //CPU emuZ80(); //coCPU emuVDP(); //VDP emuInput(); //Joystick emuSound(); //Тут апдейт буфера draw_frame(); //Рисуем на экране то что вышло } }
emuSound() { for(i=0;i<384;i++) BUFFER[Part+i]=FM_PSG_DAC(); //Строим половинку из новых данных } При этом вся бодяга : Code emuflag=0; emuM68K(); //CPU emuZ80(); //coCPU emuVDP(); //VDP emuInput(); //Joystick emuSound(); //Тут апдейт буфера draw_frame(); //Рисуем на экране то что вышло должна успевать выполняться за 16.(6) мс - иначе произойдет порча буфера, а если будет быстрее выполняться - будут задержки. Поэтому необходим тюнинг системы - варьируя размер буфера - мы можем подогнать нормальное звучание при максимально возможном ФПС'е: FPS=22050/Buffer_length Для 43 FPS к примеру нужен буфер в 512*2 байт Есть другой способ - понизить рейт (взять не 22050, а 16000. Но на 11025 уже не очень хорошо играет). И ещё - у VS1003 DREQ уходит в 1 когда внешний буфер 32 байт закончен Но это не означает что она прекратила звучать, всё сделано с расчётом на то что есть ещё время чтоб доложить (слава яйцам - щелчков не будет!) новых 32 байта Это лично сам проверил и убедился! Саундблястеры в этом плане сосут 
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
|
|
| |
Romanich | Дата: Пятница, 2009-04-10, 04:48:08 | Сообщение # 9 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| вчера проверил - работает! только происходит уравниловка FPS'а всех игр. Там где можно быстрее - будет медленно, там где под завязку - оптимально. 40 FPS - не больше (максимальное значение с которым звук не тормозит в тяжелых играх типа: Contra Hard Corps, Comix Zone итп.) всё-таки эмуляция мегодрайва дохуа ресурсов сжирает...
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
Сообщение отредактировал Romanich - Пятница, 2009-04-10, 04:50:12 |
|
| |
lvd | Дата: Пятница, 2009-04-10, 12:41:36 | Сообщение # 10 |
 Retry, Abort, Ignore?
Группа: Человеки
Сообщений: 2528
Статус: Offline
| Quote (Romanich) только происходит уравниловка FPS'а всех игр. Там где можно быстрее - будет медленно, там где под завязку - оптимально. Чо-то ниасилел - как это? Понятно, что если проц дохломощный - то смд середины 80х годов он ниасилет. Но зачем требовать повышения фпс от лёгких игр?... Фпс должен быть ровно таким же, как и на реал железе, и точка. Ускорятельства - только по специальному желанию юзера.
Многого нет здесь: http://lvd.nedopc.com
|
|
| |
Romanich | Дата: Понедельник, 2009-04-13, 04:05:15 | Сообщение # 11 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| Quote (lvd) Фпс должен быть ровно таким же, как и на реал железе, и точка. Ускорятельства - только по специальному желанию юзера. Блин, что ты, что newart меня пытаются пролечить по этим ФПСам эмулятор - это такое дело - что можно получить процессинг не только 50/60 фпс, но и другие значения - например 40 или 90 FPS - соответственно будет всё быстро идти Что значит "работать во фрейм"? у мну все кадры показываются и не пропускаются в отличие от avtoframeskip'а на GENS'е (под винду который)
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
|
|
| |
Black_Cat | Дата: Понедельник, 2009-04-13, 08:11:54 | Сообщение # 12 |
 Не умею ничего делать, потому учу
Группа: Заблокированные
Сообщений: 659
Статус: Offline
| Quote (Romanich) Что значит "работать во фрейм"? эт когда растр обновляется синхронно с частотой кадров.. При этом картинка не идёт волнами, а стоит как влитая.. в противном случае на экране наблюдается волнообразное изменение растра с разностной частотой. Поэтому если ты ускорил обсчёт игрухи в 1,5 раза, то и кадровую частоту тож можешь поднять соответственно (в идеале), тогда игруха будет отображаться во фрейм всегда.. Но т.к. диапазон рабочих частот монитора не бесконечен, то в ряде случаев не удаётся обновлять экран пропорционально производительности обсчёта. Вот в этих случаях Nevart и говорил, что лучше например затормозить слишком быстрый обсчёт, чем потерять синхронность работы "во фрейм".
"Очень трудно найти чёрную кошку в тёмной комнате... особенно, если её там нет.", "Forever!". zx.clan.su - Soviet Union ZX Spectrum Community - форум посвящённый развитию Спека.
Сообщение отредактировал Black_Cat - Понедельник, 2009-04-13, 08:17:02 |
|
| |
lvd | Дата: Понедельник, 2009-04-13, 16:41:48 | Сообщение # 13 |
 Retry, Abort, Ignore?
Группа: Человеки
Сообщений: 2528
Статус: Offline
| Quote (Romanich) эмулятор - это такое дело - что можно получить процессинг не только 50/60 фпс, но и другие значения - например 40 или 90 FPS - соответственно будет всё быстро идти А зачем быстро. Должно идти точно так же, как и на реальном железе. Quote (Romanich) Что значит "работать во фрейм"? у мну все кадры показываются и не пропускаются в отличие от avtoframeskip'а на GENS'е (под винду который) генс на п4-1.5ггц ничего не скип. Всё же не блацкфин какой. =) А вообще про фреймы не парься. Фреймовость, сечение с лучом и т.п. имеют значение только на ЭЛТ, на лсд и прочих светодиодах такого нет. Достаточно просто раз в эн миллисекунд (эн - произвольное) обновлять экран. А всякая фреймовость - суть стробоскопические фефекты от бегущего по экрану лучика, под которым светится точечка. Нету лучика - нету фреймовости, хоть обосрись.
Многого нет здесь: http://lvd.nedopc.com
|
|
| |
Black_Cat | Дата: Понедельник, 2009-04-13, 19:21:51 | Сообщение # 14 |
 Не умею ничего делать, потому учу
Группа: Заблокированные
Сообщений: 659
Статус: Offline
| Quote (lvd) А всякая фреймовость - суть стробоскопические фефекты от бегущего по экрану лучика, под которым светится точечка. Нету лучика - нету фреймовости, хоть обосрись. не всё так просто фреймовость остаётся и в TFT. Фреймовые эффекты возникают если частота вывода в контроллер экрана не совпадает с его собственной частотой обновления экрана. Проявляется это в виде бегущих изломов при отображении вертикальных линий перемещающихся по горизонтали, причём бегут эти изломы с разностной частотой. При фотографировании с короткой выдержкой эти изломы видно.
"Очень трудно найти чёрную кошку в тёмной комнате... особенно, если её там нет.", "Forever!". zx.clan.su - Soviet Union ZX Spectrum Community - форум посвящённый развитию Спека.
Сообщение отредактировал Black_Cat - Понедельник, 2009-04-13, 19:38:47 |
|
| |
Romanich | Дата: Четверг, 2009-04-16, 06:58:05 | Сообщение # 15 |
 Младший одепт
Группа: Человеки
Сообщений: 578
Статус: Offline
| Quote (lvd) генс на п4-1.5ггц ничего не скип. Всё же не блацкфин какой. =) у мну 2.(6)GHz, 2 ядра (но не дуба) - генс работает нормально только при включенном автофреймскипе. если же в нем выставить пропуск кадров -0, то пойдет на 30% быстрее и звук изговнячится... а ZSNESW 1.43 в Demolition Man'е (Level 2) тормозит - уровень движется рывками. а ZSNESW 1.51 - ацтой - BTDD не запускается я вообще ржу с этих эмуляторов - старше версия и такое гумно. ZSNES под ДОС который и то лучше... P.S. сделал на своём девайсе в сего-эмуле смарт-скип - фрейм пропускается када буфер апдетится. теперь звук ВО ВСЕХ играх ровный и с нужным темпом. проёб кадров в обычных играх глазом не заметен. в соник 3д бляст, контра хардкорпс - пропуск заметен в моменты када DAC загружается по полной (мега взрывы) P.P.S. официально считаю работу над сего-эмулем на DT законченной
Живу схемами, питаюсь концепциями :) http://emu-apparatchik.narod.ru
|
|
| |
|
|