lvd wrote:ОЧЕНЬ крепко подумать насчёт ДРЕК. В доках на вски говорится, что оно может дёргаться во время пересылки байтов. Не вызывает ли это лишние прерывания? Да и вообще, дёргаться каждые 32 байта в прерывание - ахтунг. Проц зафлуживается. Может, исхитриться и слать бОльшими кусками (глубина того буфера в ВСках около 4 кило, вродеб).
согласно тем же докам - мы можем пропихать без опроса DREQ не более 32 байта. после этого DREQ=0, до тех пор пока часть не отиграет. Затем када снова DREQ=1 - кладем опять 32 байта... итд.
Даже если допустить дергание DREQ во время пересылки данных по SPI, ничего левого не будет - так как мы в высокоприоритетном обработчике прерывания с запрещенными вложенностями. Прерывание по высокому уровню.
Я так делал - и оно работает в эмуле GBC,NES с офигенной скоростью - тормозов нет. Ибо когда играют 32 байта - предостаточно времени на эмуляцию всего остального.
У мну 8 бит моно 22050Гц. 32 байта буфер , итого 22050/32=690 Гц - воспринимаем прерывание DREQ как прерывание таймера 690 Гц.
Буфер апдейтился прямо в обработчике прерывания.
----
Сейчас же я переделал по-другому:
- Code: Select all
#define RATE 22050
#define SND_BUFSIZE 512
- Code: Select all
EMU:
dos_update_input(); //Апдейтим кнопки
system_frame(); //Фрейм эмуляции
dos_update_video(); //Отрисовка на экран
goto EMU;
- Code: Select all
int system_frame(void)
{
//Эмулируем...
...
...
...
audio_update(); //Обновляем буфер когда сэмулировался фрейм(весь кадр)
}
- Code: Select all
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; //Данные готовы
}
//Макрос посылки 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)
Поясните как можно сделать лучше...