emu: remember page editor cursor position in memview
[zymosis.git] / src / ZXEmuT / tapes.c
blob55d9fe870bedd4f5041d15efe1ae77b1fd28a0d5
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>
22 #include "tapes.h"
23 #include "libvideo/video.h"
24 #include "console.h"
25 #include "emuutils.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);
53 b = (b&0x7f)<<1;
59 #define TAPE_COUNTER_MAX (9999*8)
61 static void tapeDrawCounter (int cnt) {
62 int dofs[4], digs[4];
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;
67 dofs[2] = 0;
68 digs[2] = cnt%10; cnt /= 10;
69 dofs[1] = 0;
70 digs[1] = cnt%10; cnt /= 10;
71 dofs[0] = 0;
72 digs[0] = 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;
94 tapeDrawCounter(cnt);
95 } else {
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);
108 optTapePlaying = 0;
109 //tapCurEdge = 0;
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);
120 emuStopTape();
121 tapStopAfterNextEdge = 0;
125 void emuTapeAdvanceFrame (void) {
126 if (optTapePlaying) {
127 tapNextEdgeTS -= machineInfo.tsperframe;
128 emuTapeAcceleratorAdvanceFrame();
133 void emuTapeEdgeAdvance (int curts) {
134 if (tapNeedRewind) {
135 emuStopTape();
136 return;
139 if (zxCurTape != NULL && optTapePlaying) {
140 libspectrum_dword ts;
141 int flags;
143 if (libspectrum_tape_get_next_edge(&ts, &flags, zxCurTape) != LIBSPECTRUM_ERROR_NONE) {
144 if (optTapePlaying < 0 && optTapeAutoPauseEmu) emuSetPaused(1);
145 emuStopTape();
146 cprintf("TAPE: libspectrum error!\n");
147 return;
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;
156 } else {
157 tapStopAfterNextEdge = (flags&LIBSPECTRUM_TAPE_FLAGS_STOP48 ? -1 : 1);
159 } else {
160 tapStopAfterNextEdge = 0;
163 if (ts > 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;
168 } else {
169 tapNextEdge = tapCurEdge;
172 if (tapNextEdge != tapCurEdge) emuTapeAcceleratorEdgeAdvance(flags);
173 //fprintf(stderr, "emuTapeEdgeAdvance: tapCurFrameTS=%5lld; tapNextEdgeTS=%5lld; tapNextEdge=%d\n", tapCurFrameTS, tapNextEdgeTS, tapNextEdge);
174 } else {
175 emuStopTape();
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);
185 emuStopTape();
186 tapStopAfterNextEdge = 0;
187 return 1;
189 tapStopAfterNextEdge = 0;
191 return 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);
204 return tapCurEdge;
206 return -1;
210 void emuRewindTape (void) {
211 tapNeedRewind = 0;
212 tapTSPos = 0;
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 ;-)
225 emuSetMaxSpeed(1);
227 emuTapeAcceleratorStart();
228 emuTapeEdgeAdvance(z80.tstates);
233 void emuUnloadTape (void) {
234 if (zxCurTape != NULL) {
235 emuStopTape();
236 tapNeedRewind = 0;
237 libspectrum_tape_free(zxCurTape);
238 zxCurTape = NULL;
243 void emuClearTape (void) {
244 if (zxCurTape != NULL) {
245 emuStopTape();
246 tapNeedRewind = 0;
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) {
266 emuUnloadTape();
267 if ((zxCurTape = libspectrum_tape_alloc()) == NULL) return -1;
268 if (libspectrum_tape_read(zxCurTape, buf, size, LIBSPECTRUM_ID_UNKNOWN, name) != LIBSPECTRUM_ERROR_NONE) {
269 emuUnloadTape();
270 return -1;
272 emutapCalcLength();
273 emuRewindTape();
274 return 0;
279 static int emuInsertTape (const char *name) {
280 size_t size;
281 int res;
282 char *buf;
284 if ((buf = loadWholeFile(name, &size, &name)) == NULL) return -1;
286 res = emuInsertTapeFromBuf(name, buf, size);
287 free(buf);
288 return res;
293 #ifdef USE_OLD_TAPE_ACCELERATOR
294 # include "tapeaccel.c"
295 #else
296 # include "tapeaccel_exp.c"
297 #endif
298 #include "tapeldrs.c"
299 #include "tapeldrx.c"