Unable to get XA audio working properly

Audio and Music (Sound Processing Unit) based area of development, including VAB, XA, etc
Post Reply
SuperWill29
What is PSXDEV?
What is PSXDEV?
Posts: 2
Joined: June 21st, 2020, 12:49 pm

Unable to get XA audio working properly

Post by SuperWill29 » May 6th, 2025, 10:31 am

I have recently been following a series of tutorials by LameGuy64, and following that, I have successfully managed to pull off concepts like sprite flipping, sample playback, and CD audio. However, I have been struggling for the past week to get XA audio working, based on some tutorial code.
The demo starts fine and in PCSX Redux, the music plays fine, but the framerate dips down to half speed, and the moving object is in slow motion. In DuckStation, the music doesn't play at all, but it runs at full speed.
I also tried setting the part myXAFile to myXAFile[0] as in the tutorial, but that doesn't solve the problem, and for some reason, the background jitters as well, and VS Code complains about "Excess elements in array initializer".
I am using Visual Studio Code with the PSXDEV extension.
I am about out of ideas as to what's wrong. Is it the code itself or the VS Code libraries that are the problem? I was able to get XA audio working properly years ago using the normal SDK. What am I doing wrong?


Code:

User avatar
MottZilla
Verified
Serious PSXDEV User
Serious PSXDEV User
Posts: 97
Joined: July 4th, 2015, 7:04 am
Location: North America

Post by MottZilla » May 18th, 2025, 2:39 pm

Did you try removing the Callback? That would probably help atleast with diagnosing. And I suspect that is your problem.

I recently implemented XA audio into my homebrew demo as I previously used CDDA. I did not use any tutorial or demo as a basis. I just referenced Nocash's documentation mainly. Once you setup the Mode and Filter it's just a matter of doing a Read at the proper sector and it'll play on its own.

Then you just need to frequently check on the position of the disc reading using CdlGetlocL so you know when the end of the song is reached and then do whatever you want to do to handle that. You could loop it or do a pause command as the most likely actions.

Edit: Hm, looking at the source you provided you seem to be playing XA back differently. You seem to be reading it into a buffer in main memory. So you could try the approach I used instead.

1. Do CdControl Setmode to set CdlModeSpeed | CdlModeRT | CdlModeSF if you're using a 8 channel stereo 37khz XA file. If you are using a 4 channel stereo 37khz file you'll need to remove CdlModeSpeed (you need to use 1x speed).

2. After that do CdControl Setfilter to select the correct file and channel for the song.

3. Finally you do CdControl ReadN, passing the CdlLOC struct that points to the sector where the song data starts. Doing just that should get your music playing if the file is stored on the disc in the XA format.

As previously mentioned the system will play the audio without further intervention but you will need to keep checking using GetlocL to find when the end of the song has been reached. Just check once per frame and it'll probably be fine.
Last edited by MottZilla on May 18th, 2025, 2:52 pm, edited 1 time in total.

User avatar
Administrator
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2717
Joined: December 31st, 2012, 5:37 pm
I am a: Shadow
PlayStation Model: H2000/5502

Post by Administrator » May 18th, 2025, 2:49 pm

There's an old writeup explaining how to get XA working. Try following that tutorial (link below).
Note that you can use The Revenge of STRIPISO to replace STRIPISO for modern systems.

https://www.psxdev.net/help/psx_extende ... cture.html

From there once XA is working, you can start to migrate your toolchain to more modern equivalents such as migrating from BUILDCD to MKPSXISO (available from Lameguy64) to ensure your CD mastering process is correct. If something breaks, you'll then know what the cause is as you would have narrowed down your troubleshooting window.
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

User avatar
MottZilla
Verified
Serious PSXDEV User
Serious PSXDEV User
Posts: 97
Joined: July 4th, 2015, 7:04 am
Location: North America

Post by MottZilla » May 18th, 2025, 2:56 pm

It looks like that tutorial is what his code is based on. Perhaps the different SDK and that example don't work together. The method I mentioned should work with anything as it's just sending the right CD-ROM commands.

User avatar
Administrator
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2717
Joined: December 31st, 2012, 5:37 pm
I am a: Shadow
PlayStation Model: H2000/5502

Post by Administrator » May 18th, 2025, 3:00 pm

MottZilla wrote: May 18th, 2025, 2:56 pm It looks like that tutorial is what his code is based on. Perhaps the different SDK and that example don't work together. The method I mentioned should work with anything as it's just sending the right CD-ROM commands.
Ah, in that case you would be correct but in my opinion handling XA using the CD-ROM commands would be a bit redundant when the library functions already exist to do so.

I would have to say that the problem would be the libraries being used. I'm am guessing you're using the Lameguy64 library but if they're trying to replicate the Psy-Q XA functions it very well could have a bug present.

Try using these libraries instead: https://github.com/NDR008/VSCodePSX
Once the issue has been proven and found, open report on the broken library so the developer is aware of it.
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

User avatar
MottZilla
Verified
Serious PSXDEV User
Serious PSXDEV User
Posts: 97
Joined: July 4th, 2015, 7:04 am
Location: North America

Post by MottZilla » May 18th, 2025, 3:20 pm

Perhaps I worded it wrong or I'm not understanding what you mean. My suggestion is to use the standard CdControl() functions that should be preset in both SDKs to talk to the CD-ROM directly to setup the XA playback.

From the example, it seems as though it's setting up like it's going to be reading CdSectors to a buffer and setting up the callback for every time a sector is ready. This as far as I know is totally unnecessary. By setting the mode for the XA playback it's handled by the hardware and the CPU doesn't need to try to transfer the sector data to anywhere, you can ignore it.

You could use the callback though for the purposes of frequently checking the position for the end of the track. But you could also use the method I have used in my demo where I just make sure every frame to check with GetlocL to see if the XA playback needs to loop or end.

It's obviously my opinion and I'm biased for what worked in my case. The methods are very similar but I feel like mine is less bloated.

User avatar
Administrator
Verified
Admin / PSXDEV
Admin / PSXDEV
Posts: 2717
Joined: December 31st, 2012, 5:37 pm
I am a: Shadow
PlayStation Model: H2000/5502

Post by Administrator » May 18th, 2025, 7:11 pm

Sorry, I worded it incorrectly. The statement "handling the CD-ROM commands" meant using direct commands natively. Your method would be much cleaner but it's much more complicated as like you mentioned, one needs to study the NO$PSX documentation to figure out how to actually playback XA.

Example of direct CD-ROM commands I was talking about

Code: Select all

CdControlF(CdlPause, 0);
CdControlF(CdlGetlocL, 0);
...
The callback in the original code might be just an example of the structure or program flow for developers who already have a callback present in their game build.
Development Console: SCPH-5502 with 8MB RAM, MM3 Modchip, PAL 60 Colour Modification (for NTSC), PSIO Switch Board, DB-9 breakout headers for both RGB and Serial output and an Xplorer with CAETLA 0.34.

PlayStation Development PC: Windows 98 SE, Pentium 3 at 400MHz, 128MB SDRAM, DTL-H2000, DTL-H2010, DTL-H201A, DTL-S2020 (with 4GB SCSI-2 HDD), 21" Sony G420, CD-R burner, 3.25" and 5.25" Floppy Diskette Drives, ZIP 100 Diskette Drive and an IBM Model M keyboard.

User avatar
MottZilla
Verified
Serious PSXDEV User
Serious PSXDEV User
Posts: 97
Joined: July 4th, 2015, 7:04 am
Location: North America

Post by MottZilla » May 19th, 2025, 1:40 pm

My recommendation is to do this to start XA playback.

Code: Select all

	CdControl(CdlSetmode,&MusicXA_Mode,0);
	CdControl(CdlSetfilter,(char*)&MusicXA_Filter,0);
	CdControl(CdlReadN,(char*)&SongLoc,0);
SongLoc is a CdlLOC struct. MusicXA_Filter is a CdlFILTER struct. You'd need to set these up too ofcourse, but that is up to how you want to design it.

The way I do it in my demo, at program startup I call a function to find the XA file on the disc and store the sector number for using later as part of setting up the SongLoc. The function just uses CdSearchFile() to fill out a CdlFILE struct which is then used with CdPosToInt() to get that sector number for the XA file.

With the sector number in hand starting a song just requires the functions above but ofcourse you must setup the mode, filter, and SongLoc. SongLoc is done by using that XA File Sector number and using CdIntToPos(). I do this so I can add to the sector number an offset for other songs that may be on the same channel. And then I use that sector number where it starts along with the length of the song to store the ending sector for later use.

Setting up the filter and mode is very easy. If you just use MC32.exe then your filter just needs the .file member set to 1, and then you just set the .chan member to whatever channel your song is on.

For the mode, you need to use the appropriate settings depending on your XA file. If your XA is 4 Channel, Stereo, 37khz then you need to use CdlModeRT | CdlModeSF; as you must read at single speed. If your XA is 8 Channel, Stereo, 37khz then you should use CdlModeSpeed | CdlModeRT | CdlModeSF; as you'll want to be reading at double speeed.

So all this gets your music playing. It's simpler than all this text may suggest. For handling the end of your song for looping or just stopping you just need a function called each frame that uses CdControl(CdlGetlocL,0,(char*)&response);

By using that you can take the response to populate a CdlLOC and then use CdPosToInt() on it to find the current sector position. Then you can compare that to the EndSector you saved when you started playing the song. With that you'll be able to either loop the song, silence the music, or do whatever else you might want to do.

I have all this in a source file that isn't very big and it works great. I feel like it's a lot less complicated than the XASAMPLE that is usually shown. Maybe I might put together my own to help those out that might find it more clear.

Post Reply

Who is online

Users browsing this forum: No registered users and 15 guests