Пишу простой звуковой движок, чтение XM взял из MinifMod - предка uFMOD-а. Чтение Wave-данных свелось примерно к: procedure ReadModuleTick(WaveBuffer : pointer); begin ZeroMemory(WaveBuffer, Module.samplespertick shl 3); FMUSIC_UpdateXM(Module); FSOUND_Mixer_FPU_Ramp(WaveBuffer, Module.samplespertick, #0); FSOUND_MixerClipCopy_Float32(WaveBuffer, WaveBuffer, Module.samplespertick); end; Вопрос: можно ли чтото похожее замутить с uFMOD-ом ?
ещё как пробовал. там проигрывание осуществляется на уровне самого движка, а мне надо вручную считывать сгенерированные Wave-данные
Asterix, читай первый пост. 2 внутренние функции Код (Text): FSOUND_Mixer_FPU_Ramp/FSOUND_MixerClipCopy_Float32 позволяют получить wave-данные (они собственно и проигрываются), равный в моём случае одному текущему тику XM-файла.
DevilDevil Уже ответил Вам мылом. Прямого доступа к PCM данным не предусмотрено (исключение - версия для Колибри) на уровне АПИ, но исходники открыты В ufmod.asm чётко виден цикл, который копирует PCM данные в драйвер. Можете добавить туда свой код и перекомпилировать
Quantum, ааа, так ты - русский! хе-хе-хе... я асм знаю совсем чуть-чуть, поэтому сложновато. особенно непонятно, где какие функции. догадки: - всё, что мне нужно - это "core.asm" + в "ufmod.asm" посматривать. - где-то должна быть структура FMUSIC_MODULE - должны быть функции типа LoadXM, FreeXM, UpdateXM и Mixer-функции - какие проблемы с синхронизацией, используются глобальные переменные ? В Minifmod, кстати, я эту проблему решал, хитро, но решал. Хотя можно и обычной критической секцией обходиться.
DevilDevil Скорее наоборот. Всё, что связано с выводом PCM на драйвер - это в ufmod.asm. В core.asm находится движок, но его Вам трогать врядли понадобиться Нечто вроде того имеется, но работает совсем не так, как в miniFMOD. А что Вам нужно из FMUSIC_MODULE? Да, всё это есть, но не предусмотрено возможности вызывать эти функции извне. Проблема в том, что если Вы вовремя не дадите миксеру квант времени, чтобы заполнить буфер, звучать всё будет как минимум обрывисто. Потом по форумам начинают сеять сплетни о том, что uFMOD уступает по качеству звучания каким-то другим движкам. Поэтому движок берёт на себя синхронизацию с буфером драйвера. Вот место в коде ufmod.asm где выводится PCM: Код (Text): align 4 fill_loop_2: ; <--- начало цикла lodsd if INFO_API_ON push edi cdq mov edi,eax push esi xor eax,edx mov esi,255*volumerampsteps/2 ; *** куча кода dec ecx stosw jnz fill_loop_2 ; <--- конец цикла Адрес буфер драйвера помещается в регистр ESI перед началом цикла. Чтоб PCM копировался не в драйвер, а в какой-то другой массив, достаточно подменить значение ESI перед началом цикла. Но для этого нужно более-менее хорошо разбираться в ассемблере.
Quantum, я половину сказанного недопонимаю, но постараюсь провести аналогии с minifMod, может ридём к общему пониманию. PCM рендерится не в драйвер, а в свой внутрненний буффер. В драйверный буффер в определённый момент копируются данные из внутреннего буффера. что есть квант времени? может быть мы говорим о разных вещах, но MinifMod-овский двиг требует, условно говоря, количество семплов, которые надо смиксировать. Я смешивал сразу 1 тик в свой буффер, размер которого мне известен ( samplespertick*4 ). С драйверным буффером я общаюсь сам . SamplesPerTick. + необходимо узнавать, что трек закончился. Но более важно, я хочу иметь доступ к нескольким открытым трекам (нескольким FMUSIC_MODULE). Насколько сложно сделать их "public" и использовать ? Я попытался поискать сорсы для Kolibri, безуспешно o_O? + мне надо производить чтение из Delphi-йского TStream-а.
DevilDevil Это справедливо для miniFMOD, если мне не изменяет память, но в uFMOD всё совсем иначе: во внутреннем буфере данные хранятся не в PCM, а в некотором 32-битном формате, который использует встроенный миксер. В определённый момент данные конвертируются на лету в 16-битный PCM и копируются в драйвер. В частности благодаря этой схеме uFMOD на порядок быстрее miniFMOD'а. Это время, которое выделяется потоку, который подгружает данные в буфер драйвера. Если оставить это на совести пользовательского кода, нет гарантии, что данные запишутся вовремя. samplespertick хранится по адресу переменной _mod + 60 байт. Но _mod не экпортируется. Правда, ничто не мешает сделать её паблик. Есть флаг XM_NOLOOP с которым проигрывание не зацикливается. Если задать этот флаг, то конец трека можно определить по состоянию хендла треда. Переменная с этим хэндлом - hThread, но она тоже не экспортируется. Стандартные виндовые функции для синхронизации вроде WaitForSingleObject как раз для подобных ситуаций и предназначены. Дело не в паблик, а в том, что эти функции не предназначены для вызова извне. Если не подставить нужные значения в регистры и стек, вызов любой из этих "функций" окончится плачевно. Они на офф. сайте ufmod.sf.net в соответсвующем пакете. И в последнем релизе Колибри тоже присутствуют. Только там изпользуется совсем другая схема чтения файлов, выделения динамической памяти и т.д. Т.е. под win32 от этого кода пользы не будет. На данном этапе адаптировать исходники библиотеки под Ваши нужды мне представляется сложной задачей. Фишку с рендерингом в произвольный буфер вместо определённого драйвера как в Колибри некогда планировалось перенести в win32/linux/unix, но это произойдёт не скоро, если вообще произойдёт.
Это всё не то. Там можно несколько полей сравнивать на -1 вроде. Возможно, в MiniFMod так же. да врядли из-за такой не особо значительной вещи на порядок. по идее можно враппер сделать Вот в OggVorbis, например, вообще нет проигрывания. Тем не менее справляются как то люди. В ModPlug та же ситуация кстати. Хм... вот какой вопрос, личный почти... не знаешь, кого нибудь из фрилансеров, с кем пожно обговорить данный вопрос ?
Как не то? Я не представляю себе как можно более эффективно определить конец проигрывания. Не сравнивать же значение какой-то глобальной переменной в цикле пока не надоест, когда можно получить уведомление асинхронно через событие? Возможно, я не совсем ясно обьяснил ситуацию. Суть в том, что минифмод приводит всё к PCM на стадии микширования, а это значит что преобразование осуществляется для каждого из 32 каналов. уФМОД приводит всё к PCM один раз (!) непосредственно перед отправкой данных в драйвер. В добавок к этому, уФМОД использует целочисленный миксер, а не ФПУ-шный как в миниФМОД. Производительность действительно выше на порядок и я имею в виду десятичный порядок. Можно, но для этого нужно хорошо разобраться в коде, т.е. обязанность ложиться на разработчиков, но я пока не представляю себе пользы от экспорта LoadXM, UpdateXM и т.д. Если Вам нужно загрузить трек в память, но не начинать проигрывание, т.е. как при вызове LoadXM, просто вызовите uFMOD_PlaySong с флагом XM_SUSPENDED или как-то так мы его окрестили. В 99% случаев людям нужна либа для проигрывания, а не для абстрактной загрузки стрима в память, чтоб потом самостоятельно разруливать общение с драйвером, синхронизацию и т.д. Поэтому надстройки над Ogg, позволяющие одним вызовом функции начать воспроизведение более популярны, чем сам Ogg, как ни парадоксально Я не говорю, что запрошенная Вами фича никому больше не нужна, более того идея добавить такую возможность уже возникала, но пока имеются более приоритетные TODO. Дык, никто ж не захочет заниматься разбором километровых ассемблерных листингов, тем более что движок постоянно меняется и к следующей версии придётся разбираться по новой. Я бы на Вашем месте заюзал уже упомянутый модплуг, если проект не критичен к размеру, ведь так?