Add XA/VAG playback support, progress on blender_io_export_psx_mesh#4

This commit is contained in:
ABelliqueux 2021-08-15 19:12:03 +02:00
parent 6c82310a3d
commit 17d30079ca
42 changed files with 379 additions and 141 deletions

View File

@ -21,6 +21,16 @@ TIM/bg_camPath_002.tim \
TIM/bg_camPath_003.tim \
TIM/bg_camPath_004.tim \
TIM/bg_camPath_005.tim \
VAG/hello.vag \
VAG/poly.vag \
VAG/0_come.vag \
VAG/1_cuek.vag \
VAG/2_erro.vag \
VAG/3_hehe.vag \
VAG/4_m4a1.vag \
VAG/5_punc.vag \
VAG/7_wron.vag \
VAG/8_yooo.vag \
OVERLAYSCRIPT ?= overlay.ld
OVERLAYSECTION ?= .lvl0 .lvl1

View File

@ -61,7 +61,7 @@ cd my-project
* `pcsx-redux -run -iso OverlayExample.cue` : run the disk image in the [pcsx-redux](https://github.com/grumpycoders/pcsx-redux/) emulator.
On first launch, `pcsx-redux` will ask for a PSX bios. You can use your own or [the open source OpenBios](https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/openbios).
A [prebuilt binary](http://psx.arthus.net/roms/bios/openbios.bin) is available here for convenience.
A [prebuilt binary](https://psx.arthus.net/roms/bios/openbios.bin) is available here for convenience.
Set it in pcsx-redux ; `Configuration > Emulation`, then reboot the emulator ; `File > Reboot`.
4. Install the [blender extension](https://github.com/ABelliqueux/blender_io_export_psx_mesh) to create your own levels.
@ -85,6 +85,33 @@ Thus, to load `Overlay.lvl1` and `main.ps-exe` in the psx ram, use :
# Credits
PSX code based on [example](http://psx.arthus.net/code/primdraw.7z) by [Lameguy64](https://github.com/Lameguy64)
## Sound credits
### XA files :
Lobby Time by Kevin MacLeod
Link: https://incompetech.filmmusic.io/song/3986-lobby-time
License: https://filmmusic.io/standard-license
Pixelland by Kevin MacLeod
Link: https://incompetech.filmmusic.io/song/4222-pixelland
License: https://filmmusic.io/standard-license
### VAG files
All the sound effects come from https://www.myinstants.com and are :
```
comedy_pop_finger_in_mouth_001(1).mp3
cuek.swf.mp3
erro.mp3
m4a1_single-kibblesbob-8540445.mp3
punch.mp3
wrong-answer-sound-effect.mp3
yooooooooooooooooooooooooo_4.mp3
hehehehhehehehhehehheheehehe.mp3
```
PSX code based on [example](https://psx.arthus.net/code/primdraw.7z) by [Lameguy64](https://github.com/Lameguy64)
An incredible amount of help from the good fellows at the [psxdev discord](https://discord.com/invite/EnaNgrqJ?utm_source=Discord%20Widget&utm_medium=Connect),
Including but not limited to @NicolasNoble, @Lameguy64, @Impiaa, @paul, @sickle, @danhans42...

BIN
VAG/0_come.vag Normal file

Binary file not shown.

BIN
VAG/1_cuek.vag Normal file

Binary file not shown.

BIN
VAG/2_erro.vag Normal file

Binary file not shown.

BIN
VAG/3_hehe.vag Normal file

Binary file not shown.

BIN
VAG/4_m4a1.vag Normal file

Binary file not shown.

BIN
VAG/5_punc.vag Normal file

Binary file not shown.

BIN
VAG/7_wron.vag Normal file

Binary file not shown.

BIN
VAG/8_yooo.vag Normal file

Binary file not shown.

3
VAG/README.md Normal file
View File

@ -0,0 +1,3 @@
See here for more informations about the VAG fileformat and tools :
https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/VAG

18
VAG/audio2vag Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
if [ $# -eq 0 ]
then
echo "Audio to VAG conversion helper script
You need to have ffmpeg and wav2vag in your path environment.
Usage:
./audio2wav input.ext freq
where freq can be 44100, 22050, 11025, 5512
"
else
ffmpeg -i $1 -f s16le -ac 1 -ar $2 tmp.dat -y
wav2vag tmp.dat ${1%.***}.vag -sraw16 -freq=$2
rm tmp.dat
fi

BIN
VAG/hello.vag Normal file

Binary file not shown.

BIN
VAG/hello_poly.vag Normal file

Binary file not shown.

BIN
VAG/poly.vag Normal file

Binary file not shown.

BIN
VAG/wav/00_sile.vag Normal file

Binary file not shown.

BIN
VAG/wav/00_sile.wav Normal file

Binary file not shown.

BIN
VAG/wav/0_come.vag Normal file

Binary file not shown.

BIN
VAG/wav/0_come.wav Normal file

Binary file not shown.

BIN
VAG/wav/1_cuek.vag Normal file

Binary file not shown.

BIN
VAG/wav/1_cuek.wav Normal file

Binary file not shown.

BIN
VAG/wav/2_erro.vag Normal file

Binary file not shown.

BIN
VAG/wav/2_erro.wav Normal file

Binary file not shown.

BIN
VAG/wav/3_hehe.vag Normal file

Binary file not shown.

BIN
VAG/wav/3_hehe.wav Normal file

Binary file not shown.

BIN
VAG/wav/4_m4a1.vag Normal file

Binary file not shown.

BIN
VAG/wav/4_m4a1.wav Normal file

Binary file not shown.

BIN
VAG/wav/5_punc.vag Normal file

Binary file not shown.

BIN
VAG/wav/5_punc.wav Normal file

Binary file not shown.

BIN
VAG/wav/7_wron.vag Normal file

Binary file not shown.

BIN
VAG/wav/7_wron.wav Normal file

Binary file not shown.

BIN
VAG/wav/8_yooo.vag Normal file

Binary file not shown.

BIN
VAG/wav/8_yooo.wav Normal file

Binary file not shown.

View File

@ -1,5 +1,5 @@
#define VMODE 0 // 0 == NTSC, 1 == PAL
#define VSYNC 1
#define VSYNC 0
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
@ -10,6 +10,15 @@
#define CLEAR_COLOR_G 0
#define CLEAR_COLOR_B 0
// Sound
// CDDA / XA volume
#define MVOL_L 0x3fff
#define MVOL_R 0x3fff
#define CDVOL_L 0x7fff
#define CDVOL_R 0x7fff
#define VOICEVOL_L 0x3fff
#define VOICEVOL_R 0x3fff
// Debug Font
#define FNT_VRAM_X 960
#define FNT_VRAM_Y 256
@ -75,10 +84,10 @@ asm(\
#define PadDown ( 1 << 6 )
#define PadLeft ( 1 << 7 )
#define Tri ( 1 << 12 )
#define Circ ( 1 << 13 )
#define Triangle ( 1 << 12 )
#define Circle ( 1 << 13 )
#define Cross ( 1 << 14 )
#define Squar ( 1 << 15 )
#define Square ( 1 << 15 )
// Joysticks
#define PadR3 ( 1 << 2 )
#define PadL3 ( 1 << 1 )

View File

@ -46,3 +46,6 @@
gte_stdp(r9); \
gte_avsz4(); \
gte_stotz(r10); }
// convert Little endian to Big endian
#define SWAP_ENDIAN32(x) (((x)>>24) | (((x)>>8) & 0xFF00) | (((x)<<8) & 0x00FF0000) | ((x)<<24))

View File

@ -1,27 +1,54 @@
#pragma once
#include "../include/psx.h"
#define CD_SECTOR_SIZE 2048
#include "../include/macros.h"
// 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)
#define XA_CHANNELS 8
#define XA_CDSPEED (XA_CHANNELS >> VSYNC)
// Number of XA samples ( != # of XA files )
#define XA_TRACKS 2
// VAG
// Number of VAG files to load
#define VAG_NBR 8
#define MALLOC_MAX VAG_NBR // Max number of time we can call SpuMalloc
// Custom struct to handle VAG files
typedef struct VAGsound {
u_char * VAGfile; // Pointer to VAG data address
u_long spu_channel; // SPU voice to playback to
u_long spu_address; // SPU address for memory freeing spu mem
} VAGsound;
// VAG header struct (see fileformat47.pdf, p.209)
typedef struct VAGhdr { // All the values in this header must be big endian
char id[4]; // VAGp 4 bytes -> 1 char * 4
unsigned int version; // 4 bytes
unsigned int reserved; // 4 bytes
unsigned int dataSize; // (in bytes) 4 bytes
unsigned int samplingFrequency;// 4 bytes
char reserved2[12]; // 12 bytes -> 1 char * 12
char name[16]; // 16 bytes -> 1 char * 16
// Waveform data after that
} VAGhdr;
// XA
typedef struct XAsound {
u_int id;
u_int size;
u_char file, channel;
u_int start, end;
int cursor;
} XAsound;
// XA track struc
typedef struct {
int start;
int end;
} XA_TRACK;
typedef struct XAbank {
u_int index;
int offset;
XAsound samples[];
} XAbank;
void setSPUsettings(SpuCommonAttr * spuSettings);
int prepareXAplayback(CdlFILTER * filter, char * channel);
int resetXAsettings(void);
void loadXAfile( char * XAfile, XA_TRACK * XATrack);
u_char startXAPlayback(int * sectorPos, CdlLOC * loc);
int stopXAPlayback(void);
int setXAchannel(CdlFILTER * filter, char * channel);
int playXAtrack(int * CurPos, XA_TRACK * XATrack, CdlFILTER * filter, CdlLOC * loc, char * channel);
// VAG playback
void initSnd(SpuCommonAttr * spuSettings, char * spu_malloc_rec);
u_long sendVAGtoSPU(unsigned int VAG_data_size, u_char *VAG_data);
void setVoiceAttr(SpuVoiceAttr * voiceAttributes, u_int pitch, long channel, u_long soundAddr );
u_long setSPUtransfer(SpuVoiceAttr * voiceAttributes, VAGsound * sound);
void playSFX(SpuVoiceAttr * voiceAttributes, VAGsound * sound);
// XA playback
void XAsetup(void);
void setXAsample(XAsound * sound, CdlFILTER * filter);

View File

@ -16,7 +16,6 @@
* eye */
// Blender debug mode
// bpy. app. debug = True
#define _WCHAR_T
#include "../include/psx.h"
#include "../include/pad.h"
#include "../include/math.h"
@ -95,8 +94,9 @@ NODE * propStartNode;
// Callback function is used for pads
void callback();
// variable FPS
ulong oldTime = 0;
int dt = 0;
long oldTime = 0;
long XATime = 0;
long dt = 0;
// Physics/collisions
short physics = 1;
VECTOR col = {0};
@ -107,26 +107,73 @@ short timediv = 1;
// Animation time, see l.206
int atime = 0;
// Sound
// SPU attributes
SpuCommonAttr spuSettings;
// Declare an array of XA_TRACK
XA_TRACK XATrack[XA_TRACKS];
// Name of file to load
// VAG playback
// Memory management table ; allow MALLOC_MAX calls to SpuMalloc() - libref47.pdf p.1044
char spu_malloc_rec[SPU_MALLOC_RECSIZ * (2 + MALLOC_MAX + 1)];
// SPU settings
SpuCommonAttr spuSettings; // structure for changing common voice attributes
SpuVoiceAttr voiceAttributes ; // structure for changing individual voice attributes
// extern VAG files
extern u_char _binary_VAG_0_come_vag_start;
extern u_char _binary_VAG_1_cuek_vag_start;
extern u_char _binary_VAG_2_erro_vag_start;
extern u_char _binary_VAG_3_hehe_vag_start;
extern u_char _binary_VAG_4_m4a1_vag_start;
extern u_char _binary_VAG_5_punc_vag_start;
extern u_char _binary_VAG_7_wron_vag_start;
extern u_char _binary_VAG_8_yooo_vag_start;
// soundBank
VAGsound VAGBank[VAG_NBR] = {
{ &_binary_VAG_0_come_vag_start,
SPU_00CH, 0 },
{ &_binary_VAG_1_cuek_vag_start,
SPU_01CH, 0 },
{ &_binary_VAG_2_erro_vag_start,
SPU_02CH, 0 },
{ &_binary_VAG_3_hehe_vag_start,
SPU_03CH, 0 },
{ &_binary_VAG_4_m4a1_vag_start,
SPU_04CH, 0 },
{ &_binary_VAG_5_punc_vag_start,
SPU_05CH, 0 },
{ &_binary_VAG_7_wron_vag_start,
SPU_06CH, 0 },
{ &_binary_VAG_8_yooo_vag_start,
SPU_07CH, 0 }
};
// XA playback
XAbank XABank = {
8,
0,
{
//channel 0
{ 0, 698464, 1, 0, 0, ((698464/2336)-1) * XA_CHANNELS, -1 },
{ 1, 366752, 1, 1 , 0, ((366752/2336)-1) * XA_CHANNELS, -1 },
//~ // channel 5
//~ // id size file channel start end cursor
//~ { 0, 18688, 0, 5, 0, 56, -1 },
//~ { 1, 44384, 0, 5 , 144, 288, -1 },
//~ // channel 6
//~ { 2, 32704, 0, 6 , 0, 104, -1 },
//~ { 3, 56064, 0, 6 , 196, 380, -1 },
//~ { 4, 53728, 0, 6 , 468, 644, -1 },
//~ // channel 7
//~ { 5, 84096, 0, 7 , 0, 260, -1 },
//~ { 6, 16352, 0, 7 , 368, 440, -1 },
//~ // channel 8
//~ { 7, 114464, 0, 8 , 0, 384, -1 }
}
};
// XA file to load
static char * loadXA = "\\INTER8.XA;1";
// ADPCM Filter
// File informations : pos, size, name
CdlFILE XAPos = {0};
// CD filter
CdlFILTER filter;
// Position of file on CD
CdlLOC loc;
// XA settings
u_char param[4];
// 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;
// File position in m/s/f
CdlLOC loc;
// Keep track of XA Sample currently playing
int sample = -1;
int main() {
// Set matrices pointers to scratchpad
@ -147,7 +194,12 @@ int main() {
// Load overlay from cd
#ifdef USECD
CdInit();
// Load level
LoadLevelCD(overlayFile, &load_all_overlays_here);
// Load XA file
CdSearchFile( &XAPos, loadXA);
// Set cd head to start of file
XABank.offset = CdPosToInt(&XAPos.pos);
#endif
// TODO : Add switch case to get the correct pointers
// Get needed pointers from level file
@ -199,21 +251,42 @@ int main() {
// Time counter
oldTime = GetRCnt(RCntCNT1);
// Sound
setSPUsettings(&spuSettings);
#ifdef USECD
loadXAfile(loadXA, XATrack);
#endif
prepareXAplayback(&filter, &channel);
CurPos = XATrack[0].start;
SpuInit();
// Init sound settings
initSnd(&spuSettings, spu_malloc_rec);
//~ spuCDsetup(&spuSettings);
XAsetup();
for (u_short vag = 0; vag < VAG_NBR; vag++ ){
VAGBank[vag].spu_address = setSPUtransfer(&voiceAttributes, &VAGBank[vag]);
}
sample = 0;
setXAsample(&XABank.samples[sample], &filter);
// Main loop
while ( VSync(VSYNC) ) {
// Sound playback
playXAtrack(&CurPos, XATrack, &filter, &loc, &channel);
dt = GetRCnt(RCntCNT1) - oldTime;
oldTime = GetRCnt(RCntCNT1);
// XA playback
// if sample is set
if (sample != -1 ){
// TODO : Fix XA playback with VSYNC = 1
// Begin XA file playback...
// if sample's cursor is 0
if (XABank.samples[sample].cursor == 0){
// Convert sector number to CD position in min/second/frame and set CdlLOC accordingly.
CdIntToPos( XABank.samples[sample].start + XABank.offset , &loc);
// Send CDROM read command
CdControlF(CdlReadS, (u_char *)&loc);
XATime = VSync(-1);
// Set playing flag
}
// if sample's cursor is close to sample's end position, stop playback
if ((XABank.samples[sample].cursor += XA_CDSPEED) >= XABank.samples[sample].end - XABank.samples[sample].start ){
//~ CdControlF(CdlStop,0);
XABank.samples[sample].cursor = -1;
//~ sample = !sample;
setXAsample(&XABank.samples[sample], &filter);
}
}
// Check if level has changed
// TODO : Proper level system / loader
if ( levelWas != level ){
@ -252,6 +325,14 @@ int main() {
// Set level lighting
setLightEnv(draw, curLvl.BGc, curLvl.BKc);
levelWas = level;
// Change XA track
XAsetup();
sample = !sample;
XABank.samples[sample].cursor = -1;
setXAsample(&XABank.samples[sample], &filter);
CdIntToPos( XABank.samples[sample].start + XABank.offset , &loc);
// Send CDROM read command
CdControlF(CdlReadS, (u_char *)&loc);
}
//~ FntPrint("Ovl:%s\nLvl : %x\nLvl: %d %d \n%x", overlayFile, &level, level, levelWas, loadLvl);
// atime is used for animations timing
@ -263,12 +344,14 @@ int main() {
// TODO : put in a function
// Reset player/prop pos
if(curLvl.actorPtr->pos.vy >= 200){
playSFX(&voiceAttributes, &VAGBank[6]);
copyVector(&curLvl.actorPtr->body->position, &actorStartPos );
copyVector(&curLvl.actorPtr->rot, &actorStartRot );
curLvl.curNode = actorStartNode;
curLvl.levelPtr = curLvl.curNode->plane;
}
if(curLvl.propPtr->pos.vy >= 200){
playSFX(&voiceAttributes, &VAGBank[3]);
copyVector(&curLvl.propPtr->body->position, &propStartPos );
copyVector(&curLvl.propPtr->rot, &propStartRot );
curLvl.propPtr->node = propStartNode;
@ -392,7 +475,7 @@ int main() {
//~ FntPrint("\nTime : %d\n", time);
FntPrint("\n#Tri : %d\n", triCount);
FntPrint("#RCnt : %d %d\n", oldTime, dt);
FntPrint("#RCnt : %d %d %d\n", VSync(-1), XA_CDSPEED, dt);
FntPrint("CamAngle : %d\n", curCamAngle);
FntFlush(-1);
display( &disp[db], &draw[db], otdisc[db], primbuff[db], &nextpri, &db);
@ -431,7 +514,7 @@ void callback() {
if (angleCam.vy > 2048 || angleCam.vy < -2048) {
angleCam.vy = 0;
}
if ( PAD & PadShldR1 && !timer ) {
if ( PAD & PadShldR1 && !(lastPad & PadShldR1) ) {
// Change camera angle switching mode if using pre-calculated BGs
if (!curLvl.camPtr->tim_data){
if(camMode < 5){
@ -454,46 +537,67 @@ void callback() {
}
}
lastPad = PAD;
timer = 10;
}
//~ if ( !(PAD & PadShldR1) && lastPad & PadShldR1 ) {
//pressed = 0;
//~ }
if ( !(PAD & PadShldR1) && lastPad & PadShldR1 ) {
lastPad = PAD;
}
if ( PAD & PadShldL2 ) {
dc_lgtangp->vy += 32;
}
if ( PAD & PadShldL1 ) {
dc_lgtangp->vz += 32;
}
if ( PAD & Tri && !timer ){
if ( PAD & Triangle && !( lastPad & Triangle ) ){
if (curLvl.actorPtr->isPrism){
curLvl.actorPtr->isPrism = 0;
} else {
curLvl.actorPtr->isPrism = 1;
}
timer = 10;
playSFX(&voiceAttributes, &VAGBank[0]);
//~ timer = 10;
lastPad = PAD;
}
if ( PAD & Cross && !timer ){
if ( !(PAD & Triangle) && lastPad & Triangle ) {
lastPad = PAD;
}
if ( PAD & Square && !( lastPad & Square ) ){
playSFX(&voiceAttributes, &VAGBank[7]);
//~ sample = 0;
//~ setXAsample(&XABank.samples[sample], &filter);
lastPad = PAD;
}
if ( !(PAD & Square) && lastPad & Square ) {
lastPad = PAD;
}
if ( PAD & Cross && !(lastPad & Cross) ){
if (curLvl.actorPtr->body->gForce.vy == 0 && (curLvl.actorPtr->body->position.vy - curLvl.actorPtr->body->min.vy) == curLvl.levelPtr->body->min.vy ){
// Use delta to find jump force
curLvl.actorPtr->body->gForce.vy = - ((200/((ONE/(dt<1?1:dt))<1?1:(ONE/(dt<1?1:dt))))*14);
//~ curLvl.actorPtr->body->gForce.vy = - ((200/((ONE/(dt<1?1:dt))<1?1:(ONE/(dt<1?1:dt))))*14);
curLvl.actorPtr->body->gForce.vy = -200;
}
//~ cursor = div - 15;
timer = 10;
playSFX(&voiceAttributes, &VAGBank[4]);
lastPad = PAD;
}
if ( !(PAD & Cross) && lastPad & Cross ) {
//~ curLvl.actorPtr->body->gForce.vy = 0;
lastPad = PAD;
}
if ( PAD & PadLeft && !timer ) {
if ( PAD & Circle && !(PAD & lastPad) ){
playSFX(&voiceAttributes, &VAGBank[5]);
lastPad = PAD;
}
if ( !(PAD & Circle) && lastPad & Circle ) {
lastPad = PAD;
}
if ( PAD & PadLeft && !(lastPad & PadLeft) ) {
if (curLvl.actorPtr->anim->interpolate){
curLvl.actorPtr->anim->interpolate = 0;
} else {
curLvl.actorPtr->anim->interpolate = 1;
}
timer = 10;
lastPad = PAD;
}
if ( !(PAD & PadLeft) && lastPad & PadLeft ) {
lastPad = PAD;
}
if (theControllers[0].type == 0x73){
@ -549,7 +653,7 @@ void callback() {
curLvl.actorPtr->rot.vy += 64;
lastPad = PAD;
}
if ( PAD & PadSelect && !timer ) {
if ( PAD & PadSelect && !(lastPad & PadSelect) ) {
//~ if (!levelHasChanged){
#ifndef USECD
printf("load:%p:%08x:%s", &load_all_overlays_here, &level, overlayFile);
@ -563,6 +667,9 @@ void callback() {
timer = 30;
lastPad = PAD;
}
if ( !(PAD & PadSelect) && lastPad & PadSelect ) {
lastPad = PAD;
}
if( theControllers[0].type == 0x73 && camMode == ACTOR){
// Cam control - horizontal
if ( theControllers[0].analog0 >= 0 && theControllers[0].analog0 < (128 - DS_DZ/2) ) {

View File

@ -1,82 +1,108 @@
#include "../include/sound.h"
#include "../include/space.h"
void setSPUsettings(SpuCommonAttr * spuSettings){
// 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;
// VAG playback
void initSnd(SpuCommonAttr * spuSettings, char * spu_malloc_rec){
SpuInitMalloc(MALLOC_MAX, spu_malloc_rec); // Maximum number of blocks, mem. management table address.
spuSettings->mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR | SPU_COMMON_CDVOLL | SPU_COMMON_CDVOLR | SPU_COMMON_CDMIX ); // Mask which attributes to set
spuSettings->mvol.left = MVOL_L; // Master volume left
spuSettings->mvol.right = MVOL_R; // see libref47.pdf, p.1058
spuSettings->cd.volume.left = CDVOL_L;
spuSettings->cd.volume.right = CDVOL_R;
// Enable CD input ON
spuSettings->cd.mix = SPU_ON;
// Apply settings
SpuSetCommonAttr(spuSettings);
SpuSetCommonAttr(spuSettings);
// Set transfer mode
SpuSetTransferMode(SPU_TRANSFER_BY_DMA);
SpuSetIRQ(SPU_OFF);
// Mute all voices
SpuSetKey(SpuOff, SPU_ALLCH);
}
int resetXAsettings(void){
// Reset parameters
u_char param = CdlModeSpeed;
// Set CD mode
return CdControlB(CdlSetmode, &param, 0);
u_long sendVAGtoSPU(unsigned int VAG_data_size, u_char *VAG_data){
u_long transferred;
SpuSetTransferMode(SpuTransByDMA); // DMA transfer; can do other processing during transfer
transferred = SpuWrite (VAG_data + sizeof(VAGhdr), VAG_data_size); // transfer VAG_data_size bytes from VAG_data address to sound buffer
SpuIsTransferCompleted (SPU_TRANSFER_WAIT); // Checks whether transfer is completed and waits for completion
return transferred;
}
int prepareXAplayback(CdlFILTER * filter, char * channel){
u_char param = CdlModeSpeed|CdlModeRT|CdlModeSF|CdlModeSize1;
void setVoiceAttr(SpuVoiceAttr * voiceAttributes, u_int pitch, long channel, u_long soundAddr ){
voiceAttributes->mask= //~ Attributes (bit string, 1 bit per attribute)
(
SPU_VOICE_VOLL |
SPU_VOICE_VOLR |
SPU_VOICE_PITCH |
SPU_VOICE_WDSA |
SPU_VOICE_ADSR_AMODE |
SPU_VOICE_ADSR_SMODE |
SPU_VOICE_ADSR_RMODE |
SPU_VOICE_ADSR_AR |
SPU_VOICE_ADSR_DR |
SPU_VOICE_ADSR_SR |
SPU_VOICE_ADSR_RR |
SPU_VOICE_ADSR_SL
);
voiceAttributes->voice = channel; //~ Voice (low 24 bits are a bit string, 1 bit per voice )
voiceAttributes->volume.left = 0x0; //~ Volume
voiceAttributes->volume.right = 0x0; //~ Volume
voiceAttributes->pitch = pitch; //~ Interval (set pitch)
voiceAttributes->addr = soundAddr; //~ Waveform data start address
voiceAttributes->a_mode = SPU_VOICE_LINEARIncN; //~ Attack rate mode = Linear Increase - see libref47.pdf p.1091
voiceAttributes->s_mode = SPU_VOICE_LINEARIncN; //~ Sustain rate mode = Linear Increase
voiceAttributes->r_mode = SPU_VOICE_LINEARDecN; //~ Release rate mode = Linear Decrease
voiceAttributes->ar = 0x0; //~ Attack rate
voiceAttributes->dr = 0x0; //~ Decay rate
voiceAttributes->rr = 0x0; //~ Release rate
voiceAttributes->sr = 0x0; //~ Sustain rate
voiceAttributes->sl = 0xf; //~ Sustain level
SpuSetVoiceAttr(voiceAttributes); // set attributes
}
u_long setSPUtransfer(SpuVoiceAttr * voiceAttributes, VAGsound * sound){
// Return spu_address
u_long transferred, spu_address;
u_int pitch;
const VAGhdr * VAGheader = (VAGhdr *) sound->VAGfile;
pitch = (SWAP_ENDIAN32(VAGheader->samplingFrequency) << 12) / 44100L;
spu_address = SpuMalloc(SWAP_ENDIAN32(VAGheader->dataSize)); // Allocate an area of dataSize bytes in the sound buffer.
SpuSetTransferStartAddr(spu_address); // Sets a starting address in the sound buffer
transferred = sendVAGtoSPU(SWAP_ENDIAN32(VAGheader->dataSize), sound->VAGfile);
setVoiceAttr(voiceAttributes, pitch, sound->spu_channel, spu_address);
// Return 1 if ok, size transferred else.
//~ if (transferred == SWAP_ENDIAN32(VAGheader->dataSize)){
//~ return 1;
//~ }
//~ return transferred;
return spu_address;
}
void playSFX(SpuVoiceAttr * voiceAttributes, VAGsound * sound){
// Set voice volume to max
voiceAttributes->mask= ( SPU_VOICE_VOLL | SPU_VOICE_VOLR );
voiceAttributes->voice = sound->spu_channel;
// Range 0 - 3fff
voiceAttributes->volume.left = VOICEVOL_L;
voiceAttributes->volume.right = VOICEVOL_R;
SpuSetVoiceAttr(voiceAttributes);
// Play voice
SpuSetKey(SpuOn, sound->spu_channel);
}
void XAsetup(void){
u_char param[4];
// ORing the parameters we need to set ; drive speed, ADPCM play, Subheader filter, sector size
// If using CdlModeSpeed(Double speed), you need to load an XA file that has 8 channels.
// In single speed, a 4 channels XA is to be used.
param[0] = CdlModeSpeed|CdlModeRT|CdlModeSF|CdlModeSize1;
// Issue primitive command to CD-ROM system (Blocking-type)
// Set the parameters above
CdControlB(CdlSetmode, &param, 0);
CdControlB(CdlSetmode, param, 0);
// Pause at current pos
CdControlF(CdlPause,0);
// Set filter
// Use file 1, channel 0
filter->file = 1;
filter->chan = *channel;
return CdControlF(CdlSetfilter, (u_char *)filter);
}
void loadXAfile( char * XAfile, XA_TRACK * XATrack){
CdlFILE XAPos;
CdSearchFile( &XAPos, XAfile);
XATrack[0].start = CdPosToInt(&XAPos.pos);
XATrack[0].end = XATrack[0].start + (XAPos.size/CD_SECTOR_SIZE) - 1;
}
u_char startXAPlayback(int * sectorPos, CdlLOC * loc){
// Convert sector number to CD position in min/second/frame and set CdlLOC accordingly.
CdIntToPos( *sectorPos, loc);
// Send CDROM read command
CdControlF(CdlReadS, (u_char *)loc);
return 1;
}
int stopXAPlayback(void){
// stop CD
return CdControlF(CdlStop,0);
}
int setXAchannel(CdlFILTER * filter, char * channel){
filter->chan = *channel;
void setXAsample(XAsound * sound, CdlFILTER * filter){
filter->chan = sound->channel;
filter->file = sound->file;
// Set filter
return CdControlF(CdlSetfilter, (u_char *)filter);
}
int playXAtrack(int * CurPos, XA_TRACK * XATrack, CdlFILTER * filter, CdlLOC * loc, char * channel){
static int gPlaying = 0;
// Sound playback
// Begin XA file playback
if (gPlaying == 0 && *CurPos == XATrack[0].start){
gPlaying = startXAPlayback(&XATrack[0].start, loc);
}
// When endPos is reached, set playing flag to 0
if ((*CurPos += XA_SECTOR_OFFSET) >= XATrack[0].end){
gPlaying = 0;
}
// If XA file end is reached, stop playback
if ( gPlaying == 0 && *CurPos >= XATrack[0].end ){
// Stop CD playback
stopXAPlayback();
// Optional
//~ resetXAsettings();
// Switch to next channel and start play back
*channel = !*channel;
setXAchannel(filter, channel);
*CurPos = XATrack[0].start;
}
CdControlF(CdlSetfilter, (u_char *)filter);
// Reset sample's cursor
sound->cursor = 0;
}

Binary file not shown.

8
xa/interleave8.txt Normal file
View File

@ -0,0 +1,8 @@
1 xa lobby.xa 1 0
1 xa pixel.xa 1 1
1 null
1 null
1 null
1 null
1 null
1 null

BIN
xa/lobby.xa Normal file

Binary file not shown.

BIN
xa/pixel.xa Normal file

Binary file not shown.