WAVRecord::WAVRecord(const char *path, double SoundRate_arg, uint32 SoundChan_arg) : wavfile(path, FileStream::MODE_WRITE_SAFE) { Finished = false; PCMBytesWritten = 0; SoundRate = SoundRate_arg; SoundChan = SoundChan_arg; memset(&raw_headers, 0, sizeof(raw_headers)); MDFN_en32msb(&raw_headers[0x00], 0x52494646); // "RIFF" // @ 0x04 = total file size - 8 bytes MDFN_en32msb(&raw_headers[0x08], 0x57415645); // "WAVE" MDFN_en32msb(&raw_headers[0x0C], 0x666d7420); // "fmt " MDFN_en32lsb(&raw_headers[0x10], 16); MDFN_en16lsb(&raw_headers[0x14], 1); // PCM format MDFN_en16lsb(&raw_headers[0x16], SoundChan); // Number of sound channels MDFN_en32lsb(&raw_headers[0x18], SoundRate); // Sampling rate MDFN_en32lsb(&raw_headers[0x1C], SoundRate * SoundChan * sizeof(int16)); //Byte rate MDFN_en16lsb(&raw_headers[0x20], SoundChan * sizeof(int16)); // Block("audio frame" in Mednafen) alignment MDFN_en16lsb(&raw_headers[0x22], sizeof(int16) * 8); // Bits per sample. MDFN_en32msb(&raw_headers[0x24], 0x64617461); // "data" // @ 0x28 = bytes of PCM data following wavfile.write(raw_headers, sizeof(raw_headers)); }
void InputDevice_DualShock::UpdateInput(const void *data) { uint8 *d8 = (uint8 *)data; buttons[0] = d8[0]; buttons[1] = d8[1]; cur_ana_button_state = d8[2] & 0x01; for(int stick = 0; stick < 2; stick++) { for(int axis = 0; axis < 2; axis++) { int32 tmp; tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32767); tmp >>= 8; axes[stick][axis] = tmp; } } if(da_rumble_compat == false) { uint8 sneaky_weaky = 0; if(rumble_param[0] == 0x01) sneaky_weaky = 0xFF; MDFN_en32lsb(&d8[4 + 32 + 0], (sneaky_weaky << 0) | (rumble_param[1] << 8)); } else { uint8 sneaky_weaky = 0; if(((rumble_param[0] & 0xC0) == 0x40) && ((rumble_param[1] & 0x01) == 0x01)) sneaky_weaky = 0xFF; MDFN_en32lsb(&d8[4 + 32 + 0], sneaky_weaky << 0); } //printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); // // // CheckManualAnaModeChange(); if(am_prev_info != analog_mode || aml_prev_info != analog_mode_locked) { MDFN_DispMessage(_("%s: Analog mode is %s(%s)."), gp_name.c_str(), analog_mode ? _("on") : _("off"), analog_mode_locked ? _("locked") : _("unlocked")); } am_prev_info = analog_mode; aml_prev_info = analog_mode_locked; }
void WAVRecord::Finish(void) { if(Finished) return; MDFN_en32lsb(&raw_headers[0x04], std::min(wavfile.tell() - 8, (int64)0xFFFFFFFFLL)); MDFN_en32lsb(&raw_headers[0x28], std::min(PCMBytesWritten, (int64)0xFFFFFFFFLL)); wavfile.seek(0, SEEK_SET); wavfile.write(raw_headers, sizeof(raw_headers)); wavfile.close(); Finished = true; }
int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, uint32 *fb, MDFN_Rect *LineWidths) { static uint8 header[32]="MEDNAFENSVESTATE"; int neowidth, neoheight; neowidth = MDFNGameInfo->ss_preview_width; neoheight = MDFNGameInfo->DisplayRect.h; if(!data_only) { memset(header+16,0,16); MDFN_en32lsb(header + 12, currFrameCounter); MDFN_en32lsb(header + 16, pcejin.lagFrameCounter); // MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); } if(wantpreview) { uint8 *previewbuffer = (uint8 *)malloc(17 * neowidth * neoheight); // MakeStatePreview(previewbuffer, fb, LineWidths); smem_write(st, fb, 17 * neowidth * neoheight); free(previewbuffer); } // State rewinding code path hack, FIXME //if(data_only) //{ // if(!MDFN_RawInputStateAction(st, 0, data_only)) // return(0); //} if(!MDFNGameInfo->StateAction(st, 0, data_only)) return(0); if(!data_only) { uint32 sizy = smem_tell(st); smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); } return(1); }
int MDFNSS_SaveSM(void *st_p, int, int, const void*, const void*, const void*) { uint8_t header[32]; StateMem *st = (StateMem*)st_p; static const char *header_magic = "MDFNSVST"; int neowidth = 0, neoheight = 0; memset(header, 0, sizeof(header)); memcpy(header, header_magic, 8); MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); if(!StateAction(st, 0, 0)) return(0); uint32_t sizy = st->loc; smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); return(1); }
static void SendCommand(uint8 cmd, uint32 len, const void* data = NULL) { uint8 buf[1 + LocalInputStateSize + 4]; // Command, unused, command length memset(buf, 0, sizeof(buf)); buf[0] = cmd; MDFN_en32lsb(&buf[1 + LocalInputStateSize], len); MDFND_SendData(buf,LocalInputStateSize + 1 + 4); if(data != NULL) { MDFND_SendData(data, len); } //DelayBuffer.push_back(std::vector<uint8>()); //DelayBuffer. }
static void SendState(void) { StateMem sm; uLongf clen; std::vector<uint8> cbuf; memset(&sm, 0, sizeof(StateMem)); if(!MDFNSS_SaveSM(&sm, 0, 0)) { throw MDFN_Error(0, _("Error during save state generation.")); } clen = sm.len + sm.len / 1000 + 12; cbuf.resize(4 + clen); MDFN_en32lsb(&cbuf[0], sm.len); compress2((Bytef *)&cbuf[0] + 4, &clen, (Bytef *)sm.data, sm.len, 7); free(sm.data); SendCommand(MDFNNPCMD_LOADSTATE, clen + 4, &cbuf[0]); }
void InputDevice_DualShock::UpdateInput(const void *data) { uint8 *d8 = (uint8 *)data; uint8* const rumb_dp = &d8[3 + 16]; buttons[0] = d8[0]; buttons[1] = d8[1]; cur_ana_button_state = d8[2] & 0x01; for(int stick = 0; stick < 2; stick++) { for(int axis = 0; axis < 2; axis++) { const uint8* aba = &d8[3] + stick * 8 + axis * 4; int32 tmp; //revert to 0.9.33, should be fixed on libretro side instead //tmp = 32767 + MDFN_de16lsb(&aba[0]) - MDFN_de16lsb(&aba[2]); //tmp = (tmp * 0x100) / 0xFFFF; tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32767); tmp >>= 8; axes[stick][axis] = tmp; } } //printf("%3d:%3d, %3d:%3d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); //printf("RUMBLE: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", rumble_magic[0], rumble_magic[1], rumble_magic[2], rumble_magic[3], rumble_magic[4], rumble_magic[5]); //printf("%d, 0x%02x 0x%02x\n", da_rumble_compat, rumble_param[0], rumble_param[1]); if(da_rumble_compat == false) { uint8 sneaky_weaky = 0; if(rumble_param[0] == 0x01) sneaky_weaky = 0xFF; //revert to 0.9.33, should be fixed on libretro side instead //MDFN_en16lsb(rumb_dp, (sneaky_weaky << 0) | (rumble_param[1] << 8)); MDFN_en32lsb(&d8[4 + 32 + 0], (sneaky_weaky << 0) | (rumble_param[1] << 8)); } else { uint8 sneaky_weaky = 0; if(((rumble_param[0] & 0xC0) == 0x40) && ((rumble_param[1] & 0x01) == 0x01)) sneaky_weaky = 0xFF; //revert to 0.9.33, should be fixed on libretro side instead //MDFN_en16lsb(rumb_dp, sneaky_weaky << 0); MDFN_en32lsb(&d8[4 + 32 + 0], sneaky_weaky << 0); } //printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); // // // CheckManualAnaModeChange(); if(am_prev_info != analog_mode || aml_prev_info != analog_mode_locked) { //MDFN_DispMessage(_("%s: Analog mode is %s(%s)."), gp_name.c_str(), analog_mode ? _("on") : _("off"), analog_mode_locked ? _("locked") : _("unlocked")); MDFN_DispMessage(_("%s: Analog toggle is %s, sticks are %s"), gp_name.c_str(), amct_enabled ? _("ENABLED") : _("DISABLED"), analog_mode ? _("ON") : _("OFF")); } aml_prev_info = analog_mode_locked; am_prev_info = analog_mode; }
int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths) { static uint8 header[32]="MEDNAFENSVESTATE"; int neowidth = 0, neoheight = 0; if(wantpreview) { bool is_multires = FALSE; // We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has // multiple horizontal resolutions. neowidth = MDFNGameInfo->nominal_width; neoheight = MDFNGameInfo->nominal_height; if(LineWidths[0].w != ~0) { uint32 first_w = LineWidths[DisplayRect->y].w; for(int y = 0; y < DisplayRect->h; y++) if(LineWidths[DisplayRect->y + y].w != first_w) { puts("Multires!"); is_multires = TRUE; } } if(!is_multires) { if(((double)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((double)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25) neowidth = DisplayRect->w; if(((double)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((double)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25) neoheight = DisplayRect->h; } } if(!data_only) { memset(header+16,0,16); MDFN_en32lsb(header + 12, currFrameCounter); MDFN_en32lsb(header + 16, pcejin.lagFrameCounter); // MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); } if(wantpreview) { /* uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight); MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format.colorspace, surface->format.Rshift, surface->format.Gshift, surface->format.Bshift, surface->format.Ashift); MDFN_Rect dest_rect; dest_rect.x = 0; dest_rect.y = 0; dest_rect.w = neowidth; dest_rect.h = neoheight; // MDFN_ResizeSurface(surface, DisplayRect, (LineWidths[0].w != ~0) ? LineWidths : NULL, dest_surface, &dest_rect); { uint32 a, b = 0; for(a = 0; a < neowidth * neoheight * 4; a+=4) { uint32 c = *(uint32 *)&previewbuffer[a]; int nr, ng, nb; surface->DecodeColor(c, nr, ng, nb); previewbuffer[b + 0] = nr; previewbuffer[b + 1] = ng; previewbuffer[b + 2] = nb; b += 3; } }*/ //PREVIEWIMAGE smem_write(st, surface->pixels, 4 * neowidth * neoheight); // free(previewbuffer); // delete dest_surface; } // State rewinding code path hack, FIXME if(data_only) { // if(!MDFN_RawInputStateAction(st, 0, data_only)) return(0); } if(!MDFNGameInfo->StateAction(st, 0, data_only)) return(0); if(!data_only) { uint32 sizy = smem_tell(st); smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); } return(1); }
void MDFNSS_SaveSM(Stream *st, bool data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const int32 *LineWidths) { StateMem sm(st); if(data_only) { MDFN_StateAction(&sm, 0, true); sm.ThrowDeferred(); } else { static const char *header_magic = "MDFNSVST"; int64 start_pos; uint8 header[32]; int neowidth = 0, neoheight = 0; memset(header, 0, sizeof(header)); if(surface && DisplayRect && LineWidths) { bool is_multires = FALSE; // We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has // multiple horizontal resolutions. neowidth = MDFNGameInfo->nominal_width; neoheight = MDFNGameInfo->nominal_height; if(LineWidths[0] != ~0) { int32 first_w = LineWidths[DisplayRect->y]; for(int y = 0; y < DisplayRect->h; y++) { if(LineWidths[DisplayRect->y + y] != first_w) { //puts("Multires!"); is_multires = TRUE; } } } if(!is_multires) { if(((double)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((double)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25) neowidth = DisplayRect->w; if(((double)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((double)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25) neoheight = DisplayRect->h; } } memcpy(header, header_magic, 8); MDFN_en64lsb(header + 8, time(NULL)); MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); start_pos = st->tell(); st->write(header, 32); if(surface && DisplayRect && LineWidths) { // // TODO: Make work with 8bpp and 16bpp. // MDFN_Surface dest_surface(NULL, neowidth, neoheight, neowidth, surface->format); MDFN_Rect dest_rect; dest_rect.x = 0; dest_rect.y = 0; dest_rect.w = neowidth; dest_rect.h = neoheight; MDFN_ResizeSurface(surface, DisplayRect, LineWidths, &dest_surface, &dest_rect); { uint32* previewbuffer = dest_surface.pixels; uint8* previewbuffer8 = (uint8*)previewbuffer; for(int32 a = 0; a < neowidth * neoheight; a++) { int nr, ng, nb; surface->DecodeColor(previewbuffer[a], nr, ng, nb); previewbuffer8[0] = nr; previewbuffer8[1] = ng; previewbuffer8[2] = nb; previewbuffer8 += 3; } } st->write((uint8*)dest_surface.pixels, 3 * neowidth * neoheight); } MDFN_StateAction(&sm, 0, data_only); sm.ThrowDeferred(); { int64 end_pos = st->tell(); uint32 pv = (end_pos - start_pos) & 0x7FFFFFFF; #ifdef MSB_FIRST pv |= 0x80000000; #endif st->seek(start_pos + 16 + 4, SEEK_SET); st->put_LE<uint32>(pv); st->seek(end_pos, SEEK_SET); // Seek to just beyond end of save state before returning. } } }
int NetplayStart(const char *PortDeviceCache[16], const uint32 PortDataLenCache[16]) { try { const char *emu_id = PACKAGE " " MEDNAFEN_VERSION; const uint32 local_players = MDFN_GetSettingUI("netplay.localplayers"); const std::string nickname = MDFN_GetSettingS("netplay.nick"); const std::string game_key = MDFN_GetSettingS("netplay.gamekey"); const std::string connect_password = MDFN_GetSettingS("netplay.password"); login_data_t *ld = NULL; std::vector<uint8> sendbuf; MDFNnetplay = true; sendbuf.resize(4 + sizeof(login_data_t) + nickname.size() + strlen(emu_id)); MDFN_en32lsb(&sendbuf[0], sendbuf.size() - 4); ld = (login_data_t*)&sendbuf[4]; if(game_key != "") { md5_context md5; uint8 md5out[16]; md5.starts(); md5.update(MDFNGameInfo->MD5, 16); md5.update((uint8 *)game_key.c_str(), game_key.size()); md5.finish(md5out); memcpy(ld->gameid, md5out, 16); } else memcpy(ld->gameid, MDFNGameInfo->MD5, 16); if(connect_password != "") { md5_context md5; uint8 md5out[16]; md5.starts(); md5.update((uint8*)connect_password.c_str(), connect_password.size()); md5.finish(md5out); memcpy(ld->password, md5out, 16); } assert(MDFNGameInfo->InputInfo->InputPorts <= 16); ld->protocol_version = 3; // Set input device number thingies here. ld->total_controllers = MDFNGameInfo->InputInfo->InputPorts; // Total number of ports MDFN_en32lsb(ld->emu_name_len, strlen(emu_id)); // Controller data sizes. for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++) ld->controller_data_size[x] = PortDataLenCache[x]; // Controller types for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++) { unsigned ct = 0; for(int d = 0; d < MDFNGameInfo->InputInfo->Types[x].NumTypes; d++) { if(!strcasecmp(MDFNGameInfo->InputInfo->Types[x].DeviceInfo[d].ShortName, PortDeviceCache[x])) { ct = d; break; } } //printf("%d, 0x%02x\n", x, ct); ld->controller_type[x] = ct; } ld->local_players = local_players; if(nickname != "") memcpy(&sendbuf[4 + sizeof(login_data_t)], nickname.c_str(), nickname.size()); memcpy(&sendbuf[4 + sizeof(login_data_t) + nickname.size()], emu_id, strlen(emu_id)); MDFND_SendData(&sendbuf[0], sendbuf.size()); TotalInputStateSize = 0; for(int x = 0; x < MDFNGameInfo->InputInfo->InputPorts; x++) TotalInputStateSize += PortDataLenCache[x]; // Hack so the server can always encode its command data length properly(a matching "hack" exists in the server). if(TotalInputStateSize < 4) TotalInputStateSize = 4; TotalInputStateSize = TotalInputStateSize; LocalPlayersMask = 0; LocalInputStateSize = 0; Joined = false; // // // MDFN_FlushGameCheats(0); /* Save our pre-netplay cheats. */ if(MDFNMOV_IsPlaying()) /* Recording's ok during netplay, playback is not. */ MDFNMOV_Stop(); } catch(std::exception &e) { NetError("%s", e.what()); return(false); } //printf("%d\n", TotalInputStateSize); return(1); }
int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths) { static const char *header_magic = "MDFNSVST"; uint8 header[32]; int neowidth = 0, neoheight = 0; memset(header, 0, sizeof(header)); if(wantpreview_and_ts) { bool is_multires = FALSE; // We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has // multiple horizontal resolutions. neowidth = MDFNGameInfo->nominal_width; neoheight = MDFNGameInfo->nominal_height; if(LineWidths[0].w != ~0) { uint32 first_w = LineWidths[DisplayRect->y].w; for(int y = 0; y < DisplayRect->h; y++) if(LineWidths[DisplayRect->y + y].w != first_w) { MDFN_printf("Multires!"); is_multires = TRUE; } } if(!is_multires) { if(((SysDDec)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((SysDDec)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25) neowidth = DisplayRect->w; if(((SysDDec)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((SysDDec)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25) neoheight = DisplayRect->h; } } if(!data_only) { memcpy(header, header_magic, 8); if(wantpreview_and_ts) MDFN_en64lsb(header + 8, time(NULL)); MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); } if(wantpreview_and_ts) { uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight); MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format); MDFN_Rect dest_rect; dest_rect.x = 0; dest_rect.y = 0; dest_rect.w = neowidth; dest_rect.h = neoheight; MDFN_ResizeSurface(surface, DisplayRect, (LineWidths[0].w != ~0) ? LineWidths : NULL, dest_surface, &dest_rect); { uint32 a, b = 0; for(a = 0; a < neowidth * neoheight * 4; a+=4) { uint32 c = *(uint32 *)&previewbuffer[a]; int nr, ng, nb; surface->DecodeColor(c, nr, ng, nb); previewbuffer[b + 0] = nr; previewbuffer[b + 1] = ng; previewbuffer[b + 2] = nb; b += 3; } } smem_write(st, previewbuffer, 3 * neowidth * neoheight); free(previewbuffer); delete dest_surface; } // State rewinding code path hack, FIXME if(data_only) { if(!MDFN_RawInputStateAction(st, 0, data_only)) return(0); } if(!MDFNGameInfo->StateAction(st, 0, data_only)) return(0); if(!data_only) { uint32 sizy = smem_tell(st); smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); } return(1); }