1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2022 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 #include <libspectrum.h>
23 #include "libvideo/video.h"
28 ////////////////////////////////////////////////////////////////////////////////
29 // numberz for tape counter
30 static VOverlay
*tapeOverlay
= NULL
;
33 static const unsigned char tapeNumberz
[80] = {
34 0xFE,0xC6,0xBA,0xBA,0xBA,0xBA,0xC6,0xFE, //0
35 0xFE,0xEE,0xCE,0xEE,0xEE,0xEE,0xC6,0xFE, //1
36 0xFE,0xC6,0xBA,0xFA,0xC6,0xBE,0x82,0xFE, //2
37 0xFE,0xC6,0xBA,0xE6,0xFA,0xBA,0xC6,0xFE, //3
38 0xFE,0xF6,0xE6,0xD6,0xB6,0x82,0xF6,0xFE, //4
39 0xFE,0x82,0xBE,0x86,0xFA,0xBA,0xC6,0xFE, //5
40 0xFE,0xC6,0xBE,0x86,0xBA,0xBA,0xC6,0xFE, //6
41 0xFE,0x82,0xFA,0xF6,0xEE,0xEE,0xEE,0xFE, //7
42 0xFE,0xC6,0xBA,0xC6,0xBA,0xBA,0xC6,0xFE, //8
43 0xFE,0xC6,0xBA,0xBA,0xC2,0xFA,0xC6,0xFE, //9
47 static void tapeDrawDigit (int d
, int x
, int y
) {
48 for (int dy
= 0; dy
< 8; ++dy
, ++y
) {
49 uint8_t b
= tapeNumberz
[(d
++)%80];
51 for (int dx
= 0; dx
< 8; ++dx
) {
52 if (b
&0x80) putPixelVO(tapeOverlay
, x
+dx
, y
, 15);
59 #define TAPE_COUNTER_MAX (9999*8)
61 static void tapeDrawCounter (int cnt
) {
63 if (cnt
< 0) cnt
= 0; else if (cnt
> TAPE_COUNTER_MAX
) cnt
= TAPE_COUNTER_MAX
;
65 dofs
[3] = cnt
%8; cnt
/= 8;
66 digs
[3] = cnt
%10; cnt
/= 10;
68 digs
[2] = cnt
%10; cnt
/= 10;
70 digs
[1] = cnt
%10; cnt
/= 10;
74 if (digs
[3] == 9) dofs
[2] = dofs
[3];
75 if (digs
[2] == 9) dofs
[1] = dofs
[2];
76 if (digs
[1] == 9) dofs
[0] = dofs
[1];
77 for (int f
= 0; f
< 4; ++f
) tapeDrawDigit(digs
[f
]*8+dofs
[f
], f
*8+2, 2);
81 ////////////////////////////////////////////////////////////////////////////////
82 static int64_t tapTSLength
= 0;
83 static int64_t tapTSPos
= 0;
86 void emuTapeDrawCounter (void) {
87 if (tapeOverlay
== NULL
) tapeOverlay
= createVO(4*8+3, 8+4);
88 clearVO(tapeOverlay
, 0);
89 drawFrameVO(tapeOverlay
, 0, 0, tapeOverlay
->w
, tapeOverlay
->h
, 15);
90 if (tapTSLength
> 0) {
91 int cnt
= (int64_t)TAPE_COUNTER_MAX
-(tapTSPos
*TAPE_COUNTER_MAX
/tapTSLength
);
93 if (cnt
< 0) cnt
= 0; else if (cnt
> TAPE_COUNTER_MAX
) cnt
= TAPE_COUNTER_MAX
;
96 tapeDrawCounter(TAPE_COUNTER_MAX
);
98 blitVO(tapeOverlay
, 2, frameSfc
->h
-14, tapeAlpha
);
102 void emuStopTape (void) {
103 if (optTapePlaying
) {
104 if (optTapePlaying
< 0) {
105 if (optTapeMaxSpeed
) { optMaxSpeedBadScreenTape
= 0; emuSetMaxSpeed(0); }
106 if (optTapeAutoPauseEmu
) emuSetPaused(1);
110 if (tapStopAfterNextEdge
== 666) tapNeedRewind
= 1;
111 tapStopAfterNextEdge
= 0;
112 emuTapeAcceleratorStop();
117 void emuTapeAutoStop (void) {
118 if (tapStopAfterNextEdge
== 666) tapNeedRewind
= 1;
119 if (optTapePlaying
< 0 && optTapeAutoPauseEmu
) emuSetPaused(1);
121 tapStopAfterNextEdge
= 0;
125 void emuTapeAdvanceFrame (void) {
126 if (optTapePlaying
) {
127 tapNextEdgeTS
-= machineInfo
.tsperframe
;
128 emuTapeAcceleratorAdvanceFrame();
133 void emuTapeEdgeAdvance (int curts
) {
139 if (zxCurTape
!= NULL
&& optTapePlaying
) {
140 libspectrum_dword ts
;
143 if (libspectrum_tape_get_next_edge(&ts
, &flags
, zxCurTape
) != LIBSPECTRUM_ERROR_NONE
) {
144 if (optTapePlaying
< 0 && optTapeAutoPauseEmu
) emuSetPaused(1);
146 cprintf("TAPE: libspectrum error!\n");
149 tapTSPos
+= (int64_t)ts
;
150 tapNextEdgeTS
= (int64_t)curts
+(int64_t)ts
;
152 if (flags
&(LIBSPECTRUM_TAPE_FLAGS_STOP
|LIBSPECTRUM_TAPE_FLAGS_STOP48
)) {
153 if (flags
&LIBSPECTRUM_TAPE_FLAGS_TAPE
) {
154 //fprintf(stderr, "END OF TAPE!\n");
155 tapStopAfterNextEdge
= 666;
157 tapStopAfterNextEdge
= (flags
&LIBSPECTRUM_TAPE_FLAGS_STOP48
? -1 : 1);
160 tapStopAfterNextEdge
= 0;
164 if (flags
&LIBSPECTRUM_TAPE_FLAGS_LEVEL_LOW
) tapNextEdge
= 0;
165 else if (flags
&LIBSPECTRUM_TAPE_FLAGS_LEVEL_HIGH
) tapNextEdge
= 1;
166 else if (flags
&LIBSPECTRUM_TAPE_FLAGS_NO_EDGE
) tapNextEdge
= tapCurEdge
;
167 else tapNextEdge
= !tapCurEdge
;
169 tapNextEdge
= tapCurEdge
;
172 if (tapNextEdge
!= tapCurEdge
) emuTapeAcceleratorEdgeAdvance(flags
);
173 //fprintf(stderr, "emuTapeEdgeAdvance: tapCurFrameTS=%5lld; tapNextEdgeTS=%5lld; tapNextEdge=%d\n", tapCurFrameTS, tapNextEdgeTS, tapNextEdge);
180 int emuTapeCheckStop (void) {
181 if (tapStopAfterNextEdge
) {
182 if (tapStopAfterNextEdge
== 666) tapNeedRewind
= 1;
183 if (tapStopAfterNextEdge
> 0 || zxModel
== ZX_MACHINE_48K
) {
184 if (optTapePlaying
< 0 && optTapeAutoPauseEmu
) emuSetPaused(1);
186 tapStopAfterNextEdge
= 0;
189 tapStopAfterNextEdge
= 0;
195 int emuTapeGetCurEdge (void) {
196 if (zxCurTape
!= NULL
&& optTapePlaying
) {
197 //fprintf(stderr, "emuTapeGetCurEdge\n");
198 while (optTapePlaying
) {
199 if (tapNextEdgeTS
> z80
.tstates
) break; // not yet
200 tapCurEdge
= tapNextEdge
;
201 if (emuTapeCheckStop()) break;
202 emuTapeEdgeAdvance(tapNextEdgeTS
);
210 void emuRewindTape (void) {
213 tapStopAfterNextEdge
= 0;
214 if (zxCurTape
!= NULL
&& libspectrum_tape_present(zxCurTape
)) {
215 libspectrum_tape_nth_block(zxCurTape
, 0);
220 void emuStartTapeEx (int autostart
) {
221 if (zxCurTape
!= NULL
&& !optTapePlaying
) {
222 if (tapNeedRewind
) emuRewindTape();
223 if ((optTapePlaying
= (autostart
? -1 : 1)) < 0 && optTapeMaxSpeed
) {
224 optMaxSpeedBadScreenTape
= optTapeAllowMaxSpeedUgly
; // let it be ugly ;-)
227 emuTapeAcceleratorStart();
228 emuTapeEdgeAdvance(z80
.tstates
);
233 void emuUnloadTape (void) {
234 if (zxCurTape
!= NULL
) {
237 libspectrum_tape_free(zxCurTape
);
243 void emuClearTape (void) {
244 if (zxCurTape
!= NULL
) {
247 libspectrum_tape_clear(zxCurTape
);
252 void emutapCalcLength (void) {
253 libspectrum_tape_block
*blk
;
254 libspectrum_tape_iterator it
;
256 tapTSLength
= tapTSPos
= 0;
257 for (blk
= libspectrum_tape_iterator_init(&it
, zxCurTape
); blk
!= NULL
; blk
= libspectrum_tape_iterator_next(&it
)) {
258 libspectrum_dword blen
= libspectrum_tape_block_length(blk
);
260 tapTSLength
+= (int64_t)blen
;
265 int emuInsertTapeFromBuf (const char *name
, const void *buf
, int size
) {
267 if ((zxCurTape
= libspectrum_tape_alloc()) == NULL
) return -1;
268 if (libspectrum_tape_read(zxCurTape
, buf
, size
, LIBSPECTRUM_ID_UNKNOWN
, name
) != LIBSPECTRUM_ERROR_NONE
) {
279 static int emuInsertTape (const char *name) {
284 if ((buf = loadWholeFile(name, &size, &name)) == NULL) return -1;
286 res = emuInsertTapeFromBuf(name, buf, size);
293 #ifdef USE_OLD_TAPE_ACCELERATOR
294 # include "tapeaccel.c"
296 # include "tapeaccel_exp.c"
298 #include "tapeldrs.c"
299 #include "tapeldrx.c"