aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2023-06-20 13:27:34 +0200
committerspicyjpeg <thatspicyjpeg@gmail.com>2023-06-20 13:27:34 +0200
commit79a966486615e60be3a37d278945dc3dd0fd933b (patch)
tree4a4cd8412c10b9646ff1966af964a314c0567005 /examples
parentced21c69f7b399dce169069334c1424e5254d582 (diff)
downloadpsn00bsdk-79a966486615e60be3a37d278945dc3dd0fd933b.tar.gz
More SPU streaming example tweaks
Diffstat (limited to 'examples')
-rw-r--r--examples/sound/cdstream/main.c6
-rw-r--r--examples/sound/cdstream/stream.c4
-rw-r--r--examples/sound/cdstream/stream.h12
-rw-r--r--examples/sound/spustream/main.c70
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;
}