diff --git a/Makefile b/Makefile index 086dc67..62d7e87 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,8 @@ hello_cd: $(MAKE) -C hello_cd all hello_cdda: $(MAKE) -C hello_cdda all +hello_xa: + $(MAKE) -C hello_xa all clean: $(MAKE) -C hello_2pads clean @@ -61,6 +63,7 @@ clean: $(MAKE) -C hello_world clean $(MAKE) -C hello_cdda clean cleansub $(MAKE) -C hello_cd cleansub + $(MAKE) -C hello_xa cleansub all: $(MAKE) -C hello_2pads @@ -83,7 +86,8 @@ all: $(MAKE) -C hello_world $(MAKE) -C hello_cd all $(MAKE) -C hello_cdda all + $(MAKE) -C hello_xa all # declare phony rules -.PHONY: hello_2pads hello_cube hello_cubetex hello_poly_fun hello_gte_opti hello_light hello_multivag hello_pad hello_poly hello_poly_ft hello_poly_gt hello_poly_gt_tw hello_poly_inline hello_sio hello_sprt hello_tile hello_vag hello_world hello_cdda hello_cd\ +.PHONY: hello_2pads hello_cube hello_cubetex hello_poly_fun hello_gte_opti hello_light hello_multivag hello_pad hello_poly hello_poly_ft hello_poly_gt hello_poly_gt_tw hello_poly_inline hello_sio hello_sprt hello_tile hello_vag hello_world hello_cdda hello_cd hello_xa \ clean all diff --git a/hello_xa/Makefile b/hello_xa/Makefile new file mode 100644 index 0000000..07355fa --- /dev/null +++ b/hello_xa/Makefile @@ -0,0 +1,12 @@ +.PHONY: all cleansub +all: + mkpsxiso -y ./isoconfig.xml +cleansub: + $(MAKE) clean + rm -f hello_xa.cue hello_xa.bin + +TARGET = hello_xa + +SRCS = hello_xa.c \ + +include ../common.mk diff --git a/hello_xa/README.md b/hello_xa/README.md new file mode 100644 index 0000000..ebbc686 --- /dev/null +++ b/hello_xa/README.md @@ -0,0 +1,121 @@ +## XA playback + +You need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image. +You also need [`psxavenc` and `xainterleave`](https://github.com/ABelliqueux/candyk-psx/tree/master/toolsrc/). + +### Generate interleaved XA file + +```bash +psxavenc -f 37800 -t xa -b 4 -c 2 -F 1 -C 0 "../hello_cdda/audio/beach.wav" "xa/beach.xa" +psxavenc -f 37800 -t xa -b 4 -c 2 -F 1 -C 0 "../hello_cdda/audiofunk.wav" "xa/funk.xa" +xainterleave 1 xa/interleave4.txt xa/inter4.xa +xainterleave 1 xa/interleave8.txt xa/inter8.xa +``` + +Alternatively, you can use the windows tool [`MC32.EXE`](https://psx.arthus.net/tools/pimp-psx.zip) to interleave several PSX media files. + +### Compile + +This will compile and build an iso image : + +```bash +make +``` + +### Clean directory + +```bash +make cleansub +``` + +## Encoding to XA + +You can use a modified version of [`psxavenc`](https://github.com/ABelliqueux/candyk-psx/tree/master/toolsrc/psxavenc) to convert your audio file to a 2336 bytes XA file : + +```bash +./psxavenc -f 37800 -t xa -b 4 -c 2 -F 1 -C 1 "input.wav" "output.xa" +``` + +You can read it back with `XAPLAY.EXE`, that's in `psyq/bin/XAplay`. + +### PSXavenc usage + +``` +./psxavenc +Usage: psxavenc [-f freq] [-b bitdepth] [-c channels] [-F num] [-C num] [-t xa|xacd|spu|str2] + + -f freq Use specified frequency + -t format Use specified output type: + xa [A.] .xa 2336-byte sectors + xacd [A.] .xa 2352-byte sectors + spu [A.] raw SPU-ADPCM data + str2 [AV] v2 .str video 2352-byte sectors + -b bitdepth Use specified bit depth (only 4 bits supported) + -c channels Use specified channel count (1 or 2) + -F num [.xa] Set the file number to num (0-255) + -C num [.xa] Set the channel number to num (0-31) +``` + +## Interleaving XA files + +You can use [`MC32.EXE`](https://psx.arthus.net/tools/pimp-psx.zip) or [`xainterleave`](https://github.com/ABelliqueux/candyk-psx/tree/master/toolsrc/xainterleave) to interleave several PSX media files. + +## xainterleave usage + +`xainterleave ` + +`mode` can be 0 for full raw sectors or 1 for just XA (divisible by 2336) + +`in.txt` is a manifest txt file as seen [here](https://github.com/ChenThread/fromage/blob/master/res/music.txt) + +Example for 1 music file, to be played at 1x CD speed (4 channels): + +``` +1 xa test.xa 1 0 +1 null +1 null +1 null +``` + +Add 4 more 1 null lines for 2x (8 channels). + +``` + 1 xa menu.xa 1 0 +sectors type file xa_file number (0-255) xa_channel number (0-31) +``` + +The format seems to correspond to the [entry_t struct](https://github.com/ABelliqueux/candyk-psx/blob/db71929903cc09398f5efc23973f9e136d123bbb/toolsrc/xainterleave/xainterleave.c#L35). + +## mkpsxiso + +You can use the following syntax to include your XA file in the CD image : + +```xml + +``` + +See here for more details : https://github.com/Lameguy64/mkpsxiso/blob/c44b78e37bbc115591717ac4dd534af6db499ea4/examples/example.xml#L85 + +## PsyQ XA Tools + +[XAPLAY.EXE](https://docs.google.com/uc?export=download&confirm=G9cM&id=0B_GAaDjR83rLZGVaZ2pvV2tjSVE) : Single channel XA playback +[XATOOL.EXE](http://psx.arthus.net/code/XA/xatut.zip) : XA structure inspector +[MC32.EXE](https://psx.arthus.net/tools/pimp-psx.zip) : Converts WAV > XA > Interleaved XA + +## More + +XA tutorial : http://psx.arthus.net/code/XA/XATUT.pdf + +Full XAtut archive : http://psx.arthus.net/code/XA/xatut.zip + +XA ADPCM documentation : http://psx.arthus.net/code/XA/XA%20ADPCM%20documentation.txt + +PsyQ XA player example : `psyq/addons/scee/CD/XAPLAYER` + +XA SCEE Technical note - July 1998 : http://psx.arthus.net/sdk/Psy-Q/DOCS/CONF/SCEE/98July/xa_sound.pdf + +PSX audio tools : https://forum.xentax.com/viewtopic.php?t=10136 + +PIMP tools : https://psx.arthus.net/tools/pimp-psx.zip + +Source : https://discord.com/channels/642647820683444236/663664210525290507/843211084609617930 diff --git a/hello_xa/hello_xa.c b/hello_xa/hello_xa.c new file mode 100644 index 0000000..da0ab25 --- /dev/null +++ b/hello_xa/hello_xa.c @@ -0,0 +1,184 @@ +// XA track playback example +// base on `psyq/addons/scee/CD/XAPLAYER` +// Refs : http://psx.arthus.net/code/XA/XATUT.pdf +// http://psx.arthus.net/code/XA/xatut.zip +// http://psx.arthus.net/code/XA/XA%20ADPCM%20documentation.txt +// based on Lameguy64's tutorial : http://lameguy64.net/svn/pstutorials/chapter1/1-display.html +#include +#include +#include +#include +#include +// CD library +#include +// SPU library +#include + +#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL +#define SCREENXRES 320 // Screen width +#define SCREENYRES 240 + (VMODE << 4) // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256 +#define CENTERX SCREENXRES/2 // Center of screen on x +#define CENTERY SCREENYRES/2 // Center of screen on y +#define MARGINX 0 // margins for text display +#define MARGINY 32 +#define FONTSIZE 8 * 7 // Text Field Height +DISPENV disp[2]; // Double buffered DISPENV and DRAWENV +DRAWENV draw[2]; +short db = 0; // index of which buffer is used, values 0, 1 + +// SPU attributes +SpuCommonAttr spuSettings; +#define CD_SECTOR_SIZE 2048 +// XA +// Sector offset for XA data 4: simple speed, 8: double speed +#define XA_SECTOR_OFFSET 4 +// Number of XA files +#define XA_TRACKS 1 +// Number of populated XA streams/channels in each XA file +#define INDEXES_IN_XA 1 +#define TOTAL_TRACKS (XA_TRACKS*INDEXES_IN_XA) + +typedef struct { + int start; + int end; +} XA_TRACK; +// Declare an array of XA_TRACK +XA_TRACK XATrack[XA_TRACKS]; +// Name of file to load +static char * loadXA = "\\INTER4.XA;1"; +CdlFILE XAPos = {0}; +// Start and end position of XA data, in sectors +static int StartPos, EndPos; +// Current pos in file +static int CurPos = -1; +// Playback status : 0 not playing, 1 playing +static int gPlaying = 0; +// Current XA channel +static char channel = 0; + +void init(void) +{ + ResetGraph(0); // Initialize drawing engine with a complete reset (0) + SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES); // Set display area for both &disp[0] and &disp[1] + SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES); // &disp[0] is on top of &disp[1] + SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES); // Set draw for both &draw[0] and &draw[1] + SetDefDrawEnv(&draw[1], 0, 0 , SCREENXRES, SCREENYRES); // &draw[0] is below &draw[1] + // Set video mode + if (VMODE){ SetVideoMode(MODE_PAL);} + SetDispMask(1); // Display on screen + setRGB0(&draw[0], 50, 50, 50); // set color for first draw area + setRGB0(&draw[1], 50, 50, 50); // set color for second draw area + draw[0].isbg = 1; // set mask for draw areas. 1 means repainting the area with the RGB color each frame + draw[1].isbg = 1; + PutDispEnv(&disp[db]); // set the disp and draw environnments + PutDrawEnv(&draw[db]); + FntLoad(960, 0); // Load font to vram at 960,0(+128) + FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height, black_bg, max. nbr. chars +} +void display(void) +{ + DrawSync(0); // Wait for all drawing to terminate + VSync(0); // Wait for the next vertical blank + PutDispEnv(&disp[db]); // set alternate disp and draw environnments + PutDrawEnv(&draw[db]); + db = !db; // flip db value (0 or 1) +} + +int main(void) +{ + // Init display + init(); + // SPU setup + // Init Spu + SpuInit(); + // Set master & CD volume to max + spuSettings.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR | SPU_COMMON_CDVOLL | SPU_COMMON_CDVOLR | SPU_COMMON_CDMIX); + spuSettings.mvol.left = 0x6000; + spuSettings.mvol.right = 0x6000; + spuSettings.cd.volume.left = 0x6000; + spuSettings.cd.volume.right = 0x6000; + // Enable CD input ON + spuSettings.cd.mix = SPU_ON; + // Apply settings + SpuSetCommonAttr(&spuSettings); + // Set transfer mode + SpuSetTransferMode(SPU_TRANSFER_BY_DMA); + // Init CD system + CdInit(); + // Optional : Set CD Attenuation volume + // + // CdlATV cd_vol; + // cd_vol.val0 = cd_vol.val1 = cd_vol.val2 = cd_vol.val3 = 0x40; + // CdMix(&cd_vol); + // + // Load XA file from cd + // Find XA file pos + CdSearchFile( &XAPos, loadXA); + XATrack[0].start = CdPosToInt(&XAPos.pos); + XATrack[0].end = XATrack[0].start + (XAPos.size/CD_SECTOR_SIZE) - 1; + StartPos = XATrack[0].start; + EndPos = XATrack[0].end; + // XA setup + u_char param[4]; + // ORing the parameters we need to set ; drive speed, ADPCM play, Subheader filter, sector size + param[0] = CdlModeSpeed|CdlModeRT|CdlModeSF|CdlModeSize1; + // Issue primitive command to CD-ROM system (Blocking-type) + // Set the parameters above + CdControlB(CdlSetmode, param, 0); + // Pause at current pos + CdControlF(CdlPause,0); + // Set filter + // This specifies the file and channel number to actually read data from. + CdlFILTER filter; + // Use file 1, channel 0 + filter.file = 1; + filter.chan = channel; + // Set filter + CdControlF(CdlSetfilter, (u_char *)&filter); + // Position of file on CD + CdlLOC loc; + // Set CurPos to StartPos + CurPos = StartPos; + while (1) // infinite loop + { + // Begin XA file playback + if (gPlaying == 0 && CurPos == StartPos){ + // Convert sector number to CD position in min/second/frame and set CdlLOC accordingly. + CdIntToPos(StartPos, &loc); + // Send CDROM read command + CdControlF(CdlReadS, (u_char *)&loc); + // Set playing flag + gPlaying = 1; + } + // When endPos is reached, set playing flag to 0 + if ((CurPos += XA_SECTOR_OFFSET) >= EndPos){ + gPlaying = 0; + } + // If XA file end is reached, stop playback + if ( gPlaying == 0 && CurPos >= EndPos ){ + // Stop XA playback + // Stop CD playback + CdControlF(CdlStop,0); + // Optional + // Reset parameters + // param[0] = CdlModeSpeed; + // Set CD mode + // CdControlB(CdlSetmode, param, 0); + // Switch to next channel and start play back + channel = !channel; + filter.chan = channel; + // Set filter + CdControlF(CdlSetfilter, (u_char *)&filter); + CurPos = StartPos; + } + + FntPrint("Hello XA ! %d\n", VSync(-1)); + FntPrint("Start, End Pos: %d %d\n", StartPos, EndPos); + FntPrint("Current Pos: %d\n", CurPos ); + FntPrint("Playback status: %d\n", gPlaying ); + + FntFlush(-1); // Draw printe stream + display(); // Execute display() + } + return 0; +} diff --git a/hello_xa/isoconfig.xml b/hello_xa/isoconfig.xml new file mode 100644 index 0000000..1362208 --- /dev/null +++ b/hello_xa/isoconfig.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hello_xa/system.cnf b/hello_xa/system.cnf new file mode 100644 index 0000000..ae2db18 --- /dev/null +++ b/hello_xa/system.cnf @@ -0,0 +1,4 @@ +BOOT=cdrom:\SCES_313.37;1 +TCB=4 +EVENT=10 +STACK=801FFFF0 diff --git a/hello_xa/xa/inter4.xa b/hello_xa/xa/inter4.xa new file mode 100644 index 0000000..fc19f26 Binary files /dev/null and b/hello_xa/xa/inter4.xa differ diff --git a/hello_xa/xa/inter8.xa b/hello_xa/xa/inter8.xa new file mode 100644 index 0000000..5ea675f Binary files /dev/null and b/hello_xa/xa/inter8.xa differ diff --git a/hello_xa/xa/interleave4.txt b/hello_xa/xa/interleave4.txt new file mode 100644 index 0000000..f51f44a --- /dev/null +++ b/hello_xa/xa/interleave4.txt @@ -0,0 +1,4 @@ +1 xa xa/funk.xa 1 0 +1 xa xa/beach.xa 1 1 +1 null +1 null diff --git a/hello_xa/xa/interleave8.txt b/hello_xa/xa/interleave8.txt new file mode 100644 index 0000000..38cc9e4 --- /dev/null +++ b/hello_xa/xa/interleave8.txt @@ -0,0 +1,8 @@ +1 xa xa/funk.xa 1 0 +1 xa xa/beach.xa 1 1 +1 null +1 null +1 null +1 null +1 null +1 null