diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx old mode 100644 new mode 100755 index 8a29a424f..377752c33 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -752,7 +752,7 @@ bool CartDetector::isProbablyMVC(const ByteBuffer& image, size_t size) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t CartDetector::isProbablyMVC(const FSNode& rom) { - constexpr size_t frameSize = 2 * CartridgeMVC::MVC_FIELD_PAD_SIZE; + constexpr size_t frameSize = 2 * CartridgeMVC::MVC_FIELD_SIZE; if(Bankswitch::typeFromExtension(rom) == Bankswitch::Type::_MVC) return frameSize; diff --git a/src/emucore/CartMVC.cxx b/src/emucore/CartMVC.cxx index 5348c55ab..1c849d332 100755 --- a/src/emucore/CartMVC.cxx +++ b/src/emucore/CartMVC.cxx @@ -65,7 +65,7 @@ class StreamReader : public Serializable } void blankPartialLines(bool index) { - constexpr int colorSize = 192 * 5; + int colorSize = myVisibleLines * 5; if (index) { // top line @@ -91,13 +91,62 @@ class StreamReader : public Serializable void swapField(bool index, bool odd) { uInt8* offset = index ? myBuffer1.data() : myBuffer2.data(); - myVersion = offset + VERSION_DATA_OFFSET; - myFrame = offset + FRAME_DATA_OFFSET; - myAudio = offset + AUDIO_DATA_OFFSET; - myGraph = offset + GRAPH_DATA_OFFSET; - myTimecode = offset + TIMECODE_DATA_OFFSET; - myColor = offset + COLOR_DATA_OFFSET; - myColorBK = offset + COLORBK_DATA_OFFSET; + class FrameFormat + { + public: + + uInt8 version[4]; // ('M', 'V', 'C', 0) + uInt8 format; // ( 1-------) + uInt8 timecode[4]; // (hour, minute, second, fame) + uInt8 vsync; // eg 3 + uInt8 vblank; // eg 37 + uInt8 overscan; // eg 30 + uInt8 visible; // eg 192 + uInt8 rate; // eg 60 + uInt8 dataStart; + + // sound[vsync+blank+overscan+visible] + // graph[5 * visible] + // color[5 * visible] + // bkcolor[1 * visible] + // timecode[60] + // padding + }; + + FrameFormat* ff = (FrameFormat* )offset; + + if (ff->format & 0x80) + { + myVSyncLines = ff->vsync; + myBlankLines = ff->vblank; + myOverscanLines = ff->overscan; + myVisibleLines = ff->visible; + myEmbeddedFrame = ff->timecode[3] + 1; + + int totalLines = myVSyncLines + myBlankLines + myOverscanLines + myVisibleLines; + + myAudio = (uInt8*)(&ff->dataStart); + myGraph = myAudio + totalLines; + myColor = ((uInt8*)myGraph) + 5 * myVisibleLines; + myColorBK = myColor + 5 * myVisibleLines; + myTimecode = myColorBK + 1 * myVisibleLines; + } + else // previous format, ntsc assumed + { + myVSyncLines = 3; + myBlankLines = 37; + myOverscanLines = 30; + myVisibleLines = 192; + myEmbeddedFrame = offset[4 + 3 -1]; + + int totalLines = myVSyncLines + myBlankLines + myOverscanLines + myVisibleLines; + + myAudio = offset + 4 + 3; + myGraph = myAudio + totalLines; + myTimecode = ((uInt8*)myGraph) + 5*myVisibleLines; + myColor = ((uInt8*)myTimecode) + 60; + myColorBK = myColor + 5*myVisibleLines; + } if (!odd) myColorBK++; @@ -106,9 +155,9 @@ class StreamReader : public Serializable bool readField(uInt32 fnum, bool index) { if(myFile) { - const size_t offset = ((fnum + 0) * CartridgeMVC::MVC_FIELD_PAD_SIZE); + const size_t offset = ((fnum + 0) * CartridgeMVC::MVC_FIELD_SIZE); - if(offset + CartridgeMVC::MVC_FIELD_PAD_SIZE < myFileSize) + if(offset + CartridgeMVC::MVC_FIELD_SIZE < myFileSize) { myFile.setPosition(offset); if(index) @@ -122,8 +171,6 @@ class StreamReader : public Serializable return false; } - uInt8 readVersion() { return *myVersion++; } - uInt8 readFrame() { return *myFrame++; } uInt8 readColor() { return *myColor++; } uInt8 readColorBK() { return *myColorBK++; } @@ -135,6 +182,12 @@ class StreamReader : public Serializable uInt8 readAudio() { return *myAudio++; } + uInt8 getVisibleLines() { return myVisibleLines; } + uInt8 getVSyncLines() { return myVSyncLines; } + uInt8 getBlankLines() { return myBlankLines; } + uInt8 getOverscanLines() { return myOverscanLines; } + uInt8 getEmbeddedFrame() { return myEmbeddedFrame; } + [[nodiscard]] uInt8 peekAudio() const { return *myAudio; } void startTimeCode() { myGraph = myTimecode; } @@ -152,8 +205,6 @@ class StreamReader : public Serializable const uInt8* myTimecode const uInt8* myColor const uInt8* myColorBK - const uInt8* myVersion - const uInt8* myFrame #endif } catch(...) @@ -176,8 +227,6 @@ class StreamReader : public Serializable const uInt8* myTimecode const uInt8* myColor const uInt8* myColorBK - const uInt8* myVersion - const uInt8* myFrame #endif } catch(...) @@ -188,16 +237,6 @@ class StreamReader : public Serializable } private: - static constexpr int - VERSION_DATA_OFFSET = 0, - FRAME_DATA_OFFSET = 4, - AUDIO_DATA_OFFSET = 7, - GRAPH_DATA_OFFSET = 269, - TIMECODE_DATA_OFFSET = 1229, - COLOR_DATA_OFFSET = 1289, - COLORBK_DATA_OFFSET = 2249, - END_DATA_OFFSET = 2441; - const uInt8* myAudio{nullptr}; const uInt8* myGraph{nullptr}; @@ -206,12 +245,16 @@ class StreamReader : public Serializable const uInt8* myTimecode{nullptr}; uInt8* myColor{nullptr}; uInt8* myColorBK{nullptr}; - const uInt8* myVersion{nullptr}; - const uInt8* myFrame{nullptr}; std::array myBuffer1; std::array myBuffer2; + uInt8 myVisibleLines{192}; + uInt8 myVSyncLines{3}; + uInt8 myBlankLines{37}; + uInt8 myOverscanLines{30}; + uInt8 myEmbeddedFrame{0}; + Serializer myFile; size_t myFileSize{0}; }; @@ -301,8 +344,7 @@ class MovieInputs : public Serializable static constexpr uInt8 TIMECODE_HEIGHT = 12, MAX_LEVEL = 11, - DEFAULT_LEVEL = 6, - BLANK_LINE_SIZE = (30+3+37-1); // 70-1 + DEFAULT_LEVEL = 6; // Automatically generated // Several not used @@ -338,9 +380,12 @@ static constexpr uInt16 addr_end_lines = 0xa80, addr_set_aud_endlines = 0xa80, addr_set_overscan_size = 0xa9a, + addr_set_vsync_size = 0xaa3, addr_set_vblank_size = 0xab0, addr_pick_extra_lines = 0xab9, addr_pick_transport = 0xac6, + addr_title_gap1 = 0xb2c, + addr_title_gap2 = 0xb40, addr_title_loop = 0xb50, addr_audio_bank = 0xb80; @@ -752,6 +797,8 @@ class MovieCart : public Serializable myROM[address & 1023] = data; } + void setConsoleTiming(ConsoleTiming timing); + private: enum Mode : uInt8 { @@ -880,6 +927,33 @@ bool MovieCart::init(string_view path) return true; } +#define RAINBOW_HEIGHT 30 +#define TITLE_HEIGHT 12 + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void MovieCart::setConsoleTiming(ConsoleTiming timing) +{ + uInt8 lines; + + switch(timing) + { + case ConsoleTiming::ntsc: + default: + lines = 192; + break; + + case ConsoleTiming::pal: + case ConsoleTiming::secam: + lines = 242; + break; + } + + uInt8 val = (lines - RAINBOW_HEIGHT - RAINBOW_HEIGHT - TITLE_HEIGHT * 2) / 2; + + writeROM(addr_title_gap1 + 1, val); + writeROM(addr_title_gap2 + 1, val); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MovieCart::writeColor(uInt16 address, uInt8 v) { @@ -1192,17 +1266,19 @@ void MovieCart::fill_addr_end_lines() // keep at overscan=29, vblank=36 // or overscan=30, vblank=36 + 1 blank line + writeROM(addr_set_vsync_size + 1, myStream.getVSyncLines()); + if(myOdd) { - writeROM(addr_set_overscan_size + 1, 29); - writeROM(addr_set_vblank_size + 1, 36); + writeROM(addr_set_overscan_size + 1, myStream.getOverscanLines()-1); + writeROM(addr_set_vblank_size + 1, myStream.getBlankLines()-1); writeROM(addr_pick_extra_lines + 1, 0); } else { - writeROM(addr_set_overscan_size + 1, 30); - writeROM(addr_set_vblank_size + 1, 36); + writeROM(addr_set_overscan_size + 1, myStream.getOverscanLines()); + writeROM(addr_set_vblank_size + 1, myStream.getBlankLines()-1); // extra line after vblank writeROM(addr_pick_extra_lines + 1, 1); @@ -1223,33 +1299,19 @@ void MovieCart::fill_addr_end_lines() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MovieCart::fill_addr_blank_lines() { - // version number - myStream.readVersion(); - myStream.readVersion(); - myStream.readVersion(); - myStream.readVersion(); + myOdd = (myStream.getEmbeddedFrame() & 1); - // frame number - myStream.readFrame(); - myStream.readFrame(); - const uInt8 v = myStream.readFrame(); - - // make sure we're in sync with frame data - myOdd = (v & 1); - - // 30 overscan - // 3 vsync - // 37 vblank + uInt8 blankTotal = (myStream.getOverscanLines() + myStream.getVSyncLines() + myStream.getBlankLines()-1); // 70-1 if(myOdd) { writeAudioData(addr_audio_bank + 0, myFirstAudioVal); - for(uInt8 i = 1; i < (BLANK_LINE_SIZE + 1); i++) + for(uInt8 i = 1; i < (blankTotal + 1); i++) writeAudio(addr_audio_bank + i); } else { - for(uInt8 i = 0; i < (BLANK_LINE_SIZE -1); i++) + for(uInt8 i = 0; i < (blankTotal -1); i++) writeAudio(addr_audio_bank + i); } } @@ -1397,7 +1459,7 @@ void MovieCart::runStateMachine() } myForceColor = 0; - myLines = 191; + myLines = myStream.getVisibleLines() - 1; myState = 1; } break; @@ -1590,6 +1652,12 @@ void CartridgeMVC::reset() myMovie->init(myPath); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeMVC::consoleChanged(ConsoleTiming timing) +{ + myMovie->setConsoleTiming(timing); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteBuffer& CartridgeMVC::getImage(size_t& size) const { diff --git a/src/emucore/CartMVC.hxx b/src/emucore/CartMVC.hxx old mode 100644 new mode 100755 index 3574ae7f0..fa28726fb --- a/src/emucore/CartMVC.hxx +++ b/src/emucore/CartMVC.hxx @@ -37,8 +37,7 @@ class CartridgeMVC : public Cartridge { public: static constexpr size_t - MVC_FIELD_SIZE = 2560, // round field to nearest 512 byte boundary - MVC_FIELD_PAD_SIZE = 4096; // round to nearest 4K + MVC_FIELD_SIZE = 4096; public: /** @@ -123,6 +122,16 @@ class CartridgeMVC : public Cartridge */ bool load(Serializer& in) override; + protected: + /** + Notification method invoked by the system when the console type + has changed. Simply used to change titlescreen format, content + still plays as encoded. + + @param timing Enum representing the new console type + */ + void consoleChanged(ConsoleTiming timing) override; + private: // Currently not used: // Pointer to a dynamically allocated ROM image of the cartridge diff --git a/test/roms/bankswitching/MVC/20centuryfox_pal.bin b/test/roms/bankswitching/MVC/20centuryfox_pal.bin new file mode 100755 index 000000000..a5d7b06c2 Binary files /dev/null and b/test/roms/bankswitching/MVC/20centuryfox_pal.bin differ diff --git a/test/roms/bankswitching/MVC/cronkite_pal.mvc b/test/roms/bankswitching/MVC/cronkite_pal.mvc new file mode 100755 index 000000000..ebe102041 Binary files /dev/null and b/test/roms/bankswitching/MVC/cronkite_pal.mvc differ diff --git a/test/roms/bankswitching/MVC/lion_pal.mvc b/test/roms/bankswitching/MVC/lion_pal.mvc new file mode 100755 index 000000000..4c4b96505 Binary files /dev/null and b/test/roms/bankswitching/MVC/lion_pal.mvc differ