1 //============================================================================
2 //
3 //   SSSS    tt          lll  lll
4 //  SS  SS   tt           ll   ll
5 //  SS     tttttt  eeee   ll   ll   aaaa
6 //   SSSS    tt   ee  ee  ll   ll      aa
7 //      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
8 //  SS  SS   tt   ee      ll   ll  aa  aa
9 //   SSSS     ttt  eeeee llll llll  aaaaa
10 //
11 // Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
12 // and the Stella Team
13 //
14 // See the file "License.txt" for information on usage and redistribution of
15 // this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 //============================================================================
17 
18 #include <cstdlib>
19 
20 #include "Event.hxx"
21 #include "KidVid.hxx"
22 
23 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KidVid(Jack jack,const Event & event,const System & system,const string & romMd5)24 KidVid::KidVid(Jack jack, const Event& event, const System& system,
25                const string& romMd5)
26   : Controller(jack, event, system, Controller::Type::KidVid),
27     myEnabled{myJack == Jack::Right}
28 {
29   // Right now, there are only two games that use the KidVid
30   if(romMd5 == "ee6665683ebdb539e89ba620981cb0f6")
31     myGame = KVBBEARS;    // Berenstain Bears
32   else if(romMd5 == "a204cd4fb1944c86e800120706512a64")
33     myGame = KVSMURFS;    // Smurfs Save the Day
34   else
35     myEnabled = false;
36 }
37 
38 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
~KidVid()39 KidVid::~KidVid()
40 {
41   closeSampleFile();
42 }
43 
44 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
update()45 void KidVid::update()
46 {
47   if(!myEnabled)
48     return;
49 
50   if(myEvent.get(Event::ConsoleReset))
51   {
52     myTape = 0; // rewind Kid Vid tape
53     closeSampleFile();
54   }
55   if(myEvent.get(Event::RightKeyboard1))
56   {
57     myTape = 2;
58     myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0;
59     myBlockIdx = KVBLOCKBITS;
60     myBlock = 0;
61     openSampleFile();
62 //cerr << "myTape = " << myTape << endl;
63   }
64   else if(myEvent.get(Event::RightKeyboard2))
65   {
66     myTape = 3;
67     myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0;
68     myBlockIdx = KVBLOCKBITS;
69     myBlock = 0;
70     openSampleFile();
71 //cerr << "myTape = " << myTape << endl;
72   }
73   else if(myEvent.get(Event::RightKeyboard3))
74   {
75     if(myGame == KVBBEARS)  /* Berenstain Bears ? */
76     {
77       myTape = 4;
78       myIdx = KVBLOCKBITS;
79 //cerr << "myTape = " << myTape << endl;
80     }
81     else                    /* no, Smurf Save The Day */
82     {
83       myTape = 1;
84       myIdx = 0;
85 //cerr << "myTape = " << myTape << endl;
86     }
87     myBlockIdx = KVBLOCKBITS;
88     myBlock = 0;
89     openSampleFile();
90   }
91 
92   // Convert separate pin states into a 'register'
93   uInt8 IOPortA = 0b11110000;
94   if(getPin(DigitalPin::One))   IOPortA |= 0b0001;
95   if(getPin(DigitalPin::Two))   IOPortA |= 0b0010;
96   if(getPin(DigitalPin::Three)) IOPortA |= 0b0100;
97   if(getPin(DigitalPin::Four))  IOPortA |= 0b1000;
98 
99   // Is the tape running?
100   if((myTape != 0) && ((IOPortA & 0b0001) == 0b0001) && !myTapeBusy)
101   {
102     IOPortA = (IOPortA & 0b11110111) | (((ourKVData[myIdx >> 3] << (myIdx & 0x07)) & 0x80) >> 4);
103 
104     // increase to next bit
105     ++myIdx;
106     --myBlockIdx;
107 
108     // increase to next block (byte)
109     if(myBlockIdx == 0)
110     {
111       if(myBlock == 0)
112         myIdx = ((myTape * 6) + 12 - KVBLOCKS) * 8; //KVData00-KVData=12
113       else
114       {
115         if(myGame == KVSMURFS)
116         {
117           if(myBlock >= ourKVBlocks[myTape - 1])
118             myIdx = 42 * 8; //KVData80-KVData=42
119           else
120           {
121             myIdx = 36 * 8;//KVPause-KVData=36
122             setNextSong();
123           }
124         }
125         else
126         {
127           if(myBlock >= ourKVBlocks[myTape + 2 - 1])
128             myIdx = 42 * 8; //KVData80-KVData=42
129           else
130           {
131             myIdx = 36 * 8;//KVPause-KVData=36
132             setNextSong();
133           }
134         }
135       }
136       ++myBlock;
137       myBlockIdx = KVBLOCKBITS;
138     }
139   }
140 
141   // Now convert the register back into separate boolean values
142   setPin(DigitalPin::One,   IOPortA & 0b0001);
143   setPin(DigitalPin::Two,   IOPortA & 0b0010);
144   setPin(DigitalPin::Three, IOPortA & 0b0100);
145   setPin(DigitalPin::Four,  IOPortA & 0b1000);
146 }
147 
148 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
openSampleFile()149 void KidVid::openSampleFile()
150 {
151 #if 0
152   static const char* const kvNameTable[6] = {
153     "kvs3.wav", "kvs1.wav", "kvs2.wav", "kvb3.wav", "kvb1.wav", "kvb2.wav"
154   };
155   static uInt32 StartSong[6] = {
156     44+38, 0, 44, 44+38+42+62+80, 44+38+42, 44+38+42+62
157   };
158 
159   if(!myEnabled)
160     return;
161 
162   if(!myFileOpened)
163   {
164     int i = myGame == KVSMURFS ? 0 : 3;
165     i += myTape - 1;
166     if(myTape == 4) i -= 3;
167 
168     mySampleFile = fopen(kvNameTable[i], "rb");
169     if(mySampleFile != nullptr)
170     {
171 cerr << "opened file: " << kvNameTable[i] << endl;
172       mySharedSampleFile = fopen("kvshared.wav", "rb");
173       if(mySharedSampleFile == nullptr)
174       {
175         fclose(mySampleFile);
176         myFileOpened = false;
177       }
178       else
179       {
180 cerr << "opened file: " << "kvshared.wav" << endl;
181 //         fseek(mySampleFile, 45, SEEK_SET);
182         myFileOpened = true;
183       }
184     }
185     else
186       myFileOpened = false;
187 
188     mySongCounter = 0;
189     myTapeBusy = false;
190     myFilePointer = StartSong[i];
191   }
192 #endif
193 }
194 
195 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
closeSampleFile()196 void KidVid::closeSampleFile()
197 {
198 #if 0
199   if(myFileOpened)
200   {
201     fclose(mySampleFile);
202     fclose(mySharedSampleFile);
203     myFileOpened = false;
204   }
205 #endif
206 }
207 
208 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setNextSong()209 void KidVid::setNextSong()
210 {
211   if(myFileOpened)
212   {
213     myBeep = (ourSongPositions[myFilePointer] & 0x80) ? false : true;
214 
215     uInt8 temp = ourSongPositions[myFilePointer] & 0x7f;
216     mySharedData = (temp < 10);
217     mySongCounter = ourSongStart[temp+1] - ourSongStart[temp];
218 
219 #if 0
220     if(mySharedData)
221       ; // fseek(mySharedSampleFile, ourSongStart[temp], SEEK_SET);
222     else
223       ; // fseek(mySampleFile, ourSongStart[temp], SEEK_SET);
224 #endif
225 
226     ++myFilePointer;
227     myTapeBusy = true;
228   }
229   else
230   {
231     myBeep = true;
232     myTapeBusy = true;
233     mySongCounter = 80*262;   /* delay needed for Harmony without tape */
234   }
235 }
236 
237 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
getNextSampleByte()238 void KidVid::getNextSampleByte()
239 {
240 //  static int oddeven = 0;
241   if(mySongCounter == 0)
242     mySampleByte = 0x80;
243 #if 0
244   else
245   {
246     oddeven = oddeven^1;
247     if(oddeven & 1)
248     {
249       mySongCounter--;
250       myTapeBusy = (mySongCounter > 262*48) || !myBeep;
251 
252       if(myFileOpened)
253       {
254         if(mySharedData)
255           mySampleByte = getc(mySharedSampleFile);
256         else
257           mySampleByte = getc(mySampleFile);
258       }
259       else
260         mySampleByte = 0x80;
261 
262       if(!myBeep && (mySongCounter == 0))
263         setNextSong();
264     }
265   }
266 #endif
267 }
268 
269 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
270 const std::array<uInt8, KidVid::KVBLOCKS> KidVid::ourKVBlocks = {
271   2+40, 2+21, 2+35,     /* Smurfs tapes 3, 1, 2 */
272   42+60, 42+78, 42+60   /* BBears tapes 1, 2, 3 (40 extra blocks for intro) */
273 };
274 
275 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
276 const std::array<uInt8, KidVid::KVBLOCKBITS> KidVid::ourKVData = {
277 /* KVData44 */
278   0x7b,  // 0111 1011b  ; (1)0
279   0x1e,  // 0001 1110b  ; 1
280   0xc6,  // 1100 0110b  ; 00
281   0x31,  // 0011 0001b  ; 01
282   0xec,  // 1110 1100b  ; 0
283   0x60,  // 0110 0000b  ; 0+
284 
285 /* KVData48 */
286   0x7b,  // 0111 1011b  ; (1)0
287   0x1e,  // 0001 1110b  ; 1
288   0xc6,  // 1100 0110b  ; 00
289   0x3d,  // 0011 1101b  ; 10
290   0x8c,  // 1000 1100b  ; 0
291   0x60,  // 0110 0000b  ; 0+
292 
293 /* KVData00 */
294   0xf6,  // 1111 0110b
295   0x31,  // 0011 0001b
296   0x8c,  // 1000 1100b
297   0x63,  // 0110 0011b
298   0x18,  // 0001 1000b
299   0xc0,  // 1100 0000b
300 
301 /* KVData01 */
302   0xf6,  // 1111 0110b
303   0x31,  // 0011 0001b
304   0x8c,  // 1000 1100b
305   0x63,  // 0110 0011b
306   0x18,  // 0001 1000b
307   0xf0,  // 1111 0000b
308 
309 /* KVData02 */
310   0xf6,  // 1111 0110b
311   0x31,  // 0011 0001b
312   0x8c,  // 1000 1100b
313   0x63,  // 0110 0011b
314   0x1e,  // 0001 1110b
315   0xc0,  // 1100 0000b
316 
317 /* KVData03 */
318   0xf6,  // 1111 0110b
319   0x31,  // 0011 0001b
320   0x8c,  // 1000 1100b
321   0x63,  // 0110 0011b
322   0x1e,  // 0001 1110b
323   0xf0,  // 1111 0000b
324 
325 /* KVPause */
326   0x3f,  // 0011 1111b
327   0xf0,  // 1111 0000b
328   0x00,  // 0000 0000b
329   0x00,  // 0000 0000b
330   0x00,  // 0000 0000b
331   0x00,  // 0000 0000b
332 
333 /* KVData80 */
334   0xf7,  // 1111 0111b  ; marks end of tape (green/yellow screen)
335   0xb1,  // 1011 0001b
336   0x8c,  // 1000 1100b
337   0x63,  // 0110 0011b
338   0x18,  // 0001 1000b
339   0xc0   // 1100 0000b
340 };
341 
342 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
343 const std::array<uInt8, KidVid::SONG_POS_SIZE> KidVid::ourSongPositions = {
344 /* kvs1 44 */
345   11, 12+0x80, 13+0x80, 14, 15+0x80, 16, 8+0x80, 17, 18+0x80, 19, 20+0x80,
346   21, 8+0x80, 22, 15+0x80, 23, 18+0x80, 14, 20+0x80, 16, 18+0x80,
347   17, 15+0x80, 19, 8+0x80, 21, 20+0x80, 22, 18+0x80, 23, 15+0x80,
348   14, 20+0x80, 16, 8+0x80, 22, 15+0x80, 23, 18+0x80, 14, 20+0x80,
349   16, 8+0x80, 9,
350 
351 /* kvs2 38 */
352   25+0x80, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29,
353   30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29,
354   30+0x80, 9,
355 
356 /* kvs3 42 */
357   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 34, 42, 36, 43, 40, 39, 38, 37,
358   34, 43, 36, 39, 40, 37, 38, 43, 34, 37, 36, 43, 40, 39, 38, 37, 34, 43,
359   36, 39, 40, 37, 38+0x80, 9,
360 
361 /* kvb1 62 */
362   0, 1, 45, 2, 3, 46, 4, 5, 47, 6, 7, 48, 4, 3, 49, 2, 1, 50, 6, 7, 51,
363   4, 5, 52, 6, 1, 53, 2, 7, 54, 6, 5, 45, 2, 1, 46, 4, 3, 47, 2, 5, 48,
364   4, 7, 49, 6, 1, 50, 2, 5, 51, 6, 3, 52, 4, 7, 53, 2, 1, 54, 6+0x80, 9,
365 
366 /* kvb2 80 */
367   0, 1, 56, 4, 3, 57, 2, 5, 58, 6, 7, 59, 2, 3, 60, 4, 1, 61, 6, 7, 62,
368   2, 5, 63, 6, 1, 64, 4, 7, 65, 6, 5, 66, 4, 1, 67, 2, 3, 68, 6, 5, 69,
369   2, 7, 70, 4, 1, 71, 2, 5, 72, 4, 3, 73, 6, 7, 74, 2, 1, 75, 6, 3, 76,
370   4, 5, 77, 6, 7, 78, 2, 3, 79, 4, 1, 80, 2, 7, 81, 4+0x80, 9,
371 
372 /* kvb3 62 */
373   0, 1, 83, 2, 3, 84, 4, 5, 85, 6, 7, 86, 4, 3, 87, 2, 1, 88, 6, 7, 89,
374   2, 5, 90, 6, 1, 91, 4, 7, 92, 6, 5, 93, 4, 1, 94, 2, 3, 95, 6, 5, 96,
375   2, 7, 97, 4, 1, 98, 6, 5, 99, 4, 3, 100, 2, 7, 101, 4, 1, 102, 2+0x80, 9
376 };
377 
378 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
379 const std::array<uInt32, KidVid::SONG_START_SIZE> KidVid::ourSongStart = {
380 /* kvshared */
381   44,          /* Welcome + intro Berenstain Bears */
382   980829,      /* boulders in the road */
383   1178398,     /* standing ovations */
384   1430063,     /* brother bear */
385   1691136,     /* good work */
386   1841665,     /* crossing a bridge */
387   2100386,     /* not bad (applause) */
388   2283843,     /* ourgame */
389   2629588,     /* start the parade */
390   2824805,     /* rewind */
391   3059116,
392 
393 /* kvs1 */
394   44,          /* Harmony into 1 */
395   164685,      /* falling notes (into 2) */
396   395182,      /* instructions */
397   750335,      /* high notes are high */
398   962016,      /* my hat's off to you */
399   1204273,     /* 1 2 3 do re mi */
400   1538258,     /* Harmony */
401   1801683,     /* concratulations (all of the Smurfs voted) */
402   2086276,     /* line or space */
403   2399093,     /* hooray */
404   2589606,     /* hear yeeh */
405   2801287,     /* over the river */
406   3111752,     /* musical deduction */
407   3436329,
408 
409 /* kvs2 */
410   44,          /* Handy intro + instructions */
411   778557,      /* place in shape */
412   1100782,     /* sailor mate + whistle */
413 //  1281887,
414   1293648,     /* attention */
415   1493569,     /* colours */
416   1801682,     /* congratulations (Handy and friends voted) */
417   2086275,
418 
419 /* kvs3 */
420   44,          /* Greedy and Clumsy intro + instructions */
421   686829,      /* red */
422   893806,      /* don't count your chicken */
423   1143119,     /* yellow */
424   1385376,     /* thank you */
425   1578241,     /* mixin' and matchin' */
426   1942802,     /* fun / colour shake */
427   2168595,     /* colours can be usefull */
428   2493172,     /* hip hip horay */
429   2662517,     /* green */
430   3022374,     /* purple */
431   3229351,     /* white */
432   3720920,
433 
434 /* kvb1 */
435   44,          /* 3 */
436   592749,      /* 5 */
437   936142,      /* 2 */
438   1465343,     /* 4 */
439   1787568,     /* 1 */
440   2145073,     /* 7 */
441   2568434,     /* 9 */
442   2822451,     /* 8 */
443   3045892,     /* 6 */
444   3709157,     /* 0 */
445   4219542,
446 
447 /* kvb2 */
448   44,          /* A */
449   303453,      /* B */
450   703294,      /* C */
451   1150175,     /* D */
452   1514736,     /* E */
453   2208577,     /* F */
454   2511986,     /* G */
455   2864787,     /* H */
456   3306964,     /* I */
457   3864389,     /* J */
458   4148982,     /* K */
459   4499431,     /* L */
460   4824008,     /* M */
461   5162697,     /* N */
462   5581354,     /* O */
463   5844779,     /* P */
464   6162300,     /* Q */
465   6590365,     /* R */
466   6839678,     /* S */
467   7225407,     /* T */
468   7552336,     /* U */
469   7867505,     /* V */
470   8316738,     /* W */
471   8608387,     /* X */
472   8940020,     /* Y */
473   9274005,     /* Z */
474   9593878,
475 
476 /* kvb3 */
477   44,          /* cat */
478   341085,      /* one */
479   653902,      /* red */
480   1018463,     /* two */
481   1265424,     /* dog */
482   1669969,     /* six */
483   1919282,     /* hat */
484   2227395,     /* ten */
485   2535508,     /* mom */
486   3057653,     /* dad */
487   3375174,     /* ball */
488   3704455,     /* fish */
489   4092536,     /* nine */
490   4487673,     /* bear */
491   5026282,     /* four */
492   5416715,     /* bird */
493   5670732,     /* tree */
494   6225805,     /* rock */
495   6736190,     /* book */
496   7110159,     /* road */
497   7676992
498 };
499