{"id":1002,"date":"2018-12-11T18:13:38","date_gmt":"2018-12-12T02:13:38","guid":{"rendered":"https:\/\/www.pagetable.com\/?p=1002"},"modified":"2018-12-11T18:13:38","modified_gmt":"2018-12-12T02:13:38","slug":"archiving-c64-tapes-correctly","status":"publish","type":"post","link":"https:\/\/www.pagetable.com\/?p=1002","title":{"rendered":"Archiving C64 Tapes Correctly"},"content":{"rendered":"<style>\n.read-ok-background {\n\tbackground-size: 25% 100%;\n\tbackground-image: linear-gradient(to right, #ccffcc, #00ff00);\n\tbackground-repeat: no-repeat;\n}\n<\/style>\n<p>It&#8217;s pretty simple to archive Commodore 64 tapes, but it&#8217;s hard if you want to do it right. Creating the <a href=\"https:\/\/www.pagetable.com\/?p=998\">complete archive of the German &#8220;INPUT 64&#8221; magazine<\/a> was not as easy as getting one copy of each of the 32 tapes and reading them. The tapes are over 30 years old by now, and many of them are hardly readable any more.<\/p>\n<h2>Good Tapes, Bad Tapes<\/h2>\n<p>Here is the overview of the tapes I have of each issue, how many I could read correctly, and what percentage that is:<\/p>\n<table border=\"1\">\n<tr>\n<th>Issue<\/th>\n<th># Copies<\/th>\n<th># Read OK<\/th>\n<th>% Read OK<\/th>\n<\/tr>\n<tr>\n<td>8501<\/td>\n<td>8<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:25% 100%;\">25%<\/td>\n<\/tr>\n<tr>\n<td>8502<\/td>\n<td>6<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:17% 100%;\">16.7%<\/td>\n<\/tr>\n<tr>\n<td>8503<\/td>\n<td>8<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:12% 100%;\">12.5%<\/td>\n<\/tr>\n<tr>\n<td>8504<\/td>\n<td>6<\/td>\n<td>0<\/td>\n<td class=\"read-ok-background\" style=\"background-size:0% 100%;\">0%<\/td>\n<\/tr>\n<tr>\n<td>8505<\/td>\n<td>6<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:17% 100%;\">16.7%<\/td>\n<\/tr>\n<tr>\n<td>8506<\/td>\n<td>6<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:17% 100%;\">16.7%<\/td>\n<\/tr>\n<tr>\n<td>8507<\/td>\n<td>6<\/td>\n<td>0<\/td>\n<td class=\"read-ok-background\" style=\"background-size:0% 100%;\">0%<\/td>\n<\/tr>\n<tr>\n<td>8508<\/td>\n<td>6<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:17% 100%;\">16.7%<\/td>\n<\/tr>\n<tr>\n<td>8509<\/td>\n<td>6<\/td>\n<td>5<\/td>\n<td class=\"read-ok-background\" style=\"background-size:83% 100%;\">83.3%<\/td>\n<\/tr>\n<tr>\n<td>8510<\/td>\n<td>6<\/td>\n<td>0<\/td>\n<td class=\"read-ok-background\" style=\"background-size:0% 100%;\">0%<\/td>\n<\/tr>\n<tr>\n<td>8511<\/td>\n<td>6<\/td>\n<td>3<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8512<\/td>\n<td>10<\/td>\n<td>3<\/td>\n<td class=\"read-ok-background\" style=\"background-size:33% 100%;\">33.3%<\/td>\n<\/tr>\n<tr>\n<td>8601<\/td>\n<td>4<\/td>\n<td>3<\/td>\n<td class=\"read-ok-background\" style=\"background-size:75% 100%;\">75%<\/td>\n<\/tr>\n<tr>\n<td>8602<\/td>\n<td>4<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8603<\/td>\n<td>4<\/td>\n<td>3<\/td>\n<td class=\"read-ok-background\" style=\"background-size:75% 100%;\">75%<\/td>\n<\/tr>\n<tr>\n<td>8604<\/td>\n<td>4<\/td>\n<td>4<\/td>\n<td class=\"read-ok-background\" style=\"background-size:100% 100%;\">100%<\/td>\n<\/tr>\n<tr>\n<td>8605<\/td>\n<td>6<\/td>\n<td>3<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8606<\/td>\n<td>4<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8607<\/td>\n<td>4<\/td>\n<td>4<\/td>\n<td class=\"read-ok-background\" style=\"background-size:100% 100%;\">100%<\/td>\n<\/tr>\n<tr>\n<td>8608<\/td>\n<td>4<\/td>\n<td>3<\/td>\n<td class=\"read-ok-background\" style=\"background-size:75% 100%;\">75%<\/td>\n<\/tr>\n<tr>\n<td>8609<\/td>\n<td>6<\/td>\n<td>4<\/td>\n<td class=\"read-ok-background\" style=\"background-size:67% 100%;\">66.7%<\/td>\n<\/tr>\n<tr>\n<td>8610<\/td>\n<td>6<\/td>\n<td>5<\/td>\n<td class=\"read-ok-background\" style=\"background-size:83% 100%;\">83.3%<\/td>\n<\/tr>\n<tr>\n<td>8611<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8612<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8701<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8702<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:100% 100%;\">100%<\/td>\n<\/tr>\n<tr>\n<td>8703<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:100% 100%;\">100%<\/td>\n<\/tr>\n<tr>\n<td>8704<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:100% 100%;\">100%<\/td>\n<\/tr>\n<tr>\n<td>8705<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<tr>\n<td>8706<\/td>\n<td>4<\/td>\n<td>1<\/td>\n<td class=\"read-ok-background\" style=\"background-size:25% 100%;\">25%<\/td>\n<\/tr>\n<tr>\n<td>8707<\/td>\n<td>6<\/td>\n<td>0<\/td>\n<td class=\"read-ok-background\" style=\"background-size:0% 100%;\">0%<\/td>\n<\/tr>\n<tr>\n<td>8708<\/td>\n<td>4<\/td>\n<td>2<\/td>\n<td class=\"read-ok-background\" style=\"background-size:50% 100%;\">50%<\/td>\n<\/tr>\n<\/table>\n<p>As you can see, some tapes are pretty much unreadable these days, others are okay. For issues that were problematic, I kept buying more copies on eBay, hoping to eventually find one that reads correctly. (Interestingly, the distribution suggests that correlates more with the brand of tape (8707 seems to be a very bad one) than with age.)<\/p>\n<p>By the way, all numbers of copies are divisible by two, because all INPUT 64 tapes have an identical copy of the data on the reverse side. So for issue 8702, for example, I only had a single tape, and both sides read correctly.<\/p>\n<h2>How to Dump Tapes<\/h2>\n<p>There are many ways to dump C64 tapes, and I&#8217;ll describe two.<\/p>\n<p>If you have a C64 and an actual Datasette reader, you can use the <a href=\"http:\/\/www.1541ultimate.net\/\">1541 Ultimate-II+<\/a> cartridge. The included dongle allows you to connect the Datasette to the cartridge, so you can directly record a tape onto a .TAP file on a USB storage device also connected to the cartridge.<\/p>\n<p>If you are doing this, make sure that your Datasette has a clean head and is correctly aligned. <a href=\"https:\/\/csdb.dk\/release\/?id=92762\">HeadAlign<\/a> by enthusi is very useful for this. If you have multiple Datasette recorders, try them all and start out with the best one before changing the alignment.<\/p>\n<p>Another way is to record the tape into a WAV file using a regular tape recorder. Online shops are full of very cheap (but good) Walkman-like devices with a built-in analog-digital-converter that connect directly to USB and show up as an audio-in device. Using a tool like Audacity and one of the many WAV-to-TAP tools (my favorite is the ancient <a href=\"http:\/\/www.zimmers.net\/anonftp\/pub\/cbm\/crossplatform\/transfer\/datassette\/index.html\">&#8220;tape64&#8221;<\/a>, whose Windows binary works nicely with Wine), you can then convert it into a TAP file.<\/p>\n<p>The advantage of this method is that you can still massage dumps of tapes that you have trouble with. In Audacity, you can use filters or split the two channels, and in conversion tools, you can adjust the threshold or the speed.<\/p>\n<p>Interestingly, some tapes read well on a tape player, others read well on a Datasette. If you have trouble getting a correct dump and few copies, you might want to try different methods of reading the tapes.<\/p>\n<h2>Checksums<\/h2>\n<p>How do I know whether a tape has in fact been read correctly? Practically all recording formats use checksums, so a tool like the excellent <a href=\"https:\/\/sourceforge.net\/projects\/tapclean\/\">tapclean<\/a> can help:<\/p>\n<pre>\n$ tapclean -t 8702a.tap\n\n----------------------------------------------------------------------\nTAPClean 0.34 - (C) 2006-2017 TC Team [Built Jun 12 2017 by ldf]\nBased on Final TAP 2.76 Console - (C) 2001-2006 Subchrist Software\n----------------------------------------------------------------------\n\nRead tolerance = 10\n\nComputer type: C64 PAL (985248 Hz)\n\n\nLoaded: 8702a.tap\nTesting...\n\nScanning...  Pauses  C64 ROM tape\n\nTAPClean version: 0.34\n\nGENERAL INFO AND TEST RESULTS\n\nTAP Name    : 8702a.tap\nTAP Size    : 1221451 bytes (1192 kB)\nTAP Version : 1\nRecognized  : 94%\nData Files  : 28\nPauses      : 186\nGaps        : 204\nMagic CRC32 : A9F18B1C\nTAP Time    : 8:44.16\nBootable    : YES (1 part, name: INPUT 64)\nLoader ID   : n\/a\n\nOverall Result    : FAIL\n\nHeader test       : PASS [Sig: OK] [Ver: OK] [Siz: OK]\nRecognition test  : FAIL [1153201 of 1221431 bytes accounted for] [94%]\nChecksum test     : PASS [28 of 28 checksummed files OK]\nRead test         : PASS [0 Errors]\nOptimization test : FAIL [0 of 28 files OK]\n\nSaved: tcreport.txt\nOperation completed in 00:00:09.\n<\/pre>\n<p>The tool recognized 28 pieces of data on the tape, and all of them had correct checksums. That&#8217;s a good sign, but not good enough. And that&#8217;s not just because single-byte checksums might be too weak to rely on.<\/p>\n<h2>Completeness<\/h2>\n<p>It is possible that some pieces of data did not get recognized. If a header is unreadable, tapclean will treat it as an unrecognized area and warn about it. In the printout above, the tape failed the &#8220;recognition test&#8221;, because it only understood 94% of the tape (which includes silence). What are the other 6%?<\/p>\n<p>Tapes often contain some garbage, and many INPUT 64 tapes have a minute of beeps at the end that don&#8217;t seem to encode any data. So these 6% may not be a problem.<\/p>\n<p>Another data point on whether all data objects got recognized is by extracting everything and having a look at the listing:<\/p>\n<pre>\n$ tapclean -t 8702a.tap -doprg\n$ ls prg\/\n007 (033C-03FB) [INPUT_64].prg\n008 (033C-03FB) [INPUT_64].prg\n010 (0318-09FF).prg\n011 (0318-09FF).prg\n013 (033C-0354) [CTEXTE].prg\n017 (3000-3FBA).prg\n021 (033C-0354) [RAHMEN_______COM].prg\n025 (C440-CFF4).prg\n029 (033C-0354) [TITELBILD].prg\n033 (0801-1891).prg\n037 (033C-0354) [l_O_H_N_S_T_E_U].prg\n041 (0801-6BCE).prg\n045 (033C-0354) [j_u_l_i_a].prg\n049 (0801-4B99).prg\n052 (033C-0354) [i_d___w_E_R_K_S].prg\n056 (0801-3F16).prg\n060 (033C-0354) [6_4_E_R__t_I_P_S].prg\n064 (0801-59CE).prg\n068 (033C-0354) [i_n_p_u_t___c_a].prg\n072 (0801-2E7C).prg\n076 (033C-0354) [l_A_B_E_L___t_O].prg\n080 (0801-2AEC).prg\n084 (033C-0354) [d_R_E_I___M_A_L].prg\n088 (0801-5538).prg\n091 (033C-0354) [eNGLISCHE_gramMA].prg\n095 (0801-5B22).prg\n098 (033C-0354) [v_O_R_S_C_H_A_U].prg\n102 (0801-2A94).prg\n<\/pre>\n<p>Commercial Commodore 64 tapes usually don&#8217;t use the original encoding as supported by the C64&#8217;s operating system. More optimized schemes are often 5x-10x more efficient. Nevertheless, the first program on tape has to use the original encoding, so that the tape is bootable.<\/p>\n<p>This tape contains a bootable program named &#8220;INPUT 64&#8221; at the beginning. The Commodore encoding saves the 192 bytes header (file name, type etc.) twice (007, 008), followed by the data, which is also saved twice (010, 011). On this tape, everything after this is in &#8220;SUPERTAPE&#8221; format. Every SUPERTAPE file consists of a single header (e.g. 013 for &#8220;CTEXTE&#8221;) and a single copy of the data (e.g. 017).<\/b><\/p>\n<p>The printout above shows that after the boot program (2x header, 2x payload), there are 12 additional files. For each file, there is a header and there is payload. So this looks okay. Here is an example of a missing object:<\/p>\n<pre>\n$ tapclean -t 8707a.tap -doprg\n[...]\nChecksum test     : PASS [29 of 29 checksummed files OK]\n[...]\n$ ls prg\/\n066 (033C-03FB) [INPUT_64].prg\n067 (033C-03FB) [INPUT_64].prg\n069 (0318-09FF).prg\n070 (0318-09FF).prg\n072 (033C-0354) [CTEXTE].prg\n076 (3000-4093).prg\n080 (033C-0354) [RAHMEN_______COM].prg\n084 (C440-CFF2).prg\n088 (033C-0354) [TITELBILD].prg\n092 (0801-1891).prg\n096 (033C-0354) [i_n_p_u_t___w_I].prg\n100 (0801-4A1D).prg\n103 (033C-0354) [eNGLISCHE_gramMA].prg\n107 (0801-5E09).prg\n111 (033C-0354) [s_P_I_D_E_R].prg\n115 (0801-471B).prg\n<b>118 (033C-0354) [a_S_S_E_M_B_L_E].prg<\/b>\n128 (033C-0354) [i_d___w_E_R_K_S].prg\n132 (0801-3E4D).prg\n135 (033C-0354) [i_c_i].prg\n139 (0801-2DB0).prg\n143 (033C-0354) [6_4_E_R__t_I_P_S].prg\n147 (0801-4911).prg\n151 (033C-0354) [p_I_N_G___p_O_N].prg\n155 (0801-247F).prg\n159 (033C-0354) [r___T_S_E_L_E_C].prg\n163 (0801-22A5).prg\n167 (033C-0354) [v_O_R_S_C_H_A_U].prg\n171 (0801-0E89).prg\n<\/pre>\n<p>The checksum test passed, but the payload for the file with header 118 (&#8220;a_S_S_E_M_B_L_E&#8221;) is missing. In this case, it&#8217;s clear, but if two entries in sequence had been missing, it would have been tricky to detect this.<\/p>\n<h2>Comparing Multiple Copies<\/h2>\n<p>With just a single copy, we cannot really know whether the data is correct. Checksums are not reliable enough, and it&#8217;s hard to detect if a file was just not recognized. If we have two copies of the tape and they read the same, we can be <i>very<\/i> confident that the dumps are correct. tapclean&#8217;s &#8220;magic CRC32&#8221; that it prints after analyzing a tape is a strong checksum of all recognized data concatenated. So if two dumped copies have the same CRC32, we can assume that the dumps were correct.<\/p>\n<p>It is quite unlikely that two dumps have the same file(s) missing, and it&#8217;s extremely unlikely that they had the same bit flips. Well, that is, if we assume that the tapes did not have mastering errors (or weaknesses), but also verifying the checksums and visual inspection of the contents should rule this out.<\/p>\n<p>The following bash script shows the CRC32 values (e.g. &#8220;3D3C8936&#8221;), the number of correctly checksummed files and the number of total files (e.g. 30-31) for each tape:<\/p>\n<pre>\nfor i in `find . -name \\*.tap`; do\n  echo $i\n  (tapclean -t $i > $i.log)&amp;\ndone\nfor i in `find . -name \\*.log`; do\n  issue=$(basename $i | cut -c 1-4)\n  numfiles=$(cat $i | grep \"^Checksum test\" | cut -d \"[\" -f 2 | cut -d \" \" -f 1-3 | sed -e \"s\/ of \/-\/\")\n  crc32=$(cat $i | grep \"^Magic CRC32\" | cut -d \":\" -f 2)\n  echo $issue $crc32 $numfiles $(echo $i | sed -e \"s\/.log$\/\/\")\ndone\n<\/pre>\n<p>Here&#8217;s example output:<\/p>\n<pre>\n8708 00000000 0-0   .\/8708a2.tap\n8708 16979EE4 32-32 .\/8708b2.tap\n8708 16979EE4 32-32 .\/8708b.tap\n8708 3D3C8936 30-31 .\/8708a.tap\n<\/pre>\n<p>8708b.tap and 8708b2.tap (the back sides of two different copies) are correct dumps: They have the same CRC32, they have all correct checksums, and the number of recognized items is even (header, data, header, data, &#8230;).<\/p>\n<h2>More Copies<\/h2>\n<p>Using this strategy, I was able to confirm correct dumps of 18 of the 32 tapes. 14 more to go.<\/p>\n<p>The obvious way is to buy more copies on eBay until I have two that produce the same data. But luckily, there was another source: The <a href=\"https:\/\/archive.org\/details\/tosec-20161111-commodore-c64\">C64 TOSEC Collection<\/a> contains dumps of 20 of the tapes. Their time stamp says 1996, which is when then tapes were 10 years old instead of 30, so they should have been in much better shape. By looking at the checkums and the contents, we can get an idea of whether they are likely correct dumps. This is what the script from before says:<\/p>\n<pre>\n8508 8F9A4357 34-34 .\/tosec\/8508.tap\n8511 F75CC32E 34-34 .\/tosec\/8511.tap\n8605 200E286D 30-30 .\/tosec\/8605.tap\n8510 D0534C58 34-34 .\/tosec\/8510.tap\n8509 74B093F1 32-32 .\/tosec\/8509.tap\n8606 DA4AF054 29-29 .\/tosec\/8606.tap\n8502 8BDAF783 40-40 .\/tosec\/8502.tap\n8512 764F2F59 31-31 .\/tosec\/8512.tap\n8705 A103816A 30-30 .\/tosec\/8705.tap\n8704 E84CC753 30-30 .\/tosec\/8704.tap\n8602 B4F9D173 32-32 .\/tosec\/8602.tap\n8612 547A7371 32-32 .\/tosec\/8612.tap\n8506 78BC0D59 35-35 .\/tosec\/8506.tap\n8603 E70B3E72 30-30 .\/tosec\/8603.tap\n8507 22A807D1 32-32 .\/tosec\/8507.tap\n8608 F9BD6BC9 34-34 .\/tosec\/8608.tap\n8505 9C7FC3F2 35-35 .\/tosec\/8505.tap\n8601 3F749A69 30-30 .\/tosec\/8601.tap\n8611 48C4C35F 28-28 .\/tosec\/8611.tap\n8703 C6757D2F 29-30 .\/tosec\/8703.tap\n<\/pre>\n<p>At least 8703 has an incorrect checksum. Several tapes have an odd number of recognized items, but sometimes, tapclean doesn&#8217;t seem to count correctly, so extracting all items (&#8220;-doprg&#8221;) and counting them makes sure what the right number is.<\/p>\n<p>If we add these 20 copies to our collection and run the script again, we will be able to verify several more correct dumps.<\/p>\n<pre>\n8502 B76D97FE 35-39 .\/1\/8502a.tap\n8502 8BDAF783 40-40 .\/1\/8502b.tap\n8502 00000000 0-0   .\/3\/8502a.tap\n8502 11D3CFC5 10-20 .\/3\/8502b.tap\n8502 A7A10C6E 0-3   .\/4\/8502a.tap\n8502 FC899939 0-0   .\/4\/8502b.tap\n8502 8BDAF783 40-40 .\/tosec\/8502.tap\n<\/pre>\n<p>In this example, 1\/8502b.tap and tosec\/8502.tap contain the same data, so this verifies that these dumps are correct. Overall, this allowed me to verify the correctness of dumps of 8502, 8505, 8506, 8508, 8611, 8612 and 8705. Seven down, seven more to go!<\/p>\n<h2>Splice Verify<\/h2>\n<p>There are many issues where one dump looks okay, but we do not have an identical one to verify it. But it is not strictly necessary to have another identical dump. If we are certain that no files are missing, and that for every file, there is another dump with the identical file, we can be very certain that the dump is correct. I call this &#8220;splice verify&#8221;.<\/p>\n<p>Let&#8217;s look at 8706:<\/p>\n<pre>\n8706 E6E7FCDA 28-28 .\/1\/8706a.tap\n8706 8F259FA2 9-18  .\/1\/8706b.tap\n8706 3BDC28F3 23-28 .\/2\/8706a.tap\n8706 1B471853 8-17  .\/2\/8706b.tap\n<\/pre>\n<p>1\/8706a.tap is a candidate for a correct dump. We can test whether there are identical copies of each item on the tape on other copies by hashing all items on the candidate and looking for them on the other copies. The following script will extract all tapes into subdirectories of &#8220;dir&#8221;:<\/p>\n<pre>\nrm -rf dir\nmkdir dir\nfor i in `find . -name \\*.tap | cut -c 3-`; do\n(\n  (\n    cd $(dirname $i)\n    rm -rf $(basename $i)-$(dirname $i).dir\n    mkdir $(basename $i)-$(dirname $i).dir\n    cd $(basename $i)-$(dirname $i).dir\n    tapclean -t ..\/$(basename $i) -doprg\n    mv prg\/* .\n    rmdir prg\n    cd ..\n    mv $(basename $i)-$(dirname $i).dir ..\/dir\/\n  ) &amp;\n)\ndone\n<\/pre>\n<p>Then the following script will search for extra copies of every item on the candidate tape:<\/p>\n<pre>\ncd dir\nfor md5 in $(md5 -q 8706a.tap-1.dir\/???\\ *); do\n  echo\n  echo $md5\n  md5 -r *\/* | grep $md5\ndone\n<\/pre>\n<p>And this script makes sure that every correctly read file on the other tapes also exists on the candidate:<\/p>\n<pre>\nfor md5 in $(md5 -r *\/???\\ * | grep -v 8706a.tap-1.dir | grep -v BAD.prg$ | cut -d \" \" -f 1 | sort | uniq); do\n  echo\n  echo $md5\n  md5 -r 8706a.tap-1.dir\/* | grep $md5\ndone\n<\/pre>\n<p>Using this method, it is possible to verify 8503, 8507, 8510, 8701 and 8706. Only two more tapes need to be verified!<\/p>\n<h2>Splicing<\/h2>\n<p>We could keep buying more copies of 8504 and 8707 on eBay, but they don&#8217;t actually appear all that often. So let&#8217;s look at how bad our dumps are. Let&#8217;s take 8504:<\/p>\n<pre>\n12C4A3EA 30-30 .\/8504a-1.tap\n7C6D8541 34-35 .\/8504b-1.tap\n1337D0C8 20-25 .\/8504a-2.tap\n868DA7B6 38-38 .\/8504b-2.tap\nB80FD685 29-30 .\/8504a-3.tap\n8948C0B7 33-34 .\/8504b-3.tap\nC909C30F 26-27 .\/8504a-4.tap\nE3F7B698 8-24  .\/8504b-4.tap\n<\/pre>\n<p>None of the dumps seems correct. 8504b-2.tap is the best, but the file count as printed by tapclean is wrong, and there is actually an item missing: The payload of &#8220;h_i_r_e_s_s_p_e&#8221;.<\/p>\n<pre>\n012 (033C-03FB) [INPUT_64].prg\n013 (033C-03FB) [INPUT_64].prg\n019 (0300-0303).prg\n020 (0300-0303).prg\n025 (033C-03FB) [GUTEN_TAG].prg\n026 (033C-03FB) [GUTEN_TAG].prg\n031 (0801-0C96).prg\n032 (0801-0C96).prg\n039 (033C-0354) [TEXTE].prg\n046 (3000-3B76).prg\n053 (033C-0354) [RAHMEN_______COM].prg\n059 (C440-CF78).prg\n066 (033C-0354) [TITELBILD].prg\n073 (0A00-0AFF).prg\n<b>080 (033C-0354) [h_i_r_e_s_s_p_e].prg<\/b>\n093 (033C-0354) [k_a_l_e_n_d_e_r].prg\n100 (0801-38A2).prg\n106 (033C-0354) [r_e_v_e_r_s_i].prg\n112 (0801-267D).prg\n119 (033C-0354) [s_h_o_r_t_____s].prg\n125 (0801-2075).prg\n131 (033C-0354) [k_o_n_t_a_k_t_e].prg\n137 (0801-57D4).prg\n144 (033C-0354) [bits___bytes_im].prg\n152 (0801-6A70).prg\n159 (033C-0354) [einkommensteuert].prg\n166 (0801-28CB).prg\n172 (033C-0354) [h_i_l_f_s_p_r_o].prg\n179 (0801-1BEC).prg\n185 (033C-0354) [n_e_w_s].prg\n191 (0801-2873).prg\n198 (033C-0354) [6_4_E_R_____t_i].prg\n205 (0801-4D89).prg\n211 (033C-0354) [a_r_t_e_m___s].prg\n217 (0801-2E30).prg\n223 (033C-0354) [s_u_p_e_r_t_a_p].prg\n230 (0801-1A4A).prg\n236 (033C-0354) [l_a_s_t__n_o_t].prg\n243 (0801-2106).prg\n<\/pre>\n<p>If it weren&#8217;t for the missing data, we could splice-verify this dump. Using the scripts from earlier, we can show that all files can be found on other copies, and all correct files from other copies are on this dump &#8211; except for the &#8220;h_i_r_e_s_s_p_e&#8221; payload.<\/p>\n<p>Then why not splice in the correct object from a correct dump? 8504b-1.tap is one of the dumps that contains a correct copy. tapclean&#8217;s tcreport.txt file for the tape with the correct data shows us some information about the &#8220;h_i_r_e_s_s_p_e&#8221; payload:<\/p>\n<pre>\n---------------------------------\nSeq. no.: 113\nFile Type: SUPERTAPE DATA\nLocation: $3DFA2 -> $3E13B -> $4E25E -> $4E269\nLA: $0801  EA: $3000  SZ: 10239\nPilot\/Trailer Size: 62\/0\nCheckbyte Actual\/Expected: $7DA9\/$7DA9, PASS\nRead Errors: 0\nUnoptimized Pulses: 12338\nCRC32: CBF1C874\n<\/pre>\n<p>It is located between offsets $3DFA2 and $4E269 inside the file. Here&#8217;s the part from the hexdump:<\/p>\n<pre>\n$ hexdump 8504a-1.tap\n0003df70  21 43 21 21 21 21 21 21  1e 21 21 21 43 fb 00 6c\n0003df80  09 00 00 0b 19 00 00 ff  47 00 00 e5 2b 00 00 d9\n0003df90  12 00 00 fe 3d 04 32 32  32 21 1e 21 37 32 2f 21\n0003dfa0  21 21 21 43 1e 32 21 21  1e 32 32 2f 21 21 21 21\n0003dfb0  40 21 32 1e 21 21 32 32  32 21 1e 21 21 43 21 32\n<\/pre>\n<p>Every byte in a TAP file (after the 20 byte header) represents the length of a pulse in units of about 8 microseconds. Zero is an escape code, after which a three byte little endian value follows which specifies pulse lengths above 255. So the zeroes here just before what tapclean identified as the beginning of the payload are areas of silence on the tape. Grouped correctly, these are the 6 very long pulses, which represent a pause of about half a second:<\/p>\n<pre>\n00 6c 09 00\n00 0b 19 00\n00 ff 47 00\n00 e5 2b 00\n00 d9 12 00\n00 fe 3d 04\n<\/pre>\n<p>Just after this is where we want to cut.<\/p>\n<p>The cutting position of the end can be found similarly, and by looking at the tcreport.txt of the tape with the broken file, we can find out what part to cut and replace with the good version.<\/p>\n<p>At the end, we need to make sure the number of data bytes in the TAP file&#8217;s header at offset 16 (32 bit little endian) is correct.<\/p>\n<p>By doing this, we can create correct versions of the two remaining issues, so now we have a verified correct dump of each of the 32 issues!<\/p>\n<h2>The Moral of the Story<\/h2>\n<p>Read your tapes early. If you have any tapes, read them now! It doesn&#8217;t matter if they have been dumped before: These dumps might be incorrect, because they might not have not been verified with a second copy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s pretty simple to archive Commodore 64 tapes, but it&#8217;s hard if you want to do it right. Creating the complete archive of the German &#8220;INPUT 64&#8221; magazine was not as easy as getting one copy of each of the 32 tapes and reading them. The tapes are over 30 years old by now, and &#8230; <a title=\"Archiving C64 Tapes Correctly\" class=\"read-more\" href=\"https:\/\/www.pagetable.com\/?p=1002\" aria-label=\"Read more about Archiving C64 Tapes Correctly\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,41,8,29],"tags":[],"class_list":["post-1002","post","type-post","status-publish","format-standard","hentry","category-archeology","category-c64","category-commodore","category-tapes"],"_links":{"self":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/1002","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1002"}],"version-history":[{"count":0,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/1002\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1002"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1002"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1002"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}