Add XA playback example

This commit is contained in:
ABelliqueux 2021-07-20 13:30:37 +02:00
parent 3324dff042
commit c7ff5b0ee0
10 changed files with 440 additions and 1 deletions

View File

@ -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

12
hello_xa/Makefile Normal file
View File

@ -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

121
hello_xa/README.md Normal file
View File

@ -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] <in> <out>
-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> <in.txt> <out.raw>`
`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
<file name="mymusic1.xa" type="xa" source="mymusic1.xa"/>
```
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

184
hello_xa/hello_xa.c Normal file
View File

@ -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 <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
// CD library
#include <libcd.h>
// SPU library
#include <libspu.h>
#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;
}

102
hello_xa/isoconfig.xml Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- MKPSXISO example XML script -->
<!-- <iso_project>
Starts an ISO image project to build. Multiple <iso_project> elements may be
specified within the same xml script which useful for multi-disc projects.
<iso_project> elements must contain at least one <track> element.
Attributes:
image_name - File name of the ISO image file to generate.
cue_sheet - Optional, file name of the cue sheet for the image file
(required if more than one track is specified).
-->
<iso_project image_name="hello_xa.bin" cue_sheet="hello_xa.cue">
<!-- <track>
Specifies a track to the ISO project. This example element creates a data
track for storing data files and CD-XA/STR streams.
Only one data track is allowed and data tracks must only be specified as the
first track in the ISO image and cannot be specified after an audio track.
Attributes:
type - Track type (either data or audio).
source - For audio tracks only, specifies the file name of a wav audio
file to use for the audio track.
-->
<track type="data">
<!-- <identifiers>
Optional, Specifies the identifier strings to use for the data track.
Attributes:
system - Optional, specifies the system identifier (PLAYSTATION if unspecified).
application - Optional, specifies the application identifier (PLAYSTATION if unspecified).
volume - Optional, specifies the volume identifier.
volume_set - Optional, specifies the volume set identifier.
publisher - Optional, specifies the publisher identifier.
data_preparer - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO
will fill it with lengthy text telling that the image file was generated
using MKPSXISO.
-->
<identifiers
system ="PLAYSTATION"
application ="PLAYSTATION"
volume ="HELOCD"
volume_set ="HELOCD"
publisher ="SCHNAPPY"
data_preparer ="MKPSXISO"
/>
<!-- <license>
Optional, specifies the license file to use, the format of the license file must be in
raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\cdgen\LCNSFILE.
License data is not included within the MKPSXISO program to avoid possible legal problems
in the open source environment... Better be safe than sorry.
Attributes:
file - Specifies the license file to inject into the ISO image.
-->
<!--
<license file="LICENSEA.DAT"/>
-->
<!-- <directory_tree>
Specifies and contains the directory structure for the data track.
Attributes:
None.
-->
<directory_tree>
<!-- <file>
Specifies a file in the directory tree.
Attributes:
name - File name to use in the directory tree (can be used for renaming).
type - Optional, type of file (data for regular files and is the default, xa for
XA audio and str for MDEC video).
source - File name of the source file.
-->
<!-- Stores system.txt as system.cnf -->
<file name="system.cnf" type="data" source="system.cnf"/>
<file name="SCES_313.37" type="data" source="hello_xa.ps-exe"/>
<file name="INTER4.XA" type="xa" source="xa/inter4.xa"/>
<file name="INTER8.XA" type="xa" source="xa/inter8.xa"/>
<dummy sectors="1024"/>
<!-- <dir>
Specifies a directory in the directory tree. <file> and <dir> elements inside the element
will be inside the specified directory.
-->
</directory_tree>
</track>
</iso_project>

4
hello_xa/system.cnf Normal file
View File

@ -0,0 +1,4 @@
BOOT=cdrom:\SCES_313.37;1
TCB=4
EVENT=10
STACK=801FFFF0

BIN
hello_xa/xa/inter4.xa Normal file

Binary file not shown.

BIN
hello_xa/xa/inter8.xa Normal file

Binary file not shown.

View File

@ -0,0 +1,4 @@
1 xa xa/funk.xa 1 0
1 xa xa/beach.xa 1 1
1 null
1 null

View File

@ -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