diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-06-20 13:27:34 +0200 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-06-20 13:27:34 +0200 |
| commit | 79a966486615e60be3a37d278945dc3dd0fd933b (patch) | |
| tree | 4a4cd8412c10b9646ff1966af964a314c0567005 /examples | |
| parent | ced21c69f7b399dce169069334c1424e5254d582 (diff) | |
| download | psn00bsdk-79a966486615e60be3a37d278945dc3dd0fd933b.tar.gz | |
More SPU streaming example tweaks
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/sound/cdstream/main.c | 6 | ||||
| -rw-r--r-- | examples/sound/cdstream/stream.c | 4 | ||||
| -rw-r--r-- | examples/sound/cdstream/stream.h | 12 | ||||
| -rw-r--r-- | examples/sound/spustream/main.c | 70 |
4 files changed, 48 insertions, 44 deletions
diff --git a/examples/sound/cdstream/main.c b/examples/sound/cdstream/main.c index c6d578c..fbca65e 100644 --- a/examples/sound/cdstream/main.c +++ b/examples/sound/cdstream/main.c @@ -312,7 +312,7 @@ int main(int argc, const char* argv[]) { SHOW_STATUS("BUFFERING STREAM\n"); setup_stream(&file.pos); - Stream_Start(&stream_ctx); + Stream_Start(&stream_ctx, false); int sectors_per_chunk = (stream_ctx.chunk_size + 2047) / 2048; int vag_sample_rate = getSPUSampleRate(stream_ctx.config.sample_rate); @@ -326,7 +326,7 @@ int main(int argc, const char* argv[]) { bool buffering = feed_stream(); FntPrint(-1, "PLAYING SPU STREAM\n\n"); - FntPrint(-1, "BUFFER: %d\n", stream_ctx.db_active); + FntPrint(-1, "BUFFER: %d (%d)\n", stream_ctx.db_active, stream_ctx.chunk_counter); FntPrint(-1, "STATUS: %s\n\n", buffering ? "READING" : "IDLE"); FntPrint(-1, "BUFFERED: %d/%d\n", stream_ctx.buffer.length, stream_ctx.config.buffer_size); @@ -359,7 +359,7 @@ int main(int argc, const char* argv[]) { if (paused) Stream_Stop(); else - Stream_Start(&stream_ctx); + Stream_Start(&stream_ctx, true); } // Note that seeking will only work correctly with .VAG files whose diff --git a/examples/sound/cdstream/stream.c b/examples/sound/cdstream/stream.c index bf73b2f..aaf5703 100644 --- a/examples/sound/cdstream/stream.c +++ b/examples/sound/cdstream/stream.c @@ -145,14 +145,14 @@ void Stream_Destroy(Stream_Context *ctx) { ExitCriticalSection(); } -bool Stream_Start(Stream_Context *ctx) { +bool Stream_Start(Stream_Context *ctx, bool resume) { if (_active_ctx) return false; _active_ctx = ctx; // Wait for the first chunk to be buffered and ready to play. - if (!ctx->chunk_counter) { + if (!resume) { _spu_irq_handler(); SpuIsTransferCompleted(SPU_TRANSFER_WAIT); } diff --git a/examples/sound/cdstream/stream.h b/examples/sound/cdstream/stream.h index 15e3ec3..aa384ed 100644 --- a/examples/sound/cdstream/stream.h +++ b/examples/sound/cdstream/stream.h @@ -121,16 +121,20 @@ void Stream_Destroy(Stream_Context *ctx); /** * @brief Starts playback of a stream. * - * @details Activates the given stream context and starts playing audio from its - * FIFO. This function must be called while no other stream is active and after - * the stream's FIFO has been filled up. + * @details Activates the given stream context and starts or resumes playing + * audio from its FIFO. This function must be called while no other stream is + * active and after the stream's FIFO has been filled up. In order to prevent + * skipping, the resume argument shall be set to true if the stream was + * previously stopped and its buffer in SPU RAM was not overwritten by another + * stream or sample data. * * @param ctx + * @param resume Should be true if resuming a previously stopped stream * @return True if the stream was started, false if another stream is active * * @see Stream_Stop() */ -bool Stream_Start(Stream_Context *ctx); +bool Stream_Start(Stream_Context *ctx, bool resume); /** * @brief Stops playback of any currently active stream. diff --git a/examples/sound/spustream/main.c b/examples/sound/spustream/main.c index 6bf2c71..28a0ce5 100644 --- a/examples/sound/spustream/main.c +++ b/examples/sound/spustream/main.c @@ -154,7 +154,7 @@ typedef struct { volatile int8_t db_active, buffering; } StreamContext; -static StreamContext str_ctx; +static StreamContext stream_ctx; void spu_irq_handler(void) { // Acknowledge the interrupt to ensure it can be triggered again. The only @@ -162,35 +162,35 @@ void spu_irq_handler(void) { // enable it again once the chunk is ready. SPU_CTRL &= ~(1 << 6); - int chunk_size = str_ctx.buffer_size * str_ctx.channels; - int chunk = (str_ctx.next_chunk + 1) % (uint32_t) str_ctx.num_chunks; + int chunk_size = stream_ctx.buffer_size * stream_ctx.channels; + int chunk = (stream_ctx.next_chunk + 1) % (uint32_t) stream_ctx.num_chunks; - str_ctx.db_active ^= 1; - str_ctx.buffering = 1; - str_ctx.next_chunk = chunk; + stream_ctx.db_active ^= 1; + stream_ctx.buffering = 1; + stream_ctx.next_chunk = chunk; // Configure to SPU to trigger an IRQ once the chunk that is going to be // filled now starts playing (so the next buffer can be loaded) and // override both channels' loop addresses to make them "jump" to the new // buffers, rather than actually looping when they encounter the loop flag // at the end of the currently playing buffers. - int addr = BUFFER_START_ADDR + (str_ctx.db_active ? chunk_size : 0); - str_ctx.spu_addr = addr; + int addr = BUFFER_START_ADDR + (stream_ctx.db_active ? chunk_size : 0); + stream_ctx.spu_addr = addr; SPU_IRQ_ADDR = getSPUAddr(addr); - for (int i = 0; i < str_ctx.channels; i++) - SPU_CH_LOOP_ADDR(i) = getSPUAddr(addr + str_ctx.buffer_size * i); + for (int i = 0; i < stream_ctx.channels; i++) + SPU_CH_LOOP_ADDR(i) = getSPUAddr(addr + stream_ctx.buffer_size * i); // Start uploading the next chunk to the SPU. SpuSetTransferStartAddr(addr); - SpuWrite((const uint32_t *) &str_ctx.data[chunk * chunk_size], chunk_size); + SpuWrite((const uint32_t *) &stream_ctx.data[chunk * chunk_size], chunk_size); } void spu_dma_handler(void) { // Re-enable the SPU IRQ once the new chunk has been fully uploaded. SPU_CTRL |= 1 << 6; - str_ctx.buffering = 0; + stream_ctx.buffering = 0; } /* Helper functions */ @@ -218,32 +218,32 @@ void init_stream(const VAG_Header *vag) { int buf_size = vag->interleave; - str_ctx.data = &((const uint8_t *) vag)[2048]; - str_ctx.buffer_size = buf_size; - str_ctx.num_chunks = (SWAP_ENDIAN(vag->size) + buf_size - 1) / buf_size; - str_ctx.sample_rate = SWAP_ENDIAN(vag->sample_rate); - str_ctx.channels = vag->channels ? vag->channels : 1; + stream_ctx.data = &((const uint8_t *) vag)[2048]; + stream_ctx.buffer_size = buf_size; + stream_ctx.num_chunks = (SWAP_ENDIAN(vag->size) + buf_size - 1) / buf_size; + stream_ctx.sample_rate = SWAP_ENDIAN(vag->sample_rate); + stream_ctx.channels = vag->channels ? vag->channels : 1; - str_ctx.db_active = 1; - str_ctx.next_chunk = -1; + stream_ctx.db_active = 1; + stream_ctx.next_chunk = -1; // Ensure at least one chunk is in SPU RAM by invoking the IRQ handler // manually and blocking until the chunk has loaded. spu_irq_handler(); - while (str_ctx.buffering) + while (stream_ctx.buffering) __asm__ volatile(""); } void start_stream(void) { - int bits = 0x00ffffff >> (24 - str_ctx.channels); + int bits = 0x00ffffff >> (24 - stream_ctx.channels); // Disable the IRQ as we're going to call spu_irq_handler() manually (due // to finicky SPU timings). SPU_CTRL &= ~(1 << 6); - for (int i = 0; i < str_ctx.channels; i++) { - SPU_CH_ADDR(i) = getSPUAddr(str_ctx.spu_addr + str_ctx.buffer_size * i); - SPU_CH_FREQ(i) = getSPUSampleRate(str_ctx.sample_rate); + for (int i = 0; i < stream_ctx.channels; i++) { + SPU_CH_ADDR(i) = getSPUAddr(stream_ctx.spu_addr + stream_ctx.buffer_size * i); + SPU_CH_FREQ(i) = getSPUSampleRate(stream_ctx.sample_rate); SPU_CH_ADSR1(i) = 0x00ff; SPU_CH_ADSR2(i) = 0x0000; } @@ -264,11 +264,11 @@ void start_stream(void) { // channels used to play the stream, to (again) prevent them from triggering // the SPU IRQ while the stream is paused. void stop_stream(void) { - int bits = 0x00ffffff >> (24 - str_ctx.channels); + int bits = 0x00ffffff >> (24 - stream_ctx.channels); SpuSetKey(0, bits); - for (int i = 0; i < str_ctx.channels; i++) + for (int i = 0; i < stream_ctx.channels; i++) SPU_CH_ADDR(i) = getSPUAddr(DUMMY_BLOCK_ADDR); SpuSetKey(1, bits); @@ -292,16 +292,16 @@ int main(int argc, const char* argv[]) { init_stream((const VAG_Header *) stream_data); start_stream(); - int paused = 0, sample_rate = getSPUSampleRate(str_ctx.sample_rate); + int paused = 0, sample_rate = getSPUSampleRate(stream_ctx.sample_rate); uint16_t last_buttons = 0xffff; while (1) { FntPrint(-1, "PLAYING SPU STREAM\n\n"); - FntPrint(-1, "BUFFER: %d\n", str_ctx.db_active); - FntPrint(-1, "STATUS: %s\n\n", str_ctx.buffering ? "BUFFERING" : "IDLE"); + FntPrint(-1, "BUFFER: %d\n", stream_ctx.db_active); + FntPrint(-1, "STATUS: %s\n\n", stream_ctx.buffering ? "BUFFERING" : "IDLE"); - FntPrint(-1, "POSITION: %d/%d\n", str_ctx.next_chunk, str_ctx.num_chunks); + FntPrint(-1, "POSITION: %d/%d\n", stream_ctx.next_chunk, stream_ctx.num_chunks); FntPrint(-1, "SMP RATE: %5d HZ\n\n", (sample_rate * 44100) >> 12); FntPrint(-1, "[START] %s\n", paused ? "RESUME" : "PAUSE"); @@ -334,22 +334,22 @@ int main(int argc, const char* argv[]) { } if (!(pad->btn & PAD_LEFT)) - str_ctx.next_chunk--; + stream_ctx.next_chunk--; if (!(pad->btn & PAD_RIGHT)) - str_ctx.next_chunk++; + stream_ctx.next_chunk++; if ((last_buttons & PAD_CIRCLE) && !(pad->btn & PAD_CIRCLE)) - str_ctx.next_chunk = -1; + stream_ctx.next_chunk = -1; if (!(pad->btn & PAD_DOWN) && (sample_rate > 0x400)) sample_rate -= 0x40; if (!(pad->btn & PAD_UP) && (sample_rate < 0x2000)) sample_rate += 0x40; if ((last_buttons & PAD_CROSS) && !(pad->btn & PAD_CROSS)) - sample_rate = getSPUSampleRate(str_ctx.sample_rate); + sample_rate = getSPUSampleRate(stream_ctx.sample_rate); // Only set the sample rate registers if necessary. if (pad->btn != 0xffff) { - for (int i = 0; i < str_ctx.channels; i++) + for (int i = 0; i < stream_ctx.channels; i++) SPU_CH_FREQ(i) = sample_rate; } |
