Приветствую Вас Гость | RSS


Главная страница » Вопрос эмуляторописателям - ZX-Форум » Регистрация » ВходСреда
2017-07-26
03:44:21
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Страница 1 из 11
ZX-Форум » Software » Other » Вопрос эмуляторописателям (или просто программистам)
Вопрос эмуляторописателям
RomanichДата: Понедельник, 2009-04-06, 09:01:35 | Сообщение # 1
Младший одепт
Группа: Человеки
Сообщений: 578
Репутация: 1
Статус: 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
Репутация: 0
Статус: Offline
Делай два буфера, с переключением между ними.
Т.е. когда заполнем буфер1, то в мп3 кидаем из буфера2, как только буфер1 заполнен, и данные из буфера2 перекинуты в мп3, делаем переглюк местами, начинаем заполнять буфер2, а из буфера1 по требованию мп3 шлем в мп3, потом опять проверка условия и возврат в начальное состояние.
 
lvdДата: Понедельник, 2009-04-06, 18:50:42 | Сообщение # 3
Retry, Abort, Ignore?
Группа: Человеки
Сообщений: 2528
Репутация: 13
Статус: 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
Репутация: 9
Статус: Offline
Сделать 1 кольцевой буфер (программный, либо аппаратный, если ДСП), заполнять буфер данными из основного цикла (большой порцией данных), читать из буфера по прерыванию. ОБЯЗАТЕЛЬНО сделать синхронизацию доступа к буферу между читателем и писателем. Принцип примерно тот же самый что изложено в предыдущих 2х постах, но буфер всего 1.
 
RomanichДата: Вторник, 2009-04-07, 02:50:43 | Сообщение # 5
Младший одепт
Группа: Человеки
Сообщений: 578
Репутация: 1
Статус: 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
Репутация: 13
Статус: Offline
Ниасилел. Ты говоришь, что у тебе звук выигрывается из буферов быстре, чем за фрейм эмуляции генериццо? Так сделай, чтоб такого не было, то бишь засинхри эмуль от звука, а не от чего-либо ещё. На амиге, например, можно синхриться и от видео, а частоту звука динамически менять и подгонять. А на пц без вариантов - звук. Подозреваю, что и на твоей бряцалке тоже.
Другое дело, что играть пцм через мр3-декодер - извращение. Как раз потому, что жёстко засинхриться нет возможности - всегда есть те самые 32 байта, к тому же вообще байты для синхронизации руками считать нужно, и точности лучше +-32 байт не достичь. Поставь обычный дельто-сигмо-цап, заюзай ДСПшный вывод в него и би хеппи...


Многого нет здесь: http://lvd.nedopc.com
 
RomanichДата: Четверг, 2009-04-09, 04:36:51 | Сообщение # 7
Младший одепт
Группа: Человеки
Сообщений: 578
Репутация: 1
Статус: Offline
Quote (lvd)
то бишь засинхри эмуль от звука, а не от чего-либо ещё.

попытаемся smile

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
Репутация: 1
Статус: 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 байта
Это лично сам проверил и убедился!
Саундблястеры в этом плане сосут wink


Живу схемами, питаюсь концепциями :)
http://emu-apparatchik.narod.ru
 
RomanichДата: Пятница, 2009-04-10, 04:48:08 | Сообщение # 9
Младший одепт
Группа: Человеки
Сообщений: 578
Репутация: 1
Статус: 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
Репутация: 13
Статус: Offline
Quote (Romanich)
только происходит уравниловка FPS'а всех игр. Там где можно быстрее - будет медленно, там где под завязку - оптимально.

Чо-то ниасилел - как это?
Понятно, что если проц дохломощный - то смд середины 80х годов он ниасилет. Но зачем требовать повышения фпс от лёгких игр?... Фпс должен быть ровно таким же, как и на реал железе, и точка. Ускорятельства - только по специальному желанию юзера.


Многого нет здесь: http://lvd.nedopc.com
 
RomanichДата: Понедельник, 2009-04-13, 04:05:15 | Сообщение # 11
Младший одепт
Группа: Человеки
Сообщений: 578
Репутация: 1
Статус: 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
Репутация: -14
Статус: 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
Репутация: 13
Статус: Offline
Quote (Romanich)
эмулятор - это такое дело - что можно получить процессинг не только 50/60 фпс, но и другие значения - например 40 или 90 FPS - соответственно будет всё быстро идти

А зачем быстро. Должно идти точно так же, как и на реальном железе.

Quote (Romanich)
Что значит "работать во фрейм"? у мну все кадры показываются и не пропускаются в отличие от avtoframeskip'а на GENS'е (под винду который)

генс на п4-1.5ггц ничего не скип. Всё же не блацкфин какой. =)
А вообще про фреймы не парься. Фреймовость, сечение с лучом и т.п. имеют значение только на ЭЛТ, на лсд и прочих светодиодах такого нет. Достаточно просто раз в эн миллисекунд (эн - произвольное) обновлять экран.
А всякая фреймовость - суть стробоскопические фефекты от бегущего по экрану лучика, под которым светится точечка. Нету лучика - нету фреймовости, хоть обосрись. biggrin


Многого нет здесь: http://lvd.nedopc.com
 
Black_CatДата: Понедельник, 2009-04-13, 19:21:51 | Сообщение # 14
Не умею ничего делать, потому учу
Группа: Заблокированные
Сообщений: 659
Репутация: -14
Статус: Offline
Quote (lvd)
А всякая фреймовость - суть стробоскопические фефекты от бегущего по экрану лучика, под которым светится точечка. Нету лучика - нету фреймовости, хоть обосрись.

не всё так просто smile фреймовость остаётся и в 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
Репутация: 1
Статус: 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
 
ZX-Форум » Software » Other » Вопрос эмуляторописателям (или просто программистам)
Страница 1 из 11
Поиск:

the DLCorp © 2006