git @ Cat's Eye Technologies linapple / 9d5dbb4
Merge pull request #2 from ghedger/master Added modifier keys to F2 reset to prevent accidental reboots when switc... Tim O'Brien 10 years ago
12 changed file(s) with 152 addition(s) and 89 deletion(s). Raw diff Collapse all Expand all
Binary diff not shown
Binary diff not shown
Binary diff not shown
6262 //
6363 ///////////////////////////////////////////////////////////
6464
65 #define MAX_OUTPUT 0x7fff
65 // GPH Changed from 0x7fff: we want some headroom to add in the Apple speaker
66 // in the mixing phase and can avoid an unnecessary divide with the
67 // associated problems by simply picking smaller values.
68 // Note also this number can theoretically go as high as 0x3fff without
69 // causing post-mix clipping, but even that sounds too loud...
70 #define MAX_OUTPUT 0x0fff
6671
6772 // See AY8910_set_clock() for definition of STEP
6873 #define STEP 0x8000
123123 //static signed long g_uInternalExecutedCycles;
124124 // TODO: Use IRQ_CHECK_TIMEOUT=128 when running at full-speed else with IRQ_CHECK_TIMEOUT=1
125125 // - What about when running benchmark?
126 static const int IRQ_CHECK_TIMEOUT = 128;
126 // GPH Dropped to IRQ_CHECK_TIMOUT=16 - Mockingboard-intensive applications sound
127 // "jerky" at 128. Does not show appreciable CPU impact in top CPU profiler.
128 static const int IRQ_CHECK_TIMEOUT = 16;
127129 static signed int g_nIrqCheckTimeout = IRQ_CHECK_TIMEOUT;
128130
129131 //
155155 }
156156 #else
157157 /* Windows specific functions of reading directory structure */
158 /* Find subdirs: */
158 /* Find subdirs: */
159159 if(strcmp(incoming_dir, "/")) {
160160 // we are not in upper direcory
161161 tmp = new char[3];
167167 B = 1;
168168 }
169169 else B = 0; // for sorting dirs
170
170
171171
172172 WIN32_FIND_DATA finfo;
173173 HANDLE h;
174174
175
176
175
176
177177 h=FindFirstFile(incoming_dir,&finfo);
178178
179179 if (h!=INVALID_HANDLE_VALUE) {
197197 strcpy(tmp, "<DIR>");
198198 sizes.Add(tmp); // add sign of directory
199199 }
200 } /* while */
201 } /* if */
200 } /* while */
201 } /* if */
202202
203203 #endif
204204 // sort directories. Please, don't laugh at my bubble sorting - it the simplest thing I've ever seen --bb
240240 (void) closedir (dp);
241241 #else
242242 /* Windows specific functions of reading directory structure */
243 /* Find files: */
243 /* Find files: */
244244
245245 h=FindFirstFile(incoming_dir,&finfo);
246246
252252 strcpy(tmp,finfo.cFileName);
253253 files.Add(tmp);
254254 tmp = new char[10]; // 1400000KB
255 snprintf(tmp, 9, "%dKB",
255 snprintf(tmp, 9, "%dKB",
256256 ((finfo.nFileSizeHigh * (MAXDWORD+1)) + finfo.nFileSizeLow));
257257 sizes.Add(tmp); // add this size to list
258258 }
263263 strcpy(tmp,finfo.cFileName);
264264 files.Add(tmp);
265265 tmp = new char[10]; // 1400000KB
266 snprintf(tmp, 9, "%dKB",
266 snprintf(tmp, 9, "%dKB",
267267 ((finfo.nFileSizeHigh * (MAXDWORD+1)) + finfo.nFileSizeLow));
268268 sizes.Add(tmp); // add this size to list
269269 }
270 } /* while */
271 } /* if */
270 } /* while */
271 } /* if */
272272
273273 #endif
274274 // do sorting for files
308308 }
309309 else tempSurface = g_origscreen;
310310
311 if(tempSurface == NULL)
311 if(tempSurface == NULL)
312312 tempSurface = screen; // use screen, if none available
313
313
314314 my_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, tempSurface->w, tempSurface->h, tempSurface->format->BitsPerPixel, 0, 0, 0, 0);
315315 if(tempSurface->format->palette && my_screen->format->palette)
316316 SDL_SetColors(my_screen, tempSurface->format->palette->colors,
358358 SDL_Rect r;
359359 r.x= 2;
360360 r.y= TOPX + (i-first_file) * 15 * facy - 1;
361 if(strlen(tmp) > 46) r.w = 46 * 6 * 1.7 * facx + 2;
362 else r.w= strlen(tmp) * 6 * 1.7 * facx + 2; // 6- FONT_SIZE_X
361 if(strlen(tmp) > 46) r.w = 46 * FONT_SIZE_X /* 6 */ * 1.7 * facx + 2;
362 else r.w= strlen(tmp) * FONT_SIZE_X /* 6 */ * 1.7 * facx + 2; // 6- FONT_SIZE_X
363363 r.h= 9 * 1.5 * facy;
364364 SDL_FillRect(screen, &r, SDL_MapRGB(screen->format,255,0,0));// in RED
365365 } /* if */
398398
399399 // control cursor
400400 keyboard = SDL_GetKeyState(NULL); // get current state of pressed (and not pressed) keys
401
401402 if (keyboard[SDLK_UP] || keyboard[SDLK_LEFT]) {
402403 if (act_file>0) act_file--; // up one position
403404 if (act_file<first_file) first_file=act_file;
550550 char *
551551 md5str (const char *input)
552552 {
553 static char result[16 * 3 +1];
553 char result[16 * 3 +1];
554554 unsigned char* digest = (unsigned char*)md5 (input);
555555 int i;
556556
391391 0, 256);
392392 // Uint32 myblack = SDL_MapRGB(screen->format, 0, 0, 0); // black color
393393 // SDL_SetColorKey(g_hStatusSurface,SDL_SRCCOLORKEY/* | SDL_RLEACCEL*/, myblack);
394
394
395395 if (drawflags & DRAW_BACKGROUND)
396396 {
397397 /* Code moved to Video.cpp in CreateDIBSections()
493493 "Conf file is linapple.conf in current directory by default",
494494 "Hugest archive of Apple][ stuff you can find at ftp.apple.asimov.net",
495495 " F1 - This help",
496 " F2 - Cold reset, Shift+F2 - Reload conf file and restart",
496 " Ctrl+Shift+F2 - Cold reset",
497 " Shift+F2 - Reload conf file and restart",
497498 " F3, F4 - Choose an image file name for floppy disk",
498499 " in Slot 6 drive 1 or 2 respectively",
499500 " Shift+F3, Shift+F4 - The same thing for Apple hard disks",
942943 break;
943944
944945 case BTN_RUN: // F2 - Run that thing! Or Shift+2 ReloadConfig and run it anyway!
945 if(mod & KMOD_SHIFT) {
946 if((mod & (KMOD_LCTRL|KMOD_LSHIFT)) == (KMOD_LCTRL|KMOD_LSHIFT) ||
947 (mod & (KMOD_RCTRL|KMOD_RSHIFT)) == (KMOD_RCTRL|KMOD_RSHIFT)) {
948 if (g_nAppMode == MODE_LOGO)
949 DiskBoot();
950 else if (g_nAppMode == MODE_RUNNING)
951 ResetMachineState();
952 if ((g_nAppMode == MODE_DEBUG) || (g_nAppMode == MODE_STEPPING))
953 DebugEnd();
954 g_nAppMode = MODE_RUNNING;
955 DrawStatusArea(/*(HDC)0,*/DRAW_TITLE);
956 VideoRedrawScreen();
957 g_bResetTiming = true;
958 }
959 else if(mod & KMOD_SHIFT) {
946960 restart = 1; // keep up flag of restarting
947961 qe.type = SDL_QUIT;
948962 SDL_PushEvent(&qe);// push quit event
949 }
950 else {
951 if (g_nAppMode == MODE_LOGO)
952 DiskBoot();
953 else if (g_nAppMode == MODE_RUNNING)
954 ResetMachineState();
955 if ((g_nAppMode == MODE_DEBUG) || (g_nAppMode == MODE_STEPPING))
956 DebugEnd();
957 g_nAppMode = MODE_RUNNING;
958 DrawStatusArea(/*(HDC)0,*/DRAW_TITLE);
959 VideoRedrawScreen();
960 g_bResetTiming = true;
961 }
963 }
962964 break;
963965
964966 case BTN_DRIVE1:
965967 case BTN_DRIVE2:
966968 if (mod & KMOD_SHIFT) {
969 if(mod & KMOD_ALT)
970 HD_FTP_Select(button - BTN_DRIVE1);// select HDV image through FTP
971 else
972 HD_Select(button - BTN_DRIVE1); // select HDV image from local disk
973 } else {
967974 if(mod & KMOD_ALT)
968 HD_FTP_Select(button - BTN_DRIVE1);// select HDV image through FTP
969 else HD_Select(button - BTN_DRIVE1); // select HDV image from local disk
970 }
971 else {
972 if(mod & KMOD_ALT) Disk_FTP_SelectImage(button - BTN_DRIVE1);//select through FTP
973 else DiskSelect(button - BTN_DRIVE1); // select image file for appropriate disk drive(#1 or #2)
975 Disk_FTP_SelectImage(button - BTN_DRIVE1);//select through FTP
976 else
977 DiskSelect(button - BTN_DRIVE1); // select image file for appropriate disk drive(#1 or #2)
974978 }
975979 /* if (!fullscreen)
976980 DrawButton((HDC)0,button);*/
182182
183183 static const DWORD g_dwDSBufferSize = 16 * 1024 * sizeof(short) * g_nMB_NumChannels;
184184
185 static const SHORT nWaveDataMin = (SHORT)0x8000;
186 static const SHORT nWaveDataMax = (SHORT)0x7FFF;
185 static const SHORT nWaveDataMin = (SHORT)0xF000;
186 static const SHORT nWaveDataMax = (SHORT)0x0FFF;
187187
188188 static short g_nMixBuffer[g_dwDSBufferSize / sizeof(short)];
189189
130130 //std::cerr << "DEBUG wanted: " << wantedSamples
131131 // << " actual: " << audioSpec.size / 4 << std::endl;
132132 frequency = audioSpec.freq;
133 bufferSize = 4 * (audioSpec.size / sizeof(short));
133 bufferSize = 8 * (audioSpec.size / sizeof(short));
134134 // bufferSize = SPKR_SAMPLE_RATE * 2 * sizeof(short); // 1 second of stereo short data
135135
136136 /*
249249 //////////////////////////////////////////////////////////////////////
250250 //////////////////////////////////////////////////////////////////////
251251
252
253 // GPH this is called on IRQ to refresh the audio at regular intervals.
254 // We'll mix the buffers here keeping in mind the need for speed.
255 //
252256 void audioCallback(short* stream, unsigned len)
253257 {
254258 int i;
255259 static short lastvalue = 0;
256
257260 assert((len & 1) == 0); // stereo
261
258262 unsigned len1, len2;
259263 unsigned available = getBufferFilled();
260
261 //std::cerr << "DEBUG callback: " << available << std::endl;
262264 unsigned num = std::min(len, available);
263265 if ((readIdx + num) < bufferSize) {
266 // No split in source (mixBuffer); perform straight-up copy.
267 //
268 // |--------------------|
269 // ^ (mixBuffer) $
270 //
271 // |--------------------|
272 // ^ (stream)
264273 memcpy(stream, &mixBuffer[readIdx], num * sizeof(short));
265274 readIdx += num;
266275 } else {
276 // Handle split in source
277 //
278 // |--------------------|
279 // (mixBuffer) ^
280 //
281 // |--------------------|
282 // ^ (stream)
267283 len1 = bufferSize - readIdx;
268284 memcpy(stream, &mixBuffer[readIdx], len1 * sizeof(short));
269285 len2 = num - len1;
271287 readIdx = len2;
272288 }
273289
290 // Fill the remainer of the buffer with last value to prevent potential
291 // clicks and pops.
274292 if (available != 0) {
275293 if (readIdx != 0)
276294 lastvalue = mixBuffer[readIdx-1];
279297 }
280298
281299 for (i = num; i < len; i++) {
282 stream[i] = lastvalue;
300 stream[i] = lastvalue;
283301 }
284
285 /* Note: cleared at the begininng of the func
286
287 int missing = len - available;
288 if (missing > 0) {
289 // buffer underrun
290 //std::cerr << "DEBUG underrun: " << missing << std::endl;
291 memset(&stream[available], 0, missing * sizeof(short));
292 }
293 */
302 /* GPH please don't do this in an IRQ handler!
294303 unsigned target = (5 * bufferSize) / 8;
295304 double factor = double(available) / target;
296305 filledStat = (63 * filledStat + factor) / 64;
297 //std::cerr << "DEBUG filledStat: " << filledStat << std::endl;
306 */
307
298308 #ifdef MOCKINGBOARD
299 // And add Mockingboard sound data to the stream
309 // And add Mockingboard sound data to the stream
310 // GPH: We are going to add the Mockingboard and speaker samples.
311 // Their independent maximum amplitudes have been selected to eliminate
312 // any possibility of wave peak clipping. This speeds up the timing-sensitive
313 // operation here (since we're in an IRQ handler) and eliminates the
314 // need for a potentially expensive divide.
300315 available = getBuffer2Filled();
301316 //std::cerr << "DEBUG callback: " << available << std::endl;
302317 num = std::min(len, available);
318 const short *pSrc;
319 short *pDest = stream;
303320 if ((readIdx2 + num) < bufferSize) {
304 // memcpy(stream, &mixBuffer[readIdx], num * sizeof(short));
305 for(i = 0; i < num; i++)
306 stream[i] |= mockBuffer[readIdx2 + i];
307 readIdx2 += num;
321 if( num ) {
322 pSrc = &mockBuffer[readIdx2];
323 readIdx2 += num;
324 while(num--) {
325 *pDest += *pSrc;
326 pDest++; pSrc++;
327 }
328 }
308329 } else {
309 len1 = bufferSize - readIdx2;
310 // memcpy(stream, &mixBuffer[readIdx], len1 * sizeof(short));
311 for(i = 0; i < len1; i++)
312 stream[i] |= mockBuffer[readIdx2 + i];
330 // We crossed the "seam" on the circular mockBuffer.
331 // We will therefore perform two copies, the segmentation being determined
332 // by the split in the source buffer (mockBuffer).
333 //
334 // |--------------------|
335 // (mockBuffer) ^
336 //
337 //
338 // |--------------------|
339 // ^ (stream)
340 len1 = bufferSize - readIdx2;
313341 len2 = num - len1;
314 // memcpy(&stream[len1], mixBuffer, len2 * sizeof(short));
315 for(i = 0; i < len2; i++)
316 stream[len1 + i] |= mockBuffer[i];
342 if(len1) {
343 pSrc = &mockBuffer[readIdx2];
344 while(len1--) {
345 *pDest += *pSrc;
346 pDest++; pSrc++;
347 }
348 }
317349 readIdx2 = len2;
318 }
319 #endif
350 if(len2) {
351 pSrc = mockBuffer;
352 while(len2--) {
353 *pDest += *pSrc;
354 pDest++; pSrc++;
355 }
356 }
357
358 }
359 #endif // #ifdef MOCKINGBOARD
320360 // normalization
361 // GPH TODO: Rather than do this in this handler, we should
362 // perform it efficiently by changing the values of
363 // MAX_OUTPUT (AY8910.cpp) and SPKR_DATA_INIT (Speaker.cpp),
364 // making them variables and making the appropriate access functions
365 // to call from Frame.cpp
321366 /* const short MY_MAX_VOLUME = (short)SDL_MIX_MAXVOLUME / 2;
322367 for(unsigned k=0;k<len;k+=2)
323368 if((short)stream[k] > MY_MAX_VOLUME)
4949 //-------------------------------------
5050
5151 // Globals (SOUND_WAVE)
52 const short SPKR_DATA_INIT = (short)0x8000; // data written to speakers buffer
53
54 static short g_nSpeakerData = SPKR_DATA_INIT;
52 // GPH This "INIT" value is the actual sample data written to the speaker when
53 // it gets whapped with a BIT $C030. Note the output is always digital.
54 // The Apple II had no notion of volume or of looping waves, only the single
55 // "click" of the speaker. We set this to a value well under the maximum to
56 // provide headroom for mixing Mockingboard sound without causing peak clipping.
57 const short SPKR_DATA_INIT = (short)0x2000; // data written to speakers buffer
58
59 static short g_nSpeakerData = 0x0000; //SPKR_DATA_INIT;
5560 static short *g_pSpeakerBuffer = NULL;
56 static UINT g_nBufferIdx = 0;
61 static UINT g_nBufferIdx = 0;
5762
5863 static short *g_pStereoBuffer = NULL; // buffer for stereo samples
5964
60
6165 static short *g_pRemainderBuffer = NULL; // Remainder buffer
62 static UINT g_nRemainderBufferSize; // Setup in SpkrInitialize()
63 static UINT g_nRemainderBufferIdx; // Setup in SpkrInitialize()
64
66 static UINT g_nRemainderBufferSize; // Setup in SpkrInitialize()
67 static UINT g_nRemainderBufferIdx; // Setup in SpkrInitialize()
6568
6669 // Application-wide globals:
67 DWORD soundtype = SOUND_WAVE; //default
70 DWORD soundtype = SOUND_WAVE; //default
6871 double g_fClksPerSpkrSample; // Setup in SetClksPerSpkrSample()
6972
7073 // Globals
300303 }
301304
302305 g_nSpkrLastCycle = g_nCumulativeCycles;
303 }
304
305 //=============================================================================
306
307 // Called by emulation code when Speaker I/O reg is accessed
306
307 // GPH Added - simulate decoupling capacitor - use approximate value
308 g_nSpeakerData = (short)((double) g_nSpeakerData * 0.995);
309 }
310
311 //=============================================================================
312
313 // Called by emulation code when Speaker I/O reg (0xC030) is accessed
308314 BYTE SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
309315 {
310316 g_bSpkrToggleFlag = true;
326332
327333 UpdateSpkr();
328334
329 g_nSpeakerData = ~g_nSpeakerData;
335 g_nSpeakerData = g_nSpeakerData ^ SPKR_DATA_INIT;
330336 }
331337
332338 return MemReadFloatingBus(nCyclesLeft); // reading from $C030..$C03F retrurns unpredictable value?
8585 /* ---------------------- FONT routines ---------------------------*/
8686 /* ----------------------------------------------------------------*/
8787
88 #define FONT_SIZE_X 6
88 #define FONT_SIZE_X 7
8989 #define FONT_SIZE_Y 8
9090 // chars in row in font bitmap
91 #define CHARS_IN_ROW 45
91 #define CHARS_IN_ROW 39
9292 extern SDL_Surface *font_sfc;
9393
9494 bool fonts_initialization(void);