Kaynağa Gözat

cso support

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@303 be3aeb3a-fb24-0410-a615-afba39da0efa
notaz 16 yıl önce
ebeveyn
işleme
71de3cd9bb

+ 182 - 1
Pico/Cart.c

@@ -18,6 +18,54 @@ static char *rom_exts[] = { "bin", "gen", "smd", "iso" };
 void (*PicoCartLoadProgressCB)(int percent) = NULL;
 void (*PicoCDLoadProgressCB)(int percent) = NULL; // handled in Pico/cd/cd_file.c
 
+/* cso struct */
+typedef struct _cso_struct
+{
+  unsigned char in_buff[2*2048];
+  unsigned char out_buff[2048];
+  struct {
+    char          magic[4];
+    unsigned int  unused;
+    unsigned int  total_bytes;
+    unsigned int  total_bytes_high; // ignored here
+    unsigned int  block_size;  // 10h
+    unsigned char ver;
+    unsigned char align;
+    unsigned char reserved[2];
+  } header;
+  unsigned int  fpos_in;  // input file read pointer
+  unsigned int  fpos_out; // pos in virtual decompressed file
+  int block_in_buff;      // block which we have read in in_buff
+  int pad;
+  int index[0];
+}
+cso_struct;
+
+static int uncompress2(void *dest, int destLen, void *source, int sourceLen)
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    stream.next_out = dest;
+    stream.avail_out = (uInt)destLen;
+
+    stream.zalloc = NULL;
+    stream.zfree = NULL;
+
+    err = inflateInit2(&stream, -15);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        return err;
+    }
+    //*destLen = stream.total_out;
+
+    return inflateEnd(&stream);
+}
 
 pm_file *pm_open(const char *path)
 {
@@ -77,6 +125,61 @@ zip_failed:
       return NULL;
     }
   }
+  else if (ext && strcasecmp(ext, "cso") == 0)
+  {
+    cso_struct *cso = NULL, *tmp = NULL;
+    int size;
+    f = fopen(path, "rb");
+    if (f == NULL)
+      goto cso_failed;
+
+    cso = malloc(sizeof(*cso));
+    if (cso == NULL)
+      goto cso_failed;
+
+    if (fread(&cso->header, 1, sizeof(cso->header), f) != sizeof(cso->header))
+      goto cso_failed;
+
+    if (strncmp(cso->header.magic, "CISO", 4) != 0) {
+      elprintf(EL_STATUS, "cso: bad header");
+      goto cso_failed;
+    }
+
+    if (cso->header.block_size != 2048) {
+      elprintf(EL_STATUS, "cso: bad block size (%u)", cso->header.block_size);
+      goto cso_failed;
+    }
+
+    size = ((cso->header.total_bytes >> 11) + 1)*4 + sizeof(*cso);
+    tmp = realloc(cso, size);
+    if (tmp == NULL)
+      goto cso_failed;
+    cso = tmp;
+    elprintf(EL_STATUS, "allocated %i bytes for CSO struct", size);
+
+    size -= sizeof(*cso); // index size
+    if (fread(cso->index, 1, size, f) != size) {
+      elprintf(EL_STATUS, "cso: premature EOF");
+      goto cso_failed;
+    }
+
+    // all ok
+    cso->fpos_in = ftell(f);
+    cso->fpos_out = 0;
+    cso->block_in_buff = -1;
+    file = malloc(sizeof(*file));
+    if (file == NULL) goto cso_failed;
+    file->file  = f;
+    file->param = cso;
+    file->size  = cso->header.total_bytes;
+    file->type  = PMT_CSO;
+    return file;
+
+cso_failed:
+    if (cso != NULL) free(cso);
+    if (f != NULL) fclose(f);
+    return NULL;
+  }
 
   /* not a zip, treat as uncompressed file */
   f = fopen(path, "rb");
@@ -117,6 +220,68 @@ size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
       /* we must reset stream pointer or else next seek/read fails */
       gzrewind(gf);
   }
+  else if (stream->type == PMT_CSO)
+  {
+    cso_struct *cso = stream->param;
+    int read_pos, read_len, out_offs, rret;
+    int block = cso->fpos_out >> 11;
+    int index = cso->index[block];
+    int index_end = cso->index[block+1];
+    unsigned char *out = ptr, *tmp_dst;
+
+    ret = 0;
+    while (bytes != 0)
+    {
+      out_offs = cso->fpos_out&0x7ff;
+      if (out_offs == 0 && bytes >= 2048)
+           tmp_dst = out;
+      else tmp_dst = cso->out_buff;
+
+      read_pos = (index&0x7fffffff) << cso->header.align;
+
+      if (index < 0) {
+        if (read_pos != cso->fpos_in)
+          fseek(stream->file, read_pos, SEEK_SET);
+        rret = fread(tmp_dst, 1, 2048, stream->file);
+        cso->fpos_in = read_pos + rret;
+        if (rret != 2048) break;
+      } else {
+        read_len = (((index_end&0x7fffffff) << cso->header.align) - read_pos) & 0xfff;
+        if (block != cso->block_in_buff)
+        {
+          if (read_pos != cso->fpos_in)
+            { fseek(stream->file, read_pos, SEEK_SET); printf("seek %i\n", read_pos); }
+          rret = fread(cso->in_buff, 1, read_len, stream->file);
+          cso->fpos_in = read_pos + rret;
+          if (rret != read_len) {
+            elprintf(EL_STATUS, "cso: read failed @ %08x", read_pos);
+            break;
+          }
+          cso->block_in_buff = block;
+        }
+        rret = uncompress2(tmp_dst, 2048, cso->in_buff, read_len);
+        if (rret != 0) {
+          elprintf(EL_STATUS, "cso: uncompress failed @ %08x with %i", read_pos, rret);
+          break;
+        }
+      }
+
+      rret = 2048;
+      if (out_offs != 0 || bytes < 2048) {
+        //elprintf(EL_STATUS, "cso: unaligned/nonfull @ %08x, offs=%i, len=%u", cso->fpos_out, out_offs, bytes);
+        if (bytes < rret) rret = bytes;
+        if (2048 - out_offs < rret) rret = 2048 - out_offs;
+        memcpy(out, tmp_dst + out_offs, rret);
+      }
+      ret += rret;
+      out += rret;
+      cso->fpos_out += rret;
+      bytes -= rret;
+      block++;
+      index = index_end;
+      index_end = cso->index[block+1];
+    }
+  }
   else
     ret = 0;
 
@@ -139,6 +304,17 @@ int pm_seek(pm_file *stream, long offset, int whence)
     }
     return gzseek((gzFile) stream->param, offset, whence);
   }
+  else if (stream->type == PMT_CSO)
+  {
+    cso_struct *cso = stream->param;
+    switch (whence)
+    {
+      case SEEK_CUR: cso->fpos_out += offset; break;
+      case SEEK_SET: cso->fpos_out  = offset; break;
+      case SEEK_END: cso->fpos_out  = cso->header.total_bytes - offset; break;
+    }
+    return cso->fpos_out;
+  }
   else
     return -1;
 }
@@ -160,6 +336,11 @@ int pm_close(pm_file *fp)
     zipfile->fp = NULL; // gzclose() closed it
     closezip(zipfile);
   }
+  else if (fp->type == PMT_CSO)
+  {
+    free(fp->param);
+    fclose(fp->file);
+  }
   else
     ret = EOF;
 
@@ -431,7 +612,7 @@ void PicoCartDetect(void)
   }
   else if ( name_cmp("MICRO MACHINES II") == 0 ||
            (name_cmp("        ") == 0 && // Micro Machines {Turbo Tournament '96, Military - It's a Blast!}
-	    (csum == 0x165e || csum == 0x168b || csum == 0xCEE0 || csum == 0x2C41)))
+           (csum == 0x165e || csum == 0x168b || csum == 0xCEE0 || csum == 0x2C41)))
   {
     SRam.start = 0x300000;
     SRam.end   = 0x380001;

+ 2 - 1
Pico/Pico.h

@@ -83,7 +83,8 @@ void Stop_CD(void); // releases all resources taken when CD game was started.
 typedef enum
 {
 	PMT_UNCOMPRESSED = 0,
-	PMT_ZIP
+	PMT_ZIP,
+	PMT_CSO
 } pm_type;
 typedef struct
 {

+ 2 - 2
Pico/PicoInt.h

@@ -113,7 +113,7 @@ extern m68ki_cpu_core PicoCpuMM68k, PicoCpuMS68k;
 }
 #define SekShouldInterrupt (CPU_INT_LEVEL > FLAG_INT_MASK)
 
-#define SekInterrupt(irq) {
+#define SekInterrupt(irq) { \
 	void *oldcontext = m68ki_cpu_p; \
 	m68k_set_context(&PicoCpuMM68k); \
 	m68k_set_irq(irq); \
@@ -481,7 +481,7 @@ PICO_INTERNAL void z80_exit(void);
 #define EL_IO      0x1000 /* all i/o (TODO) */
 
 #define EL_STATUS  0x4000 /* status messages */
-#define EL_ANOMALY 0x8000 /* some unexpected conditions */
+#define EL_ANOMALY 0x8000 /* some unexpected conditions (during emulation) */
 
 #if EL_LOGMASK
 #define elprintf(w,f,...) \

+ 0 - 1
Pico/cd/Sek.c

@@ -178,7 +178,6 @@ PICO_INTERNAL int SekInterruptS68k(int irq)
   {
     extern int dbg_irq_level_sub;
     dbg_irq_level_sub=real_irq;
-    elprintf(EL_ANOMALY, "s68k irq %i", real_irq);
     return 0;
   }
 #endif

+ 12 - 6
platform/base_readme.txt

@@ -99,12 +99,14 @@ must be stereo, or else they will play too fast/slow or won't play at all.
 Be sure NOT to use anything but classic mp3 format (don't use things like
 mp3pro).
 
-ISO files can also be zipped (but not mp3 files, as they are already
-compressed). Note that this can cause very long loading times, which may
-take up to several minutes. File naming is similar as with uncompressed ISOs.
+ISO files can also be .cso compressed or zipped (but not mp3 files, as they
+are already compressed). CSO will cause slightly longer loading times, and
+is not very good for FMV games. Zipping ISOs is not recommened, as it will
+cause very long (several minute) loading times, and make some games
+unplayable. File naming is similar as with uncompressed ISOs.
 Example:
 
-SonicCD.zip             data track
+SonicCD.cso             data track
 SonicCD_02.mp3          audio track 1 (CD track 2)
 SonicCD_03.mp3
 ...
@@ -123,11 +125,14 @@ Other important stuff
   Incorrectly named/missing mp3s may also be the cause.
 * Sega/Mega CD: If the background music is missing, you might have named your
   MP3s incorrectly. Read "How to run Sega/Mega CD games" section again.
-* Sega/Mega CD: If the game music plays too fast or too slow, you have encoded
-  your MP3s incorrectly. You will have to re-encode and/or resample them.
+* Sega/Mega CD: If the game music plays too fast/too slow/out of sync, you have
+  encoded your MP3s incorrectly. You will have to re-encode and/or resample them.
   PicoDrive is not a mp3 player, so all mp3s MUST be encoded at 44.1kHz stereo.
   Badly encoded mp3s can cause various kind of problems, like noises, incorrect
   playback speeds, not repeating music or even prevent game from starting.
+  Some games (like Snatcher) may hang in certain scenes because of this.
+  Some mp3 rippers/encoders remove silence and beginning/end of audio tracks,
+  what causes audio desyncs and/or mentioned problems.
 * Sega/Mega CD: If your games hangs at the BIOS screen (with planets shown),
   you may be using a bad BIOS dump. Try another from a different source.
 * Some Sega/Mega CD games don't use Z80 for anything, but they leave it active,
@@ -631,6 +636,7 @@ Changelog
 1.35b
   * PSP: mp3 code should no longer fail on 1.5 firmware.
   + PSP: added gamma adjustment option.
+  + Added .cso format support. Useful for non-FMV games.
   * Fixed a sram bug in memhandlers (fixes Shining in the Darkness saves).
   * PSP: fixed another bug in memhanlers, which crashed the emu for some games
     (like NBA Jam).

+ 1 - 1
platform/gizmondo/menu.c

@@ -158,7 +158,7 @@ struct my_dirent
 static unsigned short file2color(const char *fname)
 {
 	const char *ext = fname + strlen(fname) - 3;
-	static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso" };
+	static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso", "cso" };
 	static const char *other_exts[] = { "gmv", "pat" };
 	int i;
 

+ 1 - 1
platform/gp2x/menu.c

@@ -172,7 +172,7 @@ void menu_romload_end(void)
 static unsigned short file2color(const char *fname)
 {
 	const char *ext = fname + strlen(fname) - 3;
-	static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso" };
+	static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso", "cso" };
 	static const char *other_exts[] = { "gmv", "pat" };
 	int i;
 

+ 1 - 1
platform/linux/Makefile

@@ -45,7 +45,7 @@ OBJS += Pico/cd/Pico.o Pico/cd/Memory.o Pico/cd/Sek.o Pico/cd/LC89510.o \
 OBJS += Pico/sound/sound.o Pico/sound/sn76496.o Pico/sound/ym2612.o Pico/sound/mix.o
 # zlib
 OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
-	zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o
+	zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o zlib/uncompr.o
 # unzip
 OBJS += unzip/unzip.o unzip/unzip_stream.o
 # CPU cores

+ 1 - 1
platform/psp/emu.c

@@ -535,7 +535,7 @@ static int sound_thread(SceSize args, void *argp)
 
 		// shouln't happen, but just in case
 		if (samples_made - samples_done >= samples_block*3) {
-			lprintf("sthr: block skip (%i)\n", samples_made - samples_done);
+			//lprintf("sthr: block skip (%i)\n", samples_made - samples_done);
 			samples_done += samples_block; // skip
 			snd_playptr  += samples_block;
 		}

+ 1 - 1
platform/psp/menu.c

@@ -185,7 +185,7 @@ struct my_dirent
 static unsigned short file2color(const char *fname)
 {
 	const char *ext = fname + strlen(fname) - 3;
-	static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso" };
+	static const char *rom_exts[]   = { "zip", "bin", "smd", "gen", "iso", "cso" };
 	static const char *other_exts[] = { "gmv", "pat" };
 	int i;
 

+ 1 - 1
platform/psp/port_config.h

@@ -22,7 +22,7 @@ extern void blit1(void);
 #define CAN_HANDLE_240_LINES	1
 
 // logging emu events
-#define EL_LOGMASK 0 // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO) // xffff
+#define EL_LOGMASK EL_STATUS // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO) // xffff
 
 //#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
 #define dprintf(x...)