stella/src/emucore/KidVid.cxx

514 lines
13 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include <cstdlib>
#include "KidVid.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KidVid::KidVid(Jack jack, const Event& event, const System& system,
const string& rommd5)
: Controller(jack, event, system, Controller::KidVid),
myEnabled(myJack == Right),
mySampleFile(nullptr),
mySharedSampleFile(nullptr),
myFileOpened(false),
myTapeBusy(false),
myFilePointer(0),
mySongCounter(0),
myBeep(false),
mySharedData(false),
mySampleByte(0),
myGame(0),
myTape(0),
myIdx(0),
myBlock(0),
myBlockIdx(0)
{
// Right now, there are only two games that use the KidVid
if(rommd5 == "ee6665683ebdb539e89ba620981cb0f6")
myGame = KVBBEARS; // Berenstain Bears
else if(rommd5 == "a204cd4fb1944c86e800120706512a64")
myGame = KVSMURFS; // Smurfs Save the Day
else
myEnabled = false;
// Analog pins are never used by the KidVid controller
// (at least not in this implementation)
myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KidVid::~KidVid()
{
closeSampleFile();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::update()
{
if(!myEnabled)
return;
if(myEvent.get(Event::ConsoleReset))
{
myTape = 0; // rewind Kid Vid tape
closeSampleFile();
}
if(myEvent.get(Event::KeyboardZero1))
{
myTape = 2;
myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0;
myBlockIdx = KVBLOCKBITS;
myBlock = 0;
openSampleFile();
cerr << "myTape = " << myTape << endl;
}
else if(myEvent.get(Event::KeyboardZero2))
{
myTape = 3;
myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0;
myBlockIdx = KVBLOCKBITS;
myBlock = 0;
openSampleFile();
cerr << "myTape = " << myTape << endl;
}
else if(myEvent.get(Event::KeyboardZero3))
{
if(myGame == KVBBEARS) /* Berenstain Bears ? */
{
myTape = 4;
myIdx = KVBLOCKBITS;
cerr << "myTape = " << myTape << endl;
}
else /* no, Smurf Save The Day */
{
myTape = 1;
myIdx = 0;
cerr << "myTape = " << myTape << endl;
}
myBlockIdx = KVBLOCKBITS;
myBlock = 0;
openSampleFile();
}
// Convert separate pin states into a 'register'
uInt8 IOPortA = 0xf0;
if(myDigitalPinState[One]) IOPortA |= 0x01;
if(myDigitalPinState[Two]) IOPortA |= 0x02;
if(myDigitalPinState[Three]) IOPortA |= 0x04;
if(myDigitalPinState[Four]) IOPortA |= 0x08;
// Is the tape running?
if((myTape != 0) && ((IOPortA & 0x01) == 0x01) && !myTapeBusy)
{
IOPortA = (IOPortA & 0xf7) | (((ourKVData[myIdx >> 3] << (myIdx & 0x07)) & 0x80) >> 4);
// increase to next bit
myIdx++;
myBlockIdx--;
// increase to next block (byte)
if(myBlockIdx == 0)
{
if(myBlock == 0)
myIdx = ((myTape * 6) + 12 - KVBLOCKS) * 8; //KVData00-KVData=12
else
{
if(myGame == KVSMURFS)
{
if(myBlock >= ourKVBlocks[myTape - 1])
myIdx = 42 * 8; //KVData80-KVData=42
else
{
myIdx = 36 * 8;//KVPause-KVData=36
setNextSong();
}
}
else
{
if(myBlock >= ourKVBlocks[myTape + 2 - 1])
myIdx = 42 * 8; //KVData80-KVData=42
else
{
myIdx = 36 * 8;//KVPause-KVData=36
setNextSong();
}
}
}
myBlock++;
myBlockIdx = KVBLOCKBITS;
}
}
// Now convert the register back into separate boolean values
myDigitalPinState[One] = IOPortA & 0x01;
myDigitalPinState[Two] = IOPortA & 0x02;
myDigitalPinState[Three] = IOPortA & 0x04;
myDigitalPinState[Four] = IOPortA & 0x08;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::openSampleFile()
{
static const char* kvNameTable[6] = {
"kvs3.wav", "kvs1.wav", "kvs2.wav", "kvb3.wav", "kvb1.wav", "kvb2.wav"
};
static uInt32 StartSong[6] = {
44+38, 0, 44, 44+38+42+62+80, 44+38+42, 44+38+42+62
};
if(!myEnabled)
return;
if(!myFileOpened)
{
int i = myGame == KVSMURFS ? 0 : 3;
i += myTape - 1;
if(myTape == 4) i -= 3;
mySampleFile = fopen(kvNameTable[i], "rb");
if(mySampleFile != NULL)
{
cerr << "opened file: " << kvNameTable[i] << endl;
mySharedSampleFile = fopen("kvshared.wav", "rb");
if(mySharedSampleFile == NULL)
{
fclose(mySampleFile);
myFileOpened = false;
}
else
{
cerr << "opened file: " << "kvshared.wav" << endl;
// fseek(mySampleFile, 45, SEEK_SET);
myFileOpened = true;
}
}
else
myFileOpened = false;
mySongCounter = 0;
myTapeBusy = false;
myFilePointer = StartSong[i];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::closeSampleFile()
{
if(myFileOpened)
{
fclose(mySampleFile);
fclose(mySharedSampleFile);
myFileOpened = false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::setNextSong()
{
if(myFileOpened)
{
myBeep = (ourSongPositions[myFilePointer] & 0x80) ? false : true;
uInt8 temp = ourSongPositions[myFilePointer] & 0x7f;
mySharedData = (temp < 10);
mySongCounter = ourSongStart[temp+1] - ourSongStart[temp];
#if 0
if(mySharedData)
; // fseek(mySharedSampleFile, ourSongStart[temp], SEEK_SET);
else
; // fseek(mySampleFile, ourSongStart[temp], SEEK_SET);
#endif
myFilePointer++;
myTapeBusy = true;
}
else
{
myBeep = true;
myTapeBusy = true;
mySongCounter = 80*262; /* delay needed for Harmony without tape */
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KidVid::getNextSampleByte()
{
// static int oddeven = 0;
if(mySongCounter == 0)
mySampleByte = 0x80;
#if 0
else
{
oddeven = oddeven^1;
if(oddeven & 1)
{
mySongCounter--;
myTapeBusy = (mySongCounter > 262*48) || !myBeep;
if(myFileOpened)
{
if(mySharedData)
mySampleByte = getc(mySharedSampleFile);
else
mySampleByte = getc(mySampleFile);
}
else
mySampleByte = 0x80;
if(!myBeep && (mySongCounter == 0))
setNextSong();
}
}
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8 KidVid::ourKVBlocks[6] = {
2+40, 2+21, 2+35, /* Smurfs tapes 3, 1, 2 */
42+60, 42+78, 42+60 /* BBears tapes 1, 2, 3 (40 extra blocks for intro) */
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8 KidVid::ourKVData[6*8] = {
/* KVData44 */
0x7b, // 0111 1011b ; (1)0
0x1e, // 0001 1110b ; 1
0xc6, // 1100 0110b ; 00
0x31, // 0011 0001b ; 01
0xec, // 1110 1100b ; 0
0x60, // 0110 0000b ; 0+
/* KVData48 */
0x7b, // 0111 1011b ; (1)0
0x1e, // 0001 1110b ; 1
0xc6, // 1100 0110b ; 00
0x3d, // 0011 1101b ; 10
0x8c, // 1000 1100b ; 0
0x60, // 0110 0000b ; 0+
/* KVData00 */
0xf6, // 1111 0110b
0x31, // 0011 0001b
0x8c, // 1000 1100b
0x63, // 0110 0011b
0x18, // 0001 1000b
0xc0, // 1100 0000b
/* KVData01 */
0xf6, // 1111 0110b
0x31, // 0011 0001b
0x8c, // 1000 1100b
0x63, // 0110 0011b
0x18, // 0001 1000b
0xf0, // 1111 0000b
/* KVData02 */
0xf6, // 1111 0110b
0x31, // 0011 0001b
0x8c, // 1000 1100b
0x63, // 0110 0011b
0x1e, // 0001 1110b
0xc0, // 1100 0000b
/* KVData03 */
0xf6, // 1111 0110b
0x31, // 0011 0001b
0x8c, // 1000 1100b
0x63, // 0110 0011b
0x1e, // 0001 1110b
0xf0, // 1111 0000b
/* KVPause */
0x3f, // 0011 1111b
0xf0, // 1111 0000b
0x00, // 0000 0000b
0x00, // 0000 0000b
0x00, // 0000 0000b
0x00, // 0000 0000b
/* KVData80 */
0xf7, // 1111 0111b ; marks end of tape (green/yellow screen)
0xb1, // 1011 0001b
0x8c, // 1000 1100b
0x63, // 0110 0011b
0x18, // 0001 1000b
0xc0 // 1100 0000b
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8 KidVid::ourSongPositions[44+38+42+62+80+62] = {
/* kvs1 44 */
11, 12+0x80, 13+0x80, 14, 15+0x80, 16, 8+0x80, 17, 18+0x80, 19, 20+0x80,
21, 8+0x80, 22, 15+0x80, 23, 18+0x80, 14, 20+0x80, 16, 18+0x80,
17, 15+0x80, 19, 8+0x80, 21, 20+0x80, 22, 18+0x80, 23, 15+0x80,
14, 20+0x80, 16, 8+0x80, 22, 15+0x80, 23, 18+0x80, 14, 20+0x80,
16, 8+0x80, 9,
/* kvs2 38 */
25+0x80, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29,
30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29,
30+0x80, 9,
/* kvs3 42 */
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 34, 42, 36, 43, 40, 39, 38, 37,
34, 43, 36, 39, 40, 37, 38, 43, 34, 37, 36, 43, 40, 39, 38, 37, 34, 43,
36, 39, 40, 37, 38+0x80, 9,
/* kvb1 62 */
0, 1, 45, 2, 3, 46, 4, 5, 47, 6, 7, 48, 4, 3, 49, 2, 1, 50, 6, 7, 51,
4, 5, 52, 6, 1, 53, 2, 7, 54, 6, 5, 45, 2, 1, 46, 4, 3, 47, 2, 5, 48,
4, 7, 49, 6, 1, 50, 2, 5, 51, 6, 3, 52, 4, 7, 53, 2, 1, 54, 6+0x80, 9,
/* kvb2 80 */
0, 1, 56, 4, 3, 57, 2, 5, 58, 6, 7, 59, 2, 3, 60, 4, 1, 61, 6, 7, 62,
2, 5, 63, 6, 1, 64, 4, 7, 65, 6, 5, 66, 4, 1, 67, 2, 3, 68, 6, 5, 69,
2, 7, 70, 4, 1, 71, 2, 5, 72, 4, 3, 73, 6, 7, 74, 2, 1, 75, 6, 3, 76,
4, 5, 77, 6, 7, 78, 2, 3, 79, 4, 1, 80, 2, 7, 81, 4+0x80, 9,
/* kvb3 62 */
0, 1, 83, 2, 3, 84, 4, 5, 85, 6, 7, 86, 4, 3, 87, 2, 1, 88, 6, 7, 89,
2, 5, 90, 6, 1, 91, 4, 7, 92, 6, 5, 93, 4, 1, 94, 2, 3, 95, 6, 5, 96,
2, 7, 97, 4, 1, 98, 6, 5, 99, 4, 3, 100, 2, 7, 101, 4, 1, 102, 2+0x80, 9
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt32 KidVid::ourSongStart[104] = {
/* kvshared */
44, /* Welcome + intro Berenstain Bears */
980829, /* boulders in the road */
1178398, /* standing ovations */
1430063, /* brother bear */
1691136, /* good work */
1841665, /* crossing a bridge */
2100386, /* not bad (applause) */
2283843, /* ourgame */
2629588, /* start the parade */
2824805, /* rewind */
3059116,
/* kvs1 */
44, /* Harmony into 1 */
164685, /* falling notes (into 2) */
395182, /* instructions */
750335, /* high notes are high */
962016, /* my hat's off to you */
1204273, /* 1 2 3 do re mi */
1538258, /* Harmony */
1801683, /* concratulations (all of the Smurfs voted) */
2086276, /* line or space */
2399093, /* hooray */
2589606, /* hear yeeh */
2801287, /* over the river */
3111752, /* musical deduction */
3436329,
/* kvs2 */
44, /* Handy intro + instructions */
778557, /* place in shape */
1100782, /* sailor mate + whistle */
// 1281887,
1293648, /* attention */
1493569, /* colours */
1801682, /* congratulations (Handy and friends voted) */
2086275,
/* kvs3 */
44, /* Greedy and Clumsy intro + instructions */
686829, /* red */
893806, /* don't count your chicken */
1143119, /* yellow */
1385376, /* thank you */
1578241, /* mixin' and matchin' */
1942802, /* fun / colour shake */
2168595, /* colours can be usefull */
2493172, /* hip hip horay */
2662517, /* green */
3022374, /* purple */
3229351, /* white */
3720920,
/* kvb1 */
44, /* 3 */
592749, /* 5 */
936142, /* 2 */
1465343, /* 4 */
1787568, /* 1 */
2145073, /* 7 */
2568434, /* 9 */
2822451, /* 8 */
3045892, /* 6 */
3709157, /* 0 */
4219542,
/* kvb2 */
44, /* A */
303453, /* B */
703294, /* C */
1150175, /* D */
1514736, /* E */
2208577, /* F */
2511986, /* G */
2864787, /* H */
3306964, /* I */
3864389, /* J */
4148982, /* K */
4499431, /* L */
4824008, /* M */
5162697, /* N */
5581354, /* O */
5844779, /* P */
6162300, /* Q */
6590365, /* R */
6839678, /* S */
7225407, /* T */
7552336, /* U */
7867505, /* V */
8316738, /* W */
8608387, /* X */
8940020, /* Y */
9274005, /* Z */
9593878,
/* kvb3 */
44, /* cat */
341085, /* one */
653902, /* red */
1018463, /* two */
1265424, /* dog */
1669969, /* six */
1919282, /* hat */
2227395, /* ten */
2535508, /* mom */
3057653, /* dad */
3375174, /* ball */
3704455, /* fish */
4092536, /* nine */
4487673, /* bear */
5026282, /* four */
5416715, /* bird */
5670732, /* tree */
6225805, /* rock */
6736190, /* book */
7110159, /* road */
7676992
};