File.c

vbt

Staff member
Here are the little functions to access CD, it can help a little I think. Some parts can be improved (there is one or two global walues :blush: )

Code:
#include "sega_gfs.h"

#define	MAX_FILE 128

#define MAX_OPEN    20

#define MAX_DIR     128

#define GFS_ON 1

extern int file_max;

GfsDirName dir_name[MAX_DIR];

int LoadFile(char *name, Uint8 *location, Uint32 size);

//--------------------------------------------------------------------------------------------------------------------------------------

void InitCD()

{

	Sint32 ret;

	Uint32 lib_work[GFS_WORK_SIZE(MAX_OPEN) / sizeof(Uint32)];

	GfsDirTbl dirtbl; 

  GFS_DIRTBL_TYPE(&dirtbl) = GFS_DIR_NAME;

  GFS_DIRTBL_DIRNAME(&dirtbl) = dir_name;

  GFS_DIRTBL_NDIR(&dirtbl) = MAX_DIR;

  ret = GFS_Init(MAX_OPEN, lib_work, &dirtbl);

}

//--------------------------------------------------------------------------------------------------------------------------------------

void ChangeDir(char *dirname)

{

  Sint32 fid;

	GfsDirTbl dirtbl; 

	

  fid = GFS_NameToId((Sint8 *)dirname);

	GFS_DIRTBL_TYPE(&dirtbl) = GFS_DIR_NAME;

	GFS_DIRTBL_DIRNAME(&dirtbl) = dir_name;

	GFS_DIRTBL_NDIR(&dirtbl) = MAX_DIR;

	for (;;) {

   file_max = GFS_LoadDir(fid, &dirtbl)-2;

 if ( file_max >= 0) {

 	break;

 }

	}

	for (;;) {

 if (GFS_SetDir(&dirtbl) == 0) {

 	break;

 }

	}

}

//--------------------------------------------------------------------------------------------------------------------------------------

int LoadFile(char *name, Uint8 *location, Uint32 size)

{

	Sint32 	fid, i;

	for (i = 0; i < 10; i++) {

 fid = GFS_NameToId(name);

 if (fid >= 0) {

 	GFS_Load(fid, 0, location, size);

 	return 0;

 }

	}

	return -1;

}

//--------------------------------------------------------------------------------------------------------------------------------------

Sint32 GetFileSize(int file_id)

{

	GfsHn gfs;

  Sint32 sctsize, nsct, lastsize;

  

  gfs = GFS_Open(file_id);

  GFS_GetFileSize(gfs, &sctsize, &nsct, &lastsize);

  GFS_Close(gfs);

	return sctsize*nsct;

}

//--------------------------------------------------------------------------------------------------------------------------------------
 

RockinB

Staff member
Now that I'm dealing with CD access,

there are some questions and correction:

Filesize:

Your GetFileSize() does not return the correct filesize. The file does not completely use all sectors(nsct) of size sctsize. That's why there is lastsize, which is the number of unused bytes in last sector. The correct filesize would then be:

(sctsize*nsct) - (BYTES_PER_SECTOR - lastsize)

with BYTES_PER_SECTOR usually being 2048.

BTW: GFS_Load() does indeed return this correct filesize(as does GFS_Fread()), too.

Then I really don't know why you try 10 times to load the file in LoadFile()....

It could be better to keep the libwork and dirtable used when initializing global as it's done in SBL sample. I don't looked into the GFS sourcecode(except GFS_Load()), but possibly these are used later.

I have currently problems with loading files. Don't know if GFS_Load() returns when all is finished - it does return the filesize - or if I have to wait till it's completed.

But how should I do this? There is GFS_IsEof(), but you need a filehandle for this and GFS_Load() creates a local filehandle that I cannot use.

Another problem that can occur in this context: Be carefull when setting MAX_OPEN to only 1. It's possible that GFS functions try to open a file, too. And then it fails and you don't know why... .

OK, now this is part of the solution for my problem.
 

RockinB

Staff member
Back again! ;)

I found and read parts of the GFS manual. Indeed, GFS_Load() is a return on completion function. No need to pass trough the filesize, only the size of the buffer or GFS_BUFSIZ_INT.

Now, after 10 CD-R's wasted, I provide some cool sourcecode for fast CD access.

Do you remember how "The Need For Speed" eats your CD drive when loading games? The reason is because it does this: directory access -> file access -> directory access -> file access..... . The solution is to do all directory access in a batch and then accessing the files. So does my code.

Some prenotes:

PURPOSE:

It was written to allow multi language PCM's and to allow CDDA at the same time with PCM. For doing the first, PCM has to be loaded from CD, for the second, PCM has to be in sound RAM.

Besides that it could be used to read arbitrary files into work RAM, of course.

FUNCTION:

So this code places all PCM consecutively in sound RAM (4 byte boundary)starting at the beginning. Normal sound FX is placed at start of sound RAM, remaining space is left for voice PCM with specific language.

For minimizing CD access time, the files are read in the order they are placed on CD.

CAUTION:

The loading does fine, but there are some issues apart from that. My thoughts:

- maybe it's not allowed to read CD into sound RAM, or

- sound RAM access width(byte, word or whatevery) differs from that used in CD transfer

-> So unfortunately, the PCMs don't play yet.

STILL READING?

If you want to know exactly what it does, you should know about the variables:

There is an array of filenames pcmnames[] with normal SFX, array of multilanguage voice filenames voicenames[][language] and an arry pcm[] that holds the start address and length of each loaded PCM file. It's needed for playback, you know. This data is written while loading. It also contains the PCM structure which is edited before compiling.


OK, and now the code:

/* loads all PCMs consecutively into sound RAM

* non voice PCMs first,

* then the voice files according to selected language

*/

void loadPCM(Uint8 language)

{

Sint32 fid, nextfid, filesize;

Uint32 *soundRAMpointer;

Uint8 *filename;

Uint32 i, j, nextpos;

/* space for file ids for rapid file access */

Sint32 fids_NONVOICE[NUMBER_OF_NONVOICE_PCM], fids_VOICE[NUMBER_OF_VOICE_PCM];

/* need to remember loaded files

* if the same file is loaded to multiple locations

* (should not occur in general, just during development)

*/

enum BooleanLogic loaded[NUMBER_OF_ALL_PCM];

/* that much space in sound RAM

* Unit: byte

*/

Sint32 freeRAMspace = 512*1024;



clearScreen();

slPrint("Now loading PCM sound!", slLocate(10,5));

slPrint("Filename: Filesize:FileID: Location:", slLocate(0,7));

/* For fast reading, first access directory

* instead of swicthing between file and directory access again and again */

for(i = 0; i < NUMBER_OF_ALL_PCM; i++)

{

/* no file has been loaded */

loaded = FALSE;

/* manage different filename sources */

if(i < NUMBER_OF_NONVOICE_PCM)

fids_NONVOICE = GFS_NameToId(pcmnames);

else

fids_VOICE[i - NUMBER_OF_NONVOICE_PCM] = GFS_NameToId(voicenames[i - NUMBER_OF_NONVOICE_PCM][language]);

}



/* Then load the files in the same order they are placed on the CD.

* First load all non voice PCMs */

soundRAMpointer = (Uint32 *)SoundRAM;

fid = 0;

for(i = 0; i < NUMBER_OF_ALL_PCM; i++)

{

/* search next fid */

/* manage different filename sources */

nextfid = 99;

if(i < NUMBER_OF_NONVOICE_PCM)

{

for(j = 0; j < NUMBER_OF_NONVOICE_PCM; j++)

{

/* is this file located after the previously

* loaded file on disc?

* allow multiple loading of same file

*/

if((loaded[j] == FALSE) && (fids_NONVOICE[j] >= fid))

{

/* is it not as far away as nextid? */

if(nextfid > fids_NONVOICE[j])

{

nextpos = j;

filename = pcmnames[j];

nextfid = fids_NONVOICE[j];

}

}

}

}

else

{

if(i == NUMBER_OF_NONVOICE_PCM)

{

/* initialize search and remember location in sound RAM */

VOICE_PCM_START_ADDRESS = soundRAMpointer;

fid = 0;

}

for(j = 0; j < NUMBER_OF_VOICE_PCM; j++)

{

/* is this file located after the previously

* loaded file on disc?

* allow multiple loading of same file

*/

if((loaded[NUMBER_OF_NONVOICE_PCM + j] == FALSE) && (fids_VOICE[j] >= fid))

{

/* is it not as far away as nextid? */

if(nextfid > fids_VOICE[j])

{

nextpos = NUMBER_OF_NONVOICE_PCM + j;

filename = voicenames[j][language];

nextfid = fids_VOICE[j];

}

}

}

}

/* file id has been found,

* mark that we load it

*/

loaded[nextpos] = TRUE;

fid = nextfid;



/* load file and display specs

*

* NOTE: GFS_Load() returns when completed,

* as I don't want to do other stuff, that's OK

*/

slPrint(filename, slLocate(0, 9 + i));

slPrintHex((Uint32)soundRAMpointer, slLocate(31, 9 + i));

slPrintHex(fid, slLocate(22, 9 + i));

filesize = GFS_Load(fid, 0, (void *)soundRAMpointer, freeRAMspace);

slPrintHex(filesize, slLocate(13, 9 + i));

slSynch();

/* set PCM data */

pcm.data = soundRAMpointer;

pcm.size = filesize;



/* update sound RAM pointer to next free place

* and keep 4 byte boundaries for GFS_Load() */

if(filesize & 0x3 !=0)

{

soundRAMpointer += (filesize >> 2) + 1;

freeRAMspace -= (filesize & 0x3) + 0x4;

}

else

{

soundRAMpointer += (filesize >> 2);

freeRAMspace -= filesize;

}

}

return;

}


Don't know if it might help you :sleep: , but it's a very deep preview into upcoming MineSweeper features.

The Rockin'-B
 

vbt

Staff member
Originally posted by Rockin'-B@Sep 17, 2003 @ 11:32 AM

Now that I'm dealing with CD access,

there are some questions and correction:

Filesize:

Your GetFileSize() does not return the correct filesize. The file does not completely use all sectors(nsct) of size sctsize. That's why there is lastsize, which is the number of unused bytes in last sector. The correct filesize would then be:

(sctsize*nsct) - (BYTES_PER_SECTOR - lastsize)

with BYTES_PER_SECTOR usually being 2048.

BTW: GFS_Load() does indeed return this correct filesize(as does GFS_Fread()), too.

Then I really don't know why you try 10 times to load the file in LoadFile()....

It could be better to keep the libwork and dirtable used when initializing global as it's done in SBL sample. I don't looked into the GFS sourcecode(except GFS_Load()), but possibly these are used later.

I have currently problems with loading files. Don't know if GFS_Load() returns when all is finished - it does return the filesize - or if I have to wait till it's completed.

But how should I do this? There is GFS_IsEof(), but you need a filehandle for this and GFS_Load() creates a local filehandle that I cannot use.

Another problem that can occur in this context: Be carefull when setting MAX_OPEN to only 1. It's possible that GFS functions try to open a file, too. And then it fails and you don't know why... .

OK, now this is part of the solution for my problem.

Thanks for the right file size getting method. I don't remember why I did that. Maybe for a malloc before putting a file in memory. For SMS ROMs the file size was right, there was no unused bytes :) Thanks for the info, I will check for NES ROM case, I may use wrong file size, I don't know if it can cause problems.
 

vbt

Staff member
[quote name='RockinB']Now that I'm dealing with CD access,

there are some questions and correction:


Filesize:

Your GetFileSize() does not return the correct filesize. The file does not completely use all sectors(nsct) of size sctsize. That's why there is lastsize, which is the number of unused bytes in last sector. The correct filesize would then be:

(sctsize*nsct) - (BYTES_PER_SECTOR - lastsize)

with BYTES_PER_SECTOR usually being 2048.

BTW: GFS_Load() does indeed return this correct filesize(as does GFS_Fread()), too.

QUOTE]



Quite old topic I finally fiexed the function and correct file size fonction looks like this :


Code:
Sint32 GetFileSize(int file_id)

{

    GfsHn gfs;

    Sint32 sctsize, nsct, lastsize;

    

    gfs = GFS_Open(file_id);

    GFS_GetFileSize(gfs, &sctsize, &nsct, &lastsize);


    GFS_Close(gfs);

	return (sctsize*(nsct-1) + lastsize);

}


Well in fact it's almost the same you wrote Rockin'-B, I tried to fix myself before posting here :)

I still get another problem on file reading but it comes from something else.
 
Top