1 //
2 // /home/ms/source/sidplay/libsidplay/RCS/player.cpp,v
3 //
4 
5 #include "player.h"
6 #include "myendian.h"
7 #include "6510_.h"
8 
9 extern ubyte playRamRom;  // MPU bank-switch setting for player call
10 
11 // These texts are used to override the sidtune settings.
12 static const char text_PAL_VBI[] = "50 Hz VBI (PAL)";
13 static const char text_PAL_CIA[] = "CIA 1 Timer A (PAL)";
14 static const char text_NTSC_VBI[] = "60 Hz VBI (NTSC)";
15 static const char text_NTSC_CIA[] = "CIA 1 Timer A (NTSC)";
16 
17 static const int FREQ_VBI_PAL = 50;   // Hz
18 static const int FREQ_VBI_NTSC = 60;  //
19 
20 // Table used to check sidtune for usage of PlaySID digis.
21 static const uword c64addrTable[] =
22 {
23 	// PlaySID extended SID registers (0xd49d left out).
24 	//0xd41d, 0xd41e, 0xd41f,  // SID is too often written to as 32 bytes!
25 	0xd43d, 0xd43e, 0xd43f,
26 	0xd45d, 0xd45e, 0xd45f, 0xd47d, 0xd47e, 0xd47f,
27 	//0xd51d, 0xd51e, 0xd51f,  // SID is too often written to as 32 bytes!
28 	0xd53d, 0xd53e, 0xd53f,
29 	0xd55d, 0xd55e, 0xd55f, 0xd57d, 0xd57e, 0xd57f
30 };
31 // Number of addresses in c64addrTable[].
32 static const int numberOfC64addr = sizeof(c64addrTable) / sizeof(uword);
33 static ubyte oldValues[numberOfC64addr];
34 
35 
sidEmuInitializeSong(emuEngine & thisEmuEngine,sidTune & thisTune,uword songNumber)36 bool sidEmuInitializeSong(emuEngine & thisEmuEngine,
37 						  sidTune & thisTune,
38 						  uword songNumber)
39 {
40 	// Do a regular song initialization.
41 	bool ret = sidEmuInitializeSongOld(thisEmuEngine,thisTune,songNumber);
42 	if (ret && (thisEmuEngine.config.digiPlayerScans!=0))
43 	{
44 		// Run the music player for a couple of player calls and check for
45 		// changes in the PlaySID extended SID registers. If no digis are
46 		// used, apply a higher amplification on each SID voice. First
47 		// check also covers writings of the player INIT routine. Old values
48         // are stored before song INIT.
49 		bool useDigis = false;
50 		int loops = thisEmuEngine.config.digiPlayerScans;
51 		while (loops)
52 		{
53 			for (int i = 0; i < numberOfC64addr; i++)
54 			{
55 				if (oldValues[i] != c64mem2[c64addrTable[i]])
56 				{
57 					useDigis = true;
58 					break;
59 				}
60 				oldValues[i] = c64mem2[c64addrTable[i]];
61 			}
62 			if (useDigis)
63 			{
64 				break;
65 			}
66 			uword replayPC = thisTune.getPlayAddr();
67 			// playRamRom was set by sidEmuInitializeSongOld(..).
68 			if ( replayPC == 0 )
69 			{
70 				playRamRom = c64mem1[1];
71 				if ((playRamRom & 2) != 0)  // isKernal?
72 				{
73 					replayPC = readLEword(c64mem1+0x0314);  // IRQ
74 				}
75 				else
76 				{
77 					replayPC = readLEword(c64mem1+0xfffe);  // NMI
78 				}
79 			}
80 			interpreter(replayPC,playRamRom,0,0,0);
81 			loops--;
82 		};
83 		thisEmuEngine.amplifyThreeVoiceTunes(!useDigis);
84 		// Here re-init song to start at beginning.
85 		ret = sidEmuInitializeSongOld(thisEmuEngine,thisTune,songNumber);
86 	}
87 	return ret;
88 }
89 
90 
sidEmuInitializeSongOld(emuEngine & thisEmuEngine,sidTune & thisTune,uword songNumber)91 bool sidEmuInitializeSongOld(emuEngine & thisEmuEngine,
92 							 sidTune & thisTune,
93 							 uword songNumber)
94 {
95 	if (!thisEmuEngine.isReady || !thisTune.status )
96 	{
97 		return false;
98 	}
99 	else
100 	{
101 		// ------------------------------------------- Determine clock/speed.
102 
103 		// Get speed/clock setting for song and preselect
104 		// speed/clock descriptions strings, reg = song init akkumulator.
105 		ubyte reg = thisTune.selectSong(songNumber) -1;
106 
107 		const char* the_description;
108 
109 		ubyte the_clock = thisTune.info.clockSpeed;
110         // Choose clock speed emu user prefers. If sidtune doesn't
111         // contain clock speed setting (=0), use emu setting.
112         if ( the_clock == SIDTUNE_CLOCK_ANY )
113             the_clock &= thisEmuEngine.config.clockSpeed;
114         else if ( !the_clock )
115             the_clock = thisEmuEngine.config.clockSpeed;
116 
117 		ubyte the_speed = thisTune.info.songSpeed;
118 
119 		if (thisEmuEngine.config.forceSongSpeed)
120 		{
121 			the_clock = thisEmuEngine.config.clockSpeed;
122 		}
123 
124 		// Select speed description string.
125 		if (the_clock == SIDTUNE_CLOCK_PAL)
126 		{
127 			if (the_speed == SIDTUNE_SPEED_VBI)
128 			{
129 				the_description = text_PAL_VBI;
130 			}
131 			else  //if (thisTune.info.songSpeed == SIDTUNE_SPEED_CIA_1A)
132 			{
133 				the_description = text_PAL_CIA;
134 			}
135 		}
136 		else  //if (the_clock == SIDTUNE_CLOCK_NTSC)
137 		{
138 			if (the_speed == SIDTUNE_SPEED_VBI)
139 			{
140 				the_description = text_NTSC_VBI;
141 			}
142 			else  //if (thisTune.info.songSpeed == SIDTUNE_SPEED_CIA_1A)
143 			{
144 				the_description = text_NTSC_CIA;
145 			}
146 		}
147 
148 		// Substitute correct VBI frequency.
149 		if ((the_clock==SIDTUNE_CLOCK_PAL) &&
150 			(the_speed==SIDTUNE_SPEED_VBI))
151 		{
152 			the_speed = FREQ_VBI_PAL;
153 		}
154 
155 		if ((the_clock==SIDTUNE_CLOCK_NTSC) &&
156 			(the_speed==SIDTUNE_SPEED_VBI))
157 		{
158 			the_speed = FREQ_VBI_NTSC;
159 		}
160 
161 		// Transfer the speed settings to the emulator engine.
162 		// From here on we don't touch the SID clock speed setting.
163         extern void sidEmuConfigureClock( int );
164         sidEmuConfigureClock( the_clock );
165 		extern void sidEmuSetReplayingSpeed(int clockMode, uword callsPerSec);  // --> 6581_.cpp
166 		sidEmuSetReplayingSpeed(the_clock,the_speed);
167 
168         // Make available chosen speed setting in userspace.
169         thisTune.info.clockSpeed = the_clock;
170         thisTune.info.songSpeed = the_speed;
171 		thisTune.info.speedString = the_description;
172 
173 		// ------------------------------------------------------------------
174 
175 		thisEmuEngine.MPUreset();
176 
177 		if ( !thisTune.placeSidTuneInC64mem(thisEmuEngine.MPUreturnRAMbase()) )
178 		{
179 			return false;
180 		}
181 
182 		if (thisTune.info.musPlayer)
183 		{
184 			thisTune.MUS_installPlayer(thisEmuEngine.MPUreturnRAMbase());
185 		}
186 
187 		thisEmuEngine.amplifyThreeVoiceTunes(false);  // assume digis are used
188 		if ( !thisEmuEngine.reset() )  // currently always returns true
189 		{
190 			return false;
191 		}
192 
193         if (thisEmuEngine.config.digiPlayerScans!=0)
194         {
195             // Save the SID registers to allow later comparison.
196             for (int i = 0; i < numberOfC64addr; i++)
197             {
198                 oldValues[i] = c64mem2[c64addrTable[i]];
199             }
200         }
201 
202 		// In PlaySID-mode the interpreter will ignore some of the parameters.
203 		//bool retcode =
204 		interpreter(thisTune.info.initAddr,c64memRamRom(thisTune.info.initAddr),reg,reg,reg);
205 		playRamRom = c64memRamRom(thisTune.info.playAddr);
206 
207 		// This code is only used to be able to print out the initial IRQ address.
208 		if (thisTune.info.playAddr == 0)
209 		{
210 			// Get the address of the interrupt handler.
211 			if ((c64mem1[1] & 2) != 0)  // isKernal?
212 			{
213 				thisTune.setIRQaddress(readEndian(c64mem1[0x0315],c64mem1[0x0314]));  // IRQ
214 			}
215 			else
216 			{
217 				thisTune.setIRQaddress(readEndian(c64mem1[0xffff],c64mem1[0xfffe]));  // NMI
218 			}
219 		}
220 		else
221 		{
222 			thisTune.setIRQaddress(0);
223 		}
224 
225 #if defined(SIDEMU_TIME_COUNT)
226 		thisEmuEngine.resetSecondsThisSong();
227 #endif
228 		return true;
229 
230 	}  // top else (emu&sidtune okay)
231 }
232