if (f == NULL)\r
goto cso_failed;\r
\r
-#ifndef __EPOC32__\r
+#ifdef __GP2X__\r
/* we use our own buffering */\r
setvbuf(f, NULL, _IONBF, 0);\r
#endif\r
strncpy(file->ext, ext, sizeof(file->ext) - 1);\r
fseek(f, 0, SEEK_SET);\r
\r
-#ifndef __EPOC32__ // makes things worse on Symbian\r
+#ifdef __GP2X__\r
if (file->size > 0x400000)\r
/* we use our own buffering */\r
setvbuf(f, NULL, _IONBF, 0);\r
+++ /dev/null
-/***********************************************************\r
- * *\r
- * This source was taken from the Gens project *\r
- * Written by Stéphane Dallongeville *\r
- * Copyright (c) 2002 by Stéphane Dallongeville *\r
- * Modified/adapted for PicoDrive by notaz, 2007 *\r
- * *\r
- ***********************************************************/\r
-\r
-#ifndef _LC89510_H\r
-#define _LC89510_H\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-typedef struct\r
-{\r
-// unsigned short Fader; // 34\r
-// unsigned short Control; // 36\r
-// unsigned short Cur_Comm;// unused\r
-\r
- // "Receive status"\r
- unsigned short Status;\r
- unsigned short Minute;\r
- unsigned short Seconde;\r
- unsigned short Frame;\r
- unsigned char Ext;\r
- unsigned char pad[3];\r
-} CDD;\r
-\r
-\r
-PICO_INTERNAL void CDD_Export_Status(void);\r
-PICO_INTERNAL void CDD_Import_Command(void);\r
-\r
-void CDD_Reset(void);\r
-\r
-#ifdef __cplusplus\r
-};\r
-#endif\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*
- * Buffering handling
- * (C) notaz, 2007,2008
- *
- * This work is licensed under the terms of MAME license.
- * See COPYING file in the top-level directory.
- */
-
-#include "../pico_int.h"
-#include "../cd/cue.h"
-
-int PicoCDBuffers = 0;
-static unsigned char *cd_buffer = NULL;
-static int prev_lba = 0x80000000;
-
-static int hits, reads;
-
-#undef dprintf
-#define dprintf(...)
-
-void PicoCDBufferInit(void)
-{
- void *tmp = NULL;
-
- prev_lba = 0x80000000;
- hits = reads = 0;
-
- if (PicoCDBuffers <= 1) {
- PicoCDBuffers = 0;
- return; /* buffering off */
- }
-
- /* try alloc'ing until we succeed */
- while (PicoCDBuffers > 0)
- {
- tmp = realloc(cd_buffer, PicoCDBuffers * 2048 + 304);
- if (tmp != NULL) break;
- PicoCDBuffers >>= 1;
- }
-
- if (PicoCDBuffers <= 0) return; /* buffering became off */
-
- cd_buffer = tmp;
-}
-
-
-void PicoCDBufferFree(void)
-{
- if (cd_buffer) {
- free(cd_buffer);
- cd_buffer = NULL;
- }
- if (reads)
- elprintf(EL_STATUS, "CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads);
-}
-
-
-void PicoCDBufferFlush(void)
-{
- prev_lba = 0x80000000;
-}
-
-
-/* this is was a try to fight slow SD access of GP2X */
-PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
-{
- int is_bin, offs, read_len, moved = 0;
- reads++;
-
- is_bin = Pico_mcd->TOC.Tracks[0].ftype == CT_BIN;
-
- if (PicoCDBuffers <= 0)
- {
- /* no buffering */
- int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
- pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
- pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
- return;
- }
-
- /* hit? */
- offs = lba - prev_lba;
- if (offs >= 0 && offs < PicoCDBuffers)
- {
- hits++;
- if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
- memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
- return;
- }
-
- if (prev_lba + PicoCDBuffers != lba)
- {
- int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
- dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
- pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
- }
-
- dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
-
- if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
- {
- read_len = prev_lba - lba;
- dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
- memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
- moved = 1;
- }
- else
- {
- read_len = PicoCDBuffers;
- }
-
- if (PicoMessage != NULL && read_len >= 512)
- {
- PicoMessage("Buffering data...");
- }
-
- if (is_bin)
- {
- int i = 0;
-#ifdef _PSP_FW_VERSION
- int bufs = (read_len*2048) / (2048+304);
- pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F);
- for (i = 1; i < bufs; i++)
- // should really use memmove here, but my memcpy32 implementation is also suitable here
- memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4);
-#endif
- for (; i < read_len - 1; i++)
- {
- pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F);
- // pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more
- }
- // further data might be moved, do not overwrite
- pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
- pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
- }
- else
- {
- pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
- }
- memcpy32(dest, (int *) cd_buffer, 2048/4);
- prev_lba = lba;
-
- if (moved)
- {
- /* file pointer must point to the same data in file, as would-be data after our buffer */
- int where_seek;
- lba += PicoCDBuffers;
- where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
- pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
- }
-}
-
+++ /dev/null
-/***********************************************************
- * *
- * This source was taken from the Gens project *
- * Written by Stéphane Dallongeville *
- * Copyright (c) 2002 by Stéphane Dallongeville *
- * Modified/adapted for PicoDrive by notaz, 2007 *
- * *
- ***********************************************************/
-
-#include "../pico_int.h"
-#include "cd_file.h"
-#include "cue.h"
-
-//#define cdprintf(f,...) printf(f "\n",##__VA_ARGS__) // tmp
-
-static void to_upper(char *d, const char *s)
-{
- for (; *s != 0; d++, s++) {
- if ('a' <= *s && *s <= 'z')
- *d = *s - 'a' + 'A';
- else
- *d = *s;
- }
-}
-
-static int audio_track_mp3(const char *fname, int index)
-{
- _scd_track *Tracks = Pico_mcd->TOC.Tracks;
- FILE *tmp_file;
- int fs, ret;
-
- tmp_file = fopen(fname, "rb");
- if (tmp_file == NULL)
- return -1;
-
- ret = fseek(tmp_file, 0, SEEK_END);
- fs = ftell(tmp_file); // used to calculate length
- fseek(tmp_file, 0, SEEK_SET);
-
-#ifdef _PSP_FW_VERSION
- // some systems (like PSP) can't have many open files at a time,
- // so we work with their names instead.
- fclose(tmp_file);
- tmp_file = (void *) strdup(fname);
-#endif
- Tracks[index].KBtps = (short) mp3_get_bitrate(tmp_file, fs);
- Tracks[index].KBtps >>= 3;
- if (ret != 0 || Tracks[index].KBtps <= 0)
- {
- elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, Tracks[index].KBtps);
-#ifdef _PSP_FW_VERSION
- free(tmp_file);
-#else
- fclose(tmp_file);
-#endif
- return -1;
- }
-
- Tracks[index].F = tmp_file;
-
- // MP3 File
- Tracks[index].ftype = CT_MP3;
- fs *= 75;
- fs /= Tracks[index].KBtps * 1000;
- Tracks[index].Length = fs;
- Tracks[index].Offset = 0;
-
- return 0;
-}
-
-PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
-{
- int i, j, num_track, Cur_LBA, index, ret;
- int iso_name_len, missed, cd_img_sectors;
- _scd_track *Tracks = Pico_mcd->TOC.Tracks;
- char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
- cue_data_t *cue_data = NULL;
- pm_file *pmf;
- static const char *exts[] = {
- "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
- "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
- };
-
- if (PicoCDLoadProgressCB != NULL)
- PicoCDLoadProgressCB(cd_img_name, 1);
-
- Unload_ISO();
-
- /* is this a .cue? */
- cue_data = cue_parse(cd_img_name);
- if (cue_data != NULL) {
- cd_img_name = cue_data->tracks[1].fname;
- Tracks[0].ftype = cue_data->tracks[1].type;
- }
- else
- Tracks[0].ftype = type == CIT_BIN ? CT_BIN : CT_ISO;
-
- Tracks[0].F = pmf = pm_open(cd_img_name);
- if (Tracks[0].F == NULL)
- {
- Tracks[0].ftype = 0;
- Tracks[0].Length = 0;
- if (cue_data != NULL)
- cue_destroy(cue_data);
- return -1;
- }
-
- if (Tracks[0].ftype == CT_ISO)
- cd_img_sectors = pmf->size >>= 11; // size in sectors
- else cd_img_sectors = pmf->size /= 2352;
- Tracks[0].Offset = 0;
-
- Tracks[0].MSF.M = 0; // minutes
- Tracks[0].MSF.S = 2; // seconds
- Tracks[0].MSF.F = 0; // frames
-
- elprintf(EL_STATUS, "Track 1: %02d:%02d:%02d %9i DATA %s",
- Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F,
- Tracks[0].Length, cd_img_name);
-
- Cur_LBA = Tracks[0].Length = cd_img_sectors;
-
- if (cue_data != NULL)
- {
- if (cue_data->tracks[2].fname == NULL) { // NULL means track2 is in same file as track1
- Cur_LBA = Tracks[0].Length = cue_data->tracks[2].sector_offset;
- }
- i = 100 / cue_data->track_count+1;
- for (num_track = 2; num_track <= cue_data->track_count; num_track++)
- {
- if (PicoCDLoadProgressCB != NULL)
- PicoCDLoadProgressCB(cd_img_name, i * num_track);
- index = num_track - 1;
- Cur_LBA += cue_data->tracks[num_track].pregap;
- if (cue_data->tracks[num_track].type == CT_MP3) {
- ret = audio_track_mp3(cue_data->tracks[num_track].fname, index);
- if (ret != 0) break;
- }
- else
- {
- Tracks[index].ftype = cue_data->tracks[num_track].type;
- if (cue_data->tracks[num_track].fname != NULL)
- {
- pm_file *pmfn = pm_open(cue_data->tracks[num_track].fname);
- if (pmfn != NULL)
- {
- // addume raw, ignore header for wav..
- Tracks[index].F = pmfn;
- Tracks[index].Length = pmfn->size / 2352;
- Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
- }
- else
- {
- elprintf(EL_STATUS, "track %2i (%s): can't determine length",
- num_track, cue_data->tracks[num_track].fname);
- Tracks[index].Length = 2*75;
- Tracks[index].Offset = 0;
- }
- }
- else
- {
- if (num_track < cue_data->track_count)
- Tracks[index].Length = cue_data->tracks[num_track+1].sector_offset -
- cue_data->tracks[num_track].sector_offset;
- else
- Tracks[index].Length = cd_img_sectors - cue_data->tracks[num_track].sector_offset;
- Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
- }
- }
-
- if (cue_data->tracks[num_track].sector_xlength != 0)
- // overriden by custom cue command
- Tracks[index].Length = cue_data->tracks[num_track].sector_xlength;
-
- LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
- Cur_LBA += Tracks[index].Length;
-
- elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO %s", num_track, Tracks[index].MSF.M,
- Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length,
- cue_data->tracks[num_track].fname);
- }
- cue_destroy(cue_data);
- goto finish;
- }
-
- /* mp3 track autosearch, Gens-like */
- iso_name_len = strlen(cd_img_name);
- if (iso_name_len >= sizeof(tmp_name))
- iso_name_len = sizeof(tmp_name) - 1;
-
- for (num_track = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
- {
- if (PicoCDLoadProgressCB != NULL && i > 1)
- PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4);
-
- for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
- {
- int ext_len;
- char *p;
-
- index = num_track - 1;
-
- sprintf(tmp_ext, exts[j], i);
- ext_len = strlen(tmp_ext);
- to_upper(tmp_ext_u, tmp_ext);
-
- memcpy(tmp_name, cd_img_name, iso_name_len + 1);
- p = tmp_name + iso_name_len - 4;
-
- strcpy(p, tmp_ext);
- ret = audio_track_mp3(tmp_name, index);
- if (ret != 0) {
- strcpy(p, tmp_ext_u);
- ret = audio_track_mp3(tmp_name, index);
- }
-
- if (ret != 0 && i > 1 && iso_name_len > ext_len) {
- p = tmp_name + iso_name_len - ext_len;
- strcpy(p, tmp_ext);
- ret = audio_track_mp3(tmp_name, index);
- if (ret != 0) {
- strcpy(p, tmp_ext_u);
- ret = audio_track_mp3(tmp_name, index);
- }
- }
-
- if (ret == 0)
- {
- LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
- Cur_LBA += Tracks[index].Length;
-
- elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
- Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length, tmp_name);
-
- num_track++;
- missed = 0;
- break;
- }
- }
- if (ret != 0 && i > 1) missed++;
- }
-
-finish:
- Pico_mcd->TOC.Last_Track = num_track - 1;
-
- index = num_track - 1;
-
- LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
-
- elprintf(EL_STATUS, "End CD - %02d:%02d:%02d\n", Tracks[index].MSF.M,
- Tracks[index].MSF.S, Tracks[index].MSF.F);
-
- if (PicoCDLoadProgressCB != NULL)
- PicoCDLoadProgressCB(cd_img_name, 100);
-
- return 0;
-}
-
-
-PICO_INTERNAL void Unload_ISO(void)
-{
- int i;
-
- if (Pico_mcd == NULL) return;
-
- if (Pico_mcd->TOC.Tracks[0].F) pm_close(Pico_mcd->TOC.Tracks[0].F);
-
- for(i = 1; i < 100; i++)
- {
- if (Pico_mcd->TOC.Tracks[i].F != NULL)
- {
- if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)
-#ifdef _PSP_FW_VERSION
- free(Pico_mcd->TOC.Tracks[i].F);
-#else
- fclose(Pico_mcd->TOC.Tracks[i].F);
-#endif
- else
- pm_close(Pico_mcd->TOC.Tracks[i].F);
- }
- }
- memset(Pico_mcd->TOC.Tracks, 0, sizeof(Pico_mcd->TOC.Tracks));
-}
-
-#if 1*0
-
-PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
-{
- if (Pico_mcd->s68k_regs[0x36] & 1) // DATA
- {
- if (Pico_mcd->TOC.Tracks[0].F == NULL) return -1;
-
- // moved below..
- //fseek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
- //fread(cp_buf, 1, 2048, Pico_mcd->TOC.Tracks[0].F);
-
- cdprintf("Read file CDC 1 data sector :\n");
- }
- else // AUDIO
- {
- cdprintf("Read file CDC 1 audio sector :\n");
- }
-
- // Update CDC stuff
-
- CDC_Update_Header();
-
- if (Pico_mcd->s68k_regs[0x36] & 1) // DATA track
- {
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
- {
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x04) // WRRQ : this bit enable write to buffer
- {
- int where_read = 0;
-
- // CAUTION : lookahead bit not implemented
-
- if (Pico_mcd->scd.Cur_LBA < 0)
- where_read = 0;
- else if (Pico_mcd->scd.Cur_LBA >= Pico_mcd->TOC.Tracks[0].Length)
- where_read = Pico_mcd->TOC.Tracks[0].Length - 1;
- else where_read = Pico_mcd->scd.Cur_LBA;
-
- Pico_mcd->scd.Cur_LBA++;
-
- Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF; // add one sector to WA
- Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
-
- *(unsigned int *)(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N) = Pico_mcd->cdc.HEAD.N;
- //memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N + 4], cp_buf, 2048);
-
- //pm_seek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
- //pm_read(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, 2048, Pico_mcd->TOC.Tracks[0].F);
- PicoCDBufferRead(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, where_read);
-
- cdprintf("Read -> WA = %d Buffer[%d] =", Pico_mcd->cdc.WA.N, Pico_mcd->cdc.PT.N & 0x3FFF);
- cdprintf("Header 1 = %.2X %.2X %.2X %.2X", Pico_mcd->cdc.HEAD.B.B0,
- Pico_mcd->cdc.HEAD.B.B1, Pico_mcd->cdc.HEAD.B.B2, Pico_mcd->cdc.HEAD.B.B3);
- cdprintf("Header 2 = %.2X %.2X %.2X %.2X --- %.2X %.2X\n\n",
- Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 0) & 0x3FFF],
- Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 1) & 0x3FFF],
- Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 2) & 0x3FFF],
- Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 3) & 0x3FFF],
- Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 4) & 0x3FFF],
- Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 5) & 0x3FFF]);
- }
-
- }
- }
- else // music track
- {
- Pico_mcd->scd.Cur_LBA++;
-
- Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF; // add one sector to WA
- Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
-
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
- {
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x04) // WRRQ : this bit enable write to buffer
- {
- // CAUTION : lookahead bit not implemented
-
- // this is pretty rough, but oh well - not much depends on this anyway
- memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N], cdda_out_buffer, 2352);
- }
- }
- }
-
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
- {
- Pico_mcd->cdc.STAT.B.B0 = 0x80;
-
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x10) // determine form bit form sub header ?
- {
- Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x08;
- }
- else
- {
- Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x0C;
- }
-
- if (Pico_mcd->cdc.CTRL.B.B0 & 0x02) Pico_mcd->cdc.STAT.B.B3 = 0x20; // ECC done
- else Pico_mcd->cdc.STAT.B.B3 = 0x00; // ECC not done
-
- if (Pico_mcd->cdc.IFCTRL & 0x20)
- {
- if (Pico_mcd->s68k_regs[0x33] & (1<<5))
- {
- elprintf(EL_INTS, "cdc dec irq 5");
- SekInterruptS68k(5);
- }
-
- Pico_mcd->cdc.IFSTAT &= ~0x20; // DEC interrupt happen
- Pico_mcd->cdc.Decode_Reg_Read = 0; // Reset read after DEC int
- }
- }
-
-
- return 0;
-}
-
-#endif
+++ /dev/null
-#ifndef _CD_FILE_H
-#define _CD_FILE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum
-{
- CIT_NOT_CD = 0,
- CIT_ISO,
- CIT_BIN,
- CIT_CUE
-}
-cd_img_type;
-
-
-PICO_INTERNAL int Load_CD_Image(const char *iso_name, cd_img_type type);
-PICO_INTERNAL void Unload_ISO(void);
-PICO_INTERNAL int FILE_Read_One_LBA_CDC(void);
-
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif
--- /dev/null
+/*
+ * CD image handler
+ * (C) notaz, 2007,2013
+ *
+ * This work is licensed under the terms of MAME license.
+ * See COPYING file in the top-level directory.
+ */
+
+#include "../pico_int.h"
+#include "genplus_macros.h"
+#include "cdd.h"
+#include "cue.h"
+
+static int handle_mp3(const char *fname, int index)
+{
+ track_t *track = &cdd.toc.tracks[index];
+ FILE *tmp_file;
+ int kBps;
+ int fs, ret;
+
+ tmp_file = fopen(fname, "rb");
+ if (tmp_file == NULL)
+ return -1;
+
+ ret = fseek(tmp_file, 0, SEEK_END);
+ fs = ftell(tmp_file);
+ fseek(tmp_file, 0, SEEK_SET);
+
+#ifdef _PSP_FW_VERSION
+ // some systems (like PSP) can't have many open files at a time,
+ // so we work with their names instead.
+ fclose(tmp_file);
+ tmp_file = (void *) strdup(fname);
+#endif
+
+ kBps = mp3_get_bitrate(tmp_file, fs) / 8;
+ if (ret != 0 || kBps <= 0)
+ {
+ elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, kBps);
+#ifdef _PSP_FW_VERSION
+ free(tmp_file);
+#else
+ fclose(tmp_file);
+#endif
+ return -1;
+ }
+
+ track->fd = tmp_file;
+ track->offset = 0;
+
+ fs *= 75;
+ fs /= kBps * 1000;
+ return fs;
+}
+
+static void to_upper(char *d, const char *s)
+{
+ for (; *s != 0; d++, s++) {
+ if ('a' <= *s && *s <= 'z')
+ *d = *s - 'a' + 'A';
+ else
+ *d = *s;
+ }
+}
+
+// cdd.c uses lba - 150
+static void sprintf_lba(char *buf, size_t size, int lba)
+{
+ lba += 150;
+ snprintf(buf, size, "%02d:%02d:%02d", lba / 60 / 75,
+ (lba / 75) % 60, lba % 75);
+}
+
+int load_cd_image(const char *cd_img_name, int *type)
+{
+ static const char *exts[] = {
+ "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
+ "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
+ };
+ int i, j, n, lba, index, length, ret;
+ int iso_name_len, missed, cd_img_sectors;
+ char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
+ track_t *tracks = cdd.toc.tracks;
+ cue_data_t *cue_data = NULL;
+ pm_file *pmf;
+
+ if (PicoCDLoadProgressCB != NULL)
+ PicoCDLoadProgressCB(cd_img_name, 1);
+
+ Pico_mcd->cdda_type = CT_UNKNOWN;
+
+ /* is this a .cue? */
+ cue_data = cue_parse(cd_img_name);
+ if (cue_data != NULL) {
+ cd_img_name = cue_data->tracks[1].fname;
+ *type = cue_data->tracks[1].type;
+ }
+
+ pmf = pm_open(cd_img_name);
+ if (pmf == NULL)
+ {
+ if (cue_data != NULL)
+ cue_destroy(cue_data);
+ return -1;
+ }
+ tracks[0].fd = pmf;
+
+ if (*type == CT_ISO)
+ cd_img_sectors = pmf->size >>= 11; // size in sectors
+ else cd_img_sectors = pmf->size /= 2352;
+
+ // cdd.c operates with lba - 150
+ tracks[0].start = 0;
+ tracks[0].end = cd_img_sectors;
+ tracks[0].offset = 0;
+
+ sprintf_lba(tmp_ext, sizeof(tmp_ext), 0);
+ elprintf(EL_STATUS, "Track 1: %s %9i DATA %s",
+ tmp_ext, tracks[0].end, cd_img_name);
+
+ lba = cd_img_sectors;
+
+ if (cue_data != NULL)
+ {
+ if (cue_data->tracks[2].fname == NULL) {
+ // NULL fname means track2 is in same file as track1
+ lba = tracks[0].end = cue_data->tracks[2].sector_offset;
+ }
+ i = 100 / cue_data->track_count + 1; // progress display
+
+ for (n = 2; n <= cue_data->track_count; n++)
+ {
+ if (PicoCDLoadProgressCB != NULL)
+ PicoCDLoadProgressCB(cd_img_name, i * n);
+
+ index = n - 1;
+ lba += cue_data->tracks[n].pregap;
+ if (cue_data->tracks[n].type == CT_MP3) {
+ ret = handle_mp3(cue_data->tracks[n].fname, index);
+ if (ret < 0)
+ break;
+ length = ret;
+ }
+ else if (cue_data->tracks[n].fname != NULL)
+ {
+ pm_file *f = pm_open(cue_data->tracks[n].fname);
+ if (f != NULL)
+ {
+ // assume raw, ignore header for wav..
+ tracks[index].fd = f;
+ tracks[index].offset = cue_data->tracks[n].sector_offset;
+ length = f->size / 2352;
+ }
+ else
+ {
+ elprintf(EL_STATUS, "track %2i (%s): can't determine length",
+ n, cue_data->tracks[n].fname);
+ tracks[index].offset = 0;
+ length = 2*75;
+ }
+ }
+ else
+ {
+ if (n < cue_data->track_count)
+ length = cue_data->tracks[n+1].sector_offset -
+ cue_data->tracks[n].sector_offset;
+ else
+ length = cd_img_sectors - cue_data->tracks[n].sector_offset;
+ tracks[index].offset = cue_data->tracks[n].sector_offset;
+ }
+
+ if (cue_data->tracks[n].sector_xlength != 0)
+ // overriden by custom cue command
+ length = cue_data->tracks[n].sector_xlength;
+
+ Pico_mcd->cdda_type = cue_data->tracks[n].type;
+
+ tracks[index].start = lba;
+ lba += length;
+ tracks[index].end = lba;
+
+ sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
+ elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s",
+ n, tmp_ext, length, cue_data->tracks[n].fname);
+ }
+ cue_destroy(cue_data);
+ goto finish;
+ }
+
+ /* mp3 track autosearch, Gens-like */
+ iso_name_len = strlen(cd_img_name);
+ if (iso_name_len >= sizeof(tmp_name))
+ iso_name_len = sizeof(tmp_name) - 1;
+
+ for (n = 2, i = 0, missed = 0; i < 100 && missed < 4; i++)
+ {
+ if (PicoCDLoadProgressCB != NULL && i > 1)
+ PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4);
+
+ for (j = 0; j < sizeof(exts)/sizeof(char *); j++)
+ {
+ int ext_len;
+ char *p;
+
+ index = n - 1;
+
+ snprintf(tmp_ext, sizeof(tmp_ext), exts[j], i);
+ ext_len = strlen(tmp_ext);
+ to_upper(tmp_ext_u, tmp_ext);
+
+ memcpy(tmp_name, cd_img_name, iso_name_len + 1);
+ p = tmp_name + iso_name_len - 4;
+
+ strcpy(p, tmp_ext);
+ ret = handle_mp3(tmp_name, index);
+ if (ret <= 0) {
+ strcpy(p, tmp_ext_u);
+ ret = handle_mp3(tmp_name, index);
+ }
+
+ if (ret <= 0 && i > 1 && iso_name_len > ext_len) {
+ p = tmp_name + iso_name_len - ext_len;
+ strcpy(p, tmp_ext);
+ ret = handle_mp3(tmp_name, index);
+ if (ret <= 0) {
+ strcpy(p, tmp_ext_u);
+ ret = handle_mp3(tmp_name, index);
+ }
+ }
+
+ if (ret > 0)
+ {
+ length = ret;
+ tracks[index].start = lba;
+ lba += length;
+ tracks[index].end = lba;
+
+ Pico_mcd->cdda_type = CT_MP3;
+
+ sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
+ elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO - %s",
+ n, tmp_ext, length, tmp_name);
+
+ n++;
+ missed = 0;
+ break;
+ }
+ }
+ if (ret <= 0 && i > 1)
+ missed++;
+ }
+
+finish:
+ cdd.toc.last = n - 1;
+ cdd.toc.end = lba;
+
+ sprintf_lba(tmp_ext, sizeof(tmp_ext), cdd.toc.end);
+ elprintf(EL_STATUS, "End CD - %s\n", tmp_ext);
+
+ if (PicoCDLoadProgressCB != NULL)
+ PicoCDLoadProgressCB(cd_img_name, 100);
+
+ return 0;
+}
+
+// vim:shiftwidth=2:ts=2:expandtab
+++ /dev/null
-/***********************************************************\r
- * *\r
- * This source file was taken from the Gens project *\r
- * Written by Stéphane Dallongeville *\r
- * Copyright (c) 2002 by Stéphane Dallongeville *\r
- * Modified/adapted for PicoDrive by notaz, 2007 *\r
- * *\r
- ***********************************************************/\r
-\r
-#include <stdio.h>\r
-\r
-#include "../pico_int.h"\r
-#include "cd_sys.h"\r
-#include "cd_file.h"\r
-\r
-#define DEBUG_CD\r
-\r
-#define TRAY_OPEN 0x0500 // TRAY OPEN CDD status\r
-#define NOCD 0x0000 // CD removed CDD status\r
-#define STOPPED 0x0900 // STOPPED CDD status (happen after stop or close tray command)\r
-#define READY 0x0400 // READY CDD status (also used for seeking)\r
-#define FAST_FOW 0x0300 // FAST FORWARD track CDD status\r
-#define FAST_REV 0x10300 // FAST REVERSE track CDD status\r
-#define PLAYING 0x0100 // PLAYING audio track CDD status\r
-\r
-//#undef cdprintf\r
-//#define cdprintf(x, ...) elprintf(EL_STATUS, x, ##__VA_ARGS__)\r
-\r
-#define CDC_Update_Header()\r
-\r
-static int CD_Present = 0;\r
-\r
-\r
-#define CHECK_TRAY_OPEN \\r
-if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) \\r
-{ \\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \\r
- \\r
- Pico_mcd->cdd.Minute = 0; \\r
- Pico_mcd->cdd.Seconde = 0; \\r
- Pico_mcd->cdd.Frame = 0; \\r
- Pico_mcd->cdd.Ext = 0; \\r
- \\r
- Pico_mcd->scd.CDD_Complete = 1; \\r
- \\r
- return 2; \\r
-}\r
-\r
-\r
-#define CHECK_CD_PRESENT \\r
-if (!CD_Present) \\r
-{ \\r
- Pico_mcd->scd.Status_CDD = NOCD; \\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \\r
- \\r
- Pico_mcd->cdd.Minute = 0; \\r
- Pico_mcd->cdd.Seconde = 0; \\r
- Pico_mcd->cdd.Frame = 0; \\r
- Pico_mcd->cdd.Ext = 0; \\r
- \\r
- Pico_mcd->scd.CDD_Complete = 1; \\r
- \\r
- return 3; \\r
-}\r
-\r
-\r
-static int MSF_to_LBA(_msf *MSF)\r
-{\r
- return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;\r
-}\r
-\r
-\r
-PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF)\r
-{\r
- if (lba < -150) lba = 0;\r
- else lba += 150;\r
- MSF->M = lba / (60 * 75);\r
- MSF->S = (lba / 75) % 60;\r
- MSF->F = lba % 75;\r
-}\r
-\r
-\r
-static unsigned int MSF_to_Track(_msf *MSF)\r
-{\r
- int i, Start, Cur;\r
-\r
- Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;\r
-\r
- for(i = 1; i <= (Pico_mcd->TOC.Last_Track + 1); i++)\r
- {\r
- Cur = Pico_mcd->TOC.Tracks[i - 1].MSF.M << 16;\r
- Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.S << 8;\r
- Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.F;\r
-\r
- if (Cur > Start) break;\r
- }\r
-\r
- --i;\r
-\r
- if (i > Pico_mcd->TOC.Last_Track) return 100;\r
- else if (i < 1) i = 1;\r
-\r
- return (unsigned) i;\r
-}\r
-\r
-\r
-static unsigned int LBA_to_Track(int lba)\r
-{\r
- _msf MSF;\r
-\r
- LBA_to_MSF(lba, &MSF);\r
- return MSF_to_Track(&MSF);\r
-}\r
-\r
-\r
-static void Track_to_MSF(int track, _msf *MSF)\r
-{\r
- if (track < 1) track = 1;\r
- else if (track > Pico_mcd->TOC.Last_Track) track = Pico_mcd->TOC.Last_Track;\r
-\r
- MSF->M = Pico_mcd->TOC.Tracks[track - 1].MSF.M;\r
- MSF->S = Pico_mcd->TOC.Tracks[track - 1].MSF.S;\r
- MSF->F = Pico_mcd->TOC.Tracks[track - 1].MSF.F;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Track_to_LBA(int track)\r
-{\r
- _msf MSF;\r
-\r
- Track_to_MSF(track, &MSF);\r
- return MSF_to_LBA(&MSF);\r
-}\r
-\r
-\r
-PICO_INTERNAL void Check_CD_Command(void)\r
-{\r
- cdprintf("CHECK CD COMMAND");\r
-\r
- // Check CDC\r
- if (Pico_mcd->scd.Status_CDC & 1) // CDC is reading data ...\r
- {\r
- cdprintf("Got a read command");\r
-\r
- // DATA ?\r
- if (Pico_mcd->scd.Cur_Track == 1) {\r
- Pico_mcd->s68k_regs[0x36] |= 0x01;\r
-\r
- if (Pico_mcd->scd.File_Add_Delay == 0)\r
- {\r
- unsigned char header[4];\r
- _msf MSF;\r
-\r
- LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
-\r
- header[0] = INT_TO_BCDB(MSF.M);\r
- header[1] = INT_TO_BCDB(MSF.S);\r
- header[2] = INT_TO_BCDB(MSF.F);\r
- header[3] = 0x01;\r
-\r
- //FILE_Read_One_LBA_CDC();\r
- Pico_mcd->scd.Cur_LBA +=\r
- cdc_decoder_update(header);\r
- }\r
- else Pico_mcd->scd.File_Add_Delay--;\r
- }\r
- else {\r
- Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO\r
- unsigned char header[4] = { 0, };\r
- cdc_decoder_update(header);\r
- }\r
- }\r
-\r
- // Check CDD\r
- if (Pico_mcd->scd.CDD_Complete)\r
- {\r
- Pico_mcd->scd.CDD_Complete = 0;\r
-\r
- CDD_Export_Status();\r
- }\r
-\r
- if (Pico_mcd->scd.Status_CDD == FAST_FOW)\r
- {\r
- Pico_mcd->scd.Cur_LBA += 10;\r
- CDC_Update_Header();\r
-\r
- }\r
- else if (Pico_mcd->scd.Status_CDD == FAST_REV)\r
- {\r
- Pico_mcd->scd.Cur_LBA -= 10;\r
- if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;\r
- CDC_Update_Header();\r
- }\r
-}\r
-\r
-\r
-PICO_INTERNAL int Init_CD_Driver(void)\r
-{\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL void End_CD_Driver(void)\r
-{\r
- Unload_ISO();\r
-}\r
-\r
-\r
-PICO_INTERNAL void Reset_CD(void)\r
-{\r
- Pico_mcd->scd.Cur_Track = 0;\r
- Pico_mcd->scd.Cur_LBA = -150;\r
- Pico_mcd->scd.Status_CDC &= ~1;\r
- if (Pico_mcd->scd.Status_CDD != TRAY_OPEN)\r
- Pico_mcd->scd.Status_CDD = CD_Present ? READY : NOCD;\r
- Pico_mcd->scd.CDD_Complete = 0;\r
- Pico_mcd->scd.File_Add_Delay = 0;\r
-}\r
-\r
-\r
-int Insert_CD(const char *cdimg_name, int type)\r
-{\r
- int ret = 1;\r
-\r
- CD_Present = 0;\r
-\r
- if (cdimg_name != NULL && type != CIT_NOT_CD)\r
- {\r
- ret = Load_CD_Image(cdimg_name, type);\r
- if (ret == 0) {\r
- CD_Present = 1;\r
-\r
- if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)\r
- {\r
- if (Pico_mcd->bios[0x122 ^ 1] == '2')\r
- Close_Tray_CDD_cC();\r
- // else bios will issue it\r
- }\r
- else\r
- {\r
- Pico_mcd->scd.Status_CDD = READY;\r
- }\r
- }\r
- }\r
-\r
- if (Pico_mcd->scd.Status_CDD != TRAY_OPEN && !CD_Present)\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
-\r
- return ret;\r
-}\r
-\r
-\r
-int Stop_CD(void)\r
-{\r
- int ret = CD_Present;\r
-\r
- Unload_ISO();\r
- CD_Present = 0;\r
-\r
- return ret;\r
-}\r
-\r
-\r
-/*\r
-PICO_INTERNAL void Change_CD(void)\r
-{\r
- if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();\r
- else Open_Tray_CDD_cD();\r
-}\r
-*/\r
-\r
-PICO_INTERNAL int Get_Status_CDD_c0(void)\r
-{\r
- cdprintf("Status command : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
-\r
- // Clear immediat status\r
- if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)\r
- Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
- else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)\r
- Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
- else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)\r
- Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Stop_CDD_c1(void)\r
-{\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read\r
-\r
- if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;\r
- else Pico_mcd->scd.Status_CDD = NOCD;\r
- Pico_mcd->cdd.Status = 0x0000;\r
-\r
- Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Pos_CDD_c20(void)\r
-{\r
- _msf MSF;\r
-\r
- cdprintf("command 200 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
-\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->cdd.Status &= 0xFF;\r
- if (!CD_Present)\r
- {\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- }\r
-// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
- cdprintf("Status CDD = %.4X Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
-\r
- LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
- Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
- Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Track_Pos_CDD_c21(void)\r
-{\r
- int elapsed_time;\r
- _msf MSF;\r
-\r
- cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
-\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->cdd.Status &= 0xFF;\r
- if (!CD_Present)\r
- {\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- }\r
-// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
- elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));\r
- LBA_to_MSF(elapsed_time - 150, &MSF);\r
-\r
- cdprintf(" elapsed = %d", elapsed_time);\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
- Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
- Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Current_Track_CDD_c22(void)\r
-{\r
- cdprintf("Status CDD = %.4X Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
-\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->cdd.Status &= 0xFF;\r
- if (!CD_Present)\r
- {\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- }\r
-// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
- Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
-\r
- if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
- else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void)\r
-{\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->cdd.Status &= 0xFF;\r
- if (!CD_Present)\r
- {\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- }\r
-// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.M);\r
- Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.S);\r
- Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.F);\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void)\r
-{\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->cdd.Status &= 0xFF;\r
- if (!CD_Present)\r
- {\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
- }\r
-// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(1);\r
- Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Last_Track);\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Get_Track_Adr_CDD_c25(void)\r
-{\r
- int track_number;\r
-\r
- CHECK_TRAY_OPEN\r
-\r
- // track number in TC4 & TC5\r
-\r
- track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
-\r
- Pico_mcd->cdd.Status &= 0xFF;\r
- if (!CD_Present)\r
- {\r
- Pico_mcd->scd.Status_CDD = NOCD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- }\r
-// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
- Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
-\r
- if (track_number > Pico_mcd->TOC.Last_Track) track_number = Pico_mcd->TOC.Last_Track;\r
- else if (track_number < 1) track_number = 1;\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.M);\r
- Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.S);\r
- Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.F);\r
- Pico_mcd->cdd.Ext = track_number % 10;\r
-\r
- if (track_number == 1) Pico_mcd->cdd.Frame |= 0x0800; // data track\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Play_CDD_c3(void)\r
-{\r
- _msf MSF;\r
- int delay, new_lba;\r
-\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- // MSF of the track to play in TC buffer\r
-\r
- MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
- MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
- MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
-\r
- Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
-\r
- new_lba = MSF_to_LBA(&MSF);\r
- delay = new_lba - Pico_mcd->scd.Cur_LBA;\r
- if (delay < 0) delay = -delay;\r
- delay >>= 12;\r
-\r
- if (Pico_mcd->scd.Cur_LBA > 0 && delay < 13)\r
- // based on genplus GX\r
- delay = 13;\r
-\r
- Pico_mcd->scd.Cur_LBA = new_lba;\r
- CDC_Update_Header();\r
-\r
- cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
-\r
- if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;\r
-\r
- Pico_mcd->scd.Status_CDD = PLAYING;\r
- Pico_mcd->cdd.Status = 0x0102;\r
-// Pico_mcd->cdd.Status = COMM_OK;\r
-\r
- if (Pico_mcd->scd.File_Add_Delay == 0) Pico_mcd->scd.File_Add_Delay = delay;\r
-\r
- if (Pico_mcd->scd.Cur_Track == 1)\r
- {\r
- Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA\r
- }\r
- else\r
- {\r
- Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO\r
- cdda_start_play();\r
- }\r
-\r
- if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
- else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Seek_CDD_c4(void)\r
-{\r
- _msf MSF;\r
-\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- // MSF to seek in TC buffer\r
-\r
- MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
- MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
- MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
-\r
- Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
- Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);\r
- CDC_Update_Header();\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read\r
-\r
- Pico_mcd->scd.Status_CDD = READY;\r
- Pico_mcd->cdd.Status = 0x0200;\r
-\r
- // DATA ?\r
- if (Pico_mcd->scd.Cur_Track == 1)\r
- Pico_mcd->s68k_regs[0x36] |= 0x01;\r
- else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Pause_CDD_c6(void)\r
-{\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read to start a new one if raw data\r
-\r
- Pico_mcd->scd.Status_CDD = READY;\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
-\r
- Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Resume_CDD_c7(void)\r
-{\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
-\r
-#ifdef DEBUG_CD\r
- {\r
- _msf MSF;\r
- LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
- cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
- }\r
-#endif\r
-\r
- Pico_mcd->scd.Status_CDD = PLAYING;\r
- Pico_mcd->cdd.Status = 0x0102;\r
-\r
- if (Pico_mcd->scd.Cur_Track == 1)\r
- {\r
- Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA\r
- }\r
- else\r
- {\r
- Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO\r
- cdda_start_play();\r
- }\r
-\r
- if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
- else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Fast_Foward_CDD_c8(void)\r
-{\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read\r
-\r
- Pico_mcd->scd.Status_CDD = FAST_FOW;\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Fast_Rewind_CDD_c9(void)\r
-{\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read\r
-\r
- Pico_mcd->scd.Status_CDD = FAST_REV;\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
-\r
- Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Close_Tray_CDD_cC(void)\r
-{\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read\r
-\r
- elprintf(EL_STATUS, "tray close\n");\r
-\r
- if (PicoMCDcloseTray != NULL)\r
- PicoMCDcloseTray();\r
-\r
- Pico_mcd->scd.Status_CDD = CD_Present ? STOPPED : NOCD;\r
- Pico_mcd->cdd.Status = 0x0000;\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int Open_Tray_CDD_cD(void)\r
-{\r
- CHECK_TRAY_OPEN\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read\r
-\r
- elprintf(EL_STATUS, "tray open\n");\r
-\r
- Unload_ISO();\r
- CD_Present = 0;\r
-\r
- if (PicoMCDopenTray != NULL)\r
- PicoMCDopenTray();\r
-\r
- Pico_mcd->scd.Status_CDD = TRAY_OPEN;\r
- Pico_mcd->cdd.Status = 0x0E00;\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int CDD_cA(void)\r
-{\r
- CHECK_TRAY_OPEN\r
- CHECK_CD_PRESENT\r
-\r
- Pico_mcd->scd.Status_CDC &= ~1;\r
-\r
- Pico_mcd->scd.Status_CDD = READY;\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);\r
- Pico_mcd->cdd.Frame = INT_TO_BCDW(1);\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- Pico_mcd->scd.CDD_Complete = 1;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-PICO_INTERNAL int CDD_Def(void)\r
-{\r
- Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
-\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- return 0;\r
-}\r
-\r
-\r
-static int bswapwrite(int a, unsigned short d)\r
-{\r
- *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);\r
- return d + (d >> 8);\r
-}\r
-\r
-PICO_INTERNAL void CDD_Export_Status(void)\r
-{\r
- unsigned int csum;\r
-\r
- csum = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);\r
- csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);\r
- csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);\r
- csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);\r
- Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;\r
- csum += Pico_mcd->cdd.Ext;\r
- Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;\r
-\r
- Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control\r
-\r
- if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)\r
- {\r
- elprintf(EL_INTS, "cdd export irq 4");\r
- SekInterruptS68k(4);\r
- }\r
-\r
-// cdprintf("CDD exported status\n");\r
- cdprintf("out: Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X",\r
- (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],\r
- (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],\r
- (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],\r
- (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],\r
- (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);\r
-}\r
-\r
-\r
-PICO_INTERNAL void CDD_Import_Command(void)\r
-{\r
-// cdprintf("CDD importing command\n");\r
- cdprintf("in: Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X",\r
- (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],\r
- (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],\r
- (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],\r
- (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],\r
- (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);\r
-\r
- switch (Pico_mcd->s68k_regs[0x38+10+0])\r
- {\r
- case 0x0: // STATUS (?)\r
- Get_Status_CDD_c0();\r
- break;\r
-\r
- case 0x1: // STOP ALL (?)\r
- Stop_CDD_c1();\r
- break;\r
-\r
- case 0x2: // GET TOC INFORMATIONS\r
- switch(Pico_mcd->s68k_regs[0x38+10+3])\r
- {\r
- case 0x0: // get current position (MSF format)\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);\r
- Get_Pos_CDD_c20();\r
- break;\r
-\r
- case 0x1: // get elapsed time of current track played/scanned (relative MSF format)\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;\r
- Get_Track_Pos_CDD_c21();\r
- break;\r
-\r
- case 0x2: // get current track in RS2-RS3\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 2;\r
- Get_Current_Track_CDD_c22();\r
- break;\r
-\r
- case 0x3: // get total length (MSF format)\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;\r
- Get_Total_Lenght_CDD_c23();\r
- break;\r
-\r
- case 0x4: // first & last track number\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;\r
- Get_First_Last_Track_CDD_c24();\r
- break;\r
-\r
- case 0x5: // get track addresse (MSF format)\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;\r
- Get_Track_Adr_CDD_c25();\r
- break;\r
-\r
- default : // invalid, then we return status\r
- Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;\r
- Get_Status_CDD_c0();\r
- break;\r
- }\r
- break;\r
-\r
- case 0x3: // READ\r
- Play_CDD_c3();\r
- break;\r
-\r
- case 0x4: // SEEK\r
- Seek_CDD_c4();\r
- break;\r
-\r
- case 0x6: // PAUSE/STOP\r
- Pause_CDD_c6();\r
- break;\r
-\r
- case 0x7: // RESUME\r
- Resume_CDD_c7();\r
- break;\r
-\r
- case 0x8: // FAST FOWARD\r
- Fast_Foward_CDD_c8();\r
- break;\r
-\r
- case 0x9: // FAST REWIND\r
- Fast_Rewind_CDD_c9();\r
- break;\r
-\r
- case 0xA: // RECOVER INITIAL STATE (?)\r
- CDD_cA();\r
- break;\r
-\r
- case 0xC: // CLOSE TRAY\r
- Close_Tray_CDD_cC();\r
- break;\r
-\r
- case 0xD: // OPEN TRAY\r
- Open_Tray_CDD_cD();\r
- break;\r
-\r
- default: // UNKNOWN\r
- CDD_Def();\r
- break;\r
- }\r
-}\r
-\r
-void CDD_Reset(void)\r
-{\r
- // Reseting CDD\r
-\r
- memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control\r
- Pico_mcd->cdd.Status = 0;\r
- Pico_mcd->cdd.Minute = 0;\r
- Pico_mcd->cdd.Seconde = 0;\r
- Pico_mcd->cdd.Frame = 0;\r
- Pico_mcd->cdd.Ext = 0;\r
-\r
- // clear receive status and transfer command\r
- memset(Pico_mcd->s68k_regs+0x38, 0, 20);\r
- Pico_mcd->s68k_regs[0x38+9] = 0xF; // Default checksum\r
-}\r
-\r
-\r
+++ /dev/null
-/***********************************************************\r
- * *\r
- * This source was taken from the Gens project *\r
- * Written by Stéphane Dallongeville *\r
- * Copyright (c) 2002 by Stéphane Dallongeville *\r
- * Modified/adapted for PicoDrive by notaz, 2007 *\r
- * *\r
- ***********************************************************/\r
-\r
-#ifndef _CD_SYS_H\r
-#define _CD_SYS_H\r
-\r
-#include "cd_file.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-\r
-#define INT_TO_BCDB(c) \\r
-((c) > 99)?(0x99):((((c) / 10) << 4) + ((c) % 10));\r
-\r
-#define INT_TO_BCDW(c) \\r
-((c) > 99)?(0x0909):((((c) / 10) << 8) + ((c) % 10));\r
-\r
-#define BCDB_TO_INT(c) \\r
-(((c) >> 4) * 10) + ((c) & 0xF);\r
-\r
-#define BCDW_TO_INT(c) \\r
-(((c) >> 8) * 10) + ((c) & 0xF);\r
-\r
-\r
-typedef struct\r
-{\r
- unsigned char M;\r
- unsigned char S;\r
- unsigned char F;\r
-} _msf;\r
-\r
-typedef struct\r
-{\r
- _msf MSF;\r
- //\r
- char ftype; // cue_track_type\r
- void *F;\r
- int Length;\r
- int Offset; // sector offset, when single file is used for multiple virtual tracks\r
- short KBtps; // kbytes per sec for mp3s (bitrate / 1000 / 8)\r
- short pad;\r
-} _scd_track;\r
-\r
-typedef struct\r
-{\r
-// unsigned char First_Track; // always 1\r
- _scd_track Tracks[100];\r
- unsigned int Last_Track;\r
-} _scd_toc;\r
-\r
-typedef struct {\r
- unsigned int Status_CDD;\r
- unsigned int Status_CDC;\r
- int Cur_LBA;\r
- unsigned int Cur_Track;\r
- int File_Add_Delay;\r
- char CDD_Complete;\r
- int pad[6];\r
-} _scd;\r
-\r
-\r
-PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF);\r
-PICO_INTERNAL int Track_to_LBA(int track);\r
-\r
-// moved to pico.h\r
-// int Insert_CD(char *iso_name, int is_bin);\r
-// void Stop_CD(void);\r
-\r
-PICO_INTERNAL void Check_CD_Command(void);\r
-\r
-PICO_INTERNAL int Init_CD_Driver(void);\r
-PICO_INTERNAL void End_CD_Driver(void);\r
-PICO_INTERNAL void Reset_CD(void);\r
-\r
-PICO_INTERNAL int Get_Status_CDD_c0(void);\r
-PICO_INTERNAL int Stop_CDD_c1(void);\r
-PICO_INTERNAL int Get_Pos_CDD_c20(void);\r
-PICO_INTERNAL int Get_Track_Pos_CDD_c21(void);\r
-PICO_INTERNAL int Get_Current_Track_CDD_c22(void);\r
-PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void);\r
-PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void);\r
-PICO_INTERNAL int Get_Track_Adr_CDD_c25(void);\r
-PICO_INTERNAL int Play_CDD_c3(void);\r
-PICO_INTERNAL int Seek_CDD_c4(void);\r
-PICO_INTERNAL int Pause_CDD_c6(void);\r
-PICO_INTERNAL int Resume_CDD_c7(void);\r
-PICO_INTERNAL int Fast_Foward_CDD_c8(void);\r
-PICO_INTERNAL int Fast_Rewind_CDD_c9(void);\r
-PICO_INTERNAL int CDD_cA(void);\r
-PICO_INTERNAL int Close_Tray_CDD_cC(void);\r
-PICO_INTERNAL int Open_Tray_CDD_cD(void);\r
-\r
-PICO_INTERNAL int CDD_Def(void);\r
-\r
-\r
-#ifdef __cplusplus\r
-};\r
-#endif\r
-\r
-#endif\r
-\r
Pico_mcd->s68k_regs[0x0b] = dma_addr;
}
-// tmp
-static void cdd_read_data(uint8 *dst)
-{
- int lba = Pico_mcd->scd.Cur_LBA;
-
- /* only read DATA track sectors */
- if (0 <= lba && lba < Pico_mcd->TOC.Tracks[0].Length)
- {
- /* read sector data (Mode 1 = 2048 bytes) */
- PicoCDBufferRead(dst, lba);
- }
-}
-
void cdc_dma_update(void)
{
/* end of DMA transfer ? */
--- /dev/null
+/***************************************************************************************
+ * Genesis Plus
+ * CD drive processor & CD-DA fader
+ *
+ * Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
+ *
+ * Redistribution and use of this code or any derivative works are permitted
+ * provided that the following conditions are met:
+ *
+ * - Redistributions may not be sold, nor may they be used in a commercial
+ * product or activity.
+ *
+ * - Redistributions that are modified from the original source must include the
+ * complete source code, including the source code for all components used by a
+ * binary built from the modified sources. However, as a special exception, the
+ * source code distributed need not include anything that is normally distributed
+ * (in either source or binary form) with the major components (compiler, kernel,
+ * and so on) of the operating system on which the executable runs, unless that
+ * component itself accompanies the executable.
+ *
+ * - Redistributions must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************************/
+
+#include "../pico_int.h"
+#include "genplus_macros.h"
+#include "cue.h"
+#include "cdd.h"
+
+#ifdef USE_LIBTREMOR
+#define SUPPORTED_EXT 20
+#else
+#define SUPPORTED_EXT 10
+#endif
+
+cdd_t cdd;
+
+/* BCD conversion lookup tables */
+static const uint8 lut_BCD_8[100] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+};
+
+static const uint16 lut_BCD_16[100] =
+{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
+ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109,
+ 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309,
+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
+ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509,
+ 0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, 0x0609,
+ 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709,
+ 0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809,
+ 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909,
+};
+
+/* pre-build TOC */
+static const uint16 toc_snatcher[21] =
+{
+ 56014, 495, 10120, 20555, 1580, 5417, 12502, 16090, 6553, 9681,
+ 8148, 20228, 8622, 6142, 5858, 1287, 7424, 3535, 31697, 2485,
+ 31380
+};
+
+static const uint16 toc_lunar[52] =
+{
+ 5422, 1057, 7932, 5401, 6380, 6592, 5862, 5937, 5478, 5870,
+ 6673, 6613, 6429, 4996, 4977, 5657, 3720, 5892, 3140, 3263,
+ 6351, 5187, 3249, 1464, 1596, 1750, 1751, 6599, 4578, 5205,
+ 1550, 1827, 2328, 1346, 1569, 1613, 7199, 4928, 1656, 2549,
+ 1875, 3901, 1850, 2399, 2028, 1724, 4889, 14551, 1184, 2132,
+ 685, 3167
+};
+
+static const uint32 toc_shadow[15] =
+{
+ 10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
+ 11637, 2547, 2521, 3856, 900
+};
+
+static const uint32 toc_dungeon[13] =
+{
+ 2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
+ 3325, 6825, 25275
+};
+
+static const uint32 toc_ffight[26] =
+{
+ 11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764,
+ 9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024,
+ 14562, 10320, 8627, 3795, 3047
+};
+
+static const uint32 toc_ffightj[29] =
+{
+ 11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763,
+ 9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026,
+ 14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
+};
+
+/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
+static const unsigned char waveHeader[32] =
+{
+ 0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
+ 0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
+};
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+static void ogg_free(int i)
+{
+ /* clear OGG file descriptor to prevent file from being closed */
+ cdd.toc.tracks[i].vf.datasource = NULL;
+
+ /* close VORBIS file structure */
+ ov_clear(&cdd.toc.tracks[i].vf);
+
+ /* indicates that the track is a seekable VORBIS file */
+ cdd.toc.tracks[i].vf.seekable = 1;
+
+ /* reset file reading position */
+ fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET);
+}
+#endif
+#endif
+
+void cdd_reset(void)
+{
+ /* reset cycle counter */
+ cdd.cycles = 0;
+
+ /* reset drive access latency */
+ cdd.latency = 0;
+
+ /* reset track index */
+ cdd.index = 0;
+
+ /* reset logical block address */
+ cdd.lba = 0;
+
+ /* reset status */
+ cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
+
+ /* reset CD-DA fader (full volume) */
+ cdd.volume = 0x400;
+
+ /* clear CD-DA output */
+ cdd.audio[0] = cdd.audio[1] = 0;
+}
+
+/* FIXME: use cdd_read_audio() instead */
+static void cdd_change_track(int index, int lba)
+{
+ int i, base, lba_offset, lb_len;
+
+ for (i = index; i > 0; i--)
+ if (cdd.toc.tracks[i].fd != NULL)
+ break;
+
+ Pico_mcd->cdda_stream = cdd.toc.tracks[i].fd;
+ base = cdd.toc.tracks[index].offset;
+ lba_offset = lba - cdd.toc.tracks[index].start;
+ lb_len = cdd.toc.tracks[index].end - cdd.toc.tracks[index].start;
+
+ elprintf(EL_CD, "play #%d lba %d base %d", index, lba, base);
+
+ cdda_start_play(base, lba_offset, lb_len);
+}
+
+int cdd_context_save(uint8 *state)
+{
+ int bufferptr = 0;
+
+ save_param(&cdd.cycles, sizeof(cdd.cycles));
+ save_param(&cdd.latency, sizeof(cdd.latency));
+ save_param(&cdd.index, sizeof(cdd.index));
+ save_param(&cdd.lba, sizeof(cdd.lba));
+ save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
+ save_param(&cdd.volume, sizeof(cdd.volume));
+ save_param(&cdd.status, sizeof(cdd.status));
+
+ return bufferptr;
+}
+
+int cdd_context_load(uint8 *state)
+{
+ int lba;
+ int bufferptr = 0;
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* close previous track VORBIS file structure to save memory */
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ ogg_free(cdd.index);
+ }
+#endif
+#endif
+
+ load_param(&cdd.cycles, sizeof(cdd.cycles));
+ load_param(&cdd.latency, sizeof(cdd.latency));
+ load_param(&cdd.index, sizeof(cdd.index));
+ load_param(&cdd.lba, sizeof(cdd.lba));
+ load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
+ load_param(&cdd.volume, sizeof(cdd.volume));
+ load_param(&cdd.status, sizeof(cdd.status));
+
+ /* adjust current LBA within track limit */
+ lba = cdd.lba;
+ if (lba < cdd.toc.tracks[cdd.index].start)
+ {
+ lba = cdd.toc.tracks[cdd.index].start;
+ }
+
+ /* seek to current track position */
+ if (!cdd.index)
+ {
+ /* DATA track */
+ if (cdd.toc.tracks[0].fd)
+ {
+ pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
+ }
+ }
+#ifdef USE_LIBTREMOR
+ else if (cdd.toc.tracks[cdd.index].vf.seekable)
+ {
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* VORBIS file need to be opened first */
+ ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
+#endif
+ /* VORBIS AUDIO track */
+ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
+ }
+#endif
+#if 0
+ else if (cdd.toc.tracks[cdd.index].fd)
+ {
+ /* PCM AUDIO track */
+ fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
+ }
+#else
+ else
+ {
+ cdd_change_track(cdd.index, lba);
+ }
+#endif
+
+ return bufferptr;
+}
+
+int cdd_context_load_old(uint8 *state)
+{
+ memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
+ return 12 * 4;
+}
+
+int cdd_load(const char *filename, int type)
+{
+ char header[0x210];
+ int ret;
+
+ /* first unmount any loaded disc */
+ cdd_unload();
+
+ /* genplus parses cue here, in PD we use our own parser */
+ ret = load_cd_image(filename, &type);
+ if (ret != 0)
+ return ret;
+
+ /* read first 16 bytes */
+ pm_read(header, 0x10, cdd.toc.tracks[0].fd);
+
+ /* look for valid CD image ID string */
+ if (memcmp("SEGADISCSYSTEM", header, 14))
+ {
+ /* if not found, read next 16 bytes */
+ pm_read(header, 0x10, cdd.toc.tracks[0].fd);
+
+ /* look again for valid CD image ID string */
+ if (memcmp("SEGADISCSYSTEM", header, 14))
+ {
+ elprintf(EL_STATUS|EL_ANOMALY, "cd: bad cd image?");
+ /* assume bin without security code */
+ }
+
+ /* BIN format (2352 bytes data blocks) */
+ cdd.sectorSize = 2352;
+ }
+ else
+ {
+ /* ISO format (2048 bytes data blocks) */
+ cdd.sectorSize = 2048;
+ }
+
+ ret = (type == CT_BIN) ? 2352 : 2048;
+ if (ret != cdd.sectorSize)
+ elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
+
+ /* read CD image header + security code */
+ pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
+
+ /* Simulate audio tracks if none found */
+ if (cdd.toc.last == 1)
+ {
+ /* Some games require exact TOC infos */
+ if (strstr(header + 0x180,"T-95035") != NULL)
+ {
+ /* Snatcher */
+ cdd.toc.last = cdd.toc.end = 0;
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_snatcher[cdd.toc.last];
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while (cdd.toc.last < 21);
+ }
+ else if (strstr(header + 0x180,"T-127015") != NULL)
+ {
+ /* Lunar - The Silver Star */
+ cdd.toc.last = cdd.toc.end = 0;
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_lunar[cdd.toc.last];
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while (cdd.toc.last < 52);
+ }
+ else if (strstr(header + 0x180,"T-113045") != NULL)
+ {
+ /* Shadow of the Beast II */
+ cdd.toc.last = cdd.toc.end = 0;
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last];
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while (cdd.toc.last < 15);
+ }
+ else if (strstr(header + 0x180,"T-143025") != NULL)
+ {
+ /* Dungeon Explorer */
+ cdd.toc.last = cdd.toc.end = 0;
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_dungeon[cdd.toc.last];
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while (cdd.toc.last < 13);
+ }
+ else if (strstr(header + 0x180,"MK-4410") != NULL)
+ {
+ /* Final Fight CD (USA, Europe) */
+ cdd.toc.last = cdd.toc.end = 0;
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffight[cdd.toc.last];
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while (cdd.toc.last < 26);
+ }
+ else if (strstr(header + 0x180,"G-6013") != NULL)
+ {
+ /* Final Fight CD (Japan) */
+ cdd.toc.last = cdd.toc.end = 0;
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffightj[cdd.toc.last];
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while (cdd.toc.last < 29);
+ }
+#if 0
+ else
+ {
+ /* default TOC (99 tracks & 2s per audio tracks) */
+ do
+ {
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + 2*75;
+ cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + 2*75;
+ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
+ cdd.toc.last++;
+ }
+ while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
+ }
+#endif
+ }
+
+ /* Lead-out */
+ cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
+
+ /* CD loaded */
+ cdd.loaded = 1;
+ return 0;
+}
+
+int cdd_unload(void)
+{
+ int was_loaded = cdd.loaded;
+
+ if (cdd.loaded)
+ {
+ int i;
+
+ /* close CD tracks */
+ if (cdd.toc.tracks[0].fd)
+ {
+ pm_close(cdd.toc.tracks[0].fd);
+ cdd.toc.tracks[0].fd = NULL;
+ }
+
+ for (i = 1; i < cdd.toc.last; i++)
+ {
+#ifdef USE_LIBTREMOR
+ if (cdd.toc.tracks[i].vf.datasource)
+ {
+ /* close VORBIS file (if still opened) */
+ ov_clear(&cdd.toc.tracks[i].vf);
+ }
+ else
+#endif
+ if (cdd.toc.tracks[i].fd)
+ {
+ /* close file */
+ if (Pico_mcd->cdda_type == CT_MP3)
+ fclose(cdd.toc.tracks[i].fd);
+ else
+ pm_close(cdd.toc.tracks[0].fd);
+
+ /* detect single file images */
+ if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
+ {
+ /* exit loop */
+ i = cdd.toc.last;
+ }
+ }
+ }
+
+ /* CD unloaded */
+ cdd.loaded = 0;
+ }
+
+ /* reset TOC */
+ memset(&cdd.toc, 0x00, sizeof(cdd.toc));
+
+ /* unknown CD image file format */
+ cdd.sectorSize = 0;
+
+ return was_loaded;
+}
+
+void cdd_read_data(uint8 *dst)
+{
+ /* only read DATA track sectors */
+ if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
+ {
+ /* BIN format ? */
+ if (cdd.sectorSize == 2352)
+ {
+ /* skip 16-byte header */
+ pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
+ }
+
+ /* read sector data (Mode 1 = 2048 bytes) */
+ pm_read(dst, 2048, cdd.toc.tracks[0].fd);
+ }
+}
+
+#if 0
+void cdd_read_audio(unsigned int samples)
+{
+ /* previous audio outputs */
+ int16 l = cdd.audio[0];
+ int16 r = cdd.audio[1];
+
+ /* get number of internal clocks (samples) needed */
+ samples = blip_clocks_needed(blip[0], samples);
+
+ /* audio track playing ? */
+ if (!Pico_mcd->regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
+ {
+ int i, mul, delta;
+
+ /* current CD-DA fader volume */
+ int curVol = cdd.volume;
+
+ /* CD-DA fader volume setup (0-1024) */
+ int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
+
+ /* read samples from current block */
+#ifdef USE_LIBTREMOR
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ int len, done = 0;
+ int16 *ptr = (int16 *) (cdc.ram);
+ samples = samples * 4;
+ while (done < samples)
+ {
+ len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
+ if (len <= 0)
+ {
+ done = samples;
+ break;
+ }
+ done += len;
+ }
+ samples = done / 4;
+
+ /* process 16-bit (host-endian) stereo samples */
+ for (i=0; i<samples; i++)
+ {
+ /* CD-DA fader multiplier (cf. LC7883 datasheet) */
+ /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
+ mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
+
+ /* left channel */
+ delta = ((ptr[0] * mul) / 1024) - l;
+ ptr++;
+ l += delta;
+ blip_add_delta_fast(blip[0], i, delta);
+
+ /* right channel */
+ delta = ((ptr[0] * mul) / 1024) - r;
+ ptr++;
+ r += delta;
+ blip_add_delta_fast(blip[1], i, delta);
+
+ /* update CD-DA fader volume (one step/sample) */
+ if (curVol < endVol)
+ {
+ /* fade-in */
+ curVol++;
+ }
+ else if (curVol > endVol)
+ {
+ /* fade-out */
+ curVol--;
+ }
+ else if (!curVol)
+ {
+ /* audio will remain muted until next setup */
+ break;
+ }
+ }
+ }
+ else
+#endif
+ {
+#ifdef LSB_FIRST
+ int16 *ptr = (int16 *) (cdc.ram);
+#else
+ uint8 *ptr = cdc.ram;
+#endif
+ fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
+
+ /* process 16-bit (little-endian) stereo samples */
+ for (i=0; i<samples; i++)
+ {
+ /* CD-DA fader multiplier (cf. LC7883 datasheet) */
+ /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
+ mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
+
+ /* left channel */
+ #ifdef LSB_FIRST
+ delta = ((ptr[0] * mul) / 1024) - l;
+ ptr++;
+ #else
+ delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
+ ptr += 2;
+ #endif
+ l += delta;
+ blip_add_delta_fast(blip[0], i, delta);
+
+ /* right channel */
+ #ifdef LSB_FIRST
+ delta = ((ptr[0] * mul) / 1024) - r;
+ ptr++;
+ #else
+ delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
+ ptr += 2;
+ #endif
+ r += delta;
+ blip_add_delta_fast(blip[1], i, delta);
+
+ /* update CD-DA fader volume (one step/sample) */
+ if (curVol < endVol)
+ {
+ /* fade-in */
+ curVol++;
+ }
+ else if (curVol > endVol)
+ {
+ /* fade-out */
+ curVol--;
+ }
+ else if (!curVol)
+ {
+ /* audio will remain muted until next setup */
+ break;
+ }
+ }
+ }
+
+ /* save current CD-DA fader volume */
+ cdd.volume = curVol;
+
+ /* save last audio output for next frame */
+ cdd.audio[0] = l;
+ cdd.audio[1] = r;
+ }
+ else
+ {
+ /* no audio output */
+ if (l) blip_add_delta_fast(blip[0], 0, -l);
+ if (r) blip_add_delta_fast(blip[1], 0, -r);
+
+ /* save audio output for next frame */
+ cdd.audio[0] = 0;
+ cdd.audio[1] = 0;
+ }
+
+ /* end of Blip Buffer timeframe */
+ blip_end_frame(blip[0], samples);
+ blip_end_frame(blip[1], samples);
+}
+#endif
+
+
+void cdd_update(void)
+{
+#ifdef LOG_CDD
+ error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
+#endif
+
+ /* seeking disc */
+ if (cdd.status == CD_SEEK)
+ {
+ /* drive latency */
+ if (cdd.latency > 0)
+ {
+ cdd.latency--;
+ return;
+ }
+
+ /* drive is ready */
+ cdd.status = CD_READY;
+ }
+
+ /* reading disc */
+ else if (cdd.status == CD_PLAY)
+ {
+ /* drive latency */
+ if (cdd.latency > 0)
+ {
+ cdd.latency--;
+ return;
+ }
+
+ /* track type */
+ if (!cdd.index)
+ {
+ /* DATA sector header (CD-ROM Mode 1) */
+ uint8 header[4];
+ uint32 msf = cdd.lba + 150;
+ header[0] = lut_BCD_8[(msf / 75) / 60];
+ header[1] = lut_BCD_8[(msf / 75) % 60];
+ header[2] = lut_BCD_8[(msf % 75)];
+ header[3] = 0x01;
+
+ /* data track sector read is controlled by CDC */
+ cdd.lba += cdc_decoder_update(header);
+ }
+ else if (cdd.index < cdd.toc.last)
+ {
+ uint8 header[4] = { 0, };
+
+ /* check against audio track start index */
+ if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
+ {
+ /* audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x00;
+ }
+
+ /* audio blocks are still sent to CDC as well as CD DAC/Fader */
+ cdc_decoder_update(header);
+
+ /* next audio block is automatically read */
+ cdd.lba++;
+ }
+ else
+ {
+ /* end of disc */
+ cdd.status = CD_END;
+ return;
+ }
+
+ /* check end of current track */
+ if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
+ {
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* close previous track VORBIS file structure to save memory */
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ ogg_free(cdd.index);
+ }
+#endif
+#endif
+ /* play next track */
+ cdd.index++;
+
+ /* PAUSE between tracks */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* seek to next audio track start */
+#ifdef USE_LIBTREMOR
+ if (cdd.toc.tracks[cdd.index].vf.seekable)
+ {
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* VORBIS file need to be opened first */
+ ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
+#endif
+ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset);
+ }
+ else
+#endif
+#if 0
+ if (cdd.toc.tracks[cdd.index].fd)
+ {
+ fseek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
+ }
+#else
+ {
+ cdd_change_track(cdd.index, cdd.lba);
+ }
+#endif
+ }
+ }
+
+ /* scanning disc */
+ else if (cdd.status == CD_SCAN)
+ {
+ /* fast-forward or fast-rewind */
+ cdd.lba += cdd.scanOffset;
+
+ /* check current track limits */
+ if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
+ {
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* close previous track VORBIS file structure to save memory */
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ ogg_free(cdd.index);
+ }
+#endif
+#endif
+ /* next track */
+ cdd.index++;
+
+ /* skip directly to track start position */
+ cdd.lba = cdd.toc.tracks[cdd.index].start;
+
+ /* AUDIO track playing ? */
+ if (cdd.status == CD_PLAY)
+ {
+ Pico_mcd->regs[0x36>>1].byte.h = 0x00;
+ }
+ }
+ else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
+ {
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* close previous track VORBIS file structure to save memory */
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ ogg_free(cdd.index);
+ }
+#endif
+#endif
+
+ /* previous track */
+ cdd.index--;
+
+ /* skip directly to track end position */
+ cdd.lba = cdd.toc.tracks[cdd.index].end;
+ }
+
+ /* check disc limits */
+ if (cdd.index < 0)
+ {
+ cdd.index = 0;
+ cdd.lba = 0;
+ }
+ else if (cdd.index >= cdd.toc.last)
+ {
+ /* no AUDIO track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* end of disc */
+ cdd.index = cdd.toc.last;
+ cdd.lba = cdd.toc.end;
+ cdd.status = CD_END;
+ return;
+ }
+
+ /* seek to current block */
+ if (!cdd.index)
+ {
+ /* no AUDIO track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* DATA track */
+ pm_seek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
+ }
+#ifdef USE_LIBTREMOR
+ else if (cdd.toc.tracks[cdd.index].vf.seekable)
+ {
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* check if a new track is being played */
+ if (!cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ /* VORBIS file need to be opened first */
+ ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
+ }
+#endif
+ /* VORBIS AUDIO track */
+ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
+ }
+#endif
+#if 0
+ else if (cdd.toc.tracks[cdd.index].fd)
+ {
+ /* PCM AUDIO track */
+ fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
+ }
+#else
+ else
+ {
+ cdd_change_track(cdd.index, cdd.lba);
+ }
+#endif
+ }
+}
+
+#define set_reg16(r, v) { \
+ uint16 _v = v; \
+ Pico_mcd->s68k_regs[(r)] = _v >> 8; \
+ Pico_mcd->s68k_regs[(r)+1] = _v; \
+}
+
+void cdd_process(void)
+{
+ /* Process CDD command */
+ switch (Pico_mcd->regs[0x42>>1].byte.h & 0x0f)
+ {
+ case 0x00: /* Drive Status */
+ {
+ /* RS1-RS8 normally unchanged */
+ Pico_mcd->regs[0x38>>1].byte.h = cdd.status;
+
+ /* unless RS1 indicated invalid track infos */
+ if (Pico_mcd->regs[0x38>>1].byte.l == 0x0f)
+ {
+ /* and SEEK has ended */
+ if (cdd.status != CD_SEEK)
+ {
+ /* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
+ Pico_mcd->regs[0x38>>1].byte.l = 0x02;
+ set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
+ }
+ }
+ break;
+ }
+
+ case 0x01: /* Stop Drive */
+ {
+ /* update status */
+ cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
+
+ /* no audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
+ set_reg16(0x38, 0x0000);
+ set_reg16(0x3a, 0x0000);
+ set_reg16(0x3c, 0x0000);
+ set_reg16(0x3e, 0x0000);
+ set_reg16(0x40, 0x000f);
+ return;
+ }
+
+ case 0x02: /* Read TOC */
+ {
+ /* Infos automatically retrieved by CDD processor from Q-Channel */
+ /* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
+ switch (Pico_mcd->regs[0x44>>1].byte.l)
+ {
+ case 0x00: /* Current Absolute Time (MM:SS:FF) */
+ {
+ int lba = cdd.lba + 150;
+ set_reg16(0x38, cdd.status << 8);
+ set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+ set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+ set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+ Pico_mcd->regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
+ break;
+ }
+
+ case 0x01: /* Current Track Relative Time (MM:SS:FF) */
+ {
+ int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
+ set_reg16(0x38, (cdd.status << 8) | 0x01);
+ set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+ set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+ set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+ Pico_mcd->regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
+ break;
+ }
+
+ case 0x02: /* Current Track Number */
+ {
+ set_reg16(0x38, (cdd.status << 8) | 0x02);
+ set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
+ set_reg16(0x3c, 0x0000);
+ set_reg16(0x3e, 0x0000); /* Disk Control Code (?) in RS6 */
+ Pico_mcd->regs[0x40>>1].byte.h = 0x00;
+ break;
+ }
+
+ case 0x03: /* Total length (MM:SS:FF) */
+ {
+ int lba = cdd.toc.end + 150;
+ set_reg16(0x38, (cdd.status << 8) | 0x03);
+ set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+ set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+ set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+ Pico_mcd->regs[0x40>>1].byte.h = 0x00;
+ break;
+ }
+
+ case 0x04: /* First & Last Track Numbers */
+ {
+ set_reg16(0x38, (cdd.status << 8) | 0x04);
+ set_reg16(0x3a, 0x0001);
+ set_reg16(0x3c, lut_BCD_16[cdd.toc.last]);
+ set_reg16(0x3e, 0x0000); /* Drive Version (?) in RS6-RS7 */
+ Pico_mcd->regs[0x40>>1].byte.h = 0x00; /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
+ break;
+ }
+
+ case 0x05: /* Track Start Time (MM:SS:FF) */
+ {
+ int track = Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l;
+ int lba = cdd.toc.tracks[track-1].start + 150;
+ set_reg16(0x38, (cdd.status << 8) | 0x05);
+ set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
+ set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
+ set_reg16(0x3e, lut_BCD_16[(lba%75)]);
+ Pico_mcd->regs[0x40>>1].byte.h = track % 10; /* Track Number (low digit) */
+ if (track == 1)
+ {
+ /* RS6 bit 3 is set for the first (DATA) track */
+ Pico_mcd->regs[0x3e>>1].byte.h |= 0x08;
+ }
+ break;
+ }
+
+ default:
+ {
+#ifdef LOG_ERROR
+ error("Unknown CDD Command %02X (%X)\n", Pico_mcd->regs[0x44>>1].byte.l, s68k.pc);
+#endif
+ return;
+ }
+ }
+ break;
+ }
+
+ case 0x03: /* Play */
+ {
+ /* reset track index */
+ int index = 0;
+
+ /* new LBA position */
+ int lba = ((Pico_mcd->regs[0x44>>1].byte.h * 10 + Pico_mcd->regs[0x44>>1].byte.l) * 60 +
+ (Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l)) * 75 +
+ (Pico_mcd->regs[0x48>>1].byte.h * 10 + Pico_mcd->regs[0x48>>1].byte.l) - 150;
+
+ /* CD drive latency */
+ if (!cdd.latency)
+ {
+ /* Fixes a few games hanging during intro because they expect data to be read with some delay */
+ /* Radical Rex needs at least one interrupt delay */
+ /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */
+ /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
+ /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
+ cdd.latency = 10;
+ }
+
+ /* CD drive seek time */
+ /* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
+ /* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
+ /* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to */
+ /* be enough delayed to start in sync with intro sequence, as compared with real hardware recording). */
+ if (lba > cdd.lba)
+ {
+ cdd.latency += (((lba - cdd.lba) * 120) / 270000);
+ }
+ else
+ {
+ cdd.latency += (((cdd.lba - lba) * 120) / 270000);
+ }
+
+ /* update current LBA */
+ cdd.lba = lba;
+
+ /* get track index */
+ while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* check if track index has changed */
+ if (index != cdd.index)
+ {
+ /* close previous track VORBIS file structure to save memory */
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ ogg_free(cdd.index);
+ }
+
+ /* open current track VORBIS file */
+ if (cdd.toc.tracks[index].vf.seekable)
+ {
+ ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
+ }
+ }
+#endif
+#endif
+
+ /* update current track index */
+ cdd.index = index;
+
+ /* stay within track limits when seeking files */
+ if (lba < cdd.toc.tracks[index].start)
+ {
+ lba = cdd.toc.tracks[index].start;
+ }
+
+ /* seek to current block */
+ if (!index)
+ {
+ /* DATA track */
+ pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
+ }
+#ifdef USE_LIBTREMOR
+ else if (cdd.toc.tracks[index].vf.seekable)
+ {
+ /* VORBIS AUDIO track */
+ ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
+ }
+#endif
+#if 0
+ else if (cdd.toc.tracks[index].fd)
+ {
+ /* PCM AUDIO track */
+ fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
+ }
+#else
+ else
+ {
+ cdd_change_track(index, lba);
+ }
+#endif
+
+ /* no audio track playing (yet) */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* update status */
+ cdd.status = CD_PLAY;
+
+ /* return track index in RS2-RS3 */
+ set_reg16(0x38, (CD_PLAY << 8) | 0x02);
+ set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A);
+ set_reg16(0x3c, 0x0000);
+ set_reg16(0x3e, 0x0000);
+ Pico_mcd->regs[0x40>>1].byte.h = 0x00;
+ break;
+ }
+
+ case 0x04: /* Seek */
+ {
+ /* reset track index */
+ int index = 0;
+
+ /* new LBA position */
+ int lba = ((Pico_mcd->regs[0x44>>1].byte.h * 10 + Pico_mcd->regs[0x44>>1].byte.l) * 60 +
+ (Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l)) * 75 +
+ (Pico_mcd->regs[0x48>>1].byte.h * 10 + Pico_mcd->regs[0x48>>1].byte.l) - 150;
+
+ /* CD drive seek time */
+ /* We are using similar linear model as above, although still not exactly accurate, */
+ /* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
+ /* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
+ if (lba > cdd.lba)
+ {
+ cdd.latency = ((lba - cdd.lba) * 120) / 270000;
+ }
+ else
+ {
+ cdd.latency = ((cdd.lba - lba) * 120) / 270000;
+ }
+
+ /* update current LBA */
+ cdd.lba = lba;
+
+ /* get current track index */
+ while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
+
+#ifdef USE_LIBTREMOR
+#ifdef DISABLE_MANY_OGG_OPEN_FILES
+ /* check if track index has changed */
+ if (index != cdd.index)
+ {
+ /* close previous track VORBIS file structure to save memory */
+ if (cdd.toc.tracks[cdd.index].vf.datasource)
+ {
+ ogg_free(cdd.index);
+ }
+
+ /* open current track VORBIS file */
+ if (cdd.toc.tracks[index].vf.seekable)
+ {
+ ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
+ }
+ }
+#endif
+#endif
+
+ /* update current track index */
+ cdd.index = index;
+
+ /* stay within track limits */
+ if (lba < cdd.toc.tracks[index].start)
+ {
+ lba = cdd.toc.tracks[index].start;
+ }
+
+ /* seek to current block */
+ if (!index)
+ {
+ /* DATA track */
+ pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
+ }
+#ifdef USE_LIBTREMOR
+ else if (cdd.toc.tracks[index].vf.seekable)
+ {
+ /* VORBIS AUDIO track */
+ ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
+ }
+#endif
+#if 0
+ else if (cdd.toc.tracks[index].fd)
+ {
+ /* PCM AUDIO track */
+ fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
+ }
+#endif
+
+ /* no audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* update status */
+ cdd.status = CD_SEEK;
+
+ /* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */
+ set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
+ set_reg16(0x3a, 0x0000);
+ set_reg16(0x3c, 0x0000);
+ set_reg16(0x3e, 0x0000);
+ set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
+ return;
+ }
+
+ case 0x06: /* Pause */
+ {
+ /* no audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* update status (RS1-RS8 unchanged) */
+ cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_READY;
+ break;
+ }
+
+ case 0x07: /* Resume */
+ {
+ /* update status (RS1-RS8 unchanged) */
+ cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_PLAY;
+ break;
+ }
+
+ case 0x08: /* Forward Scan */
+ {
+ /* reset scanning direction / speed */
+ cdd.scanOffset = CD_SCAN_SPEED;
+
+ /* update status (RS1-RS8 unchanged) */
+ cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_SCAN;
+ break;
+ }
+
+ case 0x09: /* Rewind Scan */
+ {
+ /* reset scanning direction / speed */
+ cdd.scanOffset = -CD_SCAN_SPEED;
+
+ /* update status (RS1-RS8 unchanged) */
+ cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_SCAN;
+ break;
+ }
+
+
+ case 0x0a: /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
+ {
+ /* TC3 corresponds to seek direction (00=forward, FF=reverse) */
+ /* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
+ /* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
+ /* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
+
+ /* no audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* update status (RS1-RS8 unchanged) */
+ cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_READY;
+ break;
+ }
+
+ case 0x0c: /* Close Tray */
+ {
+ /* no audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* update status */
+ cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
+
+ /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
+ set_reg16(0x38, 0x0000);
+ set_reg16(0x3a, 0x0000);
+ set_reg16(0x3c, 0x0000);
+ set_reg16(0x3e, 0x0000);
+ set_reg16(0x40, 0x000f);
+
+ if (PicoMCDcloseTray)
+ PicoMCDcloseTray();
+ return;
+ }
+
+ case 0x0d: /* Open Tray */
+ {
+ /* no audio track playing */
+ Pico_mcd->regs[0x36>>1].byte.h = 0x01;
+
+ /* update status (RS1-RS8 ignored) */
+ cdd.status = CD_OPEN;
+ set_reg16(0x38, CD_OPEN << 8);
+ set_reg16(0x3a, 0x0000);
+ set_reg16(0x3c, 0x0000);
+ set_reg16(0x3e, 0x0000);
+ set_reg16(0x40, ~CD_OPEN & 0x0f);
+
+ if (PicoMCDopenTray)
+ PicoMCDopenTray();
+ return;
+ }
+
+ default: /* Unknown command */
+#ifdef LOG_CDD
+ error("Unknown CDD Command !!!\n");
+#endif
+ Pico_mcd->regs[0x38>>1].byte.h = cdd.status;
+ break;
+ }
+
+ /* only compute checksum when necessary */
+ Pico_mcd->regs[0x40>>1].byte.l =
+ ~(Pico_mcd->regs[0x38>>1].byte.h + Pico_mcd->regs[0x38>>1].byte.l +
+ Pico_mcd->regs[0x3a>>1].byte.h + Pico_mcd->regs[0x3a>>1].byte.l +
+ Pico_mcd->regs[0x3c>>1].byte.h + Pico_mcd->regs[0x3c>>1].byte.l +
+ Pico_mcd->regs[0x3e>>1].byte.h + Pico_mcd->regs[0x3e>>1].byte.l +
+ Pico_mcd->regs[0x40>>1].byte.h) & 0x0f;
+}
+
+// vim:shiftwidth=2:ts=2:expandtab
--- /dev/null
+/***************************************************************************************
+ * Genesis Plus
+ * CD drive processor & CD-DA fader
+ *
+ * Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
+ *
+ * Redistribution and use of this code or any derivative works are permitted
+ * provided that the following conditions are met:
+ *
+ * - Redistributions may not be sold, nor may they be used in a commercial
+ * product or activity.
+ *
+ * - Redistributions that are modified from the original source must include the
+ * complete source code, including the source code for all components used by a
+ * binary built from the modified sources. However, as a special exception, the
+ * source code distributed need not include anything that is normally distributed
+ * (in either source or binary form) with the major components (compiler, kernel,
+ * and so on) of the operating system on which the executable runs, unless that
+ * component itself accompanies the executable.
+ *
+ * - Redistributions must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************************/
+#ifndef _HW_CDD_
+#define _HW_CDD_
+
+#ifdef USE_LIBTREMOR
+#include "tremor/ivorbisfile.h"
+#endif
+
+/* CDD status */
+#define NO_DISC 0x00
+#define CD_PLAY 0x01
+#define CD_SEEK 0x02
+#define CD_SCAN 0x03
+#define CD_READY 0x04
+#define CD_OPEN 0x05 /* similar to 0x0E ? */
+#define CD_STOP 0x09
+#define CD_END 0x0C
+
+/* CD blocks scanning speed */
+#define CD_SCAN_SPEED 30
+
+#define CD_MAX_TRACKS 100
+
+/* CD track */
+typedef struct
+{
+ void *fd;
+#ifdef USE_LIBTREMOR
+ OggVorbis_File vf;
+#endif
+ int offset;
+ int start;
+ int end;
+} track_t;
+
+/* CD TOC */
+typedef struct
+{
+ int end;
+ int last;
+ track_t tracks[CD_MAX_TRACKS];
+} toc_t;
+
+/* CDD hardware */
+typedef struct
+{
+ uint32 cycles;
+ uint32 latency;
+ int loaded;
+ int index;
+ int lba;
+ int scanOffset;
+ int volume;
+ uint8 status;
+ uint16 sectorSize;
+ toc_t toc;
+ int16 audio[2];
+} cdd_t;
+
+extern cdd_t cdd;
+
+#endif
data->tracks[count].type = CT_MP3;
else if (strcasecmp(ext, "wav") == 0)
data->tracks[count].type = CT_WAV;
+ else if (strcasecmp(ext, "bin") == 0)
+ data->tracks[count].type = CT_BIN;
else {
elprintf(EL_STATUS, "unhandled audio format: \"%s\"",
data->tracks[count].fname);
PICO_INTERNAL void PicoInitMCD(void)
{
SekInitS68k();
- Init_CD_Driver();
- gfx_init();
}
PICO_INTERNAL void PicoExitMCD(void)
{
- End_CD_Driver();
}
PICO_INTERNAL void PicoPowerMCD(void)
memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
+ Pico_mcd->s68k_regs[0x38+9] = 0x0f; // default checksum
cdc_init();
- Reset_CD();
+ cdd_reset();
+ gfx_init();
// cold reset state (tested)
Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
Pico_mcd->m.s68k_pend_ints = 0;
cdc_reset();
- CDD_Reset();
+ cdd_reset();
#ifdef _ASM_CD_MEMORY_C
//PicoMemResetCDdecode(1); // don't have to call this in 2M mode
#endif
static void pcd_cdc_event(unsigned int now)
{
// 75Hz CDC update
- Check_CD_Command();
+ cdd_update();
+
+ /* check if a new CDD command has been processed */
+ if (!(Pico_mcd->s68k_regs[0x4b] & 0xf0))
+ {
+ /* reset CDD command wait flag */
+ Pico_mcd->s68k_regs[0x4b] = 0xf0;
+
+ if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
+ elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
+ SekInterruptS68k(4);
+ }
+ }
+
pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
}
elprintf(EL_CDREGS|EL_CD, "s68k irq mask: %02x", d);\r
d &= 0x7e;\r
if ((d ^ Pico_mcd->s68k_regs[0x33]) & d & PCDS_IEN4) {\r
- if (Pico_mcd->s68k_regs[0x37] & 4)\r
- CDD_Export_Status();\r
+ // XXX: emulate pending irq instead?\r
+ if (Pico_mcd->s68k_regs[0x37] & 4) {\r
+ elprintf(EL_INTS, "cdd export irq 4 (unmask)");\r
+ SekInterruptS68k(4);\r
+ }\r
}\r
break;\r
case 0x34: // fader\r
return; // d/m bit is unsetable\r
case 0x37: {\r
u32 d_old = Pico_mcd->s68k_regs[0x37];\r
- Pico_mcd->s68k_regs[0x37] = d&7;\r
+ Pico_mcd->s68k_regs[0x37] = d & 7;\r
if ((d&4) && !(d_old&4)) {\r
- CDD_Export_Status();\r
+ // ??\r
+ pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);\r
+\r
+ if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {\r
+ elprintf(EL_INTS, "cdd export irq 4");\r
+ SekInterruptS68k(4);\r
+ }\r
}\r
return;\r
}\r
case 0x4b:\r
Pico_mcd->s68k_regs[a] = (u8) d;\r
- CDD_Import_Command();\r
+ cdd_process();\r
return;\r
case 0x58:\r
return;\r
{
const char *rom_fname = filename;
enum media_type_e media_type;
- cd_img_type cd_img_type = CIT_NOT_CD;
+ enum cd_img_type cd_img_type = CIT_NOT_CD;
unsigned char *rom_data = NULL;
unsigned int rom_size = 0;
pm_file *rom = NULL;
goto out;
if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL)
- Stop_CD();
+ cdd_unload();
PicoCartUnload();
PicoAHW = 0;
PicoQuirks = 0;
// insert CD if it was detected
if (cd_img_type != CIT_NOT_CD) {
- ret = Insert_CD(filename, cd_img_type);
+ ret = cdd_load(filename, cd_img_type);
if (ret != 0) {
PicoCartUnload();
media_type = PM_BAD_CD;
// cd/mcd.c\r
extern void (*PicoMCDopenTray)(void);\r
extern void (*PicoMCDcloseTray)(void);\r
-extern int PicoCDBuffers;\r
\r
// pico.c\r
#define XPCM_BUFFER_SIZE (320+160)\r
void PicoTmpStateRestore(void *data);\r
extern void (*PicoStateProgressCB)(const char *str);\r
\r
-// cd/buffering.c\r
-void PicoCDBufferInit(void);\r
-void PicoCDBufferFree(void);\r
-void PicoCDBufferFlush(void);\r
-\r
-// cd/cd_sys.c\r
-int Insert_CD(const char *cdimg_name, int type);\r
-int Stop_CD(void); // unloads CD, returns 1 if there was cd loaded\r
+// cd/cdd.c\r
+int cdd_load(const char *filename, int type);\r
+int cdd_unload(void);\r
\r
// Cart.c\r
typedef enum\r
PM_MARK3,\r
PM_CD,\r
};\r
+\r
+enum cd_img_type\r
+{\r
+ CIT_NOT_CD = 0,\r
+ CIT_ISO,\r
+ CIT_BIN,\r
+ CIT_CUE\r
+};\r
+\r
enum media_type_e PicoLoadMedia(const char *filename,\r
const char *carthw_cfg_fname,\r
const char *(*get_bios_filename)(int *region, const char *cd_fname),\r
};\r
\r
// MCD\r
-#include "cd/cd_sys.h"\r
-#include "cd/LC89510.h"\r
-\r
#define PCM_MIXBUF_LEN ((12500000 / 384) / 50 + 1)\r
\r
struct mcd_pcm\r
unsigned char bram[0x2000]; // 110200: 8K\r
struct mcd_misc m; // 112200: misc\r
struct mcd_pcm pcm; // 112240:\r
- _scd_toc TOC; // not to be saved\r
- CDD cdd;\r
- _scd scd;\r
+ void *cdda_stream;\r
+ int cdda_type;\r
int pcm_mixbuf[PCM_MIXBUF_LEN * 2];\r
int pcm_mixpos;\r
char pcm_mixbuf_dirty;\r
unsigned char cdc_reg_r(void);\r
unsigned short cdc_host_r(void);\r
\r
+// cd/cdd.c\r
+void cdd_reset(void);\r
+int cdd_context_save(unsigned char *state);\r
+int cdd_context_load(unsigned char *state);\r
+int cdd_context_load_old(unsigned char *state);\r
+void cdd_read_data(unsigned char *dst);\r
+void cdd_read_audio(unsigned int samples);\r
+void cdd_update(void);\r
+void cdd_process(void);\r
+\r
+// cd/cd_image.c\r
+int load_cd_image(const char *cd_img_name, int *type);\r
+\r
// cd/gfx.c\r
void gfx_init(void);\r
void gfx_start(unsigned int base);\r
void SekInterruptClearS68k(int irq);\r
\r
// sound/sound.c\r
-PICO_INTERNAL void cdda_start_play();\r
extern short cdda_out_buffer[2*1152];\r
extern int PsndLen_exc_cnt;\r
extern int PsndLen_exc_add;\r
extern int timer_a_next_oflow, timer_a_step; // in z80 cycles\r
extern int timer_b_next_oflow, timer_b_step;\r
\r
+void cdda_start_play(int lba_base, int lba_offset, int lb_len);\r
+\r
void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new);\r
void ym2612_pack_state(void);\r
void ym2612_unpack_state(void);\r
PICO_INTERNAL_ASM void wram_2M_to_1M(unsigned char *m);\r
PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m);\r
\r
-// cd/buffering.c\r
-PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba);\r
-\r
// sound/sound.c\r
PICO_INTERNAL void PsndReset(void);\r
PICO_INTERNAL void PsndDoDAC(int line_to);\r
// feed it back it's own registers, just like after loading state\r
memcpy(YM2612GetRegs(), state, 0x204);\r
ym2612_unpack_state();\r
- if ((PicoAHW & PAHW_MCD) && !(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
- cdda_start_play();\r
}\r
\r
if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state\r
}\r
\r
// cdda\r
-static pm_file *cdda_stream = NULL;\r
-\r
static void cdda_raw_update(int *buffer, int length)\r
{\r
int ret, cdda_bytes, mult = 1;\r
- if (cdda_stream == NULL)\r
- return;\r
\r
cdda_bytes = length*4;\r
if (PsndRate <= 22050 + 100) mult = 2;\r
if (PsndRate < 22050 - 100) mult = 4;\r
cdda_bytes *= mult;\r
\r
- ret = pm_read(cdda_out_buffer, cdda_bytes, cdda_stream);\r
+ ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);\r
if (ret < cdda_bytes) {\r
memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);\r
- cdda_stream = NULL;\r
+ Pico_mcd->cdda_stream = NULL;\r
return;\r
}\r
\r
}\r
}\r
\r
-PICO_INTERNAL void cdda_start_play(void)\r
+void cdda_start_play(int lba_base, int lba_offset, int lb_len)\r
{\r
- int lba_offset, index, lba_length, i;\r
-\r
- elprintf(EL_STATUS, "cdda play track #%i", Pico_mcd->scd.Cur_Track);\r
-\r
- index = Pico_mcd->scd.Cur_Track - 1;\r
-\r
- lba_offset = Pico_mcd->scd.Cur_LBA - Track_to_LBA(index + 1);\r
- if (lba_offset < 0) lba_offset = 0;\r
- lba_offset += Pico_mcd->TOC.Tracks[index].Offset;\r
-\r
- // find the actual file for this track\r
- for (i = index; i > 0; i--)\r
- if (Pico_mcd->TOC.Tracks[i].F != NULL) break;\r
-\r
- if (Pico_mcd->TOC.Tracks[i].F == NULL) {\r
- elprintf(EL_STATUS|EL_ANOMALY, "no track?!");\r
- return;\r
- }\r
-\r
- if (Pico_mcd->TOC.Tracks[i].ftype == CT_MP3)\r
+ if (Pico_mcd->cdda_type == CT_MP3)\r
{\r
int pos1024 = 0;\r
\r
- lba_length = Pico_mcd->TOC.Tracks[i].Length;\r
- for (i++; i < Pico_mcd->TOC.Last_Track; i++) {\r
- if (Pico_mcd->TOC.Tracks[i].F != NULL) break;\r
- lba_length += Pico_mcd->TOC.Tracks[i].Length;\r
- }\r
-\r
if (lba_offset)\r
- pos1024 = lba_offset * 1024 / lba_length;\r
+ pos1024 = lba_offset * 1024 / lb_len;\r
\r
- mp3_start_play(Pico_mcd->TOC.Tracks[index].F, pos1024);\r
+ mp3_start_play(Pico_mcd->cdda_stream, pos1024);\r
return;\r
}\r
\r
- cdda_stream = Pico_mcd->TOC.Tracks[i].F;\r
- PicoCDBufferFlush(); // buffering relies on fp not being touched\r
- pm_seek(cdda_stream, lba_offset * 2352, SEEK_SET);\r
- if (Pico_mcd->TOC.Tracks[i].ftype == CT_WAV)\r
+ pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET);\r
+ if (Pico_mcd->cdda_type == CT_WAV)\r
{\r
// skip headers, assume it's 44kHz stereo uncompressed\r
- pm_seek(cdda_stream, 44, SEEK_CUR);\r
+ pm_seek(Pico_mcd->cdda_stream, 44, SEEK_CUR);\r
}\r
}\r
\r
\r
// CD: CDDA audio\r
// CD mode, cdda enabled, not data track, CDC is reading\r
- if ((PicoAHW & PAHW_MCD) && (PicoOpt & POPT_EN_MCD_CDDA) &&\r
- !(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
+ if ((PicoAHW & PAHW_MCD) && (PicoOpt & POPT_EN_MCD_CDDA)\r
+ && Pico_mcd->cdda_stream != NULL\r
+ && !(Pico_mcd->s68k_regs[0x36] & 1))\r
{\r
// note: only 44, 22 and 11 kHz supported, with forced stereo\r
- int index = Pico_mcd->scd.Cur_Track - 1;\r
-\r
- if (Pico_mcd->TOC.Tracks[index].ftype == CT_MP3)\r
+ if (Pico_mcd->cdda_type == CT_MP3)\r
mp3_update(buf32, length, stereo);\r
else\r
cdda_raw_update(buf32, length);\r
CHUNK_GA_REGS,\r
CHUNK_PCM,\r
CHUNK_CDC, // old\r
- CHUNK_CDD, // 20\r
- CHUNK_SCD,\r
+ CHUNK_CDD, // 20 old\r
+ CHUNK_SCD, // old\r
CHUNK_RC, // old\r
CHUNK_MISC_CD,\r
//\r
CHUNK_CD_EVT = 50,\r
CHUNK_CD_GFX,\r
CHUNK_CD_CDC,\r
+ CHUNK_CD_CDD,\r
//\r
CHUNK_DEFAULT_COUNT,\r
CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt)\r
CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);\r
CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);\r
- CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);\r
- CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);\r
CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);\r
memset(buff, 0, 0x40);\r
memcpy(buff, pcd_event_times, sizeof(pcd_event_times));\r
CHECKED_WRITE(CHUNK_CD_GFX, len, buf2);\r
len = cdc_context_save(buf2);\r
CHECKED_WRITE(CHUNK_CD_CDC, len, buf2);\r
+ len = cdd_context_save(buf2);\r
+ CHECKED_WRITE(CHUNK_CD_CDD, len, buf2);\r
\r
if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
wram_2M_to_1M(Pico_mcd->word_ram2M);\r
case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;\r
case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
- case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;\r
- case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;\r
case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;\r
\r
case CHUNK_CD_EVT:\r
len_check = cdc_context_load(buf);\r
break;\r
\r
+ case CHUNK_CD_CDD:\r
+ CHECKED_READ_LIM(buf);\r
+ len_check = cdd_context_load(buf);\r
+ break;\r
+\r
// old, to be removed:\r
case CHUNK_CDC:\r
CHECKED_READ_LIM(buf);\r
cdc_context_load_old(buf);\r
break;\r
\r
+ case CHUNK_SCD:\r
+ CHECKED_READ_LIM(buf);\r
+ cdd_context_load_old(buf);\r
+ break;\r
+\r
// 32x stuff\r
#ifndef NO_32X\r
case CHUNK_MSH2:\r
{\r
SekCycleAimS68k = SekCycleCntS68k;\r
pcd_state_loaded();\r
-\r
- if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
- cdda_start_play();\r
}\r
\r
retval = 0;\r
\r
Eke\r
CD graphics processor and CD controller implementation (from Genesis Plus GX)\r
-\r
-Stephane Dallongeville\r
-Gens, MD/Mega CD/32X emulator. Some Sega CD code is based on this emu.\r
#ifdef PSP\r
\r
people @ ps2dev.org forums / PSPSDK crew\r
* Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful\r
info about genesis hardware.\r
* Steve Snake for all that he has done for Genesis emulation scene.\r
+* Stephane Dallongeville for writing Gens and making it open source.\r
* Tasco Deluxe for his reverse engineering work on SVP and some mappers.\r
* Bart Trzynadlowski for his SSFII and 68000 docs.\r
* Haze for his research (http://haze.mameworld.info).\r
endif
# CD
SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \
- $(R)pico/cd/cdc.c $(R)pico/cd/cd_sys.c $(R)pico/cd/cd_file.c \
+ $(R)pico/cd/cdc.c $(R)pico/cd/cdd.c $(R)pico/cd/cd_image.c \
$(R)pico/cd/cue.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \
- $(R)pico/cd/misc.c $(R)pico/cd/pcm.c $(R)pico/cd/buffering.c
+ $(R)pico/cd/misc.c $(R)pico/cd/pcm.c
# 32X
ifneq "$(no_32x)" "1"
SRCS_COMMON += $(R)pico/32x/32x.c $(R)pico/32x/memory.c $(R)pico/32x/draw.c \
return 0;
return 1;
- case MA_CDOPT_READAHEAD:
- if (strcasecmp(var, "ReadAhead buffer") != 0) return 0;
- PicoCDBuffers = atoi(val) / 2;
- return 1;
-
case MA_32XOPT_MSH2_CYCLES:
currentConfig.msh2_khz = atoi(val);
Pico32xSetClocks(currentConfig.msh2_khz * 1000, 0);
\r
int emu_swap_cd(const char *fname)\r
{\r
- cd_img_type cd_type;\r
+ enum cd_img_type cd_type;\r
int ret = -1;\r
\r
cd_type = PicoCdCheck(fname, NULL);\r
if (cd_type != CIT_NOT_CD)\r
- ret = Insert_CD(fname, cd_type);\r
+ ret = cdd_load(fname, cd_type);\r
if (ret != 0) {\r
menu_update_msg("Load failed, invalid CD image?");\r
return 0;\r
}\r
\r
strncpy(rom_fname_loaded, fname, sizeof(rom_fname_loaded)-1);\r
- rom_fname_loaded[sizeof(rom_fname_loaded)-1] = 0;\r
+ rom_fname_loaded[sizeof(rom_fname_loaded) - 1] = 0;\r
+\r
return 1;\r
}\r
\r
PsndRate = currentConfig.s_PsndRate;\r
PicoRegionOverride = currentConfig.s_PicoRegion;\r
PicoAutoRgnOrder = currentConfig.s_PicoAutoRgnOrder;\r
- PicoCDBuffers = currentConfig.s_PicoCDBuffers;\r
}\r
\r
int emu_read_config(const char *rom_fname, int no_defaults)\r
\r
PicoLoopPrepare();\r
\r
- // prepare CD buffer\r
- if (PicoAHW & PAHW_MCD)\r
- PicoCDBufferInit();\r
-\r
plat_video_loop_prepare();\r
emu_loop_prep();\r
pemu_sound_start();\r
\r
pemu_loop_end();\r
emu_sound_stop();\r
-\r
- // pemu_loop_end() might want to do 1 frame for bg image,\r
- // so free CD buffer here\r
- if (PicoAHW & PAHW_MCD)\r
- PicoCDBufferFree();\r
}\r
-\r
// ------------ SCD options menu ------------
-static const char *mgn_cdopt_ra(int id, int *offs)
-{
- *offs = -5;
- if (PicoCDBuffers <= 0)
- return " OFF";
- sprintf(static_buff, "%5iK", PicoCDBuffers * 2);
- return static_buff;
-}
-
-static int mh_cdopt_ra(int id, int keys)
-{
- if (keys & PBTN_LEFT) {
- PicoCDBuffers >>= 1;
- if (PicoCDBuffers < 2)
- PicoCDBuffers = 0;
- } else {
- if (PicoCDBuffers <= 0)
- PicoCDBuffers = 1;
- PicoCDBuffers <<= 1;
- if (PicoCDBuffers > 8*1024)
- PicoCDBuffers = 8*1024; // 16M
- }
- return 0;
-}
-
static const char h_cdleds[] = "Show power/CD LEDs of emulated console";
static const char h_cdda[] = "Play audio tracks from mp3s/wavs/bins";
static const char h_cdpcm[] = "Emulate PCM audio chip for effects/voices/music";
mee_onoff_h("CD LEDs", MA_CDOPT_LEDS, currentConfig.EmuOpt, EOPT_EN_CD_LEDS, h_cdleds),
mee_onoff_h("CDDA audio", MA_CDOPT_CDDA, PicoOpt, POPT_EN_MCD_CDDA, h_cdda),
mee_onoff_h("PCM audio", MA_CDOPT_PCM, PicoOpt, POPT_EN_MCD_PCM, h_cdpcm),
- mee_cust ("ReadAhead buffer", MA_CDOPT_READAHEAD, mh_cdopt_ra, mgn_cdopt_ra),
mee_onoff_h("SaveRAM cart", MA_CDOPT_SAVERAM, PicoOpt, POPT_EN_MCD_RAMCART, h_srcart),
mee_onoff_h("Scale/Rot. fx (slow)", MA_CDOPT_SCALEROT_CHIP, PicoOpt, POPT_EN_MCD_GFX, h_scfx),
mee_end,
break;
case MA_MAIN_CHANGE_CD:
if (PicoAHW & PAHW_MCD) {
- if (!Stop_CD())
+ if (!cdd_unload())
menu_loop_tray();
return 1;
}
static bool disk_set_image_index(unsigned int index)
{
- cd_img_type cd_type;
+ enum cd_img_type cd_type;
int ret;
if (index >= sizeof(disks) / sizeof(disks[0]))
ret = -1;
cd_type = PicoCdCheck(disks[index].fname, NULL);
if (cd_type != CIT_NOT_CD)
- ret = Insert_CD(disks[index].fname, cd_type);
+ ret = cdd_load(disks[index].fname, cd_type);
if (ret != 0) {
lprintf("Load failed, invalid CD image?\n");
return 0;
#endif
PsndRate = 44100;
PicoAutoRgnOrder = 0x184; // US, EU, JP
- PicoCDBuffers = 0;
vout_width = 320;
vout_height = 240;