aboutsummaryrefslogtreecommitdiff
path: root/examples/sound
diff options
context:
space:
mode:
Diffstat (limited to 'examples/sound')
-rw-r--r--examples/sound/spustream/CMakeLists.txt7
-rw-r--r--examples/sound/spustream/main.c74
-rw-r--r--examples/sound/spustream/stream.binbin0 -> 4685824 bytes
-rw-r--r--examples/sound/vagsample/main.c73
4 files changed, 68 insertions, 86 deletions
diff --git a/examples/sound/spustream/CMakeLists.txt b/examples/sound/spustream/CMakeLists.txt
index 9e84fa3..397796a 100644
--- a/examples/sound/spustream/CMakeLists.txt
+++ b/examples/sound/spustream/CMakeLists.txt
@@ -14,12 +14,11 @@ project(
# TODO: add rules to actually generate a valid STREAM.BIN file
file(GLOB _sources *.c)
psn00bsdk_add_executable(spustream STATIC ${_sources})
-#psn00bsdk_add_cd_image(spustream_iso spustream iso.xml DEPENDS spustream)
+psn00bsdk_add_cd_image(spustream_iso spustream iso.xml DEPENDS spustream)
install(
FILES
- #${PROJECT_BINARY_DIR}/spustream.bin
- #${PROJECT_BINARY_DIR}/spustream.cue
- ${PROJECT_BINARY_DIR}/spustream.exe
+ ${PROJECT_BINARY_DIR}/spustream.bin
+ ${PROJECT_BINARY_DIR}/spustream.cue
TYPE BIN
)
diff --git a/examples/sound/spustream/main.c b/examples/sound/spustream/main.c
index 6b9db93..6179179 100644
--- a/examples/sound/spustream/main.c
+++ b/examples/sound/spustream/main.c
@@ -51,10 +51,9 @@
* +----------+----------+----------+----------+----------+----------+----
* \________________________Chunk________________________/
*
- * Such file isn't provided as PSn00bSDK doesn't yet have a tool for audio
- * transcoding. A Python script is included to generate STREAM.BIN from one or
- * more SPU ADPCM (.VAG) files, one for each channel (the .VAG format only
- * supports mono).
+ * A Python script is included to generate STREAM.BIN from one or more SPU
+ * ADPCM (.VAG) files, one for each channel (the .VAG format only supports
+ * mono).
*
* Of course SPU streaming isn't the only way to play music, as the CD drive
* can play CD-DA tracks and XA files natively with zero CPU overhead. However
@@ -101,7 +100,7 @@
// size can be increased to get more idle time between CD reads, however it is
// usually best to keep it to 1-2 seconds as SPU RAM is only 512 KB.
#define SAMPLE_RATE 0x1000 // 44100 Hz
-#define BUFFER_SIZE 26624 // (26624 / 16 * 28) / 44100 = 1.05 seconds
+#define BUFFER_SIZE 0x6800 // (0x6800 / 16 * 28) / 44100 = 1.05 seconds
#define NUM_CHANNELS 2
#define CHANNEL_MASK 0x03
@@ -123,8 +122,8 @@ typedef struct {
} DB;
typedef struct {
- DB db[2];
- uint32_t db_active;
+ DB db[2];
+ int db_active;
} CONTEXT;
void init_context(CONTEXT *ctx) {
@@ -170,23 +169,13 @@ void display(CONTEXT *ctx) {
/* Stream interrupt handlers */
-// This is a silent looping sample used to keep unused SPU channels busy,
-// preventing them from accidentally triggering the SPU RAM interrupt and
-// throwing off the timing (all channels are always reading sample data, even
-// when "stopped"). It is 64 bytes as that is the minimum size for SPU DMA
-// transfers, however only the first 16 bytes are kept. The rest is going to be
-// overwritten by chunks.
-// https://problemkaputt.de/psx-spx.htm#spuinterrupt
-const uint8_t SPU_DUMMY_BLOCK[] = {
- 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
// The first 4 KB of SPU RAM are reserved for capture buffers, so we have to
-// place stream buffers after those. Sony's SPU library additionally places a
-// dummy sample at 0x1000; we are going to do the same with the block above.
+// place stream buffers after those. A dummy sample is additionally placed by
+// default by the SPU library at 0x1000; it is going to be used here to keep
+// unused SPU channels busy, preventing them from accidentally triggering the
+// SPU RAM interrupt and throwing off the timing (all channels are always
+// reading sample data, even when "stopped").
+// https://problemkaputt.de/psx-spx.htm#spuinterrupt
#define DUMMY_BLOCK_ADDR 0x1000
#define BUFFER_START_ADDR 0x1010
#define CHUNK_SIZE (BUFFER_SIZE * NUM_CHANNELS)
@@ -207,7 +196,7 @@ static volatile StreamContext str_ctx;
// read from the CD and uploaded to SPU RAM. Due to DMA limitations it can't be
// allocated on the stack (especially not in the interrupt callbacks' stack,
// whose size is very limited).
-static uint8_t sector_buffer[2048];
+static uint32_t sector_buffer[512];
void spu_irq_handler(void) {
// Acknowledge the interrupt to ensure it can be triggered again. The only
@@ -231,7 +220,7 @@ void spu_irq_handler(void) {
str_ctx.spu_addr = BUFFER_START_ADDR + CHUNK_SIZE * str_ctx.db_active;
SPU_IRQ_ADDR = SPU_RAM_ADDR(str_ctx.spu_addr);
- for (uint32_t i = 0; i < NUM_CHANNELS; i++)
+ for (int i = 0; i < NUM_CHANNELS; i++)
SPU_CH_LOOP_ADDR(i) = SPU_RAM_ADDR(str_ctx.spu_addr + BUFFER_SIZE * i);
// Start loading the next chunk. cd_event_handler() will be called
@@ -241,7 +230,7 @@ void spu_irq_handler(void) {
CdControlF(CdlReadN, &pos);
}
-void cd_event_handler(int32_t event, uint8_t *payload) {
+void cd_event_handler(int event, uint8_t *payload) {
// Ignore all events other than a sector being ready.
// TODO: read errors should be handled properly
if (event != CdlDataReady)
@@ -255,12 +244,12 @@ void cd_event_handler(int32_t event, uint8_t *payload) {
// other buffer, as we're overriding loop addresses) at the end.
// NOTE: this isn't actually necessary here as the stream converter script
// already sets these flags in the file.
- /*for (uint32_t i = 0; i < NUM_CHANNELS; i++) {
+ /*for (int i = 0; i < NUM_CHANNELS; i++) {
if (
str_ctx.spu_pos >= (BUFFER_SIZE * i - 2048) &&
str_ctx.spu_pos < (BUFFER_SIZE * i)
)
- sector[(BUFFER_SIZE * i - str_ctx.spu_pos) - 15] = 0x03;
+ sector_buffer[(BUFFER_SIZE * i - str_ctx.spu_pos) - 15] = 0x03;
}*/
// Copy the sector to SPU RAM, appending it to the buffer that is not
@@ -268,7 +257,7 @@ void cd_event_handler(int32_t event, uint8_t *payload) {
// just treat the chunk as a single blob of data and copy it as-is; we only
// have to trim the padding at the end (if any) to avoid overwriting other
// data in SPU RAM.
- uint32_t length = CHUNK_SIZE - str_ctx.spu_pos;
+ size_t length = CHUNK_SIZE - str_ctx.spu_pos;
if (length > 2048)
length = 2048;
@@ -278,7 +267,6 @@ void cd_event_handler(int32_t event, uint8_t *payload) {
// If the buffer has been filled completely, stop reading and re-enable the
// SPU IRQ.
- // TODO TODO: preload first sector
if (str_ctx.spu_pos >= CHUNK_SIZE) {
CdControlF(CdlPause, 0);
SPU_CTRL |= 0x0040;
@@ -287,17 +275,17 @@ void cd_event_handler(int32_t event, uint8_t *payload) {
/* Stream helpers */
-void init_spu_channels(void) {
- // Upload the dummy block to the SPU and play it on all channels, locking
- // them up and stopping them from messing with the SPU interrupt.
- // TODO: is this really necessary? (needs testing on real hardware)
- SpuSetTransferStartAddr(DUMMY_BLOCK_ADDR);
- SpuWrite(SPU_DUMMY_BLOCK, 64);
-
+// This isn't actually required for this example, however it is necessary if
+// you want to allocate the stream buffers into a region of SPU RAM that was
+// previously used (to make sure the IRQ isn't going to be triggered by any
+// inactive channels).
+void reset_spu_channels(void) {
SPU_KEY_OFF = 0x00ffffff;
- for (uint32_t i = 0; i < 24; i++)
+ for (int i = 0; i < 24; i++) {
SPU_CH_ADDR(i) = SPU_RAM_ADDR(DUMMY_BLOCK_ADDR);
+ SPU_CH_FREQ(i) = 0x1000;
+ }
SPU_KEY_ON = 0x00ffffff;
}
@@ -324,16 +312,16 @@ void init_stream(CdlFILE *file) {
spu_irq_handler();
while (str_ctx.spu_pos < CHUNK_SIZE)
- __asm__("nop");
+ __asm__ volatile("");
}
void start_stream(void) {
SPU_KEY_OFF = CHANNEL_MASK;
- for (uint32_t i = 0; i < NUM_CHANNELS; i++) {
+ for (int i = 0; i < NUM_CHANNELS; i++) {
SPU_CH_ADDR(i) = SPU_RAM_ADDR(BUFFER_START_ADDR + BUFFER_SIZE * i);
SPU_CH_FREQ(i) = SAMPLE_RATE;
- SPU_CH_ADSR(i) = 0x1fee80ff; // or 0x9fc080ff, 0xdff18087
+ SPU_CH_ADSR(i) = 0x1fee80ff;
}
// Unmute the channels and route them for stereo output. You'll want to
@@ -361,7 +349,7 @@ int main(int argc, const char* argv[]) {
SHOW_STATUS("INITIALIZING\n");
SpuInit();
CdInit();
- init_spu_channels();
+ reset_spu_channels();
SHOW_STATUS("LOCATING STREAM FILE\n");
@@ -429,7 +417,7 @@ int main(int argc, const char* argv[]) {
// Only set the sample rate registers if necessary.
if (pad->btn != 0xffff) {
- for (uint32_t i = 0; i < NUM_CHANNELS; i++)
+ for (int i = 0; i < NUM_CHANNELS; i++)
SPU_CH_FREQ(i) = sample_rate;
}
diff --git a/examples/sound/spustream/stream.bin b/examples/sound/spustream/stream.bin
new file mode 100644
index 0000000..e53b726
--- /dev/null
+++ b/examples/sound/spustream/stream.bin
Binary files differ
diff --git a/examples/sound/vagsample/main.c b/examples/sound/vagsample/main.c
index 2b04c34..c79e68e 100644
--- a/examples/sound/vagsample/main.c
+++ b/examples/sound/vagsample/main.c
@@ -32,13 +32,14 @@
*/
#include <stdio.h>
-#include <sys/types.h>
+#include <stdint.h>
#include <psxetc.h>
#include <psxgte.h>
#include <psxgpu.h>
#include <psxpad.h>
#include <psxapi.h>
#include <psxspu.h>
+#include <hwregs_c.h>
extern const unsigned char proyt[];
extern const int proyt_size;
@@ -103,8 +104,8 @@ void init(void)
SpuSetTransferStartAddr(addr_temp);
// Upload first sound clip and wait for transfer to finish
- SpuWrite(((unsigned char*)proyt)+48, proyt_size-48);
- SpuWait();
+ SpuWrite((const uint32_t *) &proyt[48], proyt_size-48);
+ SpuIsTransferCompleted(SPU_TRANSFER_WAIT);
// Obtain the address of the sound and advance address for the next one
// Samples are addressed in 8-byte units, so it'll have to be divided by 8
@@ -115,8 +116,8 @@ void init(void)
// Upload second sound clip
SpuSetTransferStartAddr(addr_temp);
- SpuWrite(((unsigned char*)tdfx)+48, tdfx_size-48);
- SpuWait();
+ SpuWrite((const uint32_t *) &tdfx[48], tdfx_size-48);
+ SpuIsTransferCompleted(SPU_TRANSFER_WAIT);
// Obtain the address of the second sound clip
tdfx_addr = addr_temp/8;
@@ -127,7 +128,7 @@ void init(void)
// Begin pad polling
InitPAD( pad_buff[0], 34, pad_buff[1], 34 );
StartPAD();
-
+ ChangeClearPAD(0);
} /* init */
// Display function
@@ -158,27 +159,17 @@ int main(int argc, const char *argv[])
int counter,nextchan;
int cross_pressed;
int circle_pressed;
-
PADTYPE *pad;
- SpuVoiceRaw voice;
// Init stuff
init();
-
- // Set common values for the SpuVoiceRaw stuct
- // Technically one struct can be used to play all sounds as the
- // parameters are copied to the SPU registers
-
- voice.vol.left = 0x3FFE; // Left voice volume, 3FFEh = max
- voice.vol.right = 0x3FFE; // Right voice volume, 3FFEh = max
- voice.adsr_param = 0xdff18087; // ADSR parameters
-
+
// Main loop
counter = 0;
nextchan = 0;
cross_pressed = 0;
circle_pressed = 0;
-
+
while(1)
{
pad = (PADTYPE*)&pad_buff[0][0];
@@ -194,22 +185,24 @@ int main(int argc, const char *argv[])
if( !cross_pressed )
{
// Voice frequency
- // (400h = 11.25KHz, 1000h = 44.1KHz)
- voice.freq = 0x800;
+ // (800h = 22.05KHz)
+ SPU_CH_FREQ(nextchan) = 0x800;
// Voice start playback address
// (transfer address / 8)
- voice.addr = proyt_addr;
+ SPU_CH_ADDR(nextchan) = proyt_addr;
// Voice loop address
// (transfer address / 8)
- voice.loop_addr = proyt_addr;
-
+ SPU_CH_LOOP_ADDR(nextchan) = proyt_addr;
+ // Voice volume and envelope
+ SPU_CH_VOL_L(nextchan) = 0x3fff;
+ SPU_CH_VOL_R(nextchan) = 0x3fff;
+ SPU_CH_ADSR(nextchan) = 0x1fee80ff;
+
// Set voice to key-off to allow restart
- SpuSetKey(0, 1<<nextchan);
- // Set voice parameters
- SpuSetVoiceRaw(nextchan, &voice);
+ SPU_KEY_OFF = 1 << nextchan;
// Set voice to key-on
- SpuSetKey(1, 1<<nextchan);
-
+ SPU_KEY_ON = 1 << nextchan;
+
// Advance to next voice
nextchan++;
if( nextchan > 23 )
@@ -229,27 +222,29 @@ int main(int argc, const char *argv[])
if( !circle_pressed )
{
// Voice frequency
- // (400h = 11.25KHz, 1000h = 44.1KHz)
- voice.freq = 0x1000;
+ // (1000h = 44.1KHz)
+ SPU_CH_FREQ(nextchan) = 0x1000;
// Voice start playback address
// (transfer address / 8)
- voice.addr = tdfx_addr;
+ SPU_CH_ADDR(nextchan) = tdfx_addr;
// Voice loop address
// (transfer address / 8)
- voice.loop_addr = tdfx_addr;
-
+ SPU_CH_LOOP_ADDR(nextchan) = tdfx_addr;
+ // Voice volume and envelope
+ SPU_CH_VOL_L(nextchan) = 0x3fff;
+ SPU_CH_VOL_R(nextchan) = 0x3fff;
+ SPU_CH_ADSR(nextchan) = 0x1fee80ff;
+
// Set voice to key-off to allow restart
- SpuSetKey(0, 1<<nextchan);
- // Set voice parameters
- SpuSetVoiceRaw(nextchan, &voice);
+ SPU_KEY_OFF = 1 << nextchan;
// Set voice to key-on
- SpuSetKey(1, 1<<nextchan);
-
+ SPU_KEY_ON = 1 << nextchan;
+
// Advance to next voice
nextchan++;
if( nextchan > 23 )
nextchan = 0;
-
+
circle_pressed = 1;
}
}