Skip to content

Commit

Permalink
Fix setjmp.h, FntSort(), examples, rewrite system/timer
Browse files Browse the repository at this point in the history
  • Loading branch information
spicyjpeg committed Jul 3, 2023
1 parent 472cf1c commit 06e65be
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 215 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,32 @@ to ensure the changelog can be parsed correctly.

-------------------------------------------------------------------------------

## 2023-07-03: 0.24

spicyjpeg:

- libc: Fixed various mistakes in the GTE leading zero count intrinsics and the
`setjmp.h` header.

- psxgpu: `PutDispEnv()` no longer requires manual adjustments in order to
center the screen in PAL mode. `FntSort()` now supports printing multiple
lines.

- smd: The .SMD model parser code from n00bdemo has been split off into its own
library, usable from any PSn00bSDK project.

- examples: `beginner/hello`, `beginner/cppdemo` and `system/timer` have been
rewritten completely. `cdrom/cdxa` now checks for the end of the file properly
rather than relying on it to be encoded in a specific way. `sound/cdstream`
has been refactored to use a ring buffer in main RAM and includes a reusable
SPU audio streaming library.

- Added some missing register macros (`SPU_CH_ADSR_VOL`) to `hwregs_c.h` and
fixed some previously wrong kernel-related constants.

- Removed the `PSN00BSDK_LIBGCC` CMake variable and related code, as the GCC
toolchain can automatically find `libgcc` on its own.

## 2023-05-11: 0.23

spicyjpeg:
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ include(ExternalProject)
project(
PSn00bSDK
LANGUAGES NONE
VERSION 0.23
VERSION 0.24
DESCRIPTION "Open source PlayStation 1 SDK"
HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
)
Expand Down
15 changes: 3 additions & 12 deletions doc/cmake_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ is usually not necessary for executables as they are linked to all libraries
by default (see `PSN00BSDK_EXECUTABLE_LINK_LIBRARIES`).

Additionally, two "hidden" libraries named `gcc` and `psn00bsdk` are linked by
default to all targets. The former is the GCC toolchain's `libgcc` (see
`PSN00BSDK_LIBGCC`) while the latter is a virtual target used to set compiler
flags and paths.
default to all targets. The former is the GCC toolchain's `libgcc`, while the
latter is a virtual target used to set compiler flags and paths.

## Commands

Expand Down Expand Up @@ -332,14 +331,6 @@ rather than setting this variable.
`PSN00BSDK_TARGET` must be set regardless of whether or not `PSN00BSDK_TC` is
also set.

### `PSN00BSDK_LIBGCC` (`FILEPATH`)

Path to the `libgcc` library bundled with the GCC toolchain. As required by GCC
this library is always linked to all targets, regardless of whether any SDK
libraries are linked or not. CMake will attempt to locate `libgcc`
automatically after finding the toolchain, so setting this variable manually is
not required in most cases.

## Internal settings

These settings are not stored in CMake's cache and can only be set from within
Expand Down Expand Up @@ -395,4 +386,4 @@ CMake's `add_custom_command()` and `add_custom_target()` to convert models and
generate LZP archives as part of the build pipeline.

-----------------------------------------
_Last updated on 2023-06-20 by spicyjpeg_
_Last updated on 2023-07-03 by spicyjpeg_
52 changes: 25 additions & 27 deletions examples/sound/cdstream/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ typedef struct {
(((uint32_t) (x) & 0xff000000) >> 24) \
)

/* Interrupt callbacks */
/* Helper functions */

#define DUMMY_BLOCK_ADDR 0x1000
#define STREAM_BUFFER_ADDR 0x1010

typedef struct {
int start_lba, stream_length;
int start_lba, stream_length, sample_rate;

volatile int next_sector;
volatile size_t refill_length;
Expand All @@ -175,13 +175,11 @@ static Stream_Context stream_ctx;
static StreamReadContext read_ctx;

void cd_read_handler(CdlIntrResult event, uint8_t *payload) {
// Mark the data as valid.
// Mark the data that has just been read as valid.
if (event != CdlDiskError)
Stream_Feed(&stream_ctx, read_ctx.refill_length * 2048);
}

/* Helper functions */

// This isn't actually required for this example, however it is necessary if the
// stream buffers are going to be allocated into a region of SPU RAM that was
// previously used (to make sure the IRQ is not going to be triggered by any
Expand Down Expand Up @@ -254,14 +252,12 @@ void setup_stream(const CdlLOC *pos) {
int num_chunks =
(SWAP_ENDIAN(vag->size) + vag->interleave - 1) / vag->interleave;

config.spu_address = STREAM_BUFFER_ADDR;
config.channel_mask = 0;
config.interleave = vag->interleave;
config.buffer_size = RAM_BUFFER_SIZE;
config.refill_threshold = 0;
config.sample_rate = SWAP_ENDIAN(vag->sample_rate);
config.refill_callback = (void *) 0;
config.underrun_callback = (void *) 0;
__builtin_memset(&config, 0, sizeof(Stream_Config));

config.spu_address = STREAM_BUFFER_ADDR;
config.interleave = vag->interleave;
config.buffer_size = RAM_BUFFER_SIZE;
config.sample_rate = SWAP_ENDIAN(vag->sample_rate);

// Use the first N channels of the SPU and pan them left/right in pairs
// (this assumes the stream contains one or more stereo tracks).
Expand All @@ -277,6 +273,7 @@ void setup_stream(const CdlLOC *pos) {
read_ctx.start_lba = CdPosToInt(pos) + 1;
read_ctx.stream_length =
(num_channels * num_chunks * vag->interleave + 2047) / 2048;
read_ctx.sample_rate = config.sample_rate;
read_ctx.next_sector = 0;
read_ctx.refill_length = 0;

Expand Down Expand Up @@ -315,23 +312,22 @@ int main(int argc, const char* argv[]) {
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);

bool paused = false;
int sample_rate = vag_sample_rate;
int sample_rate = read_ctx.sample_rate;

uint16_t last_buttons = 0xffff;

while (1) {
bool buffering = feed_stream();

FntPrint(-1, "PLAYING SPU STREAM\n\n");
FntPrint(-1, "BUFFER: %d (%d)\n", stream_ctx.db_active, stream_ctx.chunk_counter);
FntPrint(-1, "BUFFER: %d\n", stream_ctx.db_active);
FntPrint(-1, "STATUS: %s\n\n", buffering ? "READING" : "IDLE");

FntPrint(-1, "BUFFERED: %d/%d\n", stream_ctx.buffer.length, stream_ctx.config.buffer_size);
FntPrint(-1, "POSITION: %d/%d\n", read_ctx.next_sector, read_ctx.stream_length);
FntPrint(-1, "SMP RATE: %5d HZ\n\n", (sample_rate * 44100) >> 12);
FntPrint(-1, "SMP RATE: %5d HZ\n\n", sample_rate);

FntPrint(-1, "[START] %s\n", paused ? "RESUME" : "PAUSE");
FntPrint(-1, "[LEFT/RIGHT] SEEK\n");
Expand Down Expand Up @@ -371,16 +367,18 @@ int main(int argc, const char* argv[]) {
if ((last_buttons & PAD_CIRCLE) && !(pad->btn & PAD_CIRCLE))
read_ctx.next_sector = 0;

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 = vag_sample_rate;

// Only set the sample rate registers if necessary.
if (pad->btn != 0xffff)
Stream_SetSampleRate(&stream_ctx, (sample_rate * 44100) >> 12);
if (!(pad->btn & PAD_DOWN) && (sample_rate > 11000)) {
sample_rate -= 100;
Stream_SetSampleRate(&stream_ctx, sample_rate);
}
if (!(pad->btn & PAD_UP) && (sample_rate < 88200)) {
sample_rate += 100;
Stream_SetSampleRate(&stream_ctx, sample_rate);
}
if ((last_buttons & PAD_CROSS) && !(pad->btn & PAD_CROSS)) {
sample_rate = read_ctx.sample_rate;
Stream_SetSampleRate(&stream_ctx, sample_rate);
}

last_buttons = pad->btn;
}
Expand Down
76 changes: 58 additions & 18 deletions examples/sound/cdstream/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <psxgpu.h>
#include <psxspu.h>
#include <psxetc.h>
#include <psxapi.h>
Expand All @@ -27,10 +27,20 @@

#define _min(x, y) (((x) < (y)) ? (x) : (y))

/* Interrupt handlers */
/* Private utilities */

static volatile Stream_Context *_active_ctx = (void *) 0;

static Stream_Time _default_timer_function(void) {
return VSync(-1);
}

static int _get_default_timer_rate(void) {
return (GetVideoMode() == MODE_PAL) ? 50 : 60;
}

/* Interrupt handlers */

static void _spu_irq_handler(void) {
Stream_Context *ctx = _active_ctx;

Expand Down Expand Up @@ -59,7 +69,9 @@ static void _spu_irq_handler(void) {
// once the buffer's length is below the refill threshold.
ctx->db_active ^= 1;
ctx->buffering = true;
ctx->chunk_counter++;

ctx->play_time += ctx->samples_per_chunk;
ctx->last_updated = ctx->config.timer_function();

size_t tail = ctx->buffer.tail;
uint8_t *ptr = &ctx->buffer.data[ctx->buffer.tail];
Expand All @@ -82,12 +94,16 @@ static void _spu_irq_handler(void) {
uint32_t address =
ctx->config.spu_address + (ctx->db_active ? ctx->chunk_size : 0);

int sample_rate = ctx->new_sample_rate;
ctx->config.sample_rate = sample_rate;

SPU_IRQ_ADDR = getSPUAddr(address);

for (uint32_t ch = 0, mask = ctx->config.channel_mask; mask; ch++, mask >>= 1) {
if (!(mask & 1))
continue;

SPU_CH_FREQ (ch) = getSPUSampleRate(sample_rate);
SPU_CH_LOOP_ADDR(ch) = getSPUAddr(address + offset);
offset += ctx->config.interleave;

Expand All @@ -110,8 +126,8 @@ static void _spu_dma_handler(void) {
/* Public API */

void Stream_Init(Stream_Context *ctx, const Stream_Config *config) {
memset(ctx, 0, sizeof(Stream_Context));
memcpy(&(ctx->config), config, sizeof(Stream_Config));
__builtin_memset(ctx, 0, sizeof(Stream_Context));
__builtin_memcpy(&(ctx->config), config, sizeof(Stream_Config));

ctx->num_channels = 0;
for (uint32_t mask = config->channel_mask; mask; mask >>= 1) {
Expand All @@ -121,8 +137,15 @@ void Stream_Init(Stream_Context *ctx, const Stream_Config *config) {

assert(ctx->num_channels);

ctx->chunk_size = ctx->config.interleave * ctx->num_channels;
ctx->buffer.data = malloc(config->buffer_size);
if (!ctx->config.timer_function) {
ctx->config.timer_rate = _get_default_timer_rate();
ctx->config.timer_function = &_default_timer_function;
}

ctx->chunk_size = ctx->config.interleave * ctx->num_channels;
ctx->samples_per_chunk = ctx->config.interleave / 16 * 28;
ctx->new_sample_rate = ctx->config.sample_rate;
ctx->buffer.data = malloc(config->buffer_size);

assert(ctx->buffer.data);

Expand Down Expand Up @@ -160,14 +183,17 @@ bool Stream_Start(Stream_Context *ctx, bool resume) {
uint32_t address =
ctx->config.spu_address + (ctx->db_active ? ctx->chunk_size : 0);

int sample_rate = ctx->new_sample_rate;
ctx->config.sample_rate = sample_rate;

SpuSetKey(0, ctx->config.channel_mask);

for (uint32_t ch = 0, mask = ctx->config.channel_mask; mask; ch++, mask >>= 1) {
if (!(mask & 1))
continue;

SPU_CH_ADDR (ch) = getSPUAddr(address);
SPU_CH_FREQ (ch) = getSPUSampleRate(ctx->config.sample_rate);
SPU_CH_FREQ (ch) = getSPUSampleRate(sample_rate);
SPU_CH_ADSR1(ch) = 0x00ff;
SPU_CH_ADSR2(ch) = 0x0000;

Expand Down Expand Up @@ -197,26 +223,40 @@ bool Stream_Stop(void) {

SpuSetKey(1, ctx->config.channel_mask);

_active_ctx = (void *) 0;
ctx->last_stopped = ctx->config.timer_function();
_active_ctx = (void *) 0;

return true;
}

void Stream_SetSampleRate(Stream_Context *ctx, int value) {
ctx->config.sample_rate = value;

if (!Stream_IsActive(ctx))
return;

for (uint32_t ch = 0, mask = ctx->config.channel_mask; mask; ch++, mask >>= 1) {
if (mask & 1)
SPU_CH_FREQ(ch) = getSPUSampleRate(value);
}
ctx->new_sample_rate = value;
}

bool Stream_IsActive(const Stream_Context *ctx) {
return (ctx == _active_ctx);
}

uint32_t Stream_GetSamplesPlayed(const Stream_Context *ctx) {
// Calculate the time elapsed from the last update (or since the stream was
// stopped) and use the value to estimate how many samples have been played
// since then.
Stream_Time delta;

if (ctx == _active_ctx)
delta = ctx->config.timer_function() - ctx->last_updated;
else
delta = ctx->last_stopped - ctx->last_updated;

return ctx->play_time + (
(delta * ctx->config.sample_rate) / ctx->config.timer_rate
);
}

void Stream_ResetSamplesPlayed(Stream_Context *ctx) {
ctx->play_time = 0;
}

size_t Stream_GetRefillLength(const Stream_Context *ctx) {
int unbuf_total = (int) ctx->config.buffer_size - (int) ctx->buffer.length;

Expand Down
Loading

0 comments on commit 06e65be

Please sign in to comment.