Commit Graph

190 Commits

Author SHA1 Message Date
kris
cb287ea0e7 Add a DHGRColours enum mapping the DHGR logical colours to their
(memory-order) 4-bit values.
2019-06-19 21:54:49 +01:00
kris
5dcbca4aae Exit gracefully when running out of video frames 2019-06-19 21:54:07 +01:00
kris
38663088ef Remove CycleCounter, it's unused 2019-06-19 21:51:45 +01:00
kris
bd0aa6ad6b Simplify the accounting of audio ticks in video framing, and fix an off-by-one that was causing audio and video to become desynchronized.
Switch from 14340Hz to 14700Hz, which is 44100/3 i.e. a divisor of the
most common audio input sample rate.  This gives better quality
(and/or faster to encode) audio quality at the cost of producing <2%
faster playback.
2019-06-19 21:47:49 +01:00
kris
32bb4347ad Fix unit test 2019-06-19 21:45:58 +01:00
kris
a6d7cf73b1 Fix warning about missing newline at EOF 2019-06-17 23:46:52 +01:00
kris
079036042a Add TODO about Opcode.apply being currently unused 2019-06-17 23:46:24 +01:00
kris
1dcd16744b Add a .gitignore file 2019-06-17 23:45:05 +01:00
kris
20a6f03482 Default to DHGR and NTSC palette 2019-06-15 21:32:56 +01:00
kris
44f8ab39e4 Vectorizing does not help, the array is not big enough to amortize the
python overheads.
2019-06-15 21:30:25 +01:00
kris
bf2057cbb9 random.getrandbits() is much faster than random.randint() 2019-06-15 21:23:36 +01:00
kris
ca817999f6 Parametrize the RGB palette to encode with, and support both NTSC and
IIGS palettes.

Move the palette diff_matrix generation into make_data_tables.py since
that is the only place it is used.

Demand-load the edit distance matrices when transcoding.
2019-06-15 21:02:00 +01:00
kris
824154fd39 Compress the precomputed edit_distance arrays 2019-06-14 22:08:34 +01:00
kris
c2c57b47d5 Add type annotations 2019-06-14 22:03:37 +01:00
kris
549752e112 Rename FrameSequencer to FrameGrabber and break out into separate file.
Add a test case that the bmp2dhr output of input filenames containing
'.'  are handled correctly.

Break out video.Mode into video_mode.VideoMode to resolve circular
dependency.
2019-06-14 21:59:39 +01:00
kris
d5f2482a0a Add tests for _diff_weights 2019-06-14 00:13:28 +01:00
kris
b781bf3a10 No longer used 2019-06-14 00:13:14 +01:00
kris
ec65684221 FrameSequencer:
- Extract out a (File)FrameSequencer class from Video to encapsulate
the generation of still frames.  This also makes Video easier to test.

- Fix FileFrameSequencer.frames() to correctly handle filenames
  containing '.'

- Temporarily switch to the BMP2DHR NTSC palette (#5) for evaluation.

Video:
- Temporarily hardcode DHGR decoding

- Optimize _heapify_priorities() by using numpy to vectorize the
  construction of the list of tuples.  This requires changing the
  random nonce to an int so the intermediate array has a uniform type.

- Use the efficient 28-bit representation of DHGR (aux, main, aux,
  main) tuples introduced in DHGRBitmap to evaluate diffs

- Switch to np.int type for accumulating diffs, and random.randint(0,
  10000) instead of float for nonce values.

- Fix/improve some of the error evaluation in _index_changes:
  - skip offsets whose diffs have already been cleared
  - hoist some stuff out of _compute_error into the parent

- Add some validation that when we run out of work to do with a frame,
  the source and target memory maps should be equal.  This isn't
  happening sometimes, i.e. there is a bug.
2019-06-14 00:12:26 +01:00
kris
4251c9938f Remove unused code.
Add a new DHGRBitmap class that efficiently represents the
DHGR interleaving of the (aux, main) MemoryMap as a sequence of
28-bit integers.

This allows for easily extracting the 8-bit and 12-bit subsequences
representing the DHGR pixels that are influenced when storing a byte
at offsets 0..3 within the interleaved (aux, main, aux, main)
sequence.

Since we have precomputed all of the pairwise differences between
these 8- and 12-bit values, this allows us to efficiently compute the
edit distances between pairs of screen bytes (and/or arrays)
2019-06-13 23:44:41 +01:00
kris
a172214f16 Fix warnings 2019-06-13 23:41:28 +01:00
kris
5387eae674 Fix warning about missing newline at EOF 2019-06-13 23:40:55 +01:00
kris
fb14a20380 Precompute the edit distance between the 8-bit (2-pixel) and 12-bit
(3-pixel) sequences that may be modified when storing bytes to the
DHGR display.

This relies on producing an efficient linear representation of the
DHGR framebuffer in terms of a packed 28-bit representation of (Aux,
Main, Aux, Main) screen bytes.
2019-06-13 23:27:30 +01:00
kris
9f950739f9 Map DHGR colours to RGB values (for now using the BMP2DHR default
NTSC palette), and compute the matrix of pairwise perceptual
differences between these colours, using CIE2000 delta values.
2019-06-12 22:14:11 +01:00
kris
bed29004c2 Add a DHGRColours enum mapping the DHGR logical colours to their
(memory-order) 4-bit values.
2019-06-12 22:12:26 +01:00
kris
2d7d4acef7 Fix test 2019-06-12 22:06:58 +01:00
kris
2156522d0f Add a .gitignore file 2019-06-12 21:50:27 +01:00
kris
b84f40308b Add TODO about Opcode.apply being currently unused 2019-06-12 21:42:17 +01:00
kris
721eb3112d Fix bug with DHGR bank switching: we were emitting the last writes to
a bank after switching to the new one, which caused video corruption.
2019-06-12 21:37:30 +01:00
kris
0c44fe634f Remove stray comment 2019-04-25 21:29:38 +01:00
kris
782156967b Add --video_mode HGR|DHGR option to support both video modes uniformly. 2019-04-25 17:38:04 +01:00
kris
a188216f90 Add a video Mode enum. 2019-04-25 16:28:25 +01:00
kris
de8747ff37 Emit the video header and add an assertion to help make sure we don't
break the stream framing.
2019-04-25 16:28:06 +01:00
kris
2a76e3d48f Add a HEADER opcode that emits the 7-byte video header, used to
select the playback mode (HGR/DHGR).
2019-04-25 16:26:38 +01:00
kris
6bde085d5e Introduce a 7-byte video header and use it to select between HGR and
DHGR playback modes.  Actually the only difference is whether to
initialize (D)HGR display since everything else is steered by the video
stream.  6 of these bytes are currently unused, but it is convenient
to pad to the same length as the TICK opcode so that it does not
complicate the ACK stream framing.

Move towards the convention of using upper-case labels for system use
(soft switches etc) and lower-case for program use.
2019-04-25 16:25:36 +01:00
kris
aaf56e6ec5 Merge remote-tracking branch 'origin/dhgr' into dhgr 2019-03-28 23:48:40 +00:00
kris
33ac880d29 Improve comment about stream padding 2019-03-28 23:47:38 +00:00
KrisKennaway
e80e10924c
Update main.s
Fix last-minute typo
2019-03-28 23:29:10 +00:00
kris
fa6c2bb25d Minor cleanups:
- Use a safe ZP address instead of $00
- Use dec instead of hex for IP address bytes
- Remove some unused Uthernet/W5100 defines

Optimize the socket buffer management
- Since we're guaranteeing 2K frame padding, the low byte is always 0
- Remove some vestiges of the Uthernet TCP demo code - AFAICT there
  isn't a need to compare high and low bytes of the S0RXRSR, this
  was just being used as a (slightly risky) check that they were both
  not equal (presumably to 0)
- (h/t Oliver Schmidt <ol.sc@web.de>) it turns out that the W5100
  automatically wraps the address pointer at the end of the 8k RX/TX
  buffer space, so since we're using 8k buffers we don't need any of the
  pointer/mask arithmetic to make sure we don't stray outside this range
- Instead, we can just save the W5100 address pointer before we start
  doing the stream buffer management and restore it when we're ready
  to read from the stream again.
- Moreover, since we know the low-byte is 0 we don't even need to
  save it.

This gives us enough free cycles to implement a keypress check.  For
now any key will pause the video and any other key resume it.

We still have a whole 16 cycles left over while maintaining the 36/37
cycle tick cadence.

We've saved 73 cycles of "dead time" though, i.e. the
op_ack + CHECKRECV + op_nop "slow path" now takes 2*73 rather than 3*73
cycles.  This should result in better audio quality.
2019-03-28 23:08:52 +00:00
kris
10fa4bc72d Proof of concept DHGR encoding/playback
- Every time we process an ACK opcode, toggle page 1/page 2 soft
  switches to steer subsequent writes between MAIN and AUX memory
- while I'm here, squeeze out some unnecessary operations from the
  buffer management

On the player side, this is implemented by maintaining two screen
memory maps, and alternating between opcode streams for each of them.
This is using entirely the wrong colour model for errors, but
surprisingly it already works pretty well in practise (and the frame
rate is acceptable on test videos)

DHGR/HGR could be made runtime selectable by adding a header byte that
determines whether to set the DHGR soft switches before initiating
the decode loop.

While I'm in here, fix op_terminate to clear keyboard strobe before
waiting.
2019-03-27 21:37:06 +00:00
kris
d4a27444c6 Merge remote-tracking branch 'origin/master' 2019-03-24 00:15:16 +00:00
kris
21a4ac0186 Fix video termination logic 2019-03-24 00:14:41 +00:00
KrisKennaway
bb3f2e4a4c
Add some more details 2019-03-24 00:03:04 +00:00
KrisKennaway
403915d783
Create README.md 2019-03-23 23:48:55 +00:00
kris
dd422d1156 Fix tests 2019-03-23 22:05:36 +00:00
kris
13fb9c3125 Clean up module and abort import if we are unable to find the address
of an opcode.
2019-03-23 22:01:49 +00:00
kris
531a6ae345 Allow player to exit cleanly
- can't emit Terminate opcode in the middle of the bytestream
- pad the TCP stream to next 2k boundary when emitting terminate opcode,
  since the player will block until receiving this much data.
2019-03-23 21:46:35 +00:00
kris
8ffc8efaac Install RESET handler that exits to ProDOS
Implement op_terminate which waits for a keypress and then exits.
2019-03-23 21:45:13 +00:00
kris
8174d853f9 Downsize image using LANCZOS resampler. 2019-03-22 00:06:29 +00:00
kris
f37d07914d Print input frame rate, and default to every_n_video_frames=2 which
gives better quality without compromising frame rate too much.
2019-03-21 23:25:51 +00:00
kris
eebbccf711 Add some docstrings
Clean up naming in edit_distance

In video encoder, when we emit additional offsets as part of an opcode,
reinsert back into the priority heapq if the new edit distance is
nonzero, in case we get the chance to fix it up later in the frame.

Also make sure to zero out the diff_weights and content_deltas
so we don't consider the offset again as a side-effect of some other
opcode.

Instead of prioritizing side-effect offsets by their previous update
priority, prioritize by those with the lowest (error - edit) delta i.e.
not introducing too much error relative to their edit distance.
2019-03-21 22:56:45 +00:00