Merge branch 'skmp/streaming-and-sfx-fixes' into 'main'

streaming: Fix prefetch behaviour, read discards race, sfx and stream playback position race

See merge request skmp/dca3-game!83
This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2025-03-29 14:33:26 +00:00
commit 2cb15f3728
5 changed files with 97 additions and 35 deletions

View file

@ -11,6 +11,8 @@
#include "crossplatform.h"
#if !defined(AUDIO_OAL) && !defined(AUDIO_MSS)
#define syncf(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
#define streamf(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
#define verbosef(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
#define debugf(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
@ -47,6 +49,8 @@
/* Quick access to the AICA channels */
#define AICA_CHANNEL(x) (AICA_MEM_CHANNELS + (x) * sizeof(aica_channel_t))
static uint32_t chn_version[64];
int aica_play_chn(int chn, int size, uint32_t aica_buffer, int fmt, int vol, int pan, int loop, int freq) {
// assert(size <= 65534);
// We gotta fix this at some point
@ -70,6 +74,7 @@ int aica_play_chn(int chn, int size, uint32_t aica_buffer, int fmt, int vol, int
chan->freq = freq;
chan->vol = vol;
chan->pan = pan;
chan->version = ++chn_version[chn];
snd_sh4_to_aica(tmp, cmd->size);
return chn;
}
@ -363,6 +368,13 @@ cSampleManager::Initialise(void)
if (channels[i].ch != -1) {
assert(channels[i].nSfx != -1);
uint32_t channel_version = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(channels[i].ch) + offsetof(aica_channel_t, version));
if (chn_version[channels[i].ch] != channel_version) {
syncf("Stream version missmatch, skipping update. expected %d got %d\n", chn_version[channels[i].ch], channel_version);
continue;
}
uint16_t channel_pos = (g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(channels[i].ch) + offsetof(aica_channel_t, pos)) & 0xffff);
// verbosef("Channel %d pos: %d\n", i, channel_pos);
if (!channels[i].loop) {
@ -389,21 +401,28 @@ cSampleManager::Initialise(void)
{
std::lock_guard<std::mutex> lk(streams[i].mtx);
if (streams[i].playing) {
uint32_t channel_version = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(streams[i].mapped_ch[0]) + offsetof(aica_channel_t, version));
if (chn_version[streams[i].mapped_ch[0]] != channel_version) {
syncf("Stream version missmatch, skipping update. expected %d got %d\n", chn_version[streams[i].mapped_ch[0]], channel_version);
continue;
}
// get channel pos
uint32_t channel_pos = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(streams[i].mapped_ch[0]) + offsetof(aica_channel_t, pos)) & 0xffff;
uint32_t logical_pos = channel_pos;
if (logical_pos > STREAM_CHANNEL_SAMPLE_COUNT/2) {
logical_pos -= STREAM_CHANNEL_SAMPLE_COUNT/2;
}
verbosef("Stream %d pos: %d, log: %d, rem: %d\n", i, channel_pos, logical_pos, streams[i].played_samples);
streamf("Stream %d pos: %d, log: %d, played: %d\n", i, channel_pos, logical_pos, streams[i].played_samples);
bool can_refill = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
bool can_fetch = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2 + STREAM_CHANNEL_SAMPLE_COUNT/2 + STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
bool can_refill = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2 + (!streams[i].first_refill)*STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
bool can_fetch = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2 + STREAM_CHANNEL_SAMPLE_COUNT/2 + (!streams[i].first_refill)*STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
// copy over data if needed from staging
if (channel_pos >= STREAM_CHANNEL_SAMPLE_COUNT/2 && !streams[i].next_is_upper_half) {
streams[i].next_is_upper_half = true;
if (can_refill) { // could we need a refill?
verbosef("Filling channel %d with lower half\n", i);
streamf("Filling channel %d with lower half\n", i);
// fill lower half
spu_memload(streams[i].aica_buffers[0], streams[i].buffer, STREAM_CHANNEL_BUFFER_SIZE/2);
if (streams[i].stereo) {
@ -419,7 +438,7 @@ cSampleManager::Initialise(void)
} else if (channel_pos < STREAM_CHANNEL_SAMPLE_COUNT/2 && streams[i].next_is_upper_half) {
streams[i].next_is_upper_half = false;
if (can_refill) { // could we need a refill?
verbosef("Filling channel %d with upper half\n", i);
streamf("Filling channel %d with upper half\n", i);
// fill upper half
spu_memload(streams[i].aica_buffers[0] + STREAM_CHANNEL_BUFFER_SIZE/2, streams[i].buffer, STREAM_CHANNEL_BUFFER_SIZE/2);
if (streams[i].stereo) {
@ -439,7 +458,7 @@ cSampleManager::Initialise(void)
// if end of file, stop
if ((streams[i].played_samples + logical_pos) > streams[i].total_samples) {
// stop channel
debugf("Auto stopping stream: %d -> {%d, %d}, %d total\n", i, streams[i].mapped_ch[0], streams[i].mapped_ch[1], streams[i].total_samples);
streamf("Auto stopping stream: %d -> {%d, %d}, %d total\n", i, streams[i].mapped_ch[0], streams[i].mapped_ch[1], streams[i].total_samples);
aica_stop_chn(streams[i].mapped_ch[0]);
aica_stop_chn(streams[i].mapped_ch[1]);
streams[i].playing = false;
@ -447,7 +466,7 @@ cSampleManager::Initialise(void)
}
if (do_read) {
debugf("Queueing stream read: %d, file: %d, buffer: %p, size: %d, tell: %d\n", i, streams[i].fd, streams[i].buffer, do_read, fs_tell(streams[i].fd));
streamf("Queueing stream read: %d, file: %d, buffer: %p, size: %d, file_offset: %d\n", i, streams[i].fd, streams[i].buffer, do_read, streams[i].file_offset);
CdStreamQueueAudioRead(streams[i].fd, streams[i].buffer, do_read, streams[i].file_offset);
streams[i].file_offset += do_read;
}
@ -487,6 +506,7 @@ cSampleManager::Initialise(void)
void
cSampleManager::Terminate(void)
{
CdStreamDiscardAudioRead(fdPedSfx);
fs_close(fdPedSfx);
}
@ -737,9 +757,9 @@ cSampleManager::LoadPedComment(uint32 nComment)
assert(m_aSamples[nComment].nByteSize <= PED_BLOCKSIZE_ADPCM);
CdStreamQueueAudioRead(nComment, (void*)nPedSlotSfxAddr[nCurrentPedSlot], m_aSamples[nComment].nByteSize, m_aSamples[nComment].nFileOffset, [](AudioReadCmd* cmd) {
CdStreamQueueAudioRead(fdPedSfx, (void*)nPedSlotSfxAddr[nCurrentPedSlot], m_aSamples[nComment].nByteSize, m_aSamples[nComment].nFileOffset, [](AudioReadCmd* cmd) {
debugf("Loading ped comment %d, offset: %d, size: %d\n", nComment, m_aSamples[nComment].nFileOffset, m_aSamples[nComment].nByteSize);
fs_seek(fdPedSfx, cmd->seek, SEEK_SET);
assert(fs_seek(fdPedSfx, cmd->seek, SEEK_SET) == cmd->seek);
// TODO: When we can dma directly to AICA, we can use this instead
@ -1027,7 +1047,7 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream, uint32_t seek_by
{
ASSERT( nStream < MAX_STREAMS );
file_t f = fs_open(DCStreamedNameTable[nFile], O_RDONLY);
debugf("PreloadStreamedFile(%p, %d, %d) is %s\n", f, nFile, nStream, DCStreamedNameTable[nFile]);
streamf("PreloadStreamedFile(%p, %d, %d) is %s\n", f, nFile, nStream, DCStreamedNameTable[nFile]);
assert(f >= 0 );
WavHeader hdr;
assert(fs_read(f, &hdr, sizeof(hdr)) == sizeof(hdr));
@ -1050,13 +1070,13 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream, uint32_t seek_by
streams[nStream].next_is_upper_half = true;
streams[nStream].first_refill = true;
debugf("PreloadStreamedFile: %s: stream: %d, freq: %d, chans: %d, byte size: %d, played samples: %d\n", DCStreamedNameTable[nFile], nStream, hdr.samplesPerSec, hdr.numOfChan, hdr.dataSize, streams[nStream].played_samples);
streamf("PreloadStreamedFile: %s: stream: %d, freq: %d, chans: %d, byte size: %d, played samples: %d\n", DCStreamedNameTable[nFile], nStream, hdr.samplesPerSec, hdr.numOfChan, hdr.dataSize, streams[nStream].played_samples);
// How to avoid the lock?
if (seek_bytes_aligned) {
streams[nStream].played_samples = seek_bytes_aligned * (streams[nStream].stereo ? 1 : 2);
debugf("Seeking aligned to: %d, played_samples: %d\n", seek_bytes_aligned, streams[nStream].played_samples);
streamf("Seeking aligned to: %d, played_samples: %d\n", seek_bytes_aligned, streams[nStream].played_samples);
fs_seek(streams[nStream].fd, 2048 + seek_bytes_aligned, SEEK_SET);
} else {
fs_seek(f, 2048, SEEK_SET);
@ -1085,7 +1105,7 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream, uint32_t seek_by
streams[nStream].file_offset = fs_tell(f);
}
verbosef("PreloadStreamedFile: %p %d - %s, %d, %d, \n", f, nFile, DCStreamedNameTable[nFile], streams[nStream].rate, streams[nStream].stereo);
streamf("PreloadStreamedFile: %p %d - %s, %d, %d, \n", f, nFile, DCStreamedNameTable[nFile], streams[nStream].rate, streams[nStream].stereo);
}
// we can't really pause a stream, so we just make it go very slow with zero volume

View file

@ -479,6 +479,7 @@ RemoveFirstInQueue(Queue *queue)
}
std::vector<AudioReadCmd> pendingAudioReads;
volatile int pendingAudioRead_fd = -1;
#if !defined(DC_SH4)
std::mutex pendingAudioReadsMutex;
#endif
@ -487,8 +488,9 @@ void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek, st
AudioReadCmd cmd = { pBuffer, fd, bytes, seek};
if (!callback) {
cmd.callback = [](AudioReadCmd* cmd){
lseek(cmd->fd, cmd->seek, SEEK_SET);
read(cmd->fd, cmd->dest, cmd->size);
assert(pendingAudioRead_fd == cmd->fd);
assert(lseek(cmd->fd, cmd->seek, SEEK_SET) == cmd->seek);
assert(read(cmd->fd, cmd->dest, cmd->size) == cmd->size);
};
} else {
cmd.callback = callback;
@ -500,7 +502,7 @@ void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek, st
auto mask = irq_disable();
#endif
for (auto it = pendingAudioReads.rbegin(); it != pendingAudioReads.rend(); ++it) {
if (it->fd == -1 || it->fd == fd) {
if (it->fd == -1) {
*it = cmd;
goto out;
}
@ -532,6 +534,12 @@ void CdStreamDiscardAudioRead(int fd) {
#if defined(DC_SH4)
irq_restore(mask);
#endif
while (pendingAudioRead_fd == fd) {
#if defined(DC_SH4)
thd_pass();
#endif
}
}
AudioReadCmd CdStreamNextAudioRead() {
@ -548,6 +556,8 @@ AudioReadCmd CdStreamNextAudioRead() {
break;
}
}
assert(pendingAudioRead_fd == -1);
pendingAudioRead_fd = cmd.fd;
#if defined(DC_SH4)
irq_restore(mask);
#endif
@ -568,6 +578,7 @@ int read_loop(int fd, void* pBuffer, size_t bytes) {
auto cmd = CdStreamNextAudioRead();
while (cmd.fd != -1) {
cmd.callback(&cmd);
pendingAudioRead_fd = -1;
cmd = CdStreamNextAudioRead();
}
}
@ -584,6 +595,7 @@ void *CdStreamThread(void *param)
auto cmd = CdStreamNextAudioRead();
while (cmd.fd != -1) {
cmd.callback(&cmd);
pendingAudioRead_fd = -1;
cmd = CdStreamNextAudioRead();
}

View file

@ -12,6 +12,8 @@
#include "thread/thread.h"
#if !defined(AUDIO_OAL) && !defined(AUDIO_MSS)
#define syncf(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
#define streamf(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
#define verbosef(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
#define debugf(...) // dbglog(DBG_CRITICAL, __VA_ARGS__)
@ -46,6 +48,8 @@
/* Quick access to the AICA channels */
#define AICA_CHANNEL(x) (AICA_MEM_CHANNELS + (x) * sizeof(aica_channel_t))
static uint32_t chn_version[64];
int aica_play_chn(int chn, int size, uint32_t aica_buffer, int fmt, int vol, int pan, int loop, int freq) {
// assert(size <= 65534);
// We gotta fix this at some point
@ -69,6 +73,7 @@ int aica_play_chn(int chn, int size, uint32_t aica_buffer, int fmt, int vol, int
chan->freq = freq;
chan->vol = vol;
chan->pan = pan;
chan->version = ++chn_version[chn];
snd_sh4_to_aica(tmp, cmd->size);
return chn;
}
@ -370,6 +375,12 @@ cSampleManager::Initialise(void)
if (channels[i].ch != -1) {
assert(channels[i].nSfx != -1);
uint32_t channel_version = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(channels[i].ch) + offsetof(aica_channel_t, version));
if (chn_version[channels[i].ch] != channel_version) {
syncf("SFX version missmatch, skipping update. expected %d got %d\n", chn_version[channels[i].ch], channel_version);
continue;
}
uint16_t channel_pos = (g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(channels[i].ch) + offsetof(aica_channel_t, pos)) & 0xffff);
// verbosef("Channel %d pos: %d\n", i, channel_pos);
if (!channels[i].loop) {
@ -396,21 +407,27 @@ cSampleManager::Initialise(void)
{
std::lock_guard<std::mutex> lk(streams[i].mtx);
if (streams[i].playing) {
uint32_t channel_version = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(streams[i].mapped_ch[0]) + offsetof(aica_channel_t, version));
if (chn_version[streams[i].mapped_ch[0]] != channel_version) {
syncf("Stream version missmatch, skipping update. expected %d got %d\n", chn_version[streams[i].mapped_ch[0]], channel_version);
continue;
}
// get channel pos
uint32_t channel_pos = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(streams[i].mapped_ch[0]) + offsetof(aica_channel_t, pos)) & 0xffff;
uint32_t logical_pos = channel_pos;
if (logical_pos > STREAM_CHANNEL_SAMPLE_COUNT/2) {
logical_pos -= STREAM_CHANNEL_SAMPLE_COUNT/2;
}
verbosef("Stream %d pos: %d, log: %d, rem: %d\n", i, channel_pos, logical_pos, streams[i].played_samples);
streamf("Stream %d pos: %d, log: %d, played: %d\n", i, channel_pos, logical_pos, streams[i].played_samples);
bool can_refill = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
bool can_fetch = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2 + STREAM_CHANNEL_SAMPLE_COUNT/2 + STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
bool can_refill = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2 + (!streams[i].first_refill)*STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
bool can_fetch = (streams[i].played_samples + STREAM_CHANNEL_SAMPLE_COUNT/2 + STREAM_CHANNEL_SAMPLE_COUNT/2 + (!streams[i].first_refill)*STREAM_CHANNEL_SAMPLE_COUNT/2) < streams[i].total_samples;
// copy over data if needed from staging
if (channel_pos >= STREAM_CHANNEL_SAMPLE_COUNT/2 && !streams[i].next_is_upper_half) {
streams[i].next_is_upper_half = true;
if (can_refill) { // could we need a refill?
verbosef("Filling channel %d with lower half\n", i);
streamf("Filling channel %d with lower half\n", i);
// fill lower half
spu_memload(streams[i].aica_buffers[0], streams[i].buffer, STREAM_CHANNEL_BUFFER_SIZE/2);
if (streams[i].stereo) {
@ -426,7 +443,7 @@ cSampleManager::Initialise(void)
} else if (channel_pos < STREAM_CHANNEL_SAMPLE_COUNT/2 && streams[i].next_is_upper_half) {
streams[i].next_is_upper_half = false;
if (can_refill) { // could we need a refill?
verbosef("Filling channel %d with upper half\n", i);
streamf("Filling channel %d with upper half\n", i);
// fill upper half
spu_memload(streams[i].aica_buffers[0] + STREAM_CHANNEL_BUFFER_SIZE/2, streams[i].buffer, STREAM_CHANNEL_BUFFER_SIZE/2);
if (streams[i].stereo) {
@ -446,7 +463,7 @@ cSampleManager::Initialise(void)
// if end of file, stop
if ((streams[i].played_samples + logical_pos) > streams[i].total_samples) {
// stop channel
debugf("Auto stopping stream: %d -> {%d, %d}, %d total\n", i, streams[i].mapped_ch[0], streams[i].mapped_ch[1], streams[i].total_samples);
streamf("Auto stopping stream: %d -> {%d, %d}, %d total\n", i, streams[i].mapped_ch[0], streams[i].mapped_ch[1], streams[i].total_samples);
aica_stop_chn(streams[i].mapped_ch[0]);
aica_stop_chn(streams[i].mapped_ch[1]);
streams[i].playing = false;
@ -454,7 +471,7 @@ cSampleManager::Initialise(void)
}
if (do_read) {
debugf("Queueing stream read: %d, file: %d, buffer: %p, size: %d, tell: %d\n", i, streams[i].fd, streams[i].buffer, do_read, fs_tell(streams[i].fd));
streamf("Queueing stream read: %d, file: %d, buffer: %p, size: %d, file_offset: %d\n", i, streams[i].fd, streams[i].buffer, do_read, streams[i].file_offset);
CdStreamQueueAudioRead(streams[i].fd, streams[i].buffer, do_read, streams[i].file_offset);
streams[i].file_offset += do_read;
}
@ -494,6 +511,7 @@ cSampleManager::Initialise(void)
void
cSampleManager::Terminate(void)
{
CdStreamDiscardAudioRead(fdPedSfx);
fs_close(fdPedSfx);
}
@ -696,8 +714,8 @@ cSampleManager::LoadMissionAudio(uint8 nSlot, uint32 nSample)
ASSERT(nSample < TOTAL_AUDIO_SAMPLES);
debugf("Loading mission audio comment %d, offset: %d, size: %d\n", nSample, m_aSamples[nSample].nFileOffset, m_aSamples[nSample].nByteSize);
CdStreamQueueAudioRead(nSample, (void*)gPlayerTalkData, m_aSamples[nSample].nByteSize, m_aSamples[nSample].nFileOffset, [](AudioReadCmd* cmd) {
fs_seek(fdPedSfx, cmd->seek, SEEK_SET);
CdStreamQueueAudioRead(fdPedSfx, (void*)gPlayerTalkData, m_aSamples[nSample].nByteSize, m_aSamples[nSample].nFileOffset, [](AudioReadCmd* cmd) {
assert(fs_seek(fdPedSfx, cmd->seek, SEEK_SET) == cmd->seek);
// TODO: When we can dma directly to AICA, we can use this instead
// fs_read(fdPedSfx, SPU_BASE_U8 + (uintptr_t)cmd->dest, cmd->size);
@ -793,8 +811,8 @@ cSampleManager::LoadPedComment(uint32 nComment)
assert(m_aSamples[nComment].nByteSize <= pedBlocksizeMax);
debugf("Loading ped comment %d, offset: %d, size: %d\n", nComment, m_aSamples[nComment].nFileOffset, m_aSamples[nComment].nByteSize);
CdStreamQueueAudioRead(nComment, (void*)nPedSlotSfxAddr[nCurrentPedSlot], m_aSamples[nComment].nByteSize, m_aSamples[nComment].nFileOffset, [](AudioReadCmd* cmd) {
fs_seek(fdPedSfx, cmd->seek, SEEK_SET);
CdStreamQueueAudioRead(fdPedSfx, (void*)nPedSlotSfxAddr[nCurrentPedSlot], m_aSamples[nComment].nByteSize, m_aSamples[nComment].nFileOffset, [](AudioReadCmd* cmd) {
assert(fs_seek(fdPedSfx, cmd->seek, SEEK_SET) == cmd->seek);
// TODO: When we can dma directly to AICA, we can use this instead
@ -1098,7 +1116,7 @@ cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream, uint32_t seek_b
ASSERT( nFile < TOTAL_STREAMED_SOUNDS );
file_t f = fs_open(DCStreamedNameTable[nFile], O_RDONLY);
debugf("PreloadStreamedFile(%p, %d, %d) is %s\n", f, nFile, nStream, DCStreamedNameTable[nFile]);
streamf("PreloadStreamedFile(%p, %d, %d) is %s\n", f, nFile, nStream, DCStreamedNameTable[nFile]);
assert(f >= 0 );
WavHeader hdr;
assert(fs_read(f, &hdr, sizeof(hdr)) == sizeof(hdr));
@ -1130,13 +1148,13 @@ cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream, uint32_t seek_b
streams[nStream].next_is_upper_half = true;
streams[nStream].first_refill = true;
debugf("PreloadStreamedFile: %s: stream: %d, freq: %d, chans: %d, byte size: %d, played samples: %d\n", DCStreamedNameTable[nFile], nStream, hdr.samplesPerSec, hdr.numOfChan, hdr.dataSize, streams[nStream].played_samples);
streamf("PreloadStreamedFile: %s: stream: %d, freq: %d, chans: %d, byte size: %d, played samples: %d\n", DCStreamedNameTable[nFile], nStream, hdr.samplesPerSec, hdr.numOfChan, hdr.dataSize, streams[nStream].played_samples);
// How to avoid the lock?
if (seek_bytes_aligned) {
streams[nStream].played_samples = seek_bytes_aligned * (streams[nStream].stereo ? 1 : 2);
debugf("Seeking aligned to: %d, played_samples: %d\n", seek_bytes_aligned, streams[nStream].played_samples);
streamf("Seeking aligned to: %d, played_samples: %d\n", seek_bytes_aligned, streams[nStream].played_samples);
fs_seek(streams[nStream].fd, 2048 + seek_bytes_aligned, SEEK_SET);
} else {
fs_seek(f, 2048, SEEK_SET);
@ -1165,7 +1183,7 @@ cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream, uint32_t seek_b
streams[nStream].file_offset = fs_tell(f);
}
verbosef("PreloadStreamedFile: %p %d - %s, %d, %d, \n", f, nFile, DCStreamedNameTable[nFile], streams[nStream].rate, streams[nStream].stereo);
streamf("PreloadStreamedFile: %p %d - %s, %d, %d, \n", f, nFile, DCStreamedNameTable[nFile], streams[nStream].rate, streams[nStream].stereo);
}
// we can't really pause a stream, so we just make it go very slow with zero volume

View file

@ -479,6 +479,7 @@ RemoveFirstInQueue(Queue *queue)
}
std::vector<AudioReadCmd> pendingAudioReads;
volatile int pendingAudioRead_fd = -1;
#if !defined(DC_SH4)
std::mutex pendingAudioReadsMutex;
#endif
@ -487,8 +488,9 @@ void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek, st
AudioReadCmd cmd = { pBuffer, fd, bytes, seek};
if (!callback) {
cmd.callback = [](AudioReadCmd* cmd){
lseek(cmd->fd, cmd->seek, SEEK_SET);
read(cmd->fd, cmd->dest, cmd->size);
assert(pendingAudioRead_fd == cmd->fd);
assert(lseek(cmd->fd, cmd->seek, SEEK_SET) == cmd->seek);
assert(read(cmd->fd, cmd->dest, cmd->size) == cmd->size);
};
} else {
cmd.callback = callback;
@ -500,7 +502,7 @@ void CdStreamQueueAudioRead(int fd, void* pBuffer, size_t bytes, size_t seek, st
auto mask = irq_disable();
#endif
for (auto it = pendingAudioReads.rbegin(); it != pendingAudioReads.rend(); ++it) {
if (it->fd == -1 || it->fd == fd) {
if (it->fd == -1) {
*it = cmd;
goto out;
}
@ -532,6 +534,12 @@ void CdStreamDiscardAudioRead(int fd) {
#if defined(DC_SH4)
irq_restore(mask);
#endif
while (pendingAudioRead_fd == fd) {
#if defined(DC_SH4)
thd_pass();
#endif
}
}
AudioReadCmd CdStreamNextAudioRead() {
@ -548,6 +556,8 @@ AudioReadCmd CdStreamNextAudioRead() {
break;
}
}
assert(pendingAudioRead_fd == -1);
pendingAudioRead_fd = cmd.fd;
#if defined(DC_SH4)
irq_restore(mask);
#endif
@ -568,6 +578,7 @@ int read_loop(int fd, void* pBuffer, size_t bytes) {
auto cmd = CdStreamNextAudioRead();
while (cmd.fd != -1) {
cmd.callback(&cmd);
pendingAudioRead_fd = -1;
cmd = CdStreamNextAudioRead();
}
}
@ -584,6 +595,7 @@ void *CdStreamThread(void *param)
auto cmd = CdStreamNextAudioRead();
while (cmd.fd != -1) {
cmd.callback(&cmd);
pendingAudioRead_fd = -1;
cmd = CdStreamNextAudioRead();
}

2
vendor/dca3-kos vendored

@ -1 +1 @@
Subproject commit a76dc89fbb81ce848c10d5b4732f0ba379e97757
Subproject commit 5f69d048aaf2548687c33afc7726d603a22e29b7