diff --git a/msu1.cpp b/msu1.cpp index 36515f10..3a8e693b 100644 --- a/msu1.cpp +++ b/msu1.cpp @@ -199,29 +199,70 @@ #define APU_DEFAULT_INPUT_RATE 32000 std::ifstream dataFile, audioFile; -uint32 dataPos, audioPos, audioResumePos, audioLoopPos; -uint16 audioTrack, audioResumeTrack; +uint32 audioLoopPos; char fName[64]; uint32 partial_samples; -bool audioResume; // Sample buffer int16 *bufPos, *bufBegin, *bufEnd; +bool AudioOpen() +{ + MSU1.MSU1_STATUS |= AudioError; + + if (audioFile.is_open()) + audioFile.close(); + + // This is an ugly hack... need to see if there's a better way to get the base name without extension + sprintf(fName, "%s", S9xGetFilename(".msu", ROMFILENAME_DIR)); + fName[strlen(fName) - 4] = '\0'; + sprintf(fName, "%s-%d.pcm", fName, MSU1.MSU1_CURRENT_TRACK); + + audioFile.clear(); + audioFile.open(fName, std::ios::in | std::ios::binary); + if (audioFile.good()) + { + if (audioFile.get() != 'M') + return false; + if (audioFile.get() != 'S') + return false; + if (audioFile.get() != 'U') + return false; + if (audioFile.get() != '1') + return false; + + audioFile.read((char *)&audioLoopPos, 4); + audioLoopPos <<= 2; + audioLoopPos += 8; + } + + MSU1.MSU1_STATUS &= ~AudioError; + return true; +} + +bool DataOpen() +{ + if (dataFile.is_open()) + dataFile.close(); + + dataFile.clear(); + dataFile.open(S9xGetFilename(".msu", ROMFILENAME_DIR), std::ios::in | std::ios::binary); + return dataFile.is_open(); +} + void S9xMSU1Init(void) { - MSU1.MSU1_STATUS = 0; - MSU1.MSU1_SEEK = 0; - MSU1.MSU1_TRACK = 0; - MSU1.MSU1_VOLUME = 0; - MSU1.MSU1_CONTROL = 0; + MSU1.MSU1_STATUS = 0; + MSU1.MSU1_DATA_SEEK = 0; + MSU1.MSU1_DATA_POS = 0; + MSU1.MSU1_TRACK_SEEK = 0; + MSU1.MSU1_CURRENT_TRACK = 0; + MSU1.MSU1_RESUME_TRACK = 0; + MSU1.MSU1_VOLUME = 0; + MSU1.MSU1_CONTROL = 0; + MSU1.MSU1_AUDIO_POS = 0; + MSU1.MSU1_RESUME_POS = 0; - dataPos = 0; - audioPos = 0; - audioResumePos = 0; - - audioTrack = 0; - audioResumeTrack = 0; bufPos = 0; bufBegin = 0; @@ -235,7 +276,7 @@ void S9xMSU1Init(void) if (audioFile.is_open()) audioFile.close(); - dataFile.open(S9xGetFilename(".msu", ROMFILENAME_DIR), std::ios::in | std::ios::binary); + DataOpen(); } void S9xMSU1Generate(int sample_count) @@ -249,26 +290,26 @@ void S9xMSU1Generate(int sample_count) int16 sample; if (audioFile.read((char *)&sample, 2).good()) { - sample = (double)sample * (double)MSU1.MSU1_VOLUME / 255.0; + sample = (int16)((double)sample * (double)MSU1.MSU1_VOLUME / 255.0); *(bufPos++) = sample; - audioPos += 2; + MSU1.MSU1_AUDIO_POS += 2; partial_samples -= 320405; } else if (audioFile.eof()) { - sample = (double)sample * (double)MSU1.MSU1_VOLUME / 255.0; + sample = (int16)((double)sample * (double)MSU1.MSU1_VOLUME / 255.0); *(bufPos++) = sample; - audioPos += 2; + MSU1.MSU1_AUDIO_POS += 2; partial_samples -= 320405; if (MSU1.MSU1_STATUS & AudioRepeating) { audioFile.clear(); - audioPos = audioLoopPos; - audioFile.seekg(audioPos); + MSU1.MSU1_AUDIO_POS = audioLoopPos; + audioFile.seekg(MSU1.MSU1_AUDIO_POS); } else { @@ -304,6 +345,7 @@ uint8 S9xMSU1ReadPort(int port) return 0; if (dataFile.fail() || dataFile.bad() || dataFile.eof()) return 0; + MSU1.MSU1_DATA_POS++; return dataFile.get(); case 2: return 'S'; @@ -318,6 +360,8 @@ uint8 S9xMSU1ReadPort(int port) case 7: return '1'; } + + return 0; } @@ -326,82 +370,44 @@ void S9xMSU1WritePort(int port, uint8 byte) switch (port) { case 0: - ((uint8 *)(&MSU1.MSU1_SEEK))[0] = byte; + ((uint8 *)(&MSU1.MSU1_DATA_SEEK))[0] = byte; break; case 1: - ((uint8 *)(&MSU1.MSU1_SEEK))[1] = byte; + ((uint8 *)(&MSU1.MSU1_DATA_SEEK))[1] = byte; break; case 2: - ((uint8 *)(&MSU1.MSU1_SEEK))[2] = byte; + ((uint8 *)(&MSU1.MSU1_DATA_SEEK))[2] = byte; break; case 3: - ((uint8 *)(&MSU1.MSU1_SEEK))[3] = byte; - dataPos = MSU1.MSU1_SEEK; + ((uint8 *)(&MSU1.MSU1_DATA_SEEK))[3] = byte; + MSU1.MSU1_DATA_POS = MSU1.MSU1_DATA_SEEK; if(dataFile.good()) - dataFile.seekg(dataPos); + dataFile.seekg(MSU1.MSU1_DATA_POS); break; case 4: - ((uint8 *)(&MSU1.MSU1_TRACK))[0] = byte; + ((uint8 *)(&MSU1.MSU1_TRACK_SEEK))[0] = byte; break; case 5: - ((uint8 *)(&MSU1.MSU1_TRACK))[1] = byte; - audioTrack = MSU1.MSU1_TRACK; - if (audioFile.is_open()) - audioFile.close(); + ((uint8 *)(&MSU1.MSU1_TRACK_SEEK))[1] = byte; + MSU1.MSU1_CURRENT_TRACK = MSU1.MSU1_TRACK_SEEK; - // This is an ugly hack... need to see if there's a better way to get the base name without extension - sprintf(fName, "%s", S9xGetFilename(".msu", ROMFILENAME_DIR)); - fName[strlen(fName) - 4] = '\0'; - sprintf(fName, "%s-%d.pcm", fName, audioTrack); + MSU1.MSU1_STATUS &= ~AudioPlaying; + MSU1.MSU1_STATUS &= ~AudioRepeating; - audioFile.clear(); - audioFile.open(fName, std::ios::in | std::ios::binary); - if (audioFile.is_open()) + if (AudioOpen()) { - MSU1.MSU1_STATUS |= AudioError; - - if (audioFile.get() != 'M') - break; - if (audioFile.get() != 'S') - break; - if (audioFile.get() != 'U') - break; - if (audioFile.get() != '1') - break; - - audioFile.read((char *)&audioLoopPos, 4); - audioLoopPos <<= 2; - audioLoopPos += 8; - - MSU1.MSU1_STATUS &= ~AudioPlaying; - MSU1.MSU1_STATUS &= ~AudioRepeating; - - if (audioResume) + if (MSU1.MSU1_CURRENT_TRACK == MSU1.MSU1_RESUME_TRACK) { - audioResumeTrack = audioTrack; - audioResumePos = audioPos; - audioResume = FALSE; + MSU1.MSU1_AUDIO_POS = MSU1.MSU1_RESUME_POS; + MSU1.MSU1_RESUME_POS = 0; + MSU1.MSU1_RESUME_TRACK = ~0; } else { - if (audioTrack == audioResumeTrack) - { - audioPos = audioResumePos; - audioResumeTrack = 0xFFFF; - audioResumePos = 0; - } - else - audioPos = 8; + MSU1.MSU1_AUDIO_POS = 8; } - audioFile.seekg(audioPos); - - MSU1.MSU1_STATUS &= ~AudioError; - } - else - { - char *e = strerror(errno); - MSU1.MSU1_STATUS |= AudioError; + audioFile.seekg(MSU1.MSU1_AUDIO_POS); } break; case 6: @@ -413,11 +419,10 @@ void S9xMSU1WritePort(int port, uint8 byte) MSU1.MSU1_STATUS = (MSU1.MSU1_STATUS & ~0x30) | ((byte & 0x03) << 4); - audioResume = ((byte & 0x05) == 0x05); - if (byte & 0x04) + if ((byte & (Play | Resume) == Resume)) { - audioResumeTrack = audioTrack; - audioResumePos = audioPos; + MSU1.MSU1_RESUME_TRACK = MSU1.MSU1_CURRENT_TRACK; + MSU1.MSU1_RESUME_POS = MSU1.MSU1_AUDIO_POS; } break; } @@ -433,3 +438,35 @@ void S9xMSU1SetOutput(int16 * out, int size) bufPos = bufBegin = out; bufEnd = out + size; } + +void S9xMSU1PostLoadState(void) +{ + if (DataOpen()) + { + dataFile.seekg(MSU1.MSU1_DATA_POS); + } + + if (MSU1.MSU1_STATUS & AudioPlaying) + { + if (AudioOpen()) + { + audioFile.seekg(4); + audioFile.read((char *)&audioLoopPos, 4); + audioLoopPos <<= 2; + audioLoopPos += 8; + + audioFile.seekg(MSU1.MSU1_AUDIO_POS); + } + else + { + MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); + MSU1.MSU1_STATUS |= AudioError; + } + } + + bufPos = 0; + bufBegin = 0; + bufEnd = 0; + + partial_samples = 0; +} diff --git a/msu1.h b/msu1.h index ddf0728a..fd071cef 100644 --- a/msu1.h +++ b/msu1.h @@ -197,10 +197,15 @@ struct SMSU1 { uint8 MSU1_STATUS; - uint32 MSU1_SEEK; - uint16 MSU1_TRACK; + uint32 MSU1_DATA_SEEK; + uint32 MSU1_DATA_POS; + uint16 MSU1_TRACK_SEEK; + uint16 MSU1_CURRENT_TRACK; + uint32 MSU1_RESUME_TRACK; uint8 MSU1_VOLUME; uint8 MSU1_CONTROL; + uint32 MSU1_AUDIO_POS; + uint32 MSU1_RESUME_POS; }; enum SMSU1_FLAG : uint8 { @@ -213,6 +218,12 @@ enum SMSU1_FLAG : uint8 { DataBusy = 0x80, }; +enum SMSU1_CMD : uint8 { + Play = 0x01, + Repeat = 0x02, + Resume = 0x04, +}; + extern struct SMSU1 MSU1; void S9xMSU1Init(void); @@ -221,5 +232,6 @@ uint8 S9xMSU1ReadPort(int port); void S9xMSU1WritePort(int port, uint8 byte); uint16 S9xMSU1Samples(void); void S9xMSU1SetOutput(int16 *out, int size); +void S9xMSU1PostLoadState(void); #endif diff --git a/snapshot.cpp b/snapshot.cpp index b3dc6ac9..c6e2105b 100644 --- a/snapshot.cpp +++ b/snapshot.cpp @@ -1135,6 +1135,23 @@ static FreezeData SnapBSX[] = ARRAY_ENTRY(6, test2192, 32, uint8_ARRAY_V) }; +#undef STRUCT +#define STRUCT struct SMSU1 + +static FreezeData SnapMSU1[] = +{ + INT_ENTRY(9, MSU1_STATUS), + INT_ENTRY(9, MSU1_DATA_SEEK), + INT_ENTRY(9, MSU1_DATA_POS), + INT_ENTRY(9, MSU1_TRACK_SEEK), + INT_ENTRY(9, MSU1_CURRENT_TRACK), + INT_ENTRY(9, MSU1_RESUME_TRACK), + INT_ENTRY(9, MSU1_VOLUME), + INT_ENTRY(9, MSU1_CONTROL), + INT_ENTRY(9, MSU1_AUDIO_POS), + INT_ENTRY(9, MSU1_RESUME_POS) +}; + #undef STRUCT #define STRUCT struct SnapshotScreenshotInfo @@ -1394,6 +1411,9 @@ void S9xFreezeToStream (STREAM stream) if (Settings.BS) FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX)); + if (Settings.MSU1) + FreezeStruct(stream, "MSU", &MSU1, SnapMSU1, COUNT(SnapMSU1)); + if (Settings.SnapshotScreenshots) { SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; @@ -1494,6 +1514,7 @@ int S9xUnfreezeFromStream (STREAM stream) uint8 *local_srtc = NULL; uint8 *local_rtc_data = NULL; uint8 *local_bsx_data = NULL; + uint8 *local_msu1_data = NULL; uint8 *local_screenshot = NULL; uint8 *local_movie_data = NULL; @@ -1599,6 +1620,10 @@ int S9xUnfreezeFromStream (STREAM stream) if (result != SUCCESS && Settings.BS) break; + result = UnfreezeStructCopy(stream, "MSU", &local_msu1_data, SnapMSU1, COUNT(SnapMSU1), version); + if (result != SUCCESS && Settings.MSU1) + break; + result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version); SnapshotMovieInfo mi; @@ -1717,6 +1742,9 @@ int S9xUnfreezeFromStream (STREAM stream) if (local_bsx_data) UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version); + if (local_msu1_data) + UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version); + if (version < SNAPSHOT_VERSION_IRQ) { printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION); @@ -1798,6 +1826,9 @@ int S9xUnfreezeFromStream (STREAM stream) if (local_bsx_data) S9xBSXPostLoadState(); + if (local_msu1_data) + S9xMSU1PostLoadState(); + if (local_movie_data) { // restore last displayed pad_read status diff --git a/snapshot.h b/snapshot.h index 33688e88..de45fd66 100644 --- a/snapshot.h +++ b/snapshot.h @@ -196,7 +196,7 @@ #define SNAPSHOT_MAGIC "#!s9xsnp" #define SNAPSHOT_VERSION_IRQ 7 #define SNAPSHOT_VERSION_BAPU 8 -#define SNAPSHOT_VERSION 8 +#define SNAPSHOT_VERSION 9 #define SUCCESS 1 #define WRONG_FORMAT (-1)