
===============================================================================
                     Standalone Player for DRAW32 Animations
===============================================================================

                    "Play it back the way it was timed."


  This is the SHORT doc for ANSIPLAY, the little command-line companion
  to DRAW32.  If you've read DRAW32.DOC already, you know where its
  animations come from (Alt+J, "Save Animation (.ANS)"); this doc covers
  the other half -- actually watching one play back correctly outside
  the editor.


===============================================================================
WHAT IS THIS THING?
===============================================================================

ANSIPLAY is a small standalone command-line program that plays back the
multi-frame .ANS animations DRAW32's animator (Alt+J > Save Animation)
writes out.  It's not an editor -- it doesn't draw, load into a canvas,
or let you change anything.  It does exactly one job: show the frames on
screen, each one paced by real wall-clock time, in order, at the delay
each frame was saved with.

It also happens to play a completely ordinary, single-frame .ANS file
just fine -- it just prints it once and exits, no pacing involved,
since there's only one frame to show.

Why this needs to exist at all: DRAW32 bakes its animation timing into
the file as a run of NUL (0x00) bytes sitting in front of each frame's
screen-clear code.  That's the traditional TheDraw-style trick, and it's
the only pacing method that survives being embedded in a plain .ANS byte
stream -- but it only actually paces anything if something between the
file and your eyeballs is throttling those bytes, the way a real modem
or a BPS-limited terminal client would.  A local console TYPE command,
or a modern telnet BBS door with no baud simulation turned on, has no
such throttle -- the NUL padding arrives instantly no matter how much of
it there is, and the "animation" just flashes through all its frames at
once.

ANSIPLAY sidesteps that entirely.  Instead of hoping something
downstream paces the bytes, it reads the NUL padding itself, converts
it back into a real delay, and waits that long with an actual Delay()
call before writing the next frame.  That works identically whether
you're watching it locally or it's being relayed through a BBS door --
the pacing is enforced right here, not left up to chance further down
the chain.



===============================================================================
USAGE
===============================================================================

      ANSIPLAY file.ans [slow] [/loop] [/speaker]

  file.ans   A SaveAnimANS output file.  Plain single-frame .ANS files
             are also accepted -- they just print once, no pacing
             needed.

  slow       Optional, 0-100.  Same scale as DRAW32's own "Output
             Display Speed" save-time prompt.
               0   (the default) plays back at the file's own recorded
                   pace, no change.
               100 the slowest setting -- an 8x multiplier stretched
                   over every recorded delay, the same maximum
                   slowdown DRAW32 itself offers when baking a speed
                   setting into a saved file.
             Anything in between scales smoothly across that range.

  /loop      Replay from frame 1 again after the last frame, forever.
             Press any key to stop it (Ctrl+C / Ctrl+Break still work
             too, if you'd rather use those out of habit).

  /speaker   Play any embedded ANSI Music through the classic PC-speaker
             Beep() instead of the default synthesized sound-card tone.
             Windows only -- see ANSI MUSIC below.

Run it with no arguments at all and it just prints a short usage
reminder instead of guessing what you meant.

EXAMPLES

      ANSIPLAY WELCOME.ANS              Play at the file's own pace, once
      ANSIPLAY WELCOME.ANS 50           Play at roughly 4.5x slower
      ANSIPLAY WELCOME.ANS 100 /loop    Slowest speed, looping forever
      ANSIPLAY LOGO.ANS /loop           Loop a single-frame file (it
                                         still just prints once per
                                         "loop" -- see FAQ below)
      ANSIPLAY JINGLE.ANS /speaker      Play back-embedded ANSI Music
                                         through the PC speaker instead
                                         of the sound card


===============================================================================
HOW THE TIMING ACTUALLY WORKS
===============================================================================

You don't need to understand any of this to use ANSIPLAY, but it
explains why playback looks the way it does, and it's short:

  1. ANSIPLAY loads the whole file into memory and looks for a trailing
     SAUCE record (128 bytes, "SAUCE" signature) and strips it off if
     present, since it's metadata, not picture content.

  2. It finds the file's real end-of-content marker -- the first 0x1A
     (Ctrl+Z) byte -- and ignores anything after it.

  3. It scans for FRAME SEPARATORS: a run of NUL bytes sitting
     immediately in front of an ESC[2J (screen-clear) code.  That NUL
     run is what DRAW32 uses to mark "a new frame starts here," so
     ANSIPLAY reads the run's length, converts it into a delay in
     hundredths of a second using the same reference rate (2400 baud)
     DRAW32 itself uses to size the padding, and remembers that delay
     instead of the raw bytes.
       A bare ESC[2J with NO padding in front of it is just ordinary
     mid-picture content -- plenty of non-animated ANSI art clears the
     screen once on its own -- so those are correctly left alone and
     not mistaken for a frame boundary.

  4. Playback then just walks the frame list: clear screen, write one
     frame's bytes straight through, wait the real delay that frame
     recorded (scaled by your "slow" argument if you gave one), clear
     the screen again, move to the next frame.  Unlike the padding
     bytes themselves, that wait is a genuine Delay() call, so it takes
     exactly as long as it claims to no matter what's reading the
     output on the other end.

Because it's reading the frame list itself rather than relying on the
editor's live canvas, ANSIPLAY also isn't held to DRAW32's in-editor
20-frame animation cap -- it'll play back a file with a great many more
separators than that without complaint.


===============================================================================
ANSI RENDERING -- WHY YOUR COLORS SHOW UP CORRECTLY
===============================================================================

  MODERN WINDOWS (10/11) AND ANY REAL TERMINAL
    ANSIPLAY turns on native ANSI/VT interpretation for its output
    (ENABLE_VIRTUAL_TERMINAL_PROCESSING under Windows) at startup, so
    the console or Windows Terminal itself reads the escape codes and
    turns them into colors, cursor moves, and screen clears the normal
    way.  

  OLDER WINDOWS (7, XP, ...)
    These have no such VT mode at all, and old-school ANSI.SYS/
    NANSI.SYS drivers have zero effect on a modern Win32 console window
    -- they're real-mode DOS drivers.  So on these systems ANSIPLAY
    falls back to a small built-in interpreter: it parses the SGR
    (color/attribute), cursor-position, cursor-relative-move, erase-
    display, erase-line, and save/restore-cursor codes itself and
    issues the equivalent Win32 Console API calls directly.  The escape
    codes themselves never reach the screen as literal text either way
    -- you just see the intended colors and movement, same as on a
    VT-aware console, only by a different route under the hood.

  ONE DELIBERATE QUIRK: BLINK BECOMES ICE-BRIGHT
    The classic ANSI "blink" SGR code (5) is interpreted as a bright
    background color instead of an actual blinking effect, on both
    rendering paths -- that's the same "ICEColor" convention DRAW32
    itself uses and that most modern ANSI art assumes, not a bug.


===============================================================================
ANSI MUSIC
===============================================================================

  DRAW32/SaveANS can embed a BASIC PLAY-style macro on a per-row basis,
  written as ESC[M<macro>0x0E (Ctrl-N) immediately before that row's
  cell data -- the same convention real ANSI Music terminals (Qmodem,
  TeliMate, ANSI.SYS) used back in the day.  ANSIPLAY recognizes those
  sequences as it outputs each frame, plays the macro locally, and never
  forwards the raw macro bytes to the screen -- exactly like a real
  ANSI Music-aware terminal, which consumes the macro silently instead
  of showing it as garbage text.

  ANSIPLAY understands the same subset of the BASIC PLAY language DRAW32
  itself does, so a macro previewed in the editor sounds identical when
  played back here: octave (O), tempo (T), default note length (L),
  notes A-G with # / + for sharp and - for flat, < > to shift the
  octave up/down, . for dotted notes, P for a rest, N<n> for a
  note-by-number, and the MN/ML/MS/MF/MB articulation letters (normal,
  legato, staccato, foreground, background -- articulation only affects
  the gap left between notes). Anything it doesn't recognize is quietly
  skipped, the same way a lenient BASIC interpreter would ignore stray
  characters rather than choke on them.

  WHERE THE SOUND ACTUALLY COMES FROM (WINDOWS ONLY)
    By default ANSIPLAY synthesizes each note as a square wave and
    plays it through the default sound card, since most modern PCs and
    virtually all VMs no longer have a physical PC speaker, which would
    make a genuine Beep() call look like a silent hang.  Pass /speaker
    on the command line to use the classic PC-speaker Windows.Beep()
    instead, for that authentic tinny sound.  Either way, playback
    blocks note-by-note the same way the original Beep() always did, so
    the pacing between notes stays correct.

  Playback of a macro can be interrupted by pressing Escape between
  notes (the note already sounding finishes out first), and is also
  subject to the same /loop "any key stops it" behavior as frame
  pacing.


===============================================================================
TROUBLESHOOTING
===============================================================================

  THE ANIMATION FLASHES THROUGH ALL AT ONCE INSTEAD OF PACING ITSELF
    That's exactly the problem ANSIPLAY exists to fix -- if you're
    still seeing it, double check you're actually running ANSIPLAY and
    not just TYPEing or catting the .ANS file directly, since a plain
    TYPE has no pacing logic of its own at all.

  COLORS OR CURSOR POSITION LOOK WRONG ON AN OLDER WINDOWS BOX
    You're on the fallback interpreter path (no native VT support on
    that OS).  It covers the subset of ANSI/SGR that TheDraw-style .ANS
    art actually uses, but an unusual or malformed escape sequence is
    simply skipped rather than risking a hang -- so something is being
    silently ignored rather than misrendered outright.  This path also
    disables the console's automatic end-of-line wrap on startup, since
    a full-width row plus an explicit CRLF would otherwise advance the
    cursor twice and leave a blank line behind it; if you're seeing
    stray blank lines, that's the symptom of this fix not applying for
    some reason.

  "FILE NOT FOUND" OR "CANNOT OPEN"
    Check the path/filename you gave on the command line -- ANSIPLAY
    checks the file exists before it tries to open it, and reports
    which of the two failed.

  A PLAIN SINGLE-FRAME .ANS JUST PRINTS ONCE AND EXITS, EVEN WITH /LOOP
    That's correct, not a bug -- see the FAQ below.


===============================================================================
FREQUENTLY ASKED QUESTIONS
===============================================================================

  Q: Does ANSIPLAY need DRAW32 installed to work?
  A: No.  It's a fully standalone player -- it only needs the .ANS file
     itself.  DRAW32 is just where that file most likely came from.

  Q: I gave it a plain, non-animated .ANS file with /loop.  Why did it
     only print once?
  A: A file with no frame separators has nothing to loop between --
     ANSIPLAY finds zero separators, prints the whole thing exactly
     once as ordinary ANSI art, and exits immediately, regardless of
     /loop. /loop only has an effect once there's an actual multi-frame
     sequence to repeat.

  Q: What does the "slow" number actually change?
  A: It scales every recorded per-frame delay by the same multiplier
     DRAW32's own Output Display Speed setting uses at save time -- 0
     leaves the file's original pace untouched, 100 stretches every
     delay by 8x.  It does not change which frames show or their order,
     only how long each one is held on screen.

  Q: Can I feed it a .BIN or pipe-coded .TXT file instead of .ANS?
  A: No -- ANSIPLAY expects the plain .ANS byte stream DRAW32's
     SaveAnimANS writes (NUL padding + ESC[2J as frame separators, an
     0x1A end marker, optional trailing SAUCE record). Other DRAW32
     save formats don't carry that same frame-separator structure.


===============================================================================
QUICK GLOSSARY
===============================================================================

  ANSI Music       A BASIC PLAY-style note macro embedded per-row in a
                   .ANS file (ESC[M<macro>0x0E), the old ANSI Music
                   terminal convention DRAW32/SaveANS can also write.
                   ANSIPLAY plays it locally instead of showing it as
                   text.
  Frame            One complete full-screen picture within a multi-
                   frame animation file.
  Frame separator  The NUL-padding-plus-ESC[2J pattern ANSIPLAY (and
                   DRAW32's own animator) reads as "a new frame starts
                   here."
  NUL padding      A run of 0x00 bytes some ANSI animations use to eat
                   up real transmission time over a rate-limited link,
                   so the frames arrive spaced out instead of all at
                   once.  ANSIPLAY reads the length of this run and
                   converts it into a real Delay() instead of relying
                   on anything downstream to throttle it.
  SAUCE            The little metadata tag (title/author/group/size)
                   some ANSI files carry appended after the art;
                   ANSIPLAY strips it before playback if present.
  VT / native VT   Windows' built-in mode (Windows 10/11 and up) that
                   lets the console itself interpret ANSI escape codes,
                   instead of a program having to translate them into
                   Console API calls by hand.


===============================================================================
                            === End of Document ===
===============================================================================
