B-Em Tape Overhaul v4.2 7th July 2025 QUICKSTART FOR WINDOWS ---------------------- Download the file b-em-40246d4-TOHv4.2-rc4-windows-x64.zip Unzip it somewhere, and then run b-em.exe. I have also provided an alternative executable, b-em-tricky.exe. This may offer significantly better video performance, but may not be stable on all machines. FILES ----- ===> b-em-40246d4-TOHv4.2-rc4.patch GNU unified diff patch, applicable against the stardot B-Em tree as of 5th July 2025: https://github.com/stardot/b-em/tree/40246d424e3c0c62a2f2aeb3a9698702ef4d9da2 Change directory to the B-Em source root and test it: $ cat b-em-40246d4-TOHv4.2-rc4.patch | patch -p1 --dry-run then apply it properly: $ cat b-em-40246d4-TOHv4.2-rc4.patch | patch -p1 You may also need to apply an additional patch to revert the bitmap lock type in vidalleg.c in order to achieve a stable screen output. This has been reported as a problem on some macOS and Linux machines. If in doubt, apply it -- change directory to src/, and: $ cat b-em-40246d4-untrickified-vidalleg.patch | patch -p1 ===> b-em-40246d4-TOHv4.2-rc4-windows-x64.zip My own builds of (patched) B-Em for Windows, as well as Allegro and zlib. Supplied in good faith, but use at your own risk. (Note that the build is 64-bit this time; some older versions of TOH provided 32-bit.) ===> b-em-tapetests-5-rc2.zip About 300 automated tests. You will need PHP installed to run them. Unzip them somewhere. Change to the directory where B-Em-TOH is installed, and then run the tests like $ php -f /path/to/tests.php SHA256 ------ f4caf91cd01af58a30582263f878e10a01a8b31a0a7bf5023fa3d931a150c5ef b-em-40246d4-TOHv4.2-rc4-windows-x64.zip 0ad386015e8ec99d8e21e0a67a8de47658422c4fd0c97b38f4984fed7659cb60 b-em-tapetests-5-rc2.zip 8e9f8b50e634b63aa67c87de77d1f90a8f651ed6c659129d7e505d90fe9d99e7 b-em-40246d4-TOHv4.2-rc4.patch 100eb171f04ce7b23bc06efa750d6b706d41255e8b36575da006da03ec37df5a b-em-40246d4-untrickified-vidalleg.patch FEATURES -------- - new, "known good" RX-side ACIA implementation (by Chris Evans, taken from beebjit under GPL); - writing to tape now implemented; UEF, CSW and TIBET formats supported; - export loaded tape as audio in WAV format, with option to shift phase 90 degrees; - accurate "tape noise" for both load and save; signal is comprehensible to an actual Beeb; - helpful "Mischief" tools for developers; generate various synthetic ACIA errors for testing purposes; - "UEF options" menus to tweak various features of UEF loading and saving behaviour; - realistic ACIA TX pipeline; correct end-of-block SAVE behaviour for both OS 1.2 and 0.1; - framework for unit testing introduced; among others, added "-tapetest" and "-record" commands to CLI, and "bx" (quit-with-code-on-breakpoint) command to debugger to support this capability; - ~300 unit tests, with a PHP script to automate them, including testing for successful load & run of many protected tape games; - proper validation of UEF and CSW file integrity; - cataloguing tape no longer disturbs tape operation in progress; - CSWs at various sample rates supported, not just 44.1K; - accurate DCD behaviour on load; - new, alternative, "more legal" turbo load mode which strips silence and leader (and fudges DCD); - new, realistic modelling of Serial ULA / ACIA dividers; accurate TDRE delay timings for all ULA and ACIA divider settings; save at weird baud rates (75, 150, 600) - TIBET loading support; - data loading from UEF chunks &102 and &114; - detects and works around swapped parity for MakeUEF < 2.4; - scaffolding in place for nearly all tape metadata UEF chunk types. TESTS ----- The automated tests take the form of a PHP script (tests.php). You will need to have a recent version of PHP installed. The tests are effective, although slightly rough in implementation. The script must then be run with the current working directory being the B-Em base directory, i.e. the one containing the B-Em.exe or b-em executable. The script should choose a sensible temporary directory for writing ephemeral files based on the detected operating system, but you can edit the script to choose a different temporary dir if necessary. These tests rely heavily on poking commands into the debugger, setting breakpoints, and using the new "bx" command to force exits with various exit codes if these breakpoints are hit. They are therefore vulnerable to breakage by changes in B-Em's debugger syntax. Tests also modulate B-Em's exit behaviour via the new "-tapetest" command-line argument. SAVING TO TAPE IS WEIRD ----------------------- Writing-to-tape exhibits a number of behaviours that may seem counterintuitive, as follows. 1. Record Mode This is a new checkbox in the menus (Tape -> Record and Append to Tape). By default, tape write operations will not end up on (simulated) tape unless Record mode has been activated. This implementation permits writing arbitrary silence to the tape when *MOTOR 1 is running. 2. Tape Noise If the tape noise generator is activated (Settings -> Sound -> Tape Signal), then Record mode boasts a second function: This setting will switch from hearing playback tape noise (i.e. LOAD) to hearing recording tape noise (i.e. SAVE). A couple of protected games seem to output leader tone to the MIC socket as they are loading (Video's Revenge, Pro Boxing Simulator), so it is possible for both sources of tape signal (record and playback, or MIC and EAR if you prefer) to be playing at the same time! If you are unable to hear anything from a SAVE even though tape signal output is enabled under Settings -> Sound, you have probably neglected to enable Record mode. (Try loading Video's Revenge from tape with Record mode activated and tape noise playing. This operation is mostly silent as you are listening to the MIC jack rather than the EAR one, but you will hear a short length of leader right at the end of the load, as the game's protection system asserts itself). The size of the audio buffer chosen for the tape noise generator is a compromise. Large buffers are reliable, but lag painfully behind what the emulator is doing on-screen. Smaller buffers promise a snappy audio response to tape events within the emulator, but are prone to drop-outs, which are clearly undesirable if you are playing B-Em's audio output into a real Beeb. Currently a BUFLEN_TN of 1280 samples is defined in tapenoise.c which works on the operating systems I have tried (Windows being the worst offender in my testing), but it may be necessary to increase this if you are suffering regular drop-outs. Note that such glitches are not always audible. 3. Append Only As the name "Record and Append to Tape" implies, data are always appended to the very end of the currently loaded tape image (or a blank one if none is loaded). There is currently no way to rewind or fast-forward into the middle of a tape and begin recording at this point. No capability exists to perform either overwriting of, or insertion before, extant data. 4. Save Tape Copy There is no way to update automatically the original tape image file with any data saved. (This is in contrast to B-Em's disc paradigm, which supports on-the-fly writes back to the original disc image.) You can of course save the current data on the tape to its own, new file (Tape -> Save Tape Copy). This offers three different tape output formats (UEF, CSW and TIBET), each of which may be saved either compressed or uncompressed, for a total of six choices. (You may also export audio to a WAV file.) However, B-Em is presently unable to convert a loaded tape into a different format. If you are appending data to an existing loaded tape, you will only be able to save it back out in its original format. This is not the case when starting with a "blank tape": In this case, B-Em will maintain parallel in-memory copies in all of its supported file formats simultaneously, any or all of which may be independently saved. PROBLEMS -------- :-) ACKNOWLEDGEMENTS ---------------- Sarah Walker, Chris Evans, Steve Fosdick, Sazhen86, vanekp. IMPROVEMENTS SINCE 4.1 ---------------------- - UEF chunk &131 description now has length checked; ASCII (not UTF-8) is now forced as per UEF 0.10 spec; - improvements to UTF-8 scaffolding with an eye on future UI enhancements; - fix for errors when both turbo load modes are activated at once with non-UEF file types (thx. Sazhen86); - motor off now resets the DCD timer (tape->ula_dcd_blipticks); - slow-startup mode now only introduces 1 second of delay rather than 2, speeds up testing; - export audio to WAV, plus alternative phase shifted mode; - added holdoff when activating strip-silence-and-leader mode, so motor has to run for 0.6 seconds before anything gets stripped. tests.php: - added test for "motor off now resets the DCD timer" - added basic tests for WAV saving IMPROVEMENTS SINCE 4.0 ---------------------- - improved exception/shutdown handling - implemented saving for non-standard (i.e. not 8N1) serial framings (thx. vanekp) - reverted crash when fullscreen selected on recent macOS (thx. Sazhen86) - added unique shutdown code for missing -tape files - fixed bug causing new blank tape to be created when sometimes it shouldn't be - fixed double free in tape catalogue - line breaks when writing TIBETs now reflect ACIA serial framing tests.php: - six new tests for saving with non-standard framings (including correct UEF chunks) - added sanity check for tests' tapefiles not being present - CLOCKSP2 test syntax fixed - corrected two bad tests that were using incorrect filenames - slow mode (+s) testing for machines on which full speed tests may be unstable, i.e. recent macOS (thx. Sazhen86) - expiry timeout extended for 75 baud save test - Pro Boxing Simulator test no longer runs demo mode; quicker other: - breaking change to BEMSNAP4 format IMPROVEMENTS SINCE 3.2 ---------------------- - large portions rewritten; - with record mode, silence is now only written to tape if it is rolling, i.e. when *MOTOR 1; - replaced RX-side ACIA code with proven code from beebjit: Castle Quest loads correctly; - fixed some problems with debugger during automated testing; - rewritten ACIA/ULA relationship: Serial ULA dividers properly implemented; independent RXC and TXC clocks into ACIA; save at 75 baud; - new command-line options to support testing, including -expire and -rs423file; - better ACIA TX pipeline model; optional simple ACIA "no-TX-poll" mode for Music 2000; - fixed some bugs in CSW writing; - Music 2000 MIDI out hopefully works again; - new save state format BEMSNAP4 supports ACIA and ULA upgrades; - hugely improved tests. IMPROVEMENTS SINCE 3.1 ---------------------- - fixed loading Haunted Abbey; tape motor runs now even if RS423 is selected in the ACIA (thanks Sazhen86); - fixed silence going missing when loading TIBET files; - fixed silence lengths being doubled in UEF chunks 112 and 116; - all tape formats may now be saved both compressed and uncompressed; - new "turbo" options menu; renames "Fast Mode" to "Overclock Tape"; adds alternative "more legal" fast load mode which strips out silence and leader; - choose to save using UEF 112 for silence instead of 116 - loaded tape filename length increased in Tape menu (thanks Sazhen86); - fixed menu bar flicker on Windows (no more polling to grey-out Catalogue Tape); - choose whether a second origin chunk should be written if appending to an existing UEF; new option for this (default: yes); - fixed several memory corruption bugs in CSW loader; - tackled mess involving saving incomplete serial frames (ACIA reset etc.) to UEF files; - fixed leader going AWOL under certain conditions; - UTF-8 now permitted (and validated) in UEF origin and instructions chunks; - compressed UEFs are no longer loaded twice; - new TIBET versioning logic (different major versions are incompatible; different minor versions are backwards compatible only); - TIBET now v0.5 (no updated spec yet, sorry); - by default, only generate baud chunk 117 if necessary, to work around Elkulator's petulance (+ new UEF save option to preserve old behaviour, i.e. force 117 before every data chunk); - moved a messy pile of global variables onto a new tape_vars_t; - permit pulsechar sequence in chunk 114 (strictly violates UEF spec, but examples of such exist in the wild; thanks Sazhen86); - much-improved tests; see below. IMPROVEMENTS TO TESTS SINCE 3.1 ------------------------------- - two dozen brand-new CSW tests; - tests.php is zero-configuration now, hopefully do not need to set paths any more; - added test for in chunk 114; - added Haunted Abbey; - fixed ultron114.uef test (TOHv3.1 was loading ultron.csw by mistake); - added tests for correct silence length loading TIBET, or UEF chunks 112 and 116; - added tests for UTF-8 in origin and instructions chunks; - much more consistent test naming; hope to make tests more usable by other projects; - fixed conflation of origin and instructions chunks in v3.1 (full-on, epic bungling on my part); - added test for file truncation within UEF magic; - added six new tests for chunk &117 saving behaviour and new -tape117 option; - added tests for -tape112; - added test for data -> silence without leader in between (which was a 3.1 bug) - added tests for new turbo mode ("-tapeskip"); - added test to make sure origin chunk is first chunk on save; - added tests to attack new TIBET versioning logic; - tests.php: display symbolic names instead of return codes; - tests.php: other cleanups and improvements; - other things I've forgotten. APPENDIX A: ACIA TX TIMING -------------------------- Writes to the MC6850's TX data register are delayed in their effects, in two ways. Investigation of these phenomena began in the BeebEm thread on Stardot: https://www.stardot.org.uk/forums/viewtopic.php?p=362215#p362215 Discussion then continued in another thread, which is the origin of the "Hoglet Histogram" program included in the tests: https://www.stardot.org.uk/forums/viewtopic.php?t=25152 APPENDIX B: BORING DEVELOPER NOTES ON UEF METADATA -------------------------------------------------- The UEF back-end contains scaffolding for a very wide variety of UEF metadata chunk types, as well as all the data chunk types. - GLOBAL: - &0 (origin) [multi] - &1 (instructions or manual) [multi] - &3 (inlay scan) [multi] - &5 (target machine) [multi] - &6 (bit multiplex) - &7 (extra palette) - &8 (rom hints) [multi] - &9 (short title) - &A (visible area) - INLINE [all multi] - &115 (phase change) - &117 (baud rate, implemented) - &120 (position marker text) - &130 (tape set info) - &131 (start of tape side) So-called "global" UEF chunks apply to the entire UEF file; examples include inlay scans (type &3), target machine (type &5), and so on. "Globals" are identified by the UEF reader immediately upon the file being loaded. Pointers to the locations of these chunks are placed onto the globals field of uef_state_t. Note that some such "global" UEF chunks may legitimately appear multiple times; a malloced list of pointers into the UEF data is created in these cases. The currently recognised global multichunk types are: origin (&1), instructions (&2), inlay scan (&3), target machine (&5) and ROM hint (&8). Meanwhile, calls to the uef_read_1200th() function will cause the UEF reader to advance through chunks until some data can be found. If the UEF reader encounters some contextual (non-global) metadata chunks as it goes, they will be returned in metadata_list whose fill is given by metadata_fill_out: int uef_read_1200th (uef_state_t *u, char *out_1200th, uef_meta_t metadata_list[UEF_MAX_METADATA], /* caller must call uef_metadata_list_finish() */ uint32_t *metadata_fill_out) These differ from the "global" UEF chunk types in that they are context-sensitive; their position in the UEF file matters. Five such chunk types are currently recognised: phase change (&115), baud rate (&117), position marker (&120), tape set info (&130), and start of tape side (&131). The uef_meta_t type contains an integer type field and an instance of a uef_meta_u_t union which contains the actual data. Note that unlike global chunk types, contextual metadata chunk types do not just point into the loaded UEF data, but copy their properties onto dedicated structures within uef_meta_u_t. Apart from baud rate (&117), nothing much is done at present with any of the metadata from either global or contextual chunk types. Validation of these chunk types is not quite comprehensive, although I have done some preliminary work making some unit test UEFs for them. Origin and instructions chunk types (&0 and &1) are now UTF-8 capable, and are validated as such. Note that chunk lengths are validated by a function chunk_verify_length() independently from their actual parsing -- this may not be particularly smart software engineering. Perhaps someone can think of ways of integrating things like instructions, short title, tape side etc. into b-em's interface.