Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - ponut64

Pages: [1]
Share your code / 68K Access / Sound Driver Demo
« on: January 04, 2020, 10:42:26 am »


Thanks cWx for linker script and help

Includes gcc 4.8 elf compiler environment

compiles main.c in PROJ folder to a binary file

the 68k_test is a jo engine demo which will load the binary to sound RAM and run it

it will print the memory written by the program on-screen.

I will be going further....

Jo-Engine release / Jo Engine update with GCC 8.3 and Mednafen
« on: May 16, 2019, 11:47:58 pm »
Hello. Linked here is an updated Jo Engine package that utilizes GCC 8.3 as well as SGL in ELF form. No code base changes have been made to Jo Engine, aside from the inclusions of SEGA_SCL and SEGA_INT, which are SBL libraries.
If a demo\feature was broken before, it's still broken.

However, with GCC 8.3 comes 10+ years of compiler optimization over previous versions, so you can expect smaller binary sizes as well as increased performance (up to 40%, by some estimates).
The biggest feature used is LTO, or link-time optimizations.
Please understand however that not all code is guaranteed to work between compiler versions. Some things that were warnings before are now flat-out errors. Other things that were totally fine in older GCC versions now may be errors or warnings. Inside Jo Engine itself, there is now a warning. Be careful.

Special Thanks to VBT and mrkotftw of SegaXtreme for making & coordinating the software package & compiler flags that were necessary to deliver this update.
The specific software package used comes from VBT's update to SSSDK:

Project announcement / what p64 does
« on: August 20, 2018, 09:22:52 pm »
So I'll start a thread, I guess, instead of spamming the help forum :)

Anyone got clues about delayed audio? Might the B-Bus be saturated, causing a command delay?

If anyone wants to build/look at the code, here it is:

And yes, most of my posts are going to be about problems, as is typical...

General Jo Engine Help / Why is this skipping?
« on: July 15, 2018, 09:10:08 am »
If anyone bothers to look at this, that's cool.

If you are someone who is particularly short on time / has better things to do (like XL2), best to move on, because I have been fumbling around with an interruptible PCM playback system for more than a month now (and there are already better solutions, but I'm stubborn).
I thought I had it good, and I do have working concepts, but I've come to the conclusion that I need a buffer to give the Saturn time to switch files in the case I want to load something while the music is playing. Otherwise, the music has to halt. I have no experience with this kind of thing...

Code: [Select]
#define PCMRAM	(631734272)
#define LWRAM (2097152)
#define HIMEM (100679680)
//HIMEM has 376 sectors (752 KB)
#define HIEND (101449728)
//Each buffer is 8 sectors / 16 KB, a total of 32 sectors / 64 KB
#define PCMBUF1 (101433344)
#define PCMBUF2 (101416960)
#define PCMBUF3 (101400576)
#define PCMWORK (101384192)

#define M3072KHZ     (31118)

Code: [Select]

Sint8* music = "SCARE.AIFF";
    music_pcmfx.mode = JoSoundMono16Bit;
//This function is supposed to play a mono PCM sound effect constantly.
//Some HIMEM is consumed in the process (32 sectors / 64KB at the END OF HIMEM)
Sint32 fid_m = GFS_NameToId(music);
music_fs = GFS_Open(fid_m);
Sint32 msize;
Sint32 nsct_m;
Sint32 stat;
Sint32 rdsize;

Sint32 nsct_f;
Sint32 fsize;
//GFS Error Information
Sint32 a_stat;
//Get sectors
GFS_GetFileSize(music_fs, NULL, &nsct_m, NULL);
GFS_GetFileInfo(music_fs, NULL, NULL, &msize, NULL);
//This determines playback time?
music_pcmfx.data_length = (msize);
_pcm[(int)0].mode = (Uint8)music_pcmfx.mode;
_pcm[(int)0].pitch = M3072KHZ;
//How many frames are we reading?
if(rt_step < msize){
music_sectors = (msize + (rt_step - 1))/(rt_step);
jo_printf(0, 18, "(%i)", msize);

GFS_SetReadPara(music_fs, rt_step);
GFS_SetTransPara(music_fs, rt_sector);
//music_fs should be SCU type since it's going to high memory.
GFS_SetTmode(music_fs, GFS_TMODE_SCU);
//Seek music to the desired location
GFS_Seek(music_fs, play_ref, GFS_SEEK_SET);
//MUSIC loading follows
GFS_NwCdRead(music_fs, (20 * 2048));

//Let's make a pre-playback loop to read from the CD to fill a series of buffers using a work buffer.
for( ; buffers_filled < 3 ; ){
if(buffers_filled == 0){
rd_pcmbuf = PCMBUF1;
if(buffers_filled == 1){
rd_pcmbuf = PCMBUF2;
if(buffers_filled == 2){
rd_pcmbuf = PCMBUF3;
if(music_frames == 4){
slDMACopy(PCMWORK, rd_pcmbuf, (8 * 2048));
buffers_filled += 1;
music_frames = 0;
if(music_frames < 4){
GFS_NwFread(music_fs, rt_sector, PCMWORK  + (music_frames * rt_step), rt_step);
play_ref += 2;
// game_code();
if(music_frames < 4){
GFS_NwGetStat(music_fs, &stat, &rdsize);
jo_printf(0, 20, "(27)");
jo_printf(0, 7, "(%i)", music_frames);
jo_printf(7, 7, "(%i)", play_ref);
jo_printf(0, 10, "(%i)", stat);
jo_printf(0, 11, "(%i)", fetch_timer);
jo_printf(10, 11, "(fetched filesize)");
}while(stat != GFS_SVR_COMPLETED && rdsize < rt_step);
jo_printf(0, 22, "(%i)", buffers_filled);
//Let's then make a test loop to playback in sequence the three playback buffers that have been filled.
for( ; buffers_filled > 0 ; ){
// game_code();
jo_printf(0, 20, "(49)");
jo_printf(0, 11, "(%i)", fetch_timer);
jo_printf(0, 22, "(%i)", buffers_filled);


if(fetch_timer == 8){
buffers_filled -= 1;
fetch_timer = 0;
if(buffers_filled == 0){
curpcmbuf = PCMBUF3;
if(buffers_filled == 1){
curpcmbuf = PCMBUF2;
if(buffers_filled == 2){
curpcmbuf = PCMBUF1;
slSndFlush(); = curpcmbuf; //this line does not matter
music_pcmfx.current_playing_channel = 0;

slSoundRequest("bbbbwbb", SND_PCM_START, 0, 0, 631767039, (0), 0, 0, 0);

slPCMOn(&_pcm[(int)0],, music_pcmfx.data_length);
//buffers_filled = 0;

Actual transfer into PCMRAM to play is handled at Vblank with an interrupt:

Code: [Select]
void	my_vlank(void){
//A new music buffer system is needed.
//A filled-by-request buffer of 4x8 sectors, 32 sectors, 64 KB, at the end of high memory...
//A system managed .. how? The core issue is the file system slows down the entire Saturn, causing skipping.
//Tenets: GFS Seek has a variable completion time (but does not halt the system). GFS_Close does not complete immediately.
//Management of the buffer system must never close or re-open the music file, unless the buffer is completely full.
//Copy memory from work area buffer directly into the PCM stream buffer
slDMACopy(curpcmbuf, PCMRAM, (8 * 2048));

General Jo Engine Help / Request for real hardware tests
« on: July 05, 2018, 07:38:21 am »
Hey guys,

I just want to know if you run this ISO if the sound eventually annihilates your sanity (with static, of course).
It would only ever do this on real hardware. You can test emulators if you want, but about all you will get are some skips and the end of the file not terminating the sound.
"But!" you may ask, "what is this?!"
This is streamed PCM playback of 30720 Hz (30.72KHz) audio using SGL, with the sound effect itself being copied straight to the PCM playback buffer.
Is this useful? Hell man, I don't know! But this actually plays sound, so it's what I have to work with because I cannot for the life of me get SBL to play any sound at all.

"What is the problem?"
I'm not sure. It could be a limitation of SGL. It could be a hardware limitation that SBL circumvents. It could just be my Saturn. But after so long of playing back the file, static gets thrown into the mix and I do not know how to suppress it.
- SGL PCM playback pointer moves to a region of memory that has bad data
- SGL PCM playback pointer eventually starts playing back the incomplete data in LWRAM as its being copied
- SGL PCM playback pointer eventually leaves the Saturn's entire possible memory map range, returning NULL data
- A-bus and B-bus DMA processes eventually cross-corrupt
- SGL PCM playback library eventually attempts to mux PCM sound outputs, resulting in garbage added
Things I have tried:
- Attempt to move SGL playback start pointer (You cannot, slPCMOn will not change its parameters once started)
- Using NULL for PCM data region (I don't want it to point to any region, since I am copying the PCM data directly to the PCM buffer) (Result: Garbage)
- Using end-of-memory for PCM data region (Result: Crash)
- Different DMA modes
- Not much else (only one song and bitrate on real hardware)
No emulators replicate this problem.

Relevant code:
Code: [Select]

#ifndef __AUDIO_H__
#define __AUDIO_H__

#define SECTOR_SIZE     (2048)
#define RING_BUF_SIZE  (2048*10)
#define PCM_ADDR  ((void*)0x25a20000)
#define PCM_SIZE  (4096*2)

#define SMP_1TASK_SAMPLE (1024)
#define SMP_LOAD_NUM (10)

#define PCMRAM (631734272)
#define LWRAM (2097152)
#define HIMEM (100679680)
#define S4410KHZ     (0)
#define S3780KHZ     (31451)
#define M3072KHZ     (31118)
#define S2205KHZ     (30720)
#define S1920KHZ (29431)
#define S18900HZ     (29404)
#define S1600KHZ     (29134)
#define S1536KHZ     (29074)
#define S1100KHZ     (27643)
#define S0800KHZ     (27086)

extern jo_sound     main_pcmfx;
extern jo_sound music_pcmfx;

//Functions go here
void pcm_music_play(void(*sysframe)(void));
void* load_pcm(Sint8* filename, const jo_sound_mode mode, jo_sound *sound, void * workAddress);
void sound_on_channel(jo_sound * const sound, const unsigned char channel);

//Modified Jo Engine functions
jo_sound music_pcmfx;
jo_sound main_pcmfx;

    {(_Stereo | _PCM16Bit), 0, 127, 0, 0x0, 0, 0, 0, 0},
    {(_Stereo | _PCM16Bit), 2, 127, 0, 0x0, 0, 0, 0, 0},
    {(_Stereo | _PCM16Bit), 4, 127, 0, 0x0, 0, 0, 0, 0},
    {(_Stereo | _PCM16Bit), 6, 127, 0, 0x0, 0, 0, 0, 0},
    {(_Stereo | _PCM16Bit), 8, 127, 0, 0x0, 0, 0, 0, 0},
    {(_Stereo | _PCM16Bit), 10, 127, 0, 0x0, 0, 0, 0, 0},

static Sint16 music_frames = 0;
static Sint16 music_sectors = 0;

void pcm_music_play(void(*sysframe)(void))
Sint8* filename = "B.PCM";
    music_pcmfx.mode = JoSoundMono16Bit;
//This function is supposed to play a mono PCM sound effect constantly.
//Some LWRAM is consumed in the process (10 sectors / 20KB).
    void* pcm = LWRAM;
void* write_buffer = LWRAM;
Sint32 fid = GFS_NameToId(filename);
GfsHn gfsm = GFS_Open(fid);
Sint8 fetch_timer = 0;
Sint32 fsize;
Sint32 nsct;
Sint32 stat;
Sint32 rdsize;
//Rate of data reading
Sint16 rt_step = (2 * 2048);
Sint16 rt_sector = 2;
//Get sectors
GFS_GetFileSize(gfsm, NULL, &nsct, NULL);
GFS_GetFileInfo(gfsm, NULL, NULL, &fsize, NULL);
//This determines playback time?
music_pcmfx.data_length = (fsize);
_pcm[(int)0].mode = (Uint8)music_pcmfx.mode;
_pcm[(int)0].pitch = M3072KHZ;
//How many frames are we reading?
if(rt_step < fsize){
music_sectors = (fsize + (rt_step - 1))/(rt_step);
jo_printf(0, 18, "(%i)", fsize);

GFS_SetReadPara(gfsm, rt_step);
GFS_SetTransPara(gfsm, rt_sector);
GFS_SetTmode(gfsm, GFS_TMODE_CPU);
//Loading follows
GFS_NwCdRead(gfsm, (10 * 2048));
for( ; music_frames <= music_sectors ; ){
//Copy memory from work area buffer directly into the PCM stream buffer
slDMACopy(write_buffer, PCMRAM, (8 * 2048));
//Very tightly timed! Not even timed right! Saturn appears to playback sounds faster than advertised; check pitch?
if(music_frames < 4){
GFS_NwFread(gfsm, rt_sector, write_buffer + (music_frames * rt_step), rt_step);
if(music_frames < 4){
GFS_NwGetStat(gfsm, &stat, &rdsize);
jo_printf(0, 7, "(%i)", music_frames);
jo_printf(7, 7, "(%i)", music_sectors);
jo_printf(0, 11, "(%i)", rdsize);
jo_printf(10, 11, "(fetched filesize)");
}while(stat != GFS_SVR_COMPLETED && rdsize < rt_step);
if(music_frames < 4){
if(music_frames == 4 && fetch_timer == 8){
music_frames = 0; fetch_timer = 0;
slSndFlush(); = pcm;
jo_printf(0, 0, "(%i)", pcm);
music_pcmfx.current_playing_channel = 0;
//HEY! slPCMOn does -NOT- accept changes to the data address during playback. IT WILL DO NOTHING.
slPCMOn(&_pcm[(int)0],, music_pcmfx.data_length);

/e: Nevermind, I seem to have fixed it!

Regardless for anyone who wants to use ADPCM, here is an updated LIBPCM.A and an updated jo engine makefile.

For anyone curious as to what the problem was, there's no SBL source code for ADPCM system. There is however LIBADP, which contains the object code for said functions, and they are in fact linked in the code its just there's no source.

So I downloaded SaturnOrbit and simply included the .o files in LIBPCM.A -- you shouldn't need LIBADP.A anymore, but it is there in any case.

You put LIBPCM.A in
Keep your old LIBPCM! Who knows what I have broken!
You also should put the following line in your Jo engine makefile

General Jo Engine Help / CD-DA Audio in Jo is broken...?
« on: June 19, 2018, 07:42:07 pm »
I'll just ask anyone here to check the "Audio" demo included in Jo engine. ATM it doesn't work.

Further, Bizhawk and Yabause refuse to load CD files that include mp3 or WAV files. Only SSF loads it, and even then it does not play the music file.
Trying to include the audio files the way Rockin' B says to also doesn't make them 'happy'.
There's got to be some way to get "CD-DA" included in an iso file, right?

I could fathom a workaround to that if we had SGL CD functions, but we don't. And given Jo Engines handling of the CD audio files is very low-level, it seems fool-proof to me.
I'm also not sure how SBL expects you to playback CD-DA.(/e: Oh, CD-XA / ADPCM .. which doesn't really help me!)
I just wonder if it is like this for anyone else.


I've got the GFS_NwFread function and structure from the Workshop 95 slides, and it compiles and "runs".
Of course what I am trying to do is use it to read XL2's ZTP files, which have segmented data meant for a modelData_t struct.

It seems XL2 loads these in segments with GFS_Load, loading one segment has information relevant to loading the next segment.
Of course I'm here because I don't understand how exactly that works, I'm guessing the reason this doesn't work with GFS_NwFread is because I'm not arranging the memory addresses right.
I say that because it doesn't load any of the other models using the current Address variable called after my dysfunctional '"ztFileStream" function is run.

I imagine all I should need to do is read from the buffer into the address for a modelData_t struct...
but i don't know how to do that...

/e: Oh, you should probably know that the function is in ZT_LOAD_MODEL.c  in ZT folder.

Code: [Select]
void * ztFileStream(Sint8 * filename, void * startAddress, entity_t * model)

    memset_l((void*)startAddress,0x0000, (0xFFFE - ((Uint32)startAddress-(Uint32)LWRAM)));  //Not 100% necessary, since data can just be overwritten, but good for testing and see how much data a level takes
    void * currentAddress;
    currentAddress = startAddress;

    Sint32 fid = GFS_NameToId((Sint8*)filename);
GfsHn gfs;
Sint32 stat;
Sint32 nsct;
Sint32 bsize;
//Model Data is the destination of data.
modelData_t bufModel;
//Destination address?
    void * ptr = &bufModel;

//Loading follows
gfs = GFS_Open(fid);
//Get sectors
GFS_GetFileSize(gfs, nsct, NULL, NULL);
bsize = 2048 * nsct;
// nsct = GFS_ByteToSct(gfs, bytesOf);

//modelData_t has an assumed size?
GFS_NwFread(gfs, nsct, (Uint32*)currentAddress, bsize);

//For loop is blank because this will run until GFS_Close, AKA always run until GFS_Close.
stat = GFS_NwExecOne(gfs);
//Copy gfs to modelData_t bufmodel???
memcpy_l((Sint32*)ptr, (Sint32*)(startAddress), (sizeof(modelData_t)));

model->pos[X]=bufModel.Origin[X]; model->pos[Y]=bufModel.Origin[Y]; model->pos[Z]=bufModel.Origin[Z];
model->length[X]=bufModel.Length[X]; model->length[Y]=bufModel.Length[Y]; model->length[Z]=bufModel.Length[Z];

//Get textures from GFS
Uint16 first_texture = loadTextures(startAddress, &bufModel);
//Get PDATA from GFS
// Sint32 bytesOff = (bufModel.TEXT_SIZE+(sizeof(modelData_t)))/2048;

// bytesOff = bufModel.TEXT_SIZE+(sizeof(modelData_t)) - (bytesOff*2048);
// currentAddress = (void*)(currentAddress + bytesOff);

currentAddress = loadPDATA((void*)currentAddress, model, &bufModel);
//Set textures from GFS
setTextures(first_texture, model, bufModel.TOTAL_MESH, true);

    return currentAddress;


General Jo Engine Help / More on ZTP
« on: May 26, 2018, 03:40:17 pm »
Hello mostly XL2,

As your tool is a work-in-progress I'd like to share a project file where I am having some issues.

Some models exported from my animations to be converted in to ZTP files are not loading. This seems non-nonsensical, as the only thing that has changed about the model is its pose.
Another conundrum is it happens in a way spread out across the range of entities. Some in a range stop loading, then models start loading again, then they have problems again.
There is something wrong with my OBJ files and I am not sure what it is.

The issue can be found in &entities[5] through to &entities[10] (and other sequences). In the binary model converter folder (starting from top level), this is RTURP05 to RTURP10. It does NOT happen for those same frames when mirrored (pose copied from L bones to R bones, some other numbers inverted some not, then exported as OBJ) on LTURN05 to LTURN10 / &entities[15] to &entities[20]. Should be noted that the LTURN is the original animation that was copied.

Thank you for reading.

General Jo Engine Help / Fixed Light Source?
« on: May 03, 2018, 06:17:43 am »
Simple question. Does anyone know how to organize a fixed light source?

It probably revolves around organizing my matrix properly, but at the moment it seems the light source is always the camera/player.
I want the light source to always be in one particular location in the world. Or rather, from one particular angle (i'm not asking it to be in the center, that would be much more complicated)

Maybe I should figure out gourad shading

General Jo Engine Help / SAT / Separating Axis Theorem math: y no werk
« on: March 28, 2018, 02:27:00 am »
I have made 2 versions (well... I broke one as it is saved too late past the conversion process to the other) of some 3D collison/zone detection math using RBB [rotated bounding box] based on the separating axis theorem.

One version uses entirely FIXED data types. It generates non-zero numbers, but there are overflows due to numbers being squared (600 squared, for instance, is beyond the range of FIXED data).

One version (that can compile) I made to combat the overflows is programmed using jo_vectorf and Sint32 values and should make the final conclusion more likely/less buggy (removal of decimal points in end comparison). But there is a problem... all the numbers are zero, and I don't know why. All of the math up to slInnerProduct (replaced with jo_vectorf_dot) and JO_SQUARE (being the overflow area) worked previously, now it doesn't work at all. At some point I had that same math working with jo_vectorf and Sint32 data, but jo_vectorf_dot would not operate since this was a situation in which the vectors were not stored as pointers (and instead "stack variables" or you know, missing the * in jo_vectorf *vector_here_is_pointer_with_star ).

And the other factoid, if I remove the initialization from jo_vectorf structs, it crashes.

Here is the jo_vectorf (float/int) code that I am trying to use:

Here, for comparison, is the (broken) more-SGL-reliant code:

Thank you for reading.
The answer is probably simple. Maybe I am trying to typecast something wrong or am using jo_float2fixed and/or toFIXED improperly.

and here's the entire project

/e: thread has a conclusion

An update on March 15th had broken my jo engine compiler. I forget the error but it was about a "failed to allocate" summat.

So if you suddenly get this, 1) disable the update service and then 2) uninstall all updates you can that were installed after Mar 13.
/e: I have found it is specifically Windows 10 "Security" Update KB4088776.

Here's a youtube video of my problem

I don't want to bother you wizards too much here since I've had lots of questions before that I eventually just figured out on my own.

But on this one I really don't have any other idea of how to continue.

Using jo_3d_set_target allows me to rotate the camera's POV, but only for 180 degrees, then it appears to stop.
Which means in practical terms I can't turn the camera around to properly face the "character".

Maybe there's some tricks of translating the entire world to get it to look like it's turning around, but the math involved is too complex for me when I am already translating the world in a circle to get the camera to appear to move around the character. Now I just need to get the camera to face the character.

Pages: [1]
SMF spam blocked by CleanTalk