============
       Introduction
       ============
       
       Recently, I made a music video for one of my songs. I made the video
       using Python 3 and Asciimatics_.
       
       I'm interested in lo-fi videos, and this was a first experiment.
       While my experiment existed solely within the bounds of a terminal
       window, there were a number of lessons learned through the process.
       
       These lessons will help me, as well as others who are interested in
       performing similar lo-fi experiments.
       
       ============================
       Use a real time (not frames)
       ============================
       
       Asciimatics uses a single integer "frame" counter.
       
       Regardless of how fast the screen is updating, it's easier to deal with
       simple seconds and fractional seconds. Approximate timing is okay, especially
       if we can readily use timing data gathered from other sources.
       
       For instance, there's timing data in closed captions. It's also easy to create
       timing data in something like Audacity. All of these use either human time or
       seconds and fractional seconds.
       
       Leverage your other tools by dropping the notion of frames. If you
       _really_ need to be frame-precise, consider using a frame-separator in
       other timestamps, maybe using an '@' as a separator between the seconds
       and frames.
       
       Idealized timeline
       ~~~~~~~~~~~~~~~~~~
       
       A show can be thought of as a series of variable-length scenes, strung together.
       
       In my music video, I had a start screen before the music started.
       
       You need to be with flexible intro and outro content, while also fully supporting
       binding the video to the audio's location. In most cases, you may be able to get
       away with having a "starting time" for a scene which is simply subtracted to all
       action in a scene.
       
       If I have three scenes, A, B, and C, and I know they start ten minutes apart,
       it could be something as simple as::
       
           scene_a = Scene(0)
           scene_a.at('0:05', do_it)
           # ... add 10 minutes of content (originally only 5)
           scene_a.at('5:05', part_of_scene_a)
           scene_b = Scene('5:00')
           scene_b.at('5:05', part_of_scene_b)
           # ... add 15 minutes of content
           scene_c = Scene('25:00')
           scene_c.at('25:05', do_it)
           show = [ scene_a, scene_c, scene_b ]
       
       Since each scene can know its own starting point, it can keep the scene timing
       consistent, even if the order of the scenes themselves change or the earlier
       scenes change length.
       
       Do you want to add a commercial? You shouldn't have to dick with timings.
       Just create the scene and stick it in the show::
       
           commercial = Scene('3:00')
           show = [ scene_a, commercial, scene_c, scene_b ]
       
       That sort of scene movement only works when music is bound to scenes, and not
       the whole show, of course.
       
       Going further
       -------------
       
       For an audio book or other long-form audio stream, you should be able to grab
       the audio file and split it up in to separate scenes.
       
       Getting markers for splits is, as mentioned, easy enough to gather in Audacity,
       but -- while you can split things up in Audacity, it shouldn't be required.
       
       If you need to use Audacity anywhere to find the split-points, it's not
       really a time-saver. If, however, you can gather split-points within the
       application, things get more interesting.
       
       Splitting audio at scene-breaks allows you to use scene-breaks as explicit
       restart points when iterating on a scene. It's faster and easier to only
       allow jumping forward and backward at scene changes, as you know the screen
       will start from black.
       
       This means on the back-end, we'll need to track the time of the scene
       change for the audio to support this, anyway. If we have the data, we
       should support splicing a new scene in to that location.
       
       Features and timeline
       ~~~~~~~~~~~~~~~~~~~~~
       
       mvp:
       
           Timeline using real time units. The line between "scene" and
           "show" can be blurry or not exist.
       
       mvp+1:
       
           Shows made of series of stitched-together scenes. Scenes described
           with starting times that may not map to their play-time.
       
       mvp+2:
       
           Scenes and timelines integrate with long audio tracks and
           arbitrary starting points within those tracks.
       
       ==========================
       Synchronize with the audio
       ==========================
       
       My first experiment used PyGame_ to run the song. This back-end is designed for
       background music in games.
       
       You need to be able to query the audio to see where it is. If the audio isn't
       where it is expected to be, you need to hold everything up until it catches up.
       
       PyGame doesn't support this. It's more of a fire-and-forget service.
       
       Idealized timeline
       ~~~~~~~~~~~~~~~~~~
       
       In the very least, you need to delay the start of a scene until the
       audio starts moving.
       
       The disadvantage of audio running in a separate thread (as is normally
       done) is that it may not be at the same place as the animation thread.
       The play speed shouldn't have glitches, but the start times can be
       a bit wobbly.
       
       At the very least, you need to support pausing until the audio is
       ready. Having all sense of time come from the audio goes one step
       further, as it makes the primary timekeeper the audio system.
       
       Some systems (such as PyGame) have a distinction between a sound effect
       that is loaded entirely in to memory and a streamed background music
       file.
       
       Even if you're technically dealing with background music, getting the
       timing right may require loading more of the file in to memory more of
       the time. Accept that you may need a whole song in memory, and that
       you can only reasonably change this during scene breaks.
       
       Going further
       -------------
       
       You should be able to do your final rendering non-real-time, so you'll
       always be properly synchronized.
       
       Non-real-time is the ideal for keeping audio and video synchronized.
       It allows you to bite off small pieces of audio at a time and know
       that everything will line up.
       
       Features and timeline
       ~~~~~~~~~~~~~~~~~~~~~
       
       mvp:
       
           Preload entire audio file in to memory and avoid streaming from
           disk. 
       
           Try to change scenes or cameras at background song boundaries.
           Keep these as isolated units, knowing they'll get stitched together
           during editing.
       
       mvp+1:
       
           Start of video is delayed until the audio starts playing.
       
           If each scene is independent, a scene may have a pause to start. This
           can be corrected in post, as needed, but should keep audio and video
           consistent.
       
           It might be useful to have the video's sense of time to come from the core
           background track, I'm not sure that's 100% needed without further testing.
       
       mvp+2:
       
           Non-realtime rendering insures that audio and video is always synchronized.
       
           This is by far the gold standard. Ideally, you can do this at faster than
           real time.
       
       ======================
       ASCII as a visual form
       ======================
       
       I used big Figlet_ ASCII Art fonts for my test video.
       
       Monitors are bigger and higher resolution than ever before, right?
       
       But this is really what you need. Huge text, even in text mode.
       
       Some of the viewers will watch it full-screen, sure, but a significant
       population will half-distractedly watch a thumbnail instead.
       
       If it's a silent film, folks will need to go larger to read what is
       going on. So, in a silent film context a text-based Roguelike user
       experience may still work? Further experiment is required.
       
       Still, consider going for an older aesthetic and angling for 40x25 (or
       thereabouts) instead of something more modern. 
       
       Idealized visual form
       ~~~~~~~~~~~~~~~~~~~~~
       
       I'm still thinking about old school RPGs.
       
       Fixed camera at best. Top-down maps. A few fixed expressions in close-up.
       Maybe a giant close-up like you find in visual novel games. 
       
       And a dedicated section for dialog to appear.
       
       Maybe menu-style alternative dialog, of course this would be just a fake,
       but it would be easy flavor.
       
       It would be mostly tile-based with a few larger graphics now and then.
       
       It would probably be less than 40 tiles wide. The Roguelike people have
       to make a lot of compromises about visible map size versus map quality,
       so if you're curious about the how and why, you can always look there.
       
       Going further
       -------------
       
       Honestly, I'd really like to have something like `The Sims`_ where instead
       of semiautonomous entities, you just had actors you could control and
       play and rewind their time.
       
       There is MakeHuman_ which provides an open-source method to generate and
       render humans. It has a lot of output formats.
       
       I wouldn't mind using the entire virtual worlds of The Sims, though.
       If we had the capacity to use assets from The Sims, (on-par with,
       say, other open-source games that require comercial assets), it would
       allow us to use the third-party assets as well, of which there are
       considerable and some with decent licenses.
       
       There are other 3D games we might be able possibly to leverage, but few
       are designed for normal, ordinary world stuff like The Sims.
       
       `Garry's Mod`_ might technically work, but modifying maps is a fair bit
       more complicated, and it uses a commercial engine... Then there's the mod
       community that mostly just steals stuff from commercial games and is
       full of fascists... Not very appealing.
       
       Features and timeline
       ~~~~~~~~~~~~~~~~~~~~~
       
       mvp:
       
           Modeled after an RPG, or a text-based Roguelike. A dedicated place
           for the dialog. The right versus left, main character versus
           whomever being talked to. It's an easy UX to write that's flexible
           for many types of stories.
       
       mvp+1:
       
           It's possible to experiment with 3D without actually having a 3D
           game. The portraits can be animated 3D models, there can be
           cut-scenes. These, too, are standard components of games.
       
       mvp+2:
       
           This would be a 3D video, so more like a silent cartoon. Instead
           of the interface having a dedicated place for dialog, it would be
           handled more like standard closed captions.
       
       =========
       Phase One
       =========
       
       Timeline using real time units. The line between "scene" and
       "show" can be blurry or not exist.
       
       Preload entire audio file in to memory and avoid streaming from
       disk. 
       
       Try to change scenes or cameras at background song boundaries.
       Keep these as isolated units, knowing they'll get stitched together
       during editing.
       
       Modeled after an RPG, or a text-based Roguelike. A dedicated place
       for the dialog. The right versus left, main character versus
       whomever being talked to. It's an easy UX to write that's flexible
       for many types of stories.
       
       
       Visual Idea
       ~~~~~~~~~~~
       
       Here's an idea for a roguelike visual (since they map to documents
       easier)::
       
           +----------------------------------------+
           |                 ",,,,.........."       |
           |                 ",,,,.,,""""".."       |
           |                 "####'##"   "..*""*    |
           |                  #...AB#    *....."    |
           |                  #.....#    """*..*"""*|
           |                #####D######    "".....0|
           |                #..........#     ""*"""*|
           |                #...>......#            |
           |                ############            |
           |                                        |
           +----------------------------------------+
           |Betty can:                              |
           |  signal to Ada to leave, ASAP.         |
           |> ask for garlic (nicely).             <|
           |  mock the blood on his necktie.        |
           |                                        |
           +----------+-----------------------------+
           | Ada      |Dracula: Good evening!       |
           |>Betty   <|Ada: We're here to fix your  |
           |          | computers.                  |
           |          |Dracula: The basement is     |
           |          | over here!                  |
           +----------+-----------------------------+
           
       
           +----------------------------------------+
           |                 """"""""""""""""       |
           |                 ",,,,.........."       |
           |                 ",,,,.,,""""".."       |
           |                 "####+##"   "..*""*    |
           |                             *....."    |
           |                             """*..*"""*|
           |                                ""...AB0|
           |                                 ""*"""*|
           |                                        |
           |                                        |
           |                                        |
           |                                        |
           |                                        |
           +You see:--+Near Old House---------------+
           |0: to car |The house appears ancient    |
           |          | with fine, hand-crafted     |
           +----------+ details now falling to ruin.|
           |>Ada     <|Betty: We're lost, Ada.      |
           | Betty    | Admit it!                   |
           |          |Ada: We're not lost! We're...|
           |          | ... Alright, Betty. We're   |
           |          | lost.                       |
           +----------+-----------------------------+
       
       Source Idea
       ~~~~~~~~~~~
       
       Here's a potential source snippet leading up to the above::
       
           ada = Actor('Ada', player=True)
           betty = Actor('Betty', player=True)
           dracula = Actor('Dracula')
           passage = Thing('to car')
           welcome_scene = Scene('0:00', map='dracula_floor_1', audio=ambient_creep,
                               title='Near Old House',
                               place={'A':ada, 'B':betty, 'D':dracula, '0':passage})
           betty.follow(ada)
           betty.say('0:01', "We're lost, Ada. Admit it!")
           ada.say("We're not lost. We're...")
           ada.say(1, "... Alright, Betty. We're lost.")
           ada.move_to('0:05', Scene.map.find('+'), proximity=3)    
           betty.choice("Dare Ada to lie about why we're here.",
                        "Say: We're computer technicians.",
                        "Say: We're here to suck his blood!",
                        "Say: We're pest control.",
                        pick=0, delay=0.5)
           betty.emote('smiles and looks at Ada.)
           ada.emote(0.2, 'squirms. "You have an idea.'
                            ' It's a bad one. That's your bad idea face.")
           betty.say("We should say we're here to suck his blood.")
           ada.say("What? No.")
           ada.say(0.2, "There's no reason he'd let us in if we said that.")
           betty.emote(0.2, 'nods. "You're right. We should do something else."')
           betty.say(0.1, "I know. I dare you to say we're computer technicians.")
           ada.say('What?')
           ada.say(0.5, "You're mean. You know that, right?")
           welcome_scene.wait(0.2)
           return welcome_scene
       
       ==========
       Reflection
       ==========
       
       It's interesting that nothing about my example actually needs the
       background track to be sample-precise with the visual. How important is
       that, really? Maybe this is something that's only really needed for the
       lyric tracks and when there's explicit syncronized timing.
       
       (For sample-precise timing to music, you might think of having a
       dedicated MIDI track for the action triggers. However, that's different
       than my above example.)
       
       Even the "real timeline" thing is a bit fuzzy. Scenes start with a real
       time that's used as an offset for timestamps mentioned in the scene,
       yes. But what I actually use in the example are mostly relative time in
       seconds.
       
       The given example has what could be a looping ambient track for the
       background. I think of it going silent and a knocking sound as part of
       the transition to the scene with the door open, but... I can also see
       long ambient tracks that fit multiple scenes.
       
       This means we'd need an `advisory_start` which would start audio within
       the file if you're jumping in to it, but let it flow naturally if you're
       starting at a previous scene. Ideally, this could be part of the next
       bit...
       
       Not all scenes will have fixed starting state. Sometimes state will
       depend upon previous state. We still need to jump to arbitrary scenes to
       aid in development. We can manage this by caching scene state at the end
       of scenes when this is needed.
       
       We could either always overwrite, or create a new file separate from
       the working file and make the developer manually overwrite. I favor
       always-overwrite, but user-overwrite would be more like traditional
       film. (I want fast and easy. Post-processing audio, as for traditional
       film, is neither of these things.)
       
       Roguelike games can easily have a dedicated region for text. My example
       above was narrow, but I think if it's a Roguelike aiming for 80+ by
       something 24 or greater is reasonable. Probably with three panes instead
       of whatever I was thinking above, one for map, one for dialog and feedback,
       and another for equipment or stats or even inventory.
       
       A design aiming after a GUI RPG allows us to have potraits, but turns
       back and forth dialog in to what is effecitvely a cut-scene. There's
       nothing wrong with that, but it's different work than the main stuff.
       
       Graphic RPGs will have smaller maps than the text-based games. Any
       graphic RPG game that uses a "minimap" of some sort does so because
       the primary view is pretty but doesn't convey enough information about
       where you are in relationship to your objectives. You see this less with
       third-person turn-based games than with first-person live-action games,
       but this is totally fine for our particular use-case. Huge, pretty tiles
       and a light-weight sketch of the neighborhood in a corner for flavor.
       
       If a show were to mostly have back-and-forth dialog, it should
       probably aim to feel more like a visual novel game and not an RPG.
       This would be lots of dialog with big portraits and usually some
       relationship-based questions.
       
       .. References (inline links when rendered)
       
       .. _Asciimatics: https://github.com/peterbrittain/asciimatics
       
       .. _Garry's Mod: https://gmod.facepunch.com/
       
       .. _Figlet: http://www.figlet.org/
       
       .. _MakeHuman: http://www.makehumancommunity.org/
       
       .. _PyGame: https://www.pygame.org/
       
       .. _The Sims: https://www.ea.com/games/the-sims
       
       ----
       
 (DIR) Category: Essays and Thoughts
       ------------------------------------------------------------------
       
 (DIR) Home
 (DIR) Phlog
 (DIR) Products
 (DIR) Categories
 (DIR) Keywords