Post subject: @Bisqwit/Flygon Simulating Dot-Crawl/Crosstalk in AviSynth?
Joined: 7/13/2006
Posts: 61
I referenced two members because I wanted them to specifically read this thread but I'm def open to answers from everyone. I want to specifically reference this video by Bisqwit... Link to video I may be chasing ghosts here but is there a way to separate and mix channels in such a way as to recreate this effect? If I understand the video description text it looks like Bisqwit converted this to a format with a YIQ color space and then back to RGB. Which, as I understand it, is similar to how other NTSC filters like Blargg's NTSC work. I do a lot of playing around with emulator footage in AviSynth and After Effects to try and recreate certain effects like making an HD clip look like it's been ran through a VCR, emulating early video codecs like those found in early FMV games, etc. This seems like an effect that would really add to the authenticity of it all if I could just figure out what exactly is going on here. Maybe you guys can point me in the right direction.
Banned User
Joined: 3/10/2004
Posts: 7698
Location: Finland
I find it amusing that back in the days when color TV was first invented and developed, those coloring artifacts were an unwanted defect caused by limited transmission bandwidth and technology, but today people are trying to emulate these defects. (The reason why the color information in analog TV is so destroyed and mangled up is because TV transmission bandwidths had been established by governments for sending B/W TV signals, and changing them to be wider would have been way too much trouble. Thus the engineers had to come up with a way to mix the color information into the same bandwidth as the existing luminance information. This meant that there had to be far less color information than luminance, and it had to be interleaved between the frequency "peaks" in the latter. It was then up to the TV to separate them appropriately. Most cheap TVs did a bad job at it, making the picture even worse than it could have been.)
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
I have no idea what can be done with AviSynth and what cannot, and have never used it for any purpose, but the NTSC filtering process for NES is rather simple, at least if you have the source material in NES palette indexes format rather than in RGB format. Here is my code (written in PHP of all things) for encoding NES graphics signal into NTSC, and for correspondingly decoding it in a very straightforward manner.
Language: PHP

<?php function GenNTSCsignal($pixel, $phase, $length=8) // Generate NTSC signal corresponding to NES color { // Voltage levels, relative to synch voltage $levels = Array(.350, .518, .962,1.550, // Signal low 1.094,1.506,1.962,1.962); // Signal high // Decode the NES color ("eeellcccc" format). $color = ($pixel & 0x0F); // 0..15 "cccc" $level = ($pixel >> 4) & 3; // 0..3 "ll" $emphasis = ($pixel >> 6); // 0..7 "eee" if($color > 13) { $level = 1; } // For colors 14..15, level 1 is forced. $result = Array(); for($p=0; $p<$length; ++$p) { // Generate the square wave: $sig = $levels[ $level + 4 * ($color <= 12*(($color+$phase)%12 < 6)) ]; // When de-emphasis bits are set, some parts of the signal are attenuated: if($emphasis & (0264513 >> (3*(($phase%12)>>1)))) $sig *= 0.746; // Normalize the signal to 0..1 range, and save: $result[] = ($sig - $levels[1]) / ($levels[7]-$levels[1]); ++$phase; } return $result; } function DecodeNTSCsignal($signal, $begin,$end, $phase, $saturation = 1.7, $brightness = 1.0) { $length = $end-$begin; $factor = $brightness/($length); if($begin < 0) $begin = 0; $c = count($signal); if($end > $c) $end = $c; $y = 0; $i = 0; $q = 0; for($p = $begin; $p < $end; ++$p) { $value = $signal[$p] * $factor; $y += $value; $value *= $saturation; $i += $value * cos( (3.141592653/6) * ($phase + $p)); $q += $value * sin( (3.141592653/6) * ($phase + $p)); } $gamma = 2.0; return 0x10000*(int)min(255, 255.95 * pow(max(0,$y + 0.946882*$i + 0.623557*$q), 2.2 / $gamma)) + 0x00100*(int)min(255, 255.95 * pow(max(0,$y + -0.274788*$i + -0.635691*$q), 2.2 / $gamma)) + 0x00001*(int)min(255, 255.95 * pow(max(0,$y + -1.108545*$i + 1.709007*$q), 2.2 / $gamma)); }
There are many ways to use it. For instance, this loop generates the entire 64-color palette (with black duplicates and stuff) in RGB:
Language: PHP

for($c=0; $c<64; ++$c) { $signal = GenNTSCsignal($c, 0, 12); // Generates 12 samples of NTSC signal at phase offset = 0 $rgb = DecodeNTSCsignal($signal, 0,12, 3.9); $palette[$c] = $rgb; }
To generate actual NTSC cross-talk & dot-crawl artifacts, you will need to generate NTSC signal for an entire scanline (8 samples per pixel, for a total of 2048 samples per scanline, with an offset that is varied on each scanline; alternatingly subtracting and adding 4); and then decode it at horizontal resolution of your choice. Decoding the RGB color corresponding to a certain floating point X coordinate on the screen (e.g. 120.25 is perfectly valid) would be: $rgb = DecodeNTSCsignal($signal, $x*2048/256+0, $x*2048/256+12, 3.9); And you can change the +0 and +12 according to your wishes. You get best results if you keep their relative difference as an integer multiple of 12, such as 48, but you might use 23 for some chroma dots, too. You can also use e.g. -6 and +6, but you may need to adjust the hue (phase) correspondingly. I don't remember whether that's the case. This is a quick & lazy algorithm with not very much sophistication to it, but should get one started. I have posted more details at the Nesdev wiki: http://wiki.nesdev.com/w/index.php/NTSC_video If your input image data does not consist of NES palette indexes, but already made RGB values, then you need more work. I don't have code for that provided, but I think you need to convert the RGB into YIQ, determine the phase & amplitude and use them to form the $sig within the inner loop of GenNTSCsignal(). EDIT: Wait a second, I do. I provided that code with the video linked to in the opening post of this thread. It just has a very significant "this is probably wrong" in it that I cannot shake.
Joined: 7/13/2006
Posts: 61
I think I'm stuck. Granted, I'm trying to interpret code that I don't quite understand because I'm not good at the maths or programming and trying to translate that into a workflow for Adobe After Effects. I've taken the signal and split it into separate YIQ components and added a low pass filter to each of those and then converted back to RGB for the output. It's working as expected but I'm not still not really sure after studying the code what's going on in each channel that's simulating the dot crawl effect. You mentioned the offset. What's going on differently on odd and even lines per channel? I've got everything split up where I can effect things different if I just knew exactly what was going on.
Joined: 7/13/2006
Posts: 61
I may have had a revelation as I'm definitely seeing some movement now. I may be way off base. Please correct me if I'm doing something wrong. By offset you mean an even scanline shifting right while an odd scanline shifts left? I did something similar in the chroma channels and it looks alright but I'm not sure how on the money that is. Am I correct in guessing that if I add a crosstalk layer that applies only to the chroma and not the luma?