static int ReadBlock (const char *key, void *block, int max_len, STREAM snap) { char buffer [20]; int len = 0; int rem = 0; if (READ_STREAM (buffer, 11, snap) != 11 || strncmp (buffer, key, 4) != 0 || (len = atoi (&buffer [4])) == 0) return (WRONG_FORMAT); if (len > max_len) { rem = len - max_len; len = max_len; } if (READ_STREAM (block, len, snap) != len) return (WRONG_FORMAT); if (rem) { char *junk = new char [rem]; READ_STREAM (junk, rem, snap); delete[] junk; } return (SUCCESS); }
void S9xMSU1PostLoadState(void) { if (DataOpen()) { REVERT_STREAM(dataStream, MSU1.MSU1_DATA_POS, 0); } if (MSU1.MSU1_STATUS & AudioPlaying) { if (AudioOpen()) { REVERT_STREAM(audioStream, 4, 0); READ_STREAM((char *)&audioLoopPos, 4, audioStream); audioLoopPos = GET_LE32(&audioLoopPos); audioLoopPos <<= 2; audioLoopPos += 8; REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0); } else { MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); MSU1.MSU1_STATUS |= AudioError; } } bufPos = 0; bufBegin = 0; bufEnd = 0; partial_frames = 0; }
static bool AudioOpen() { MSU1.MSU1_STATUS |= AudioError; AudioClose(); char ext[_MAX_EXT]; snprintf(ext, _MAX_EXT, "-%d.pcm", MSU1.MSU1_CURRENT_TRACK); audioStream = S9xMSU1OpenFile(ext); if (audioStream) { if (GETC_STREAM(audioStream) != 'M') return false; if (GETC_STREAM(audioStream) != 'S') return false; if (GETC_STREAM(audioStream) != 'U') return false; if (GETC_STREAM(audioStream) != '1') return false; READ_STREAM((char *)&audioLoopPos, 4, audioStream); audioLoopPos = GET_LE32(&audioLoopPos); audioLoopPos <<= 2; audioLoopPos += 8; MSU1.MSU1_AUDIO_POS = 8; MSU1.MSU1_STATUS &= ~AudioError; return true; } return false; }
void S9xMSU1PostLoadState(void) { if (DataOpen()) { REVERT_STREAM(dataStream, MSU1.MSU1_DATA_POS, 0); } if (MSU1.MSU1_STATUS & AudioPlaying) { uint32 savedPosition = MSU1.MSU1_AUDIO_POS; if (AudioOpen()) { REVERT_STREAM(audioStream, 4, 0); READ_STREAM((char *)&audioLoopPos, 4, audioStream); audioLoopPos = GET_LE32(&audioLoopPos); audioLoopPos <<= 2; audioLoopPos += 8; MSU1.MSU1_AUDIO_POS = savedPosition; REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0); } else { MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); MSU1.MSU1_STATUS |= AudioError; } } if (msu_resampler) msu_resampler->clear(); partial_frames = 0; }
void S9xMSU1Generate(size_t sample_count) { partial_frames += 4410 * (sample_count / 2); while ((bufPos < (bufEnd - 2)) && partial_frames >= 3204) { if (MSU1.MSU1_STATUS & AudioPlaying && audioStream) { int32 sample; int16* left = (int16*)&sample; int16* right = left + 1; int bytes_read = READ_STREAM((char *)&sample, 4, audioStream); if (bytes_read == 4) { *left = ((int32)(int16)GET_LE16(left) * MSU1.MSU1_VOLUME / 255); *right = ((int32)(int16)GET_LE16(right) * MSU1.MSU1_VOLUME / 255); *(bufPos++) = *left; *(bufPos++) = *right; MSU1.MSU1_AUDIO_POS += 4; partial_frames -= 3204; } else if (bytes_read >= 0) { if (MSU1.MSU1_STATUS & AudioRepeating) { MSU1.MSU1_AUDIO_POS = audioLoopPos; REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0); } else { MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); REVERT_STREAM(audioStream, 8, 0); } } else { MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); } } else { MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); partial_frames -= 3204; *(bufPos++) = 0; *(bufPos++) = 0; } } }
int S9xMovieOpen (const char* filename, bool8 read_only) { FILE* fd; STREAM stream; int result; int fn; char movie_filename [_MAX_PATH]; #ifdef __WIN32__ _fullpath(movie_filename, filename, _MAX_PATH); #else strcpy(movie_filename, filename); #endif if(!(fd=fopen(movie_filename, "rb+"))) if(!(fd=fopen(movie_filename, "rb"))) return FILE_NOT_FOUND; else read_only = TRUE; const bool8 wasPaused = Settings.Paused; // stop current movie before opening change_state(MOVIE_STATE_NONE); // read header if((result=read_movie_header(fd, &Movie))!=SUCCESS) { fclose(fd); return result; } read_movie_extrarominfo(fd, &Movie); fn=dup(fileno(fd)); fclose(fd); // apparently this lseek is necessary lseek(fn, Movie.SaveStateOffset, SEEK_SET); if(!(stream=REOPEN_STREAM(fn, "rb"))) return FILE_NOT_FOUND; // store previous, before changing to the movie's settings store_previous_settings(); // set from movie restore_movie_settings(); if(Movie.Opts & MOVIE_OPT_FROM_RESET) { Movie.State = MOVIE_STATE_PLAY; // prevent NSRT controller switching (in S9xPostRomInit) if(!Memory.LoadLastROM()) S9xReset(); Memory.ClearSRAM(false); // in case the SRAM read fails Movie.State = MOVIE_STATE_NONE; S9xMovieResetControls(); // save only SRAM for a from-reset snapshot result=(READ_STREAM(Memory.SRAM, 0x20000, stream) == 0x20000) ? SUCCESS : WRONG_FORMAT; } else { result=S9xUnfreezeFromStream(stream); } CLOSE_STREAM(stream); if(result!=SUCCESS) { return result; } if(!(fd=fopen(movie_filename, "rb+"))) if(!(fd=fopen(movie_filename, "rb"))) return FILE_NOT_FOUND; else read_only = TRUE; if(fseek(fd, Movie.ControllerDataOffset, SEEK_SET)) return WRONG_FORMAT; // read controller data Movie.File=fd; Movie.BytesPerSample=bytes_per_sample(); Movie.InputBufferPtr=Movie.InputBuffer; uint32 to_read=Movie.BytesPerSample * (Movie.MaxSample+1); reserve_buffer_space(to_read); fread(Movie.InputBufferPtr, 1, to_read, fd); // read "baseline" controller data if(Movie.MaxSample && Movie.MaxFrame) read_frame_controller_data(true); strncpy(Movie.Filename, movie_filename, _MAX_PATH); Movie.Filename[_MAX_PATH-1]='\0'; Movie.CurrentFrame=0; Movie.CurrentSample=0; Movie.ReadOnly=read_only; change_state(MOVIE_STATE_PLAY); Settings.Paused = wasPaused; Movie.RecordedThisSession = false; S9xUpdateFrameCounter(-1); S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_REPLAY); return SUCCESS; }
bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) { size_t soundResourceLength; bool result = false; GameSoundType resourceType = kSoundPCM; int rate = 0, size = 0; Common::File *file; if (resourceId == (uint32)-1) { return false; } #ifdef ENABLE_IHNM //TODO: move to resource_res so we can use normal "getResourceData" and "getFile" methods if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { char soundFileName[40]; int dirIndex = resourceId / 64; if ((context->fileType() & GAME_VOICEFILE) != 0) { if (_voiceSerial == 0) { sprintf(soundFileName, "Voices/VoicesS/Voices%d/VoicesS%03x", dirIndex, resourceId); } else { sprintf(soundFileName, "Voices/Voices%d/Voices%d/Voices%d%03x", _voiceSerial, dirIndex, _voiceSerial, resourceId); } } else { sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId); } file = new Common::File(); file->open(soundFileName); soundResourceLength = file->size(); } else #endif { ResourceData* resourceData = context->getResourceData(resourceId); file = context->getFile(resourceData); file->seek(resourceData->offset); soundResourceLength = resourceData->size; } Common::SeekableReadStream &readS = *file; bool uncompressedSound = false; if (soundResourceLength >= 8) { byte header[8]; readS.read(&header, 8); readS.seek(readS.pos() - 8); if (!memcmp(header, "Creative", 8)) { resourceType = kSoundVOC; } else if (!memcmp(header, "RIFF", 4) != 0) { resourceType = kSoundWAV; } else if (!memcmp(header, "FORM", 4) != 0) { resourceType = kSoundAIFF; } else if (!memcmp(header, "ajkg", 4) != 0) { resourceType = kSoundShorten; } // If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed // Patch data for this resource is in file p2_a.iaf or p2_a.voc if (_vm->getGameId() == GID_ITE && resourceId == 4 && context->getResourceData(resourceId)->patchData != NULL) uncompressedSound = true; // FIXME: Currently, the SFX.RES file in IHNM cannot be compressed if (_vm->getGameId() == GID_IHNM && (context->fileType() & GAME_SOUNDFILE)) uncompressedSound = true; if (context->isCompressed() && !uncompressedSound) { if (header[0] == char(0)) { resourceType = kSoundMP3; } else if (header[0] == char(1)) { resourceType = kSoundOGG; } else if (header[0] == char(2)) { resourceType = kSoundFLAC; } } } // Default sound type is 16-bit signed PCM, used in ITE byte rawFlags = Audio::FLAG_16BITS; if (_vm->getGameId() == GID_ITE) { if (context->fileType() & GAME_MACBINARY) { // ITE Mac has sound in the Mac snd format resourceType = kSoundMacSND; } else if (_vm->getFeatures() & GF_8BIT_UNSIGNED_PCM) { // older ITE demos rawFlags |= Audio::FLAG_UNSIGNED; rawFlags &= ~Audio::FLAG_16BITS; } else if (!uncompressedSound && !scumm_stricmp(context->fileName(), "voicesd.rsc")) { // Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded. resourceType = kSoundVOX; } } buffer.stream = 0; // Check for LE sounds if (!context->isBigEndian()) rawFlags |= Audio::FLAG_LITTLE_ENDIAN; switch (resourceType) { case kSoundPCM: { // In ITE CD German, some voices are absent and contain just 5 zero bytes. // Round down to an even number when the audio is 16-bit so makeRawStream // will accept the data (needs to be an even size for 16-bit data). // See bug #1256701 if ((soundResourceLength & 1) && (rawFlags & Audio::FLAG_16BITS)) soundResourceLength &= ~1; Audio::SeekableAudioStream *audStream = Audio::makeRawStream(READ_STREAM(soundResourceLength), 22050, rawFlags); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundVOX: buffer.stream = Audio::makeADPCMStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES, soundResourceLength, Audio::kADPCMOki, 22050, 1); buffer.streamLength = Audio::Timestamp(0, soundResourceLength * 2, buffer.stream->getRate()); result = true; break; case kSoundMacSND: { Audio::SeekableAudioStream *audStream = Audio::makeMacSndStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundAIFF: { Audio::SeekableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundVOC: { Audio::SeekableAudioStream *audStream = Audio::makeVOCStream(READ_STREAM(soundResourceLength), Audio::FLAG_UNSIGNED, DisposeAfterUse::YES); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundWAV: case kSoundShorten: if (resourceType == kSoundWAV) { result = Audio::loadWAVFromStream(readS, size, rate, rawFlags); #ifdef ENABLE_SAGA2 } else if (resourceType == kSoundShorten) { result = loadShortenFromStream(readS, size, rate, rawFlags); #endif } if (result) { Audio::SeekableAudioStream *audStream = Audio::makeRawStream(READ_STREAM(size), rate, rawFlags); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); } break; case kSoundMP3: case kSoundOGG: case kSoundFLAC: { readS.skip(9); // skip sfx header Audio::SeekableAudioStream *audStream = 0; Common::SeekableReadStream *memStream = READ_STREAM(soundResourceLength - 9); if (resourceType == kSoundMP3) { #ifdef USE_MAD audStream = Audio::makeMP3Stream(memStream, DisposeAfterUse::YES); #endif } else if (resourceType == kSoundOGG) { #ifdef USE_VORBIS audStream = Audio::makeVorbisStream(memStream, DisposeAfterUse::YES); #endif } else /* if (resourceType == kSoundFLAC) */ { #ifdef USE_FLAC audStream = Audio::makeFLACStream(memStream, DisposeAfterUse::YES); #endif } if (audStream) { buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } else { delete memStream; } } break; default: error("SndRes::load Unknown sound type"); } if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { delete file; } if (onlyHeader) { delete buffer.stream; buffer.stream = 0; } return result; }
int S9xMovieOpen (const char* filename, bool8 read_only) { FILE* fd; STREAM stream; int result; int fn; if(!(fd=fopen(filename, read_only ? "rb" : "rb+"))) return FILE_NOT_FOUND; // stop current movie before opening change_state(MOVIE_STATE_NONE); // read header if((result=read_movie_header(fd, &Movie))!=SUCCESS) { fclose(fd); return result; } fn=dup(fileno(fd)); fclose(fd); // apparently this lseek is necessary lseek(fn, Movie.SaveStateOffset, SEEK_SET); if(!(stream=REOPEN_STREAM(fn, "rb"))) return FILE_NOT_FOUND; if(Movie.Opts & MOVIE_OPT_FROM_RESET) { S9xReset(); // save only SRAM for a from-reset snapshot result=(READ_STREAM(SRAM, 0x20000, stream) == 0x20000) ? SUCCESS : WRONG_FORMAT; } else { result=S9xUnfreezeFromStream(stream); } CLOSE_STREAM(stream); if(result!=SUCCESS) { return result; } if(!(fd=fopen(filename, read_only ? "rb" : "rb+"))) return FILE_NOT_FOUND; if(fseek(fd, Movie.ControllerDataOffset, SEEK_SET)) return WRONG_FORMAT; // read controller data Movie.File=fd; Movie.BytesPerFrame=bytes_per_frame(); Movie.InputBufferPtr=Movie.InputBuffer; uint32 to_read=Movie.BytesPerFrame * (Movie.MaxFrame+1); reserve_buffer_space(to_read); fread(Movie.InputBufferPtr, 1, to_read, fd); // read "baseline" controller data read_frame_controller_data(); strncpy(Movie.Filename, filename, _MAX_PATH); Movie.Filename[_MAX_PATH-1]='\0'; Movie.CurrentFrame=0; Movie.ReadOnly=read_only; change_state(MOVIE_STATE_PLAY); S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_REPLAY); return SUCCESS; }
size_t fReader::read(char *buf, size_t len){ return READ_STREAM(buf, len, fp); }
static int ReadOrigSnapshot (STREAM snap) { char buffer [_MAX_PATH]; char rom_filename [_MAX_PATH]; int result; int i; int j; int version; int len = strlen (ORIG_SNAPSHOT_MAGIC) + 1 + 4 + 1; if (READ_STREAM (buffer, len, snap) != len) return (WRONG_FORMAT); if (strncmp (buffer, ORIG_SNAPSHOT_MAGIC, strlen (ORIG_SNAPSHOT_MAGIC)) != 0) return (WRONG_FORMAT); if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > ORIG_SNAPSHOT_VERSION) return (WRONG_VERSION); if ((result = ReadBlock ("NAM:", rom_filename, _MAX_PATH, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("HiR:", buffer, 0x41, snap)) != SUCCESS) return (result); if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 && strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0) { S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME, "Current loaded ROM image doesn't match that required by freeze-game file."); } S9xReset (); S9xSetSoundMute (TRUE); if ((result = ReadBlock ("CPU:", &OrigCPU, sizeof (OrigCPU), snap)) != SUCCESS) return (result); OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old; Memory.FixROMSpeed (); if (version == 3) { OrigCPU.Cycles = OrigCPU.Cycles_old; OrigCPU.NextEvent = OrigCPU.NextEvent_old; OrigCPU.V_Counter = OrigCPU.V_Counter_old; OrigCPU.MemSpeed = OrigCPU.MemSpeed_old; OrigCPU.MemSpeedx2 = OrigCPU.MemSpeedx2_old; OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old; } CPU.Flags = OrigCPU.Flags; CPU.BranchSkip = OrigCPU.BranchSkip; CPU.NMIActive = OrigCPU.NMIActive; CPU.IRQActive = OrigCPU.IRQActive; CPU.WaitingForInterrupt = OrigCPU.WaitingForInterrupt; CPU.WhichEvent = OrigCPU.WhichEvent; CPU.Cycles = OrigCPU.Cycles; CPU.NextEvent = OrigCPU.NextEvent; CPU.V_Counter = OrigCPU.V_Counter; CPU.MemSpeed = OrigCPU.MemSpeed; CPU.MemSpeedx2 = OrigCPU.MemSpeedx2; CPU.FastROMSpeed = OrigCPU.FastROMSpeed; if ((result = ReadBlock ("REG:", &OrigRegisters, sizeof (OrigRegisters), snap)) != SUCCESS) return (result); Registers = *(struct SRegisters *) &OrigRegisters; if ((result = ReadBlock ("PPU:", &OrigPPU, sizeof (OrigPPU), snap)) != SUCCESS) return (result); if (version == 2) { OrigPPU.OBJNameSelect = OrigPPU.OBJNameSelect_old << 13; OrigPPU.OBJNameBase <<= 1; OrigPPU.OBJNameSelect <<= 13; } PPU.BGMode = OrigPPU.BGMode; PPU.BG3Priority = OrigPPU.BG3Priority; PPU.Brightness = OrigPPU.Brightness; PPU.VMA.High = OrigPPU.VMA.High; PPU.VMA.Increment = OrigPPU.VMA.Increment; PPU.VMA.Address = OrigPPU.VMA.Address; PPU.VMA.Mask1 = OrigPPU.VMA.Mask1; PPU.VMA.FullGraphicCount = OrigPPU.VMA.FullGraphicCount; PPU.VMA.Shift = OrigPPU.VMA.Shift; for (i = 0; i < 4; i++) { PPU.BG[i].SCBase = OrigPPU.BG[i].SCBase; PPU.BG[i].VOffset = OrigPPU.BG[i].VOffset; PPU.BG[i].HOffset = OrigPPU.BG[i].HOffset; PPU.BG[i].BGSize = OrigPPU.BG[i].BGSize; PPU.BG[i].NameBase = OrigPPU.BG[i].NameBase; PPU.BG[i].SCSize = OrigPPU.BG[i].SCSize; } PPU.CGFLIP = OrigPPU.CGFLIP; for (i = 0; i < 256; i++) PPU.CGDATA [i] = OrigPPU.CGDATA [i]; PPU.FirstSprite = OrigPPU.FirstSprite; for (i = 0; i < 128; i++) { PPU.OBJ[i].HPos = OrigPPU.OBJ [i].HPos; PPU.OBJ[i].VPos = OrigPPU.OBJ [i].VPos; PPU.OBJ[i].Name = OrigPPU.OBJ [i].Name; PPU.OBJ[i].VFlip = OrigPPU.OBJ [i].VFlip; PPU.OBJ[i].HFlip = OrigPPU.OBJ [i].HFlip; PPU.OBJ[i].Priority = OrigPPU.OBJ [i].Priority; PPU.OBJ[i].Palette = OrigPPU.OBJ [i].Palette; PPU.OBJ[i].Size = OrigPPU.OBJ [i].Size; } PPU.OAMPriorityRotation = OrigPPU.OAMPriorityRotation; PPU.OAMAddr = OrigPPU.OAMAddr; PPU.OAMFlip = OrigPPU.OAMFlip; PPU.OAMTileAddress = OrigPPU.OAMTileAddress; PPU.IRQVBeamPos = OrigPPU.IRQVBeamPos; PPU.IRQHBeamPos = OrigPPU.IRQHBeamPos; PPU.VBeamPosLatched = OrigPPU.VBeamPosLatched; PPU.HBeamPosLatched = OrigPPU.HBeamPosLatched; PPU.HBeamFlip = OrigPPU.HBeamFlip; PPU.VBeamFlip = OrigPPU.VBeamFlip; PPU.HVBeamCounterLatched = OrigPPU.HVBeamCounterLatched; PPU.MatrixA = OrigPPU.MatrixA; PPU.MatrixB = OrigPPU.MatrixB; PPU.MatrixC = OrigPPU.MatrixC; PPU.MatrixD = OrigPPU.MatrixD; PPU.CentreX = OrigPPU.CentreX; PPU.CentreY = OrigPPU.CentreY; PPU.Joypad1ButtonReadPos = OrigPPU.Joypad1ButtonReadPos; PPU.Joypad2ButtonReadPos = OrigPPU.Joypad2ButtonReadPos; PPU.Joypad3ButtonReadPos = OrigPPU.Joypad3ButtonReadPos; PPU.CGADD = OrigPPU.CGADD; PPU.FixedColourRed = OrigPPU.FixedColourRed; PPU.FixedColourGreen = OrigPPU.FixedColourGreen; PPU.FixedColourBlue = OrigPPU.FixedColourBlue; PPU.SavedOAMAddr = OrigPPU.SavedOAMAddr; PPU.ScreenHeight = OrigPPU.ScreenHeight; PPU.WRAM = OrigPPU.WRAM; PPU.ForcedBlanking = OrigPPU.ForcedBlanking; PPU.OBJNameSelect = OrigPPU.OBJNameSelect; PPU.OBJSizeSelect = OrigPPU.OBJSizeSelect; PPU.OBJNameBase = OrigPPU.OBJNameBase; PPU.OAMReadFlip = OrigPPU.OAMReadFlip; memmove (PPU.OAMData, OrigPPU.OAMData, sizeof (PPU.OAMData)); PPU.VTimerEnabled = OrigPPU.VTimerEnabled; PPU.HTimerEnabled = OrigPPU.HTimerEnabled; PPU.HTimerPosition = OrigPPU.HTimerPosition; PPU.Mosaic = OrigPPU.Mosaic; memmove (PPU.BGMosaic, OrigPPU.BGMosaic, sizeof (PPU.BGMosaic)); PPU.Mode7HFlip = OrigPPU.Mode7HFlip; PPU.Mode7VFlip = OrigPPU.Mode7VFlip; PPU.Mode7Repeat = OrigPPU.Mode7Repeat; PPU.Window1Left = OrigPPU.Window1Left; PPU.Window1Right = OrigPPU.Window1Right; PPU.Window2Left = OrigPPU.Window2Left; PPU.Window2Right = OrigPPU.Window2Right; for (i = 0; i < 6; i++) { PPU.ClipWindowOverlapLogic [i] = OrigPPU.ClipWindowOverlapLogic [i]; PPU.ClipWindow1Enable [i] = OrigPPU.ClipWindow1Enable [i]; PPU.ClipWindow2Enable [i] = OrigPPU.ClipWindow2Enable [i]; PPU.ClipWindow1Inside [i] = OrigPPU.ClipWindow1Inside [i]; PPU.ClipWindow2Inside [i] = OrigPPU.ClipWindow2Inside [i]; } PPU.CGFLIPRead = OrigPPU.CGFLIPRead; PPU.Need16x8Mulitply = OrigPPU.Need16x8Mulitply; IPPU.ColorsChanged = TRUE; IPPU.OBJChanged = TRUE; S9xFixColourBrightness (); IPPU.RenderThisFrame = FALSE; if ((result = ReadBlock ("DMA:", OrigDMA, sizeof (OrigDMA), snap)) != SUCCESS) return (result); for (i = 0; i < 8; i++) { DMA[i].TransferDirection = OrigDMA[i].TransferDirection; DMA[i].AAddressFixed = OrigDMA[i].AAddressFixed; DMA[i].AAddressDecrement = OrigDMA[i].AAddressDecrement; DMA[i].TransferMode = OrigDMA[i].TransferMode; DMA[i].ABank = OrigDMA[i].ABank; DMA[i].AAddress = OrigDMA[i].AAddress; DMA[i].Address = OrigDMA[i].Address; DMA[i].BAddress = OrigDMA[i].BAddress; DMA[i].TransferBytes = OrigDMA[i].TransferBytes; DMA[i].HDMAIndirectAddressing = OrigDMA[i].HDMAIndirectAddressing; DMA[i].IndirectAddress = OrigDMA[i].IndirectAddress; DMA[i].IndirectBank = OrigDMA[i].IndirectBank; DMA[i].Repeat = OrigDMA[i].Repeat; DMA[i].LineCount = OrigDMA[i].LineCount; DMA[i].FirstLine = OrigDMA[i].FirstLine; } if ((result = ReadBlock ("VRA:", Memory.VRAM, 0x10000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("RAM:", Memory.RAM, 0x20000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("SRA:", Memory.SRAM, 0x10000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("FIL:", Memory.FillRAM, 0x8000, snap)) != SUCCESS) return (result); if (ReadBlock ("APU:", &OrigAPU, sizeof (OrigAPU), snap) == SUCCESS) { APU = *(struct SAPU *) &OrigAPU; if ((result = ReadBlock ("ARE:", &OrigAPURegisters, sizeof (OrigAPURegisters), snap)) != SUCCESS) return (result); APURegisters = *(struct SAPURegisters *) &OrigAPURegisters; if ((result = ReadBlock ("ARA:", IAPU.RAM, 0x10000, snap)) != SUCCESS) return (result); if ((result = ReadBlock ("SOU:", &OrigSoundData, sizeof (SOrigSoundData), snap)) != SUCCESS) return (result); SoundData.master_volume_left = OrigSoundData.master_volume_left; SoundData.master_volume_right = OrigSoundData.master_volume_right; SoundData.echo_volume_left = OrigSoundData.echo_volume_left; SoundData.echo_volume_right = OrigSoundData.echo_volume_right; SoundData.echo_enable = OrigSoundData.echo_enable; SoundData.echo_feedback = OrigSoundData.echo_feedback; SoundData.echo_ptr = OrigSoundData.echo_ptr; SoundData.echo_buffer_size = OrigSoundData.echo_buffer_size; SoundData.echo_write_enabled = OrigSoundData.echo_write_enabled; SoundData.echo_channel_enable = OrigSoundData.echo_channel_enable; SoundData.pitch_mod = OrigSoundData.pitch_mod; for (i = 0; i < 3; i++) SoundData.dummy [i] = OrigSoundData.dummy [i]; for (i = 0; i < NUM_CHANNELS; i++) { SoundData.channels [i].state = OrigSoundData.channels [i].state; SoundData.channels [i].type = OrigSoundData.channels [i].type; SoundData.channels [i].volume_left = OrigSoundData.channels [i].volume_left; SoundData.channels [i].volume_right = OrigSoundData.channels [i].volume_right; SoundData.channels [i].hertz = OrigSoundData.channels [i].frequency; SoundData.channels [i].count = OrigSoundData.channels [i].count; SoundData.channels [i].loop = OrigSoundData.channels [i].loop; SoundData.channels [i].envx = OrigSoundData.channels [i].envx; SoundData.channels [i].left_vol_level = OrigSoundData.channels [i].left_vol_level; SoundData.channels [i].right_vol_level = OrigSoundData.channels [i].right_vol_level; SoundData.channels [i].envx_target = OrigSoundData.channels [i].envx_target; SoundData.channels [i].env_error = OrigSoundData.channels [i].env_error; SoundData.channels [i].erate = OrigSoundData.channels [i].erate; SoundData.channels [i].direction = OrigSoundData.channels [i].direction; SoundData.channels [i].attack_rate = OrigSoundData.channels [i].attack_rate; SoundData.channels [i].decay_rate = OrigSoundData.channels [i].decay_rate; SoundData.channels [i].sustain_rate = OrigSoundData.channels [i].sustain_rate; SoundData.channels [i].release_rate = OrigSoundData.channels [i].release_rate; SoundData.channels [i].sustain_level = OrigSoundData.channels [i].sustain_level; SoundData.channels [i].sample = OrigSoundData.channels [i].sample; for (j = 0; j < 16; j++) SoundData.channels [i].decoded [j] = OrigSoundData.channels [i].decoded [j]; for (j = 0; j < 2; j++) SoundData.channels [i].previous [j] = OrigSoundData.channels [i].previous [j]; SoundData.channels [i].sample_number = OrigSoundData.channels [i].sample_number; SoundData.channels [i].last_block = OrigSoundData.channels [i].last_block; SoundData.channels [i].needs_decode = OrigSoundData.channels [i].needs_decode; SoundData.channels [i].block_pointer = OrigSoundData.channels [i].block_pointer; SoundData.channels [i].sample_pointer = OrigSoundData.channels [i].sample_pointer; SoundData.channels [i].mode = OrigSoundData.channels [i].mode; } S9xSetSoundMute (FALSE); IAPU.PC = IAPU.RAM + APURegisters.PC; S9xAPUUnpackStatus (); if (APUCheckDirectPage ()) IAPU.DirectPage = IAPU.RAM + 0x100; else IAPU.DirectPage = IAPU.RAM; Settings.APUEnabled = TRUE; IAPU.APUExecuting = TRUE; } else { Settings.APUEnabled = FALSE; IAPU.APUExecuting = FALSE; S9xSetSoundMute (TRUE); } S9xFixSoundAfterSnapshotLoad (1); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase (ICPU.ShiftedPB + Registers.PC); S9xUnpackStatus (); S9xFixCycles (); S9xReschedule (); return (SUCCESS); }
int S9xMovieOpen (const char* filename, bool8 read_only, uint8 sync_flags, uint8 sync_flags2) { FILE* fd; STREAM stream; int result; int fn; char movie_filename [_MAX_PATH]; #ifdef WIN32 _fullpath(movie_filename, filename, _MAX_PATH); #else strcpy(movie_filename, filename); #endif if(!(fd=fopen(movie_filename, "rb+"))) if(!(fd=fopen(movie_filename, "rb"))) return FILE_NOT_FOUND; else read_only = TRUE; const bool8 wasPaused = Settings.Paused; const uint32 prevFrameTime = Settings.FrameTime; // stop current movie before opening change_state(MOVIE_STATE_NONE); // read header if((result=read_movie_header(fd, &Movie))!=SUCCESS) { fclose(fd); return result; } read_movie_extrarominfo(fd, &Movie); fn=dup(fileno(fd)); fclose(fd); // apparently this lseek is necessary lseek(fn, Movie.SaveStateOffset, SEEK_SET); if(!(stream=REOPEN_STREAM(fn, "rb"))) return FILE_NOT_FOUND; // store previous, before changing to the movie's settings store_previous_settings(); // store default if (sync_flags & MOVIE_SYNC_DATA_EXISTS) { Settings.UseWIPAPUTiming = (sync_flags & MOVIE_SYNC_WIP1TIMING) ? TRUE : FALSE; Settings.SoundEnvelopeHeightReading = (sync_flags & MOVIE_SYNC_VOLUMEENVX) ? TRUE : FALSE; Settings.FakeMuteFix = (sync_flags & MOVIE_SYNC_FAKEMUTE) ? TRUE : FALSE; Settings.UpAndDown = (sync_flags & MOVIE_SYNC_LEFTRIGHT) ? TRUE : FALSE; // doesn't actually affect synchronization Settings.SoundSync = (sync_flags & MOVIE_SYNC_SYNCSOUND) ? TRUE : FALSE; // doesn't seem to affect synchronization Settings.InitFastROMSetting = (sync_flags2 & MOVIE_SYNC2_INIT_FASTROM) ? TRUE : FALSE; //Settings.ShutdownMaster = (sync_flags & MOVIE_SYNC_NOCPUSHUTDOWN) ? FALSE : TRUE; } // set from movie restore_movie_settings(); if(Movie.Opts & MOVIE_OPT_FROM_RESET) { Movie.State = MOVIE_STATE_PLAY; // prevent NSRT controller switching (in S9xPostRomInit) if(!Memory.LoadLastROM()) S9xReset(); Memory.ClearSRAM(false); // in case the SRAM read fails Movie.State = MOVIE_STATE_NONE; // save only SRAM for a from-reset snapshot result=(READ_STREAM(Memory.SRAM, 0x20000, stream) == 0x20000) ? SUCCESS : WRONG_FORMAT; } else { result=S9xUnfreezeFromStream(stream); } CLOSE_STREAM(stream); if(result!=SUCCESS) { return result; } if(!(fd=fopen(movie_filename, "rb+"))) if(!(fd=fopen(movie_filename, "rb"))) return FILE_NOT_FOUND; else read_only = TRUE; if(fseek(fd, Movie.ControllerDataOffset, SEEK_SET)) return WRONG_FORMAT; // read controller data Movie.File=fd; Movie.BytesPerFrame=bytes_per_frame(); Movie.InputBufferPtr=Movie.InputBuffer; uint32 to_read=Movie.BytesPerFrame * (Movie.MaxFrame+1); reserve_buffer_space(to_read); fread(Movie.InputBufferPtr, 1, to_read, fd); // read "baseline" controller data if(Movie.MaxFrame) read_frame_controller_data(); strncpy(Movie.Filename, movie_filename, _MAX_PATH); Movie.Filename[_MAX_PATH-1]='\0'; Movie.CurrentFrame=0; Movie.ReadOnly=read_only; change_state(MOVIE_STATE_PLAY); Settings.Paused = wasPaused; Settings.FrameTime = prevFrameTime; // restore emulation speed Movie.RecordedThisSession = false; S9xUpdateFrameCounter(-1); Movie.RequiresReset = false; S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_REPLAY); return SUCCESS; }