2 andrew_programmer:
Quantum,а ты ассемблер знаеш ?
Обижаешь. uFMOD как раз на ассемблере разрабатывается. Поэтому такой маленький размер и сравнительно низкая загрузка процессора (в данном случае загрузка связана преимущественно со скростью генерации PCM-потока).
Зато с MenuetOS я совершенно не знаком, хотя уже пытаюсь найти походящую документацию и туториальчики.
И про ковокс знаем
Сомневаюсь, правда, что многие сегодня захотят спаять эту заглушку для LPT, когда low-end звуковухи стоят копейки. В любом случае, разумнее включать поддержку конкретных железок (ковокс, SoundBlaster, ...) на уровне драйвера, чтоб пользовательские приложения знать не знали кто и как проигрывает их сэмплы. Такой подход мне кажется более выйгрышным, чем делать uFMOD под ковокс, ещё одну версию под SB, ещё одну для Adlib, ещё одну для встроенных интеловских чипсетов и т.д.
А что значит,-" каким-то системным вызовом тред создать" ?
К примеру, в Win32 API тред создаётся функцией CreateThread и/или различными надстройками над этой функцией. В *никсах тоже самое делается сишной функцией pthread_create.
Всмысле запустить другую програмку,которая будет общаться с запустившей её программой ?(тоесть она будет являться частью первой программы)
Это напоминает fork в *никсах. Нет, тред не является другой программой (процессом). Тред легковесен. Данные и код основного потока должны быть доступны из второстепенного. Время, которое система выделяет под данный процесс должно равномерно расходоваться между потоками/тредами. Конечно, если легковесных тредов в MeOS нет, можно будет адаптировать библиотеку под действующую модель многозадачности. Я ещё не разбирался с этим.
А для динамического выделения памяти есть 64 функция
Скорее всего, это то, что нужно.
2 Serge:
начал готовить АС97-драйвер
Это просто замечательно!
какме именно фичи DirectSound ты считаешь бесполезными
Бесполезными для большинства разработчиков являются расширенные эффекты (эхо, хор, полоскание, эквалайзер и т.д.) Качество этих эффектов отвратительное, а процессорного времени и памяти потребляют немеряно. Если кому и нужны эти эффекты, их обычно воплощают самостоятельно. В старых версиях можно было использовать хардварные и софтверные каналы (в 9м DX уже нельзя), что приводило к настоящей какофонии на некоторых картах.
И что именно ты понимаешь под двойным буфером?
См. выше:
ждать пока драйвер проиграет определённое количество фрагментов, чтобы дописать новые (звук должен проигрываться непрерывно, но генерироваться только по мере необходимости, минимально загружая CPU).
В Линуксе за это отвечает драйвер, а в Win32 (и в WINMM и в DX) пришлось воплощать двойной буфер мне. Принцип такой:
1. Тред проигрывания периодически опрашивает звуковую подсистему, чтобы узнать сколько она уже успела проиграть из буфера канала.
2. На основании результата из п.1 можно вычислить сколько места в буфере уже освободилось под новые PCM-блоки.
3. Вызываем функцию, которая генерирует эти самые PCM-блоки, пока буфер канала не заполнится.
4. Отдыхаем немного (чтоб загрузка CPU не страдала) и возвращаемся к п.1.
Упрощённо это реализовано следующим образом:
Code: Select all
uFMOD_Thread:
push ebp
mov ebp,mmt
push esi
inc [SW_ThreadRun] ; сигналим, что тред запущен
thread_loop_1:
; ***
; Обращаемся к драйверу чтобы узнать текущее положение курсора
; в буфере канала (т.е. какой участок он сейчас проигрывает)
; Результат в eax.
; ***
cdq
mov ecx,[FSOUND_BufferSize]
div ecx
mov ecx,[FSOUND_BlockSize]
xchg eax,edx
cdq
div ecx ; eax <= ((playing_offset / 4) % FSOUND_BufferSize) / FSOUND_BlockSize
xchg eax,esi
thread_loop_2:
; ***
; Отдыхаем немного, чтоб охладилась CPU :)
; ***
cmp [uFMOD_FillBlk],esi
je loop_2_end
call uFMOD_SW_Fill ; <- эта функция генерирует слудующий сэмпл (PCM-блок)
jmp thread_loop_2
loop_2_end:
cmp [SW_Exit],0 ; это чтоб тред можно было остановить извне
jz thread_loop_1
pop esi
dec [SW_ThreadRun] ; сигналим, что тред уже кончился
pop ebp
retn 4
Это и есть наш двойной буфер. Для сравнения см. тоже самое но для Линукса/BSD (уже без двойного буфера):
Code: Select all
uFMOD_Thread:
inc [SW_ThreadRun] ; сигналим, что тред запущен
thread_loop_1:
; ***
; Отдыхаем немного, чтоб охладилась CPU :)
; ***
call uFMOD_SW_Fill ; <- эта функция генерирует слудующий сэмпл (PCM-блок)
; ***
; Посылаем PCM блок драйверу
; ***
cmp [SW_Exit],0 ; это чтоб тред можно было остановить извне
jz thread_loop_1
dec [SW_ThreadRun] ; сигналим, что тред уже кончился
retn
Кстати, термин "двойной буфер" для звука взят из спецификации OSS, т.е. это не я его придумал.