aboutsummaryrefslogtreecommitdiff
path: root/examples/cdrom
diff options
context:
space:
mode:
authorJohn Wilbert M. Villamor <lameguy64@gmail.com>2020-04-24 19:01:28 +0800
committerJohn Wilbert M. Villamor <lameguy64@gmail.com>2020-04-24 19:01:28 +0800
commit1aa0e17df7c325a41de8cf8a57f52ed853f08bf3 (patch)
tree5ec7f69ca0104f2b0a41e2ee7d3cb0cf0c9c54c5 /examples/cdrom
parente82da2abe4c264d4b48a48d79cf9b8e4c4fb8ab6 (diff)
downloadpsn00bsdk-1aa0e17df7c325a41de8cf8a57f52ed853f08bf3.tar.gz
Refined toolchain instructions, organized examples, added automatic retry for CdRead(), added FIOCSCAN ioctl in psxsio TTY driver, added tty and console examples.
Diffstat (limited to 'examples/cdrom')
-rw-r--r--examples/cdrom/cdbrowse/ball16c.h16
-rw-r--r--examples/cdrom/cdbrowse/iso.xml33
-rw-r--r--examples/cdrom/cdbrowse/main.c517
-rw-r--r--examples/cdrom/cdbrowse/makefile52
-rw-r--r--examples/cdrom/cdbrowse/system.cnf4
-rw-r--r--examples/cdrom/cdxa/ball16c.h16
-rw-r--r--examples/cdrom/cdxa/iso.xml29
-rw-r--r--examples/cdrom/cdxa/main.c551
-rw-r--r--examples/cdrom/cdxa/makefile52
-rw-r--r--examples/cdrom/cdxa/system.cnf4
10 files changed, 1274 insertions, 0 deletions
diff --git a/examples/cdrom/cdbrowse/ball16c.h b/examples/cdrom/cdbrowse/ball16c.h
new file mode 100644
index 0000000..c79f273
--- /dev/null
+++ b/examples/cdrom/cdbrowse/ball16c.h
@@ -0,0 +1,16 @@
+unsigned int ball16c_size=192;
+unsigned char ball16c[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d,
+0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a,
+0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01,
+0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32,
+0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52,
+0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31,
+0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4,
+0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce,
+0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7,
+0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e,
+0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4,
+0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00
+};
diff --git a/examples/cdrom/cdbrowse/iso.xml b/examples/cdrom/cdbrowse/iso.xml
new file mode 100644
index 0000000..a828df1
--- /dev/null
+++ b/examples/cdrom/cdbrowse/iso.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<iso_project image_name="cdbrowse.iso">
+
+ <track type="data">
+
+ <identifiers
+ system ="PLAYSTATION"
+ application ="PLAYSTATION"
+ volume ="PSN00BSDK"
+ volume_set ="PSN00BSDK"
+ publisher ="MEIDOTEK"
+ />
+
+ <directory_tree>
+
+ <file name="system.cnf" type="data" source="system.cnf"/>
+ <file name="cdbrowse.exe" type="data" source="cdbrowse.exe"/>
+
+ <dir name="dira">
+ <dir name="diraa">
+ </dir>
+ </dir>
+ <dir name="dirb">
+ </dir>
+
+ <dummy sectors="1024"/>
+
+ </directory_tree>
+
+ </track>
+
+</iso_project>
diff --git a/examples/cdrom/cdbrowse/main.c b/examples/cdrom/cdbrowse/main.c
new file mode 100644
index 0000000..65475ad
--- /dev/null
+++ b/examples/cdrom/cdbrowse/main.c
@@ -0,0 +1,517 @@
+/*
+ * LibPSn00b Example Programs
+ *
+ * CD File Browser Example
+ * 2020 Meido-Tek Productions / PSn00bSDK Project
+ *
+ * Demonstrates listing and browsing directory contents of a CD-ROM containing
+ * an ISO9660 file system, using the directory query functions of the libpsxcd
+ * library.
+ *
+ * The ISO9660 support in libpsxcd only supports the original ISO9660
+ * version 1 file system specification, meaning it cannot query Rock Ridge
+ * or Joliet extensions that allow for long file names and unicode, despite
+ * the ISO9660 version 1 specification supporting names longer than 8.3 to
+ * begin with. However, discs written with such extensions should still be
+ * readable as the ISO9660 version should still be present for compatibility,
+ * with file names truncated to 8.3.
+ *
+ *
+ * Directory querying with libpsxcd is accomplished by using functions
+ * CdOpenDir(), CdReadDir() and CdCloseDir(). These functions work more or
+ * less the same as opendir(), readdir() and closedir() in *nix-like
+ * environments. While the library can support directories containing
+ * any number of files, the file browser in this example is limited to 40
+ * entries, but this can be easily extended if need be.
+ *
+ * Differentiating file and directory entries is easily determined by whether
+ * or not the file has a version number suffix (ie. MYFILE.DAT;1). Directory
+ * records do not have a version number suffix.
+ *
+ * Currently, the only way to signal the isofs routines of libpsxcd that a
+ * disc change has occured is by simply issuing a CdlNop command. In a file
+ * browser that is aware of a disc change occuring at any moment a CdlNop
+ * command shall be issued at regular intervals of at least once a second.
+ * This also keeps CdStatus() up to date with disc presence.
+ *
+ *
+ * Controls:
+ *
+ * Up/Down - Move selection cursor.
+ * Cross - Enter directory.
+ * Circle - Go back to root directory.
+ *
+ *
+ * Example by Lameguy64
+ *
+ *
+ * Changelog:
+ *
+ * February 25, 2020: Initial version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <psxetc.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxapi.h>
+#include <psxpad.h>
+#include <psxsio.h>
+#include <psxspu.h>
+#include <psxcd.h>
+
+#include <malloc.h>
+#include "ball16c.h"
+
+
+#define MAX_BALLS 1536 /* Number of balls to display */
+
+#define OT_LEN 8 /* Ordering table length */
+
+
+/* Screen coordinates */
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+#define CENTER_X SCREEN_XRES/2
+#define CENTER_Y SCREEN_YRES/2
+
+
+/* Display and drawing environments */
+DISPENV disp[2];
+DRAWENV draw[2];
+
+char pribuff[2][65536]; /* Primitive packet buffers */
+unsigned int ot[2][OT_LEN]; /* Ordering tables */
+char *nextpri; /* Pointer to next packet buffer offset */
+int db = 0; /* Double buffer index */
+
+
+/* Ball struct and array */
+typedef struct BALL_TYPE
+{
+ short x,y;
+ short xdir,ydir;
+ unsigned char r,g,b,p;
+} BALL_TYPE;
+
+BALL_TYPE balls[MAX_BALLS];
+
+
+/* TIM image parameters for loading the ball texture and drawing sprites */
+TIM_IMAGE tim;
+
+/* Pad input buffer*/
+char padbuff[2][34];
+
+
+int query_dir(const char* path, CdlFILE* files, int max)
+{
+ CdlDIR* dir;
+ int files_found;
+
+ printf( "Querying directory %s... ", path );
+ files_found = 0;
+
+ /* Open the directory */
+ dir = CdOpenDir( path );
+ if( dir )
+ {
+ /* Read entries */
+ while( CdReadDir( dir, &files[files_found] ) )
+ {
+ files_found++;
+ if( files_found >= max )
+ break;
+ }
+
+ /* Close directory after query */
+ CdCloseDir( dir );
+ }
+ else
+ {
+ /* If directory path does not exist */
+ printf( "Directory not found.\n" );
+ return 0;
+ }
+
+ printf( "Done.\n" );
+ return files_found;
+}
+
+
+void init()
+{
+ int i;
+
+ /* Reset GPU (also installs event handler for VSync) */
+ printf("Init GPU... ");
+ ResetGraph( 0 );
+ printf("Done.\n");
+
+
+ /* Uncomment to direct tty messages to serial */
+ //AddSIO(115200);
+
+
+ /* Initialize SPU and CD-ROM */
+ printf("Initializing CD-ROM... ");
+ SpuInit();
+ CdInit();
+ printf("Done.\n");
+
+
+ /* Set display and draw environment parameters */
+ SetDefDispEnv(&disp[0], 0, 0, SCREEN_XRES, SCREEN_YRES);
+ SetDefDispEnv(&disp[1], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES);
+
+ SetDefDrawEnv(&draw[0], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES);
+ SetDefDrawEnv(&draw[1], 0, 0, SCREEN_XRES, SCREEN_YRES);
+
+
+ /* Set clear color, area clear and dither processing */
+ setRGB0(&draw[0], 63, 0, 127);
+ draw[0].isbg = 1;
+ draw[0].dtd = 1;
+ setRGB0(&draw[1], 63, 0, 127);
+ draw[1].isbg = 1;
+ draw[1].dtd = 1;
+
+
+ /* Load and open font stream */
+ FntLoad(960, 0);
+ FntOpen(32, 32, 256, 176, 2, 400);
+
+
+ /* Upload the ball texture */
+ GetTimInfo((unsigned int*)ball16c, &tim); /* Get TIM parameters */
+ LoadImage(tim.prect, tim.paddr); /* Upload texture to VRAM */
+ if( tim.mode & 0x8 )
+ {
+ LoadImage(tim.crect, tim.caddr); /* Upload CLUT if present */
+ }
+
+
+ /* Calculate ball positions */
+ printf("Calculating balls... ");
+
+ for(i=0; i<MAX_BALLS; i++)
+ {
+ balls[i].x = (rand()%304);
+ balls[i].y = (rand()%224);
+ balls[i].xdir = 1-(rand()%3);
+ balls[i].ydir = 1-(rand()%3);
+ if( !balls[i].xdir )
+ balls[i].xdir = 1;
+ if( !balls[i].ydir )
+ balls[i].ydir = 1;
+ balls[i].xdir *= 2;
+ balls[i].ydir *= 2;
+ balls[i].r = (rand()%256);
+ balls[i].g = (rand()%256);
+ balls[i].b = (rand()%256);
+ }
+
+ printf("Done.\n");
+
+
+ /* Initialize pad */
+ InitPAD(padbuff[0], 34, padbuff[1], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+}
+
+
+int main(int argc, const char* argv[])
+{
+
+ SPRT* spr; // Primitive stuff
+ SPRT_16* sprt;
+ DR_TPAGE* tpri;
+
+ PADTYPE* pad; // Pad stuff
+
+ CdlFILE files[40]; // To store file/directory entries
+ char path[128]; // Directory path buffer
+ char disc_label[32]; // Disc label
+
+ int i,counter=0;
+ int files_found;
+ int sel_channel=0;
+ int list_scroll;
+ int p_up=0,p_down=0,p_cross=0,p_circle=0;
+ int disc_present,update_listing;
+
+ /* Init graphics and stuff before doing anything else */
+ init();
+
+ /* Updates CdStatus() */
+ CdControl( CdlNop, 0, 0 );
+
+ /* Main loop */
+ printf("Entering loop...\n");
+
+ list_scroll = 0;
+ disc_present = false;
+ update_listing = true;
+
+ while(1) {
+
+ /* Set flag if disc has been removed */
+ if( (CdStatus()&0x12) != 0x2 )
+ {
+ disc_present = false;
+ }
+
+
+ /* Get pad stats */
+ pad = ((PADTYPE*)padbuff[0]);
+
+ if( pad->stat == 0 )
+ {
+ if(( pad->type == 0x4 )||( pad->type == 0x5 )||( pad->type == 0x7 ))
+ {
+ /* Menu controls */
+ if( disc_present )
+ {
+ if( !(pad->btn&PAD_UP) )
+ {
+ if( !p_up )
+ {
+ if( sel_channel > 0 )
+ {
+ sel_channel--;
+
+ if( (sel_channel-list_scroll) < 0 )
+ {
+ list_scroll = sel_channel;
+ }
+ }
+ p_up = 1;
+ }
+ }
+ else
+ {
+ p_up = 0;
+ }
+
+ if( !(pad->btn&PAD_DOWN) )
+ {
+ if( !p_down )
+ {
+ if( sel_channel < files_found-1 )
+ {
+ sel_channel++;
+
+ if( (sel_channel-list_scroll) > 15 )
+ {
+ list_scroll = sel_channel-15;
+ }
+ }
+ p_down = 1;
+ }
+ }
+ else
+ {
+ p_down = 0;
+ }
+ }
+
+ /* Enter a selected directory */
+ if( !(pad->btn&PAD_CROSS) )
+ {
+ if( !p_cross )
+ {
+ if( disc_present )
+ {
+ if( strchr( files[sel_channel].name, ';' ) == 0 )
+ {
+ if( strcmp( files[sel_channel].name, ".." )
+ == 0 )
+ {
+ *(strrchr( path, '\\' )+1) = 0x0;
+ if( strlen( path ) > 1 )
+ {
+ path[strlen( path )-1] = 0x0;
+ }
+ }
+ else if( strcmp( files[sel_channel].name, "." ) )
+ {
+ if( strlen( path ) > 1 )
+ {
+ strcat( path, "\\" );
+ }
+ strcat( path, files[sel_channel].name );
+ }
+ update_listing = true;
+ }
+ }
+ else
+ {
+ strcpy( path, "\\" );
+ update_listing = true;
+ }
+ p_cross = 1;
+ }
+ }
+ else
+ {
+ p_cross = 0;
+ }
+
+ /* Return to root directory */
+ if( !(pad->btn&PAD_CIRCLE) )
+ {
+ if( !p_circle )
+ {
+ strcpy( path, "\\" );
+ update_listing = true;
+ p_circle = 1;
+ }
+ }
+ else
+ {
+ p_circle = 0;
+ }
+ }
+ }
+
+
+ /* Updates directory listing */
+ if( update_listing )
+ {
+ if ( (CdStatus()&0x12) == 0x2 )
+ {
+
+ /* Reset path and update label if new disc inserted */
+ if( !disc_present )
+ {
+ strcpy( path, "\\" );
+ CdGetVolumeLabel(disc_label);
+ disc_present = true;
+ }
+
+ /* Query directory */
+ files_found = query_dir( path, files, 40 );
+ sel_channel = 0;
+ list_scroll = 0;
+
+ }
+ update_listing = false;
+ }
+
+
+ /* Display information */
+ FntPrint( -1, "\n PSN00BSDK CD BROWSER EXAMPLE\n\n" );
+
+ if( disc_present )
+ {
+ FntPrint( -1, " FILES:%d LABEL:%s\n", files_found, disc_label );
+ FntPrint( -1, " %s\n", path );
+
+ for(i=0; i<16; i++)
+ {
+ if( (i+list_scroll) > (files_found-1) )
+ break;
+
+ if( (i+list_scroll) == sel_channel )
+ {
+ FntPrint( -1, " ->%s\n", files[i+list_scroll].name );
+ }
+ else
+ {
+ FntPrint( -1, " %s\n", files[i+list_scroll].name );
+ }
+
+ }
+ }
+ else
+ {
+ if( (CdStatus()&0x12) == 0x2 )
+ {
+ FntPrint( -1, "\n PRESS <X> TO LIST CONTENTS %x\n",
+ CdStatus() );
+ }
+ else
+ {
+ FntPrint( -1, "\n NO DISC INSERTED %x\n",
+ CdStatus() );
+ }
+ }
+
+ /* Clear ordering table and set start address of primitive buffer */
+ ClearOTagR(ot[db], OT_LEN);
+ nextpri = pribuff[db];
+
+
+ /* Sort the balls */
+ sprt = (SPRT_16*)nextpri;
+ for( i=0; i<MAX_BALLS; i++ ) {
+
+ setSprt16(sprt);
+ setXY0(sprt, balls[i].x, balls[i].y);
+ setRGB0(sprt, balls[i].r, balls[i].g, balls[i].b);
+ setUV0(sprt, 0, 0);
+ setClut(sprt, tim.crect->x, tim.crect->y);
+
+ addPrim(ot[db]+(OT_LEN-1), sprt);
+ sprt++;
+
+ balls[i].x += balls[i].xdir;
+ balls[i].y += balls[i].ydir;
+
+ if( ( balls[i].x+16 ) > SCREEN_XRES ) {
+ balls[i].xdir = -2;
+ } else if( balls[i].x < 0 ) {
+ balls[i].xdir = 2;
+ }
+
+ if( ( balls[i].y+16 ) > SCREEN_YRES ) {
+ balls[i].ydir = -2;
+ } else if( balls[i].y < 0 ) {
+ balls[i].ydir = 2;
+ }
+
+ }
+ nextpri = (char*)sprt;
+
+
+ /* Sort a TPage primitive so the sprites will draw pixels from */
+ /* the correct texture page in VRAM */
+ tpri = (DR_TPAGE*)nextpri;
+ setDrawTPage(tpri, 0, 0, getTPage(0, 0, tim.prect->x, tim.prect->y));
+ addPrim(ot[db]+(OT_LEN-1), tpri);
+ nextpri += sizeof(DR_TPAGE);
+
+ /* Draw font */
+ FntFlush(-1);
+
+ /* Wait for GPU and VSync */
+ DrawSync(0);
+ VSync(0);
+
+ /* Since draw.isbg is non-zero this clears the screen */
+ PutDispEnv(&disp[db]);
+ PutDrawEnv(&draw[db]);
+ SetDispMask(1);
+
+ /* Begin drawing the new frame */
+ DrawOTag( ot[db]+(OT_LEN-1) );
+
+ /* Alternate to the next buffer */
+ db = !db;
+
+ /* Periodically issue a CdlNop to keep CdStatus() updated */
+ counter++;
+ if( (counter%60) == 59 )
+ {
+ CdControl(CdlNop, 0, 0);
+ }
+ }
+
+ return 0;
+
+}
diff --git a/examples/cdrom/cdbrowse/makefile b/examples/cdrom/cdbrowse/makefile
new file mode 100644
index 0000000..f5ee962
--- /dev/null
+++ b/examples/cdrom/cdbrowse/makefile
@@ -0,0 +1,52 @@
+include ../../sdk-common.mk
+
+TARGET = cdbrowse.elf
+
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES = $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+
+PREFIX = mipsel-unknown-elf-
+
+LIBS = -lpsxcd -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxsio -lpsxapi -lc
+
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+CPPFLAGS = $(CFLAGS) \
+ -fno-exceptions \
+ -fno-rtti \
+ -fno-unwind-tables \
+ -fno-threadsafe-statics \
+ -fno-use-cxa-atexit
+
+AFLAGS = -g -msoft-float
+LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
+ -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+AS = $(PREFIX)as
+LD = $(PREFIX)ld
+
+all: $(OFILES)
+ $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
+ elf2x -q $(TARGET)
+
+iso:
+ mkpsxiso -y -q iso.xml
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build $(TARGET) $(TARGET:.elf=.exe)
diff --git a/examples/cdrom/cdbrowse/system.cnf b/examples/cdrom/cdbrowse/system.cnf
new file mode 100644
index 0000000..9cf5593
--- /dev/null
+++ b/examples/cdrom/cdbrowse/system.cnf
@@ -0,0 +1,4 @@
+BOOT=cdrom:\cdbrowse.exe;1
+TCB=4
+EVENT=10
+STACK=801FFFF0
diff --git a/examples/cdrom/cdxa/ball16c.h b/examples/cdrom/cdxa/ball16c.h
new file mode 100644
index 0000000..c79f273
--- /dev/null
+++ b/examples/cdrom/cdxa/ball16c.h
@@ -0,0 +1,16 @@
+unsigned int ball16c_size=192;
+unsigned char ball16c[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d,
+0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a,
+0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01,
+0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32,
+0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52,
+0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31,
+0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4,
+0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce,
+0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7,
+0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e,
+0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4,
+0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00
+};
diff --git a/examples/cdrom/cdxa/iso.xml b/examples/cdrom/cdxa/iso.xml
new file mode 100644
index 0000000..840b414
--- /dev/null
+++ b/examples/cdrom/cdxa/iso.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<iso_project image_name="cdxa.iso">
+
+ <track type="data">
+
+ <identifiers
+ system ="PLAYSTATION"
+ application ="PLAYSTATION"
+ volume ="PSN00BSDK"
+ volume_set ="PSN00BSDK"
+ publisher ="MEIDOTEK"
+ />
+
+ <directory_tree>
+
+ <file name="system.cnf" type="data" source="system.cnf"/>
+ <file name="cdxa.exe" type="data" source="cdxa.exe"/>
+
+ <!-- CD-XA file, you'll have to provide your own to make this example work -->
+ <file name="xasample.xa" type="xa" source="D:\str-temp\subcon.xa"/>
+
+ <dummy sectors="1024"/>
+
+ </directory_tree>
+
+ </track>
+
+</iso_project>
diff --git a/examples/cdrom/cdxa/main.c b/examples/cdrom/cdxa/main.c
new file mode 100644
index 0000000..55cb508
--- /dev/null
+++ b/examples/cdrom/cdxa/main.c
@@ -0,0 +1,551 @@
+/*
+ * LibPSn00b Example Programs
+ *
+ * CD-XA Audio Example
+ * 2019 Meido-Tek Productions / PSn00bSDK Project
+ *
+ * Demonstrates playback and looping of CD-XA audio using the
+ * new libpsxcd library.
+ *
+ *
+ * Since there is not yet an open source XA audio encoder yet, the
+ * only way to create XA audio data is by using the official tools.
+ * You will have to provide your own XA file to get this example
+ * to work.
+ *
+ * You will also need MKPSXISO (https://github.com/lameguy64/mkpsxiso)
+ * to build an ISO image with your XA audio data.
+ *
+ *
+ * Theory of operation:
+ *
+ * CD-XA playback is accomplished by first locating the XA file in
+ * the ISO9660 file system using CdSearchFile(). CD mode is then set
+ * using the CdlSetmode command with CdlModeSpeed, CdlModeRT and
+ * CdlModeSF flags to configure the CD controller for XA audio
+ * streaming. Trying to play XA audio without CdlModeSF, which
+ * enables filtering, will feed all XA channels to the SPU resulting
+ * in a stuttery cacophony of sounds.
+ *
+ * The XA channel for playback is selected using the CdlSetfilter
+ * command and CdlFILTER struct. XA audio is usually comprised of
+ * multiple audio streams interleaved together and this command
+ * sets which channel to filter in from all the other channels.
+ * CdlModeSF enables the filtering feature and is required when
+ * playing back XA audio streams with multiple interleaved sound
+ * channels.
+ *
+ * Playback is initiated by issuing CdlReadS with the XA file's
+ * location specified as a parameter, which is internally issued
+ * to the CD controller as the seek target before CdlReadS is
+ * actually issued.
+ *
+ * Playback can be stopped by simply issuing CdlPause during playback.
+ * It is not recommended to use CdlStop as it will stop the disc spinning
+ * and result to much slower response once the disc has stopped.
+ *
+ * The most effective method of determining the end of an XA stream is
+ * by hooking a callback routine with CdReadyCallback(), which is
+ * triggered whenever a data sector has been read and checking the
+ * header of the received sector if it belongs to the channel currently
+ * being played.
+ *
+ * Additionally, XA audio data must be encoded with video sectors at
+ * the end of each XA stream to serve as a terminator marker which
+ * triggers CdReadyCallback() during playback. From within the callback
+ * a CdlReadS command with the location of the XA data can be issued again
+ * to repeat the track or CdlPause to stop playback.
+ *
+ *
+ * Tips:
+ *
+ * - For best efficiency, it is recommended to have all XA tracks in
+ * a single XA file have roughly the same length to one another,
+ * otherwise tracks that end short will be padded with empty sectors
+ * which wastes potentially usable disc space.
+ *
+ * - The CD filter can be changed during playback and the switchover is
+ * completely seamless. Use this trick to accomplish dynamic music
+ * effects that change seamlessly based on events during gameplay.
+ *
+ * - With custom tools, it is possible to interleave data sectors with
+ * a single XA audio stream which would permit music playback during
+ * loading sessions (aside from using sequenced music). Alternatively,
+ * CdlReadN can be used to begin playback but with more reliable data
+ * reading. This is also how streaming FMV sequences are accomplished.
+ *
+ *
+ * Pros over CD audio:
+ *
+ * - Does not require changing disc speed when switching between data
+ * access and audio playback.
+ *
+ * - Permits switching between streams during playback without restart.
+ *
+ * - Near 1:4 audio compression ratio.
+ *
+ * - Data sectors can be interleaved alongside XA audio.
+ *
+ *
+ * Cons compared to CD audio:
+ *
+ * - Skips more often on a poor condition disc or optical pick-up.
+ *
+ * - Cannot be played with any CD player.
+ *
+ * - Lower audio sample rate (37.8KHz whereas CD audio is 44.1KHz, not
+ * good for audiophools).
+ *
+ *
+ * Controls:
+ *
+ * Up/Down - Select channel.
+ * Cross - Play selected channel.
+ * Circle - Stop selected channel.
+ * Right - Switch channel (without restarting playback).
+ *
+ *
+ * Example by Lameguy64
+ *
+ *
+ * Changelog:
+ *
+ * November 22, 2019 - Initial version
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <psxetc.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxapi.h>
+#include <psxpad.h>
+#include <psxsio.h>
+#include <psxspu.h>
+#include <psxcd.h>
+
+#include <malloc.h>
+#include "ball16c.h"
+
+
+#define MAX_BALLS 1536 /* Number of balls to display */
+
+#define OT_LEN 8 /* Ordering table length */
+
+
+/* Screen coordinates */
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+#define CENTER_X SCREEN_XRES/2
+#define CENTER_Y SCREEN_YRES/2
+
+
+/* Display and drawing environments */
+DISPENV disp[2];
+DRAWENV draw[2];
+
+char pribuff[2][65536]; /* Primitive packet buffers */
+unsigned int ot[2][OT_LEN]; /* Ordering tables */
+char *nextpri; /* Pointer to next packet buffer offset */
+int db = 0; /* Double buffer index */
+
+
+/* Ball struct and array */
+typedef struct BALL_TYPE
+{
+ short x,y;
+ short xdir,ydir;
+ unsigned char r,g,b,p;
+} BALL_TYPE;
+
+BALL_TYPE balls[MAX_BALLS];
+
+
+/* TIM image parameters for loading the ball texture and drawing sprites */
+TIM_IMAGE tim;
+
+
+/* XA audio handling stuff */
+volatile int num_loops=0; /* Loop counter */
+volatile int xa_play_channel; /* Currently playing channel number */
+CdlLOC xa_loc; /* XA data start location
+
+
+/* Sector header structure for video sector terminator */
+typedef struct SECTOR_HEAD
+{
+ u_short id;
+ u_short chan;
+ u_char pad[28];
+} SECTOR_HEAD;
+
+
+/* Pad input buffer*/
+char padbuff[2][34];
+
+char xa_sector_buff[2048];
+
+/* Callback for detecting end of channel (hooked by CdReadyCallback) */
+void xa_callback(int intr, unsigned char *result)
+{
+ SECTOR_HEAD *sec;
+
+ /* Only respond to data ready callbacks */
+ if (intr == CdlDataReady)
+ {
+ /* Fetch data sector */
+ CdGetSector((u_long*)&xa_sector_buff, 2048);
+
+ /* Quirk: This CdGetSector() implementation must fetch 2048 bytes */
+ /* or more otherwise the following sectors will be read in an */
+ /* incorrect byte order, probably due to stray data in the data */
+ /* FIFO. Trying to flush remaining bytes in the FIFO through */
+ /* memory reads after DMA transfer yields random deadlocking on */
+ /* real hardware for some reason. CdGetSector() probably reads */
+ /* the data FIFO in software rather than DMA transfer whereas */
+ /* CdGetSector2() uses DMA transfer in the official SDK. */
+
+ /* Check if sector belongs to the currently playing channel */
+ sec = (SECTOR_HEAD*)xa_sector_buff;
+
+ if( sec->id == 352 )
+ {
+ // Debug
+ //printf("ID=%d CHAN=%d PL=%d\n", sec->id, (sec->chan>>10)&0xF, xa_play_channel);
+
+ /* Check if sector is of the currently playing channel */
+ if( ((sec->chan>>10)&0xF) == xa_play_channel )
+ {
+ num_loops++;
+
+ /* Retry playback by seeking to start of XA data and stream */
+ CdControlF(CdlReadS, (u_char*)&xa_loc);
+
+ /* Stop playback */
+ //CdControlF(CdlPause, 0);
+ }
+ }
+ }
+}
+
+void init()
+{
+ int i;
+
+ /* Reset GPU (also installs event handler for VSync) */
+ printf("Init GPU... ");
+ ResetGraph( 0 );
+ printf("Done.\n");
+
+
+ /* Uncomment to direct tty messages to serial */
+ AddSIO(115200);
+
+
+ /* Initialize SPU and CD-ROM */
+ printf("Initializing CD-ROM... ");
+ SpuInit();
+ CdInit();
+ printf("Done.\n");
+
+
+ /* Set display and draw environment parameters */
+ SetDefDispEnv(&disp[0], 0, 0, SCREEN_XRES, SCREEN_YRES);
+ SetDefDispEnv(&disp[1], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES);
+
+ SetDefDrawEnv(&draw[0], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES);
+ SetDefDrawEnv(&draw[1], 0, 0, SCREEN_XRES, SCREEN_YRES);
+
+
+ /* Set clear color, area clear and dither processing */
+ setRGB0(&draw[0], 63, 0, 127);
+ draw[0].isbg = 1;
+ draw[0].dtd = 1;
+ setRGB0(&draw[1], 63, 0, 127);
+ draw[1].isbg = 1;
+ draw[1].dtd = 1;
+
+
+ /* Load and open font stream */
+ FntLoad(960, 0);
+ FntOpen(32, 32, 256, 176, 2, 200);
+
+
+ /* Upload the ball texture */
+ GetTimInfo((unsigned int*)ball16c, &tim); /* Get TIM parameters */
+ LoadImage(tim.prect, tim.paddr); /* Upload texture to VRAM */
+ if( tim.mode & 0x8 )
+ {
+ LoadImage(tim.crect, tim.caddr); /* Upload CLUT if present */
+ }
+
+
+ /* Calculate ball positions */
+ printf("Calculating balls... ");
+
+ for(i=0; i<MAX_BALLS; i++)
+ {
+ balls[i].x = (rand()%304);
+ balls[i].y = (rand()%224);
+ balls[i].xdir = 1-(rand()%3);
+ balls[i].ydir = 1-(rand()%3);
+ if( !balls[i].xdir )
+ balls[i].xdir = 1;
+ if( !balls[i].ydir )
+ balls[i].ydir = 1;
+ balls[i].xdir *= 2;
+ balls[i].ydir *= 2;
+ balls[i].r = (rand()%256);
+ balls[i].g = (rand()%256);
+ balls[i].b = (rand()%256);
+ }
+
+ printf("Done.\n");
+
+
+ /* Initialize pad */
+ InitPAD(padbuff[0], 34, padbuff[1], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+}
+
+
+int main(int argc, const char* argv[])
+{
+
+ SPRT *spr;
+ SPRT_16 *sprt;
+ DR_TPAGE *tpri;
+ PADTYPE *pad;
+
+ CdlFILE file;
+ CdlFILTER filter;
+
+ int i,counter=0;
+ int sel_channel=0;
+ int p_up=0,p_down=0,p_right=0,p_cross=0,p_circle=0;
+
+
+ /* Init graphics and stuff before doing anything else */
+ init();
+
+ /* Locate the XA file */
+ if( !CdSearchFile(&file, "\\XASAMPLE.XA") )
+ {
+ printf("Unable to find file.\n");
+ return 0;
+ }
+ else
+ {
+ int sec;
+ sec = CdPosToInt(&file.pos);
+ printf("XA located at sector %d size %d.\n", sec, file.size);
+ }
+
+ /* Save file location as XA location */
+ xa_loc = file.pos;
+
+ /* Hook XA callback function to CdReadyCallback (for auto stop/loop */
+ CdReadyCallback(xa_callback);
+
+ /* Set CD mode for XA streaming (2x speed, send XA to SPU, enable filter */
+ i = CdlModeSpeed|CdlModeRT|CdlModeSF;
+ CdControl(CdlSetmode, (u_char*)&i, 0);
+
+ /* Set file 1 on filter for channels 0-7 */
+ filter.file = 1;
+
+ /* Main loop */
+ printf("Entering loop...\n");
+
+ while(1) {
+
+ pad = ((PADTYPE*)padbuff[0]);
+
+ if( pad->stat == 0 )
+ {
+ if(( pad->type == 0x4 )||( pad->type == 0x5 )||( pad->type == 0x7 ))
+ {
+ /* Menu selection controls */
+ if( !(pad->btn&PAD_UP) )
+ {
+ if( !p_up )
+ {
+ if( sel_channel > 0 )
+ {
+ sel_channel--;
+ }
+ p_up = 1;
+ }
+ }
+ else
+ {
+ p_up = 0;
+ }
+
+ if( !(pad->btn&PAD_DOWN) )
+ {
+ if( !p_down )
+ {
+ if( sel_channel < 7 )
+ {
+ sel_channel++;
+ }
+ p_down = 1;
+ }
+ }
+ else
+ {
+ p_down = 0;
+ }
+
+ /* Play selected XA channel from start */
+ if( !(pad->btn&PAD_CROSS) )
+ {
+ if( !p_cross )
+ {
+ filter.chan = sel_channel;
+ CdControl(CdlSetfilter, (u_char*)&filter, 0);
+ CdControl(CdlReadS, (u_char*)&xa_loc, 0);
+ xa_play_channel = sel_channel;
+ p_cross = 1;
+ }
+ }
+ else
+ {
+ p_cross = 0;
+ }
+
+ /* Stop playback */
+ if( !(pad->btn&PAD_CIRCLE) )
+ {
+ if( !p_circle )
+ {
+ CdControl(CdlPause, 0, 0);
+ p_circle = 1;
+ }
+ }
+ else
+ {
+ p_circle = 0;
+ }
+
+ /* Change XA channel */
+ if( !(pad->btn&PAD_RIGHT) )
+ {
+ if( !p_right )
+ {
+ filter.chan = sel_channel;
+ CdControl(CdlSetfilter, (u_char*)&filter, 0);
+ xa_play_channel = sel_channel;
+ p_right = 1;
+ }
+ }
+ else
+ {
+ p_right = 0;
+ }
+
+ }
+ }
+
+
+ /* Display information */
+ FntPrint(-1, "\n PSN00BSDK XA AUDIO EXAMPLE\n\n");
+ FntPrint(-1, " CHANNEL:\n");
+
+ for(i=0; i<8; i++)
+ {
+ if( i == sel_channel )
+ {
+ FntPrint(-1, " -->%d\n", i);
+ }
+ else
+ {
+ FntPrint(-1, " %d\n", i);
+ }
+ }
+
+ FntPrint(-1, "\n CURRENT=%d STATUS=%x LOOPS=%d\n",
+ xa_play_channel, CdStatus(), num_loops);
+ FntPrint(-1, "\n <X>-PLAY (START) <O>-STOP\n <R>-SET CHANNEL\n");
+
+
+ /* Clear ordering table and set start address of primitive buffer */
+ ClearOTagR(ot[db], OT_LEN);
+ nextpri = pribuff[db];
+
+
+ /* Sort the balls */
+ sprt = (SPRT_16*)nextpri;
+ for( i=0; i<MAX_BALLS; i++ ) {
+
+ setSprt16(sprt);
+ setXY0(sprt, balls[i].x, balls[i].y);
+ setRGB0(sprt, balls[i].r, balls[i].g, balls[i].b);
+ setUV0(sprt, 0, 0);
+ setClut(sprt, tim.crect->x, tim.crect->y);
+
+ addPrim(ot[db]+(OT_LEN-1), sprt);
+ sprt++;
+
+ balls[i].x += balls[i].xdir;
+ balls[i].y += balls[i].ydir;
+
+ if( ( balls[i].x+16 ) > SCREEN_XRES ) {
+ balls[i].xdir = -2;
+ } else if( balls[i].x < 0 ) {
+ balls[i].xdir = 2;
+ }
+
+ if( ( balls[i].y+16 ) > SCREEN_YRES ) {
+ balls[i].ydir = -2;
+ } else if( balls[i].y < 0 ) {
+ balls[i].ydir = 2;
+ }
+
+ }
+ nextpri = (char*)sprt;
+
+
+ /* Sort a TPage primitive so the sprites will draw pixels from */
+ /* the correct texture page in VRAM */
+ tpri = (DR_TPAGE*)nextpri;
+ setDrawTPage(tpri, 0, 0, getTPage(0, 0, tim.prect->x, tim.prect->y));
+ addPrim(ot[db]+(OT_LEN-1), tpri);
+ nextpri += sizeof(DR_TPAGE);
+
+ /* Draw font */
+ FntFlush(-1);
+
+ /* Wait for GPU and VSync */
+ DrawSync(0);
+ VSync(0);
+
+ /* Since draw.isbg is non-zero this clears the screen */
+ PutDispEnv(&disp[db]);
+ PutDrawEnv(&draw[db]);
+ SetDispMask(1);
+
+ /* Begin drawing the new frame */
+ DrawOTag( ot[db]+(OT_LEN-1) );
+
+ /* Alternate to the next buffer */
+ db = !db;
+
+ /* Periodically issue CdlNop every second to update CdStatus() */
+ counter++;
+ if( (counter%60) == 59 )
+ {
+ CdControl(CdlNop, 0, 0);
+ }
+
+ }
+
+ return 0;
+
+}
diff --git a/examples/cdrom/cdxa/makefile b/examples/cdrom/cdxa/makefile
new file mode 100644
index 0000000..8858979
--- /dev/null
+++ b/examples/cdrom/cdxa/makefile
@@ -0,0 +1,52 @@
+include ../../sdk-common.mk
+
+TARGET = cdxa.elf
+
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES = $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+
+PREFIX = mipsel-unknown-elf-
+
+LIBS = -lpsxcd -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxsio -lpsxapi -lc
+
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+CPPFLAGS = $(CFLAGS) \
+ -fno-exceptions \
+ -fno-rtti \
+ -fno-unwind-tables \
+ -fno-threadsafe-statics \
+ -fno-use-cxa-atexit
+
+AFLAGS = -g -msoft-float
+LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
+ -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+AS = $(PREFIX)as
+LD = $(PREFIX)ld
+
+all: $(OFILES)
+ $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
+ elf2x -q $(TARGET)
+
+iso:
+ mkpsxiso -y -q iso.xml
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build $(TARGET) $(TARGET:.elf=.exe)
diff --git a/examples/cdrom/cdxa/system.cnf b/examples/cdrom/cdxa/system.cnf
new file mode 100644
index 0000000..e61e50e
--- /dev/null
+++ b/examples/cdrom/cdxa/system.cnf
@@ -0,0 +1,4 @@
+BOOT=cdrom:\cdxa.exe;1
+TCB=4
+EVENT=10
+STACK=801FFFF0