Я опубликовал вопрос на gamedev о том, как проигрывать файлы nsf (консольная музыка NES) в FMOD. Это не дало никаких результатов, но с тех пор я добился определенного прогресса. Я решил, что самым простым способом было просто скомпилировать существующий проигрыватель в dll, а затем вызвать его из C # для заполнения моего буфера. Теперь проблема в том, чтобы заставить его звучать правильно и убедиться, что все мои параметры верны.
Вот факты на данный момент:
- nsf dll имеет дело с
short
s, поэтому данные PCM16.
- Образец nsf, который я использую, имеет скорость воспроизведения 60 Гц.
- Просто для игры сейчас я использую частоту 48000.
- На основе 2 и 3, dll вычисляет необходимый размер буфера 48000/60 Гц = 800. Это означает, что он будет представлять буфер размером 800
short
с для каждого смоделированного кадра NES.
До сих пор я получил свой код C # для воспроизведения nsf в правильном темпе и темпе, но он очень зернистый / нечеткий, что я объясняю тем, что обратный вызов чтения FMOD дает длину данных 1600, тогда как я должен был ожидать 800. Я попытался поиграть со всеми числами, и он либо зависал, либо музыка меняла высоту, темп или то и другое.
Вот мой код на C #:
uint channels = 1, frequency = 48000;
FMOD.MODE mode = (FMOD.MODE.DEFAULT | FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_NORMAL);
FMOD.Sound sound = new FMOD.Sound();
FMOD.CREATESOUNDEXINFO ex = new FMOD.CREATESOUNDEXINFO();
ex.cbsize = Marshal.SizeOf(ex);
ex.fileoffset = 0;
ex.format = FMOD.SOUND_FORMAT.PCM16;
// does this even matter? It doesn't change my results as long as it's long enough for one update
ex.length = frequency;
ex.numchannels = (int)channels;
ex.defaultfrequency = (int)frequency;
ex.pcmreadcallback = pcmreadcallback;
ex.dlsname = null;
// eventually I will calculate this with frequency / nsf hz, but I'm just testing for now
ex.decodebuffersize = 800;
// from the dll
load_nsf_file("file.nsf", 8, (int)frequency); // 8 is the track number to play
var result = system.createSound(
(string)null,
(mode | FMOD.MODE.CREATESTREAM),
ref ex,
ref sound);
channel = new FMOD.Channel();
result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel);
private FMOD.RESULT PCMREADCALLBACK(IntPtr soundraw, IntPtr data, uint datalen)
{
// from the dll
process_buffer(data, (int)800); // if I use datalen, it usually crashes (I can't get datalen to = 800 safely)
return FMOD.RESULT.OK;
}
Итак, вот некоторые из моих вопросов:
- Какова связь между exinfo.decodebuffersize, частотой и параметром
datalen
обратного вызова чтения? В этом примере кода он равен 3200. Я не знаю, откуда взялся этот коэффициент 4 между ним и размером декодера.
- Является ли
datalen
в обратном вызове ссылкой на число byte
с или short
с? Функция process_buffer принимает короткий массив и его длину. Я ожидаю, что fmod говорит и о шортах, потому что я сказал ему PCM16.
- Возможно, мое качество воспроизведения плохое по совершенно другой причине. Если так, я понятия не имею, с чего начать. Есть идеи?