B-Em Tape Overhaul v4.3 2nd November 2025 QUICKSTART FOR WINDOWS ---------------------- Download the file b-em-0b6f1d2-TOHv4.3-rc1-windows-x64.zip Unzip it somewhere, and then run b-em.exe. FILES ----- ===> b-em-0b6f1d2-TOHv4.3-rc1.patch GNU unified diff patch, applicable against the stardot B-Em tree as of 2nd November 2025: https://github.com/stardot/b-em/tree/0b6f1d2112a40cbed688ce6abaa6a10a00faeb2e Change directory to the B-Em source root and test it: $ cat b-em-0b6f1d2-TOHv4.3-rc1.patch | patch -p1 --dry-run then apply it properly: $ cat b-em-0b6f1d2-TOHv4.3-rc1.patch | patch -p1 ===> b-em-0b6f1d2-TOHv4.3-rc1-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.) ===> tapetests-6-rc1.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 +t (If you are seeing crashes, also try +s.) SHA256 ------ 67926cc3d4efcacd172353bb8ca087eae0290949b337274936cccd7056c4c6d4 b-em-0b6f1d2-TOHv4.3-rc1.patch 1043df15de771ebf0727af7d69e111d39d86265f7c049853d026f1bdf826bcf2 b-em-0b6f1d2-TOHv4.3-rc1-windows-x64.zip f050ef8552990d7c91c2d8185624b3861ffdc11b86342787ff393f99abfa524a tapetests-6-rc1.zip TAPE CONTROL ------------ This release contains a new "Tape Control" window (a.k.a. tapectrl) which can be popped up from the Tape menu. There are a couple of new command-line switches associated with tapectrl: - The option -tapeuiscale may be used to adjust the initial size of the pop-up window between 0.5 and 1.5 times its nominal size. (This may be used in conjunction with the -hires (x2) option to obtain scaling between 1.0 and 3.0 times the nominal size.) These options may be particularly useful if you are using a high-DPI screen such as Apple Retina. - The option -tapeuiresize may be provided to enable free-resize of the tapectrl window. Enabling this will cause crashes on macOS if you have a recent Apple Silicon-based Mac. I have also experienced occasional crashy behaviour on Linux when using the open-source "nouveau" driver for Nvidia cards (the proprietary Nvidia X11 drivers seem stable.) I am blaming Allegro for these problems until I learn otherwise. (Note also that "-tapetest 32" on the command-line will pop up the tapectrl on startup.) Tapectrl is experimental. As a result, the option has been provided to build TOH without it. The bundled Windows build offers both a tapectrl-equipped version (b-em.exe) and a no-tapectrl version (b-em-no-tapectrl.exe), in case the former suffers from stability issues. To build without tapectrl, open src/tape2.h, and comment out this line near the top of the file: #define BUILD_TAPE_TAPECTRL Then rebuild the emulator. (There are lots of other build switches in this file. Some may not work properly.) Even if TOH is built without tapectrl, it is still possible to inspect timestamps of files using the Tape Catalogue window, and seek to specific points using the new "tapeseek" debugger command. Features: - inspection of the current tape's contents; - seeking; - indicators to inform the user what is going on; - tape inlay scans (if they are embedded in loaded UEF files via chunk &3); - tape error codes reported on the 7-segment display 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. WARNING: BACK UP YOUR CONFIG FILE BEFORE RUNNING THE TESTS! The tests will overwrite your configuration file! This occurs because the tests now use B-Em's new "-cfg" command-line option to load their own arbitrary configurations, which will unfortunately overwrite the user's own file on B-Em's shutdown. Back up your config first! Don't be a dope! Various switches are available to configure the test run. If you wish to run the tests with the tapectrl window open (recommended), add the +t option to the PHP command-line. Previously, there were crash problems running rapid tests on recent Macs, so the +s option was added to tests.php, which adds a one-second delay to the emulator's start-up procedure. However, this precaution may no longer be needed, following a change to TOH's Allegro shutdown procedure to improve stability on Windows. I would be interested to hear from anyone running these tests successfully on a recent Apple Silicon Mac without requiring the bandage of the +s (slow) option. The tests.php script must 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 location if necessary. PROBLEMS -------- - Tape tests scribble the configuration file. (See the TESTS section above.) - Writing to UEF suffers a minor timestamping bug caused by inability to write a partial serial frame out to chunk &100 or &104. If a serial frame is interrupted by deactivating Record Mode during a block SAVE, the unfinished frame will be flushed to the UEF as if it were a completed frame. This means that the data chunk is slightly longer in duration than was actually written. If Record Mode is deliberately spammed on and off during a SAVE, the growing discrepancy between the UEF's timestamps and the Tape Control window's timestamps can begin to cause glitching of the seek marker during playback. The fix would be to alter the Tape Control interval list always to use a full frame's duration as UEF does, rather than the real duration. The bug must be deliberately provoked, and it is very minor. I cannot presently be bothered to fix it. - Tapes written at strange baud rates (75, 150, 600) may not behave correctly in the tapectrl. Although a Beeb cannot read a tape at non-standard baud, it ought to be possible to write a 75 baud tape, then rewind it to listen to its audio (as much to confirm that the 75 baud write worked correctly as anything else). Seeking currently will not work properly for various reasons: Non-standard rates are not allowed in UEF chunk &117. TIBET has problems too. If you really want to be able to use tapectrl with weird-baud saves, try CSW: Start by loading a blank CSW, to force TOH to use CSW as the internal representation. Then do weird-baud saves. Right now CSW stands the best chance of working. - No support yet exists for saving UEF chunk &111 (leader+&AA+leader). These dummy bytes currently just use chunks &100 and &116 instead. There was always something more urgent so I never bothered doing this. 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 checkbox in the menus (Tape -> Record and Append to Tape). It is also available as a button on the Tape Control window. 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. TOH FEATURES ------------ - new Tape Control window; seeker bar; indicators; also display tape inlay scans via UEF chunk &3; - debugger commands added: eject tape, set tape record mode on/off, perform tape seeks, examine tapes; - timestamps now shown in tape catalogue; - 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. ACKNOWLEDGEMENTS ---------------- Sarah Walker, Chris Evans, Steve Fosdick, Sazhen86, vanekp. IMPROVEMENTS SINCE 4.2 ---------------------- - Tape Control window - New tests, and fixed old tests - Timestamping of loaded tapes - Debugger: tapeseek, tapeeject, tapelsuef, tapelstbt 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: OLD, 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.