// external funcs for Sega/Mega CD\r
int mp3_get_bitrate(FILE *f, int size);\r
void mp3_start_play(FILE *f, int pos);\r
-int mp3_get_offset(void); // 0-1023\r
void mp3_update(int *buffer, int length, int stereo);\r
\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(char *iso_name, int is_bin);\r
unsigned char s68k_pend_ints;\r
unsigned int state_flags; // 04: emu state: reset_pending, dmna_pending\r
unsigned int counter75hz;\r
- unsigned short audio_offset; // 0c: for savestates: play pointer offset (0-1023)\r
- unsigned char audio_track; // playing audio track # (zero based)\r
- char pad1;\r
+ unsigned int pad0;\r
int timer_int3; // 10\r
unsigned int timer_stopwatch;\r
unsigned char bcram_reg; // 18: battery-backed RAM cart register\r
PICO_INTERNAL int SekInterruptS68k(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
\r
if (PicoAHW & PAHW_MCD)
{
- Pico_mcd->m.audio_offset = mp3_get_offset();
memset(buff, 0, sizeof(buff));
PicoAreaPackCpu(buff, 1);
if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
if (Pico_mcd->s68k_regs[3]&4)
PicoMemResetCDdecode(Pico_mcd->s68k_regs[3]);
#endif
- if (Pico_mcd->m.audio_track > 0 && Pico_mcd->m.audio_track < Pico_mcd->TOC.Last_Track)
- mp3_start_play(Pico_mcd->TOC.Tracks[Pico_mcd->m.audio_track].F, Pico_mcd->m.audio_offset);
+ if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))
+ cdda_start_play();
// restore hint vector
*(unsigned short *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;
}
}
-/* this is a try to fight slow SD access of GP2X */
+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;
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(i * num_track);
index = num_track - 1;
Cur_LBA += cue_data->tracks[num_track].pregap;
if (cue_data->tracks[num_track].type == CT_MP3) {
Tracks[index].ftype = cue_data->tracks[num_track].type;
if (cue_data->tracks[num_track].fname != NULL)
{
- Tracks[index].F = fopen(cue_data->tracks[num_track].fname, "rb");
+ Tracks[index].F = pm_open(cue_data->tracks[num_track].fname);
elprintf(EL_STATUS, "track %2i (%s): can't determine length",
cue_data->tracks[num_track].fname);
Tracks[index].Length = 2*75;
goto finish;
}
- /* track autosearch, Gens-like */
+ /* 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;
break;
}
}
- if (ret != 0) missed++;
+ if (ret != 0 && i > 1) missed++;
}
finish:
{
if (Pico_mcd->TOC.Tracks[i].F != NULL)
{
+ if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3)
#if DONT_OPEN_MANY_FILES
- if (Pico_mcd->TOC.Tracks[i].type == TYPE_MP3)
free(Pico_mcd->TOC.Tracks[i].F);
- else
-#endif
+#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));
PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
{
-// static char cp_buf[2560];
-
if (Pico_mcd->s68k_regs[0x36] & 1) // DATA
{
if (Pico_mcd->TOC.Tracks[0].F == NULL) return -1;
}
else // AUDIO
{
- // int rate, channel;
-
- // if (Pico_mcd->TOC.Tracks[Pico_mcd->scd.Cur_Track - 1].ftype == TYPE_MP3)
- {
- // TODO
- // MP3_Update(cp_buf, &rate, &channel, 0);
- // Write_CD_Audio((short *) cp_buf, rate, channel, 588);
- }
-
cdprintf("Read file CDC 1 audio sector :\n");
}
{
// CAUTION : lookahead bit not implemented
- //memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N], cp_buf, 2352);
+ // 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);
}
}
}
return 0;
}
-
-PICO_INTERNAL int FILE_Play_CD_LBA(void)
-{
- int index = Pico_mcd->scd.Cur_Track - 1;
- Pico_mcd->m.audio_track = index;
-
- cdprintf("Play track #%i", Pico_mcd->scd.Cur_Track);
-
- if (Pico_mcd->TOC.Tracks[index].F == NULL)
- {
- return 1;
- }
-
- if (Pico_mcd->TOC.Tracks[index].ftype == TYPE_MP3)
- {
- int pos1024 = 0;
- int Track_LBA_Pos = Pico_mcd->scd.Cur_LBA - Track_to_LBA(Pico_mcd->scd.Cur_Track);
- if (Track_LBA_Pos < 0) Track_LBA_Pos = 0;
- if (Track_LBA_Pos)
- pos1024 = Track_LBA_Pos * 1024 / Pico_mcd->TOC.Tracks[index].Length;
-
- mp3_start_play(Pico_mcd->TOC.Tracks[index].F, pos1024);
- }
- else
- {
- return 3;
- }
-
- return 0;
-}
-
#define TYPE_ISO 1
#define TYPE_BIN 2
#define TYPE_MP3 3
-//#define TYPE_WAV 4
+#define TYPE_WAV 4
typedef enum
{
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);
-PICO_INTERNAL int FILE_Play_CD_LBA(void);
#ifdef __cplusplus
else\r
{\r
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO\r
- //CD_Audio_Starting = 1;\r
- FILE_Play_CD_LBA();\r
+ cdda_start_play();\r
}\r
\r
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
else\r
{\r
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO\r
- //CD_Audio_Starting = 1;\r
- FILE_Play_CD_LBA();\r
+ cdda_start_play();\r
}\r
\r
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
/* note: tracks[0] is not used */
cue_data_t *cue_parse(const char *fname)
{
- char buff[256], current_file[256], buff2[32];
+ char buff[256], current_file[256], buff2[32], *current_filep;
FILE *f, *tmpf;
- int ret, count = 0, count_alloc = 2;
+ int ret, count = 0, count_alloc = 2, pending_pregap = 0;
cue_data_t *data;
void *tmp;
f = fopen(fname, "r");
if (f == NULL) return NULL;
- current_file[0] = 0;
+ snprintf(current_file, sizeof(current_file), "%s", fname);
+ for (current_filep = current_file + strlen(current_file); current_filep > current_file; current_filep--)
+ if (current_filep[-1] == '/' || current_filep[-1] == '\\') break;
+
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track));
+ if (data == NULL) {
+ fclose(f);
+ return NULL;
+ }
while (!feof(f))
{
mystrip(buff);
if (buff[0] == 0) continue;
- if (BEGINS(buff, "TITLE ") || BEGINS(buff, "PERFORMER "))
+ if (BEGINS(buff, "REM"))
+ continue;
+ else if (BEGINS(buff, "TITLE ") || BEGINS(buff, "PERFORMER ") || BEGINS(buff, "SONGWRITER "))
continue; /* who would put those here? Ignore! */
else if (BEGINS(buff, "FILE "))
{
- get_token(buff+5, current_file, sizeof(current_file));
+ get_token(buff+5, current_filep, sizeof(current_file) - (current_filep - current_file));
}
else if (BEGINS(buff, "TRACK "))
{
}
fclose(tmpf);
}
+ data->tracks[count].pregap = pending_pregap;
+ pending_pregap = 0;
// track number
ret = get_token(buff+6, buff2, sizeof(buff2));
if (count != atoi(buff2))
data->tracks[count].fname = strdup(current_file);
}
}
- else if (BEGINS(buff, "PREGAP "))
+ else if (BEGINS(buff, "PREGAP ") || BEGINS(buff, "POSTGAP "))
{
int m, s, f;
get_token(buff+7, buff2, sizeof(buff2));
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
continue;
}
- data->tracks[count].pregap = m*60*75 + s*75 + f;
+ // pregap overrides previous postgap?
+ // by looking at some .cues produced by some programs I've decided that..
+ if (BEGINS(buff, "PREGAP "))
+ data->tracks[count].pregap = m*60*75 + s*75 + f;
+ else
+ pending_pregap = m*60*75 + s*75 + f;
}
else
{
// dac\r
static unsigned short dac_info[312]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample\r
\r
+// cdda output buffer\r
+short cdda_out_buffer[2*1152];\r
+\r
// for Pico\r
int PsndRate=0;\r
int PsndLen=0; // number of mono samples, multiply by 2 for stereo\r
state = malloc(0x200);\r
if (state == NULL) return;\r
memcpy(state, YM2612GetRegs(), 0x200);\r
- if ((PicoAHW & PAHW_MCD) && Pico_mcd->m.audio_track)\r
- Pico_mcd->m.audio_offset = mp3_get_offset();\r
}\r
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate);\r
if (preserve_state) {\r
// feed it back it's own registers, just like after loading state\r
memcpy(YM2612GetRegs(), state, 0x200);\r
YM2612PicoStateLoad();\r
- if ((PicoAHW & PAHW_MCD) && Pico_mcd->m.audio_track)\r
- mp3_start_play(Pico_mcd->TOC.Tracks[Pico_mcd->m.audio_track].F, Pico_mcd->m.audio_offset);\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
// clear all buffers\r
memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4);\r
+ memset(cdda_out_buffer, 0, sizeof(cdda_out_buffer));\r
if (PsndOut)\r
PsndClear();\r
\r
#endif\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;\r
+ if (cdda_stream == NULL) return;\r
+\r
+ cdda_bytes = length*4;\r
+ if (PsndRate <= 22050) cdda_bytes *= 2;\r
+ if (PsndRate < 22050) cdda_bytes *= 2;\r
+\r
+ ret = pm_read(cdda_out_buffer, cdda_bytes, cdda_stream);\r
+ if (ret < cdda_bytes) {\r
+ memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);\r
+ cdda_stream = NULL;\r
+ return;\r
+ }\r
+\r
+ // now mix\r
+ switch (PsndRate) {\r
+ case 44100: mix_16h_to_32(buffer, cdda_out_buffer, length*2); break;\r
+ case 22050: mix_16h_to_32_s1(buffer, cdda_out_buffer, length*2); break;\r
+ case 11025: mix_16h_to_32_s2(buffer, cdda_out_buffer, length*2); break;\r
+ }\r
+}\r
+\r
+PICO_INTERNAL void cdda_start_play(void)\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 == TYPE_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
+\r
+ mp3_start_play(Pico_mcd->TOC.Tracks[index].F, 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
+}\r
+\r
\r
PICO_INTERNAL void PsndClear(void)\r
{\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
- mp3_update(buf32, length, stereo);\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 == TYPE_MP3)\r
+ mp3_update(buf32, length, stereo);\r
+ else\r
+ cdda_raw_update(buf32, length);\r
+ }\r
\r
// convert + limit to normal 16bit output\r
PsndMix_32_to_16l(PsndOut+offset, buf32, length);\r
}\r
\r
\r
+// -----------------------------------------------------------------\r
+// z80 stuff\r
+\r
\r
#if defined(_USE_MZ80)\r
\r
#include "helix/pub/mp3dec.h"
#include "lprintf.h"
-static short mp3_out_buffer[2*1152];
static HMP3Decoder mp3dec = 0;
static int mp3_buffer_offs = 0;
readPtr += offset;
bytesLeft -= offset;
- err = MP3Decode(mp3dec, &readPtr, &bytesLeft, mp3_out_buffer, 0);
+ err = MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
if (err) {
if (err == ERR_MP3_INDATA_UNDERFLOW) {
shared_ctl->mp3_offs = shared_ctl->mp3_len; // EOF
#define mp3_update mp3_update_local
-#else
+#else // !__GP2X__
static FILE *mp3_current_file = NULL;
static int mp3_file_len = 0, mp3_file_pos = 0;
readPtr = mp3_input_buffer + offset;
bytesLeft -= offset;
- err = MP3Decode(mp3dec, &readPtr, &bytesLeft, mp3_out_buffer, 0);
+ err = MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
if (err) {
//lprintf("MP3Decode err (%i/%i) %i\n", mp3_file_pos, mp3_file_len, err);
if (err == ERR_MP3_INDATA_UNDERFLOW) {
else if (PsndRate == 11025) { mix_samples = mix_16h_to_32_s2; length_mp3 <<= 2; shr = 2; }
if (1152 - mp3_buffer_offs >= length_mp3) {
- mix_samples(buffer, mp3_out_buffer + mp3_buffer_offs*2, length<<1);
+ mix_samples(buffer, cdda_out_buffer + mp3_buffer_offs*2, length<<1);
mp3_buffer_offs += length_mp3;
} else {
int ret, left = 1152 - mp3_buffer_offs;
- mix_samples(buffer, mp3_out_buffer + mp3_buffer_offs*2, (left>>shr)<<1);
+ mix_samples(buffer, cdda_out_buffer + mp3_buffer_offs*2, (left>>shr)<<1);
ret = mp3_decode();
if (ret == 0) {
mp3_buffer_offs = length_mp3 - left;
- mix_samples(buffer + ((left>>shr)<<1), mp3_out_buffer, (mp3_buffer_offs>>shr)<<1);
+ mix_samples(buffer + ((left>>shr)<<1), cdda_out_buffer, (mp3_buffer_offs>>shr)<<1);
} else
mp3_buffer_offs = 0;
}
../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/cue.o ../../Pico/cd/gfx_cd.o \\r
../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o ../../Pico/cd/buffering.o\r
endif\r
+# Pico - Pico\r
+OBJS += ../../Pico/Pico/Pico.o ../../Pico/Pico/Memory.o\r
# Pico - carthw\r
OBJS += ../../Pico/carthw/carthw.o ../../Pico/carthw/svp/svp.o ../../Pico/carthw/svp/Memory.o \\r
../../Pico/carthw/svp/ssp16.o ../../Pico/carthw/svp/compiler.o ../../Pico/carthw/svp/stub_arm.o\r
}
-int mp3_get_offset(void)
-{
- return 0;
-}
-
-
}\r
\r
\r
-\r
-int mp3_get_offset(void) // 0-1023\r
-{\r
- return 0;\r
-}\r
-\r
void mp3_update(int *buffer, int length, int stereo)\r
{\r
}\r