add HAVE_DISK_STORAGE, and use that instead of HAVE_FLASH_STORAGE when checking for...
[kugel-rb.git] / apps / plugins / zxbox / tapefile.c
blob19f6aba980eef15b3555c92b6aa08b59807a3f44
1 /*
2 * Copyright (C) 1996-1998 Szeredi Miklos
3 * Email: mszeredi@inf.bme.hu
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version. See the file COPYING.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* This module deals with the different tape file formats (.TAP and .TZX) */
22 /* 'sptape.c' uses the functions provided by this module. */
25 #include "tapefile.h"
26 #include "tapef_p.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include "zxconfig.h"
34 #include "helpers.h"
35 #define max(x, y) ((x) > (y) ? (x) : (y))
37 #define DESC_LEN 256
39 char seg_desc[DESC_LEN];
41 #define TZXMAJPROG 1
42 #define TZXMINPROG 2
44 /*static FILE *tapefp = NULL;*/
45 static int tapefd=-1;
47 static dbyte segi, currsegi;
48 static int segbeg;
50 static int endtype, endnext, endplay;
51 static dbyte endpause;
52 static int finished;
54 static long firstseg_offs;
56 static struct tape_options tapeopt;
58 long tf_segoffs;
59 struct tapeinfo tf_tpi;
61 static dbyte loopctr, loopbeg;
62 static dbyte callctr, callbeg;
64 #define ST_NORM 0
65 #define ST_PSEQ 1
66 #define ST_DIRE 2
67 #define ST_MISC 3
69 #define PL_NONE 0
70 #define PL_PAUSE 1
71 #define PL_LEADER 2
72 #define PL_DATA 3
73 #define PL_END 4
74 #define PL_PSEQ 5
75 #define PL_DIRE 6
77 #define IMP_1MS 3500
79 static dbyte lead_pause;
80 static int playstate = PL_NONE;
81 static int currlev;
83 #define DEF_LEAD_PAUSE 2000
85 struct seginfo tf_cseg;
87 struct tzxblock {
88 int type;
89 int lenbytes;
90 int lenmul;
91 int hlen;
94 #define NUMBLOCKID 0x60
95 /* changed NONE because of warinigs */
96 /*#define NONE 0*/
97 #define NONE 0,0,0,0
98 #define COMM 1
99 #define STAN 2
102 #define RBUFLEN 1024
104 static byte rbuf[RBUFLEN];
106 /* Table containing information on TZX blocks */
108 static struct tzxblock tzxb[NUMBLOCKID] = {
109 { NONE }, /* ID: 00 */
110 { NONE },
111 { NONE },
112 { NONE },
113 { NONE },
114 { NONE },
115 { NONE },
116 { NONE },
118 { NONE }, /* ID: 08 */
119 { NONE },
120 { NONE },
121 { NONE },
122 { NONE },
123 { NONE },
124 { NONE },
125 { NONE },
127 { COMM, 2, 1, 0x04 }, /* ID: 10 */
128 { COMM, 3, 1, 0x12 },
129 { COMM, 0, 1, 0x04 },
130 { COMM, 1, 2, 0x01 },
131 { COMM, 3, 1, 0x0A },
132 { COMM, 3, 1, 0x08 },
133 { NONE },
134 { NONE },
136 { NONE }, /* ID: 18 */
137 { NONE },
138 { NONE },
139 { NONE },
140 { NONE },
141 { NONE },
142 { NONE },
143 { NONE },
145 { COMM, 0, 1, 0x02 }, /* ID: 20 */
146 { COMM, 1, 1, 0x01 },
147 { COMM, 0, 1, 0x00 },
148 { COMM, 0, 1, 0x02 },
149 { COMM, 0, 1, 0x02 },
150 { COMM, 0, 1, 0x00 },
151 { COMM, 2, 2, 0x02 },
152 { COMM, 0, 1, 0x00 },
154 { COMM, 2, 1, 0x02 }, /* ID: 28 */
155 { NONE },
156 { STAN, 0, 1, 0x00 },
157 { NONE },
158 { NONE },
159 { NONE },
160 { NONE },
161 { NONE },
163 { COMM, 1, 1, 0x01 }, /* ID: 30 */
164 { COMM, 1, 1, 0x02 },
165 { COMM, 2, 1, 0x02 },
166 { COMM, 1, 3, 0x01 },
167 { COMM, 0, 1, 0x08 },
168 { COMM, 4, 1, 0x14 },
169 { NONE },
170 { NONE },
172 { NONE }, /* ID: 38 */
173 { NONE },
174 { NONE },
175 { NONE },
176 { NONE },
177 { NONE },
178 { NONE },
179 { NONE },
181 { COMM, 3, 1, 0x04 }, /* ID: 40 */
182 { NONE },
183 { NONE },
184 { NONE },
185 { NONE },
186 { NONE },
187 { NONE },
188 { NONE },
190 { NONE }, /* ID: 48 */
191 { NONE },
192 { NONE },
193 { NONE },
194 { NONE },
195 { NONE },
196 { NONE },
197 { NONE },
199 { NONE }, /* ID: 50 */
200 { NONE },
201 { NONE },
202 { NONE },
203 { NONE },
204 { NONE },
205 { NONE },
206 { NONE },
208 { NONE }, /* ID: 58 */
209 { NONE },
210 { COMM, 0, 1, 0x09 },
211 { NONE },
212 { NONE },
213 { NONE },
214 { NONE },
215 { NONE }
219 #define PTRDIFF(pe, ps) ((int) (((long) (pe) - (long) (ps)) / sizeof(*pe)))
221 static char tzxheader[] = {'Z','X','T','a','p','e','!',0x1A};
223 static int readbuf(void *ptr, int size, /*FILE *fp*/ int fd)
225 /*return (int) fread(ptr, 1, (size_t) size, tapefp);*/
226 return (int) rb->read(fd, ptr, (size_t) size);
229 static void premature(struct seginfo *csp)
231 csp->segtype = SEG_ERROR;
232 rb->snprintf(seg_desc,DESC_LEN, "Premature end of segment");
235 static int read_tzx_header(byte *hb, struct seginfo *csp)
237 int res;
238 int segid, seght;
239 int lenoffs, lenbytes, lenmul, lenadd;
240 int hlen;
241 long length;
242 byte *hip;
244 segid = getc(tapefd);
245 if(segid == EOF) {
246 csp->segtype = SEG_END;
247 rb->snprintf(seg_desc,DESC_LEN, "End of Tape");
248 return 0;
251 hb[0] = (byte) segid;
253 if(segid < NUMBLOCKID) seght = tzxb[segid].type;
254 else seght = 0; /* was NONE here*/
256 if(seght == COMM) {
257 lenbytes = tzxb[segid].lenbytes;
258 lenmul = tzxb[segid].lenmul;
259 hlen = tzxb[segid].hlen;
260 lenadd = hlen;
261 lenoffs = hlen - lenbytes;
263 else {
264 lenoffs = 0x00;
265 lenbytes = 4;
266 lenmul = 1;
267 lenadd = 0x00;
268 hlen = 0x04;
271 if(seght == STAN) hlen += tzxb[segid].hlen;
273 hip = hb+1;
274 res = readbuf(hip, hlen, tapefd);
275 if(res != hlen) {
276 premature(csp);
277 return 0;
279 length = 0;
280 for(;lenbytes; lenbytes--)
281 length = (length << 8) + hip[lenoffs + lenbytes - 1];
283 length = (length * lenmul) + lenadd - hlen;
285 csp->len = length;
286 return 1;
289 static int read_tap_header(byte *hb, struct seginfo *csp)
291 int res;
293 res = readbuf(hb, 2, tapefd);
294 if(res < 2) {
295 if(res == 0) {
296 csp->segtype = SEG_END;
297 rb->snprintf(seg_desc,DESC_LEN, "End of Tape");
299 else premature(csp);
300 return 0;
302 csp->len = DBYTE(hb, 0);
303 return 1;
306 static int read_header(byte *hb, struct seginfo *csp)
308 segbeg = 0;
309 csp->ptr = 0;
311 csp->segtype = SEG_OTHER;
312 if(tf_tpi.type == TAP_TAP)
313 return read_tap_header(hb, csp);
314 else if(tf_tpi.type == TAP_TZX)
315 return read_tzx_header(hb, csp);
317 return 0;
320 static void isbeg(void)
322 segbeg = 1;
323 tf_cseg.len = tf_cseg.ptr = 0;
327 static int end_seg(struct seginfo *csp)
329 if(!segbeg) {
330 if(csp->len != csp->ptr) {
331 /*fseek(tapefp, tf_cseg.len - tf_cseg.ptr - 1, SEEK_CUR);*/
332 rb->lseek(tapefd, tf_cseg.len - tf_cseg.ptr - 1, SEEK_CUR);
334 if(getc(tapefd) == EOF) {
335 premature(csp);
336 return 0;
339 segi++;
340 isbeg();
342 playstate = PL_NONE;
343 return 1;
347 static int jump_to_segment(int newsegi, struct seginfo *csp)
349 if(newsegi <= segi) {
350 segi = 0;
351 isbeg();
352 /*fseek(tapefp, firstseg_offs, SEEK_SET);*/
353 rb->lseek(tapefd, firstseg_offs, SEEK_SET);
355 else if(!end_seg(csp)) return 0;
357 while(segi != newsegi) {
358 if(!read_header(rbuf, csp)) return 0;
359 if(!end_seg(csp)) return 0;
361 return 1;
365 static int next_data(void)
367 int res;
368 if(tf_cseg.ptr == tf_cseg.len) return DAT_END;
370 res = getc(tapefd);
371 if(res == EOF) {
372 rb->snprintf(seg_desc, DESC_LEN,"Premature end of segment");
373 return DAT_ERR;
375 tf_cseg.ptr++;
376 return res;
380 static void normal_segment(struct seginfo *csp)
382 rb->snprintf(seg_desc,DESC_LEN, "Data");
383 csp->type = ST_NORM;
384 csp->segtype = SEG_DATA;
385 csp->pulse = 2168; /* 2016 */
386 csp->num = 3220;
387 csp->sync1p = 667;
388 csp->sync2p = 735;
389 csp->zerop = 855; /* 672 */
390 csp->onep = 1710; /* 1568 */
391 csp->bused = 8;
395 static int interpret_tzx_header(byte *hb, struct seginfo *csp)
397 int res;
398 int segid;
399 byte *hip;
400 int offs;
401 dbyte dtmp;
403 segid = hb[0];
404 hip = hb+1;
406 switch(segid) {
407 case 0x10:
408 normal_segment(csp);
409 csp->pause = DBYTE(hip, 0x00);
410 break;
412 case 0x11:
413 rb->snprintf(seg_desc,DESC_LEN, "Turbo Data");
414 csp->type = ST_NORM;
415 csp->segtype = SEG_DATA_TURBO;
416 csp->pulse = DBYTE(hip, 0x00);
417 csp->sync1p = DBYTE(hip, 0x02);
418 csp->sync2p = DBYTE(hip, 0x04);
419 csp->zerop = DBYTE(hip, 0x06);
420 csp->onep = DBYTE(hip, 0x08);
421 csp->num = DBYTE(hip, 0x0A);
422 csp->bused = BYTE(hip, 0x0C);
423 csp->pause = DBYTE(hip, 0x0D);
424 break;
426 case 0x12:
427 rb->snprintf(seg_desc,DESC_LEN, "Pure Tone");
428 csp->type = ST_NORM;
429 csp->segtype = SEG_OTHER;
430 csp->pulse = DBYTE(hip, 0x00);
431 csp->num = DBYTE(hip, 0x02);
432 csp->sync1p = 0;
433 csp->sync2p = 0;
434 csp->zerop = 0;
435 csp->onep = 0;
436 csp->bused = 0;
437 csp->pause = 0;
438 break;
440 case 0x13:
441 rb->snprintf(seg_desc,DESC_LEN, "Pulse Sequence");
442 csp->type = ST_PSEQ;
443 csp->segtype = SEG_OTHER;
444 csp->pause = 0;
445 break;
447 case 0x14:
448 rb->snprintf(seg_desc,DESC_LEN, "Pure Data");
449 csp->type = ST_NORM;
450 csp->segtype = SEG_DATA_PURE;
451 csp->zerop = DBYTE(hip, 0x00);
452 csp->onep = DBYTE(hip, 0x02);
453 csp->bused = BYTE(hip, 0x04);
454 csp->pause = DBYTE(hip, 0x05);
455 csp->pulse = 0;
456 csp->num = 0;
457 csp->sync1p = 0;
458 csp->sync2p = 0;
459 break;
461 case 0x15:
462 rb->snprintf(seg_desc,DESC_LEN, "Direct Recording");
463 csp->type = ST_DIRE;
464 csp->segtype = SEG_OTHER;
465 csp->pulse = DBYTE(hip, 0x00);
466 csp->pause = DBYTE(hip, 0x02);
467 csp->bused = BYTE(hip, 0x04);
468 break;
470 case 0x20:
471 dtmp = DBYTE(hip, 0x00);
472 if(dtmp == 0) {
473 if(!tapeopt.stoppause) {
474 csp->type = ST_MISC;
475 csp->segtype = SEG_STOP;
477 else {
478 csp->pause = tapeopt.stoppause * 1000;
479 csp->type = ST_NORM;
480 csp->segtype = SEG_PAUSE;
482 rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape Mark");
484 else {
485 csp->pause = dtmp;
486 csp->type = ST_NORM;
487 csp->segtype = SEG_PAUSE;
488 rb->snprintf(seg_desc,DESC_LEN, "Pause for %i.%03is",
489 csp->pause / 1000, csp->pause % 1000);
491 csp->pulse = 0;
492 csp->num = 0;
493 csp->sync1p = 0;
494 csp->sync2p = 0;
495 csp->zerop = 0;
496 csp->onep = 0;
497 csp->bused = 0;
498 break;
500 case 0x21:
501 csp->type = ST_MISC;
502 csp->segtype = SEG_GRP_BEG;
503 res = readbuf(rbuf, csp->len, tapefd);
504 if(res != (int) csp->len) {
505 premature(csp);
506 return 0;
508 csp->ptr += csp->len;
510 int blen;
511 rb->snprintf(seg_desc,DESC_LEN, "Begin Group: ");
512 blen = (int) rb->strlen(seg_desc);
513 rb->strncpy(seg_desc+blen, (char *) rbuf, (unsigned) csp->len);
514 seg_desc[csp->len + blen] = '\0';
516 break;
518 case 0x22:
519 rb->snprintf(seg_desc,DESC_LEN, "End Group");
520 csp->type = ST_MISC;
521 csp->segtype = SEG_GRP_END;
522 break;
524 case 0x23:
525 offs = (signed short) DBYTE(hip, 0x00);
526 if(offs == 0) {
527 rb->snprintf(seg_desc,DESC_LEN, "Infinite loop");
528 csp->type = ST_MISC;
529 csp->segtype = SEG_STOP;
531 else {
532 csp->type = ST_MISC;
533 csp->segtype = SEG_SKIP;
534 rb->snprintf(seg_desc,DESC_LEN, "Jump to %i", segi+offs);
535 jump_to_segment(segi + offs, csp);
537 break;
539 case 0x24:
540 loopctr = DBYTE(hip, 0x00);
541 rb->snprintf(seg_desc,DESC_LEN, "Loop %i times", loopctr);
542 loopbeg = segi+1;
543 csp->type = ST_MISC;
544 csp->segtype = SEG_SKIP;
545 break;
547 case 0x25:
548 csp->type = ST_MISC;
549 csp->segtype = SEG_SKIP;
550 if(loopctr) loopctr--;
551 if(loopctr) {
552 jump_to_segment(loopbeg, csp);
553 rb->snprintf(seg_desc,DESC_LEN, "Loop to: %i", loopbeg);
555 else rb->snprintf(seg_desc,DESC_LEN, "Loop End");
556 break;
558 case 0x26:
559 csp->type = ST_MISC;
560 csp->segtype = SEG_SKIP;
561 dtmp = DBYTE(hip, 0x00);
562 if(callctr < dtmp) {
563 int offset;
564 callbeg = segi;
565 /*fseek(tapefp, callctr*2, SEEK_CUR);*/
566 rb->lseek(tapefd, callctr*2, SEEK_CUR);
567 csp->ptr += callctr*2;
568 res = readbuf(rbuf, 2, tapefd);
569 if(res != 2) {
570 premature(csp);
571 return 0;
573 csp->ptr += 2;
574 offset = (signed short) DBYTE(rbuf, 0x00);
575 rb->snprintf(seg_desc,DESC_LEN, "Call to %i", segi+offset);
576 jump_to_segment(segi+offset, csp);
577 callctr++;
579 else {
580 callctr = 0;
581 rb->snprintf(seg_desc,DESC_LEN, "Call Sequence End");
583 break;
585 case 0x27:
586 csp->type = ST_MISC;
587 csp->segtype = SEG_SKIP;
588 rb->snprintf(seg_desc,DESC_LEN, "Return");
589 if(callctr > 0) jump_to_segment(callbeg, csp);
590 break;
592 case 0x28:
593 rb->snprintf(seg_desc,DESC_LEN, "Selection (Not yet supported)");
594 csp->type = ST_MISC;
595 csp->segtype = SEG_SKIP;
596 break;
598 case 0x2A:
599 if(tapeopt.machine == MACHINE_48) {
600 rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape in 48k Mode (Stopped)");
601 csp->type = ST_MISC;
602 csp->segtype = SEG_STOP;
604 else {
605 rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape in 48k Mode (Not Stopped)");
606 csp->type = ST_MISC;
607 csp->segtype = SEG_SKIP;
609 break;
611 case 0x31:
612 case 0x30:
613 csp->type = ST_MISC;
614 csp->segtype = SEG_SKIP;
615 res = readbuf(rbuf, csp->len, tapefd);
616 if(res != (int) csp->len) {
617 premature(csp);
618 return 0;
620 csp->ptr += csp->len;
621 rb->strncpy(seg_desc, (char *) rbuf, (unsigned) csp->len);
622 seg_desc[csp->len] = '\0';
623 break;
625 case 0x32:
626 csp->type = ST_MISC;
627 csp->segtype = SEG_SKIP;
629 int numstr, i;
631 i = 0;
632 numstr = next_data();
633 for(;numstr > 0; numstr--) {
634 int tlen, tid, b;
636 tid = next_data();
637 tlen = next_data();
638 if(tid < 0 || tlen < 0) return 0;
640 for(; tlen; tlen--) {
641 b = next_data();
642 if(b < 0) return 0;
643 seg_desc[i++] = b;
645 seg_desc[i++] = '\n';
647 seg_desc[i] = '\0';
649 break;
651 case 0x33:
652 rb->snprintf(seg_desc,DESC_LEN, "Hardware Information (Not yet supported)");
653 csp->type = ST_MISC;
654 csp->segtype = SEG_SKIP;
655 break;
657 case 0x34:
658 rb->snprintf(seg_desc, DESC_LEN,"Emulation Information (Not yet supported)");
659 csp->type = ST_MISC;
660 csp->segtype = SEG_SKIP;
661 break;
663 case 0x35:
664 rb->snprintf(seg_desc,DESC_LEN, "Custom Information (Not yet supported)");
665 csp->type = ST_MISC;
666 csp->segtype = SEG_SKIP;
667 break;
669 case 0x40:
670 rb->snprintf(seg_desc, DESC_LEN,"Snapshot (Not yet supported)");
671 csp->type = ST_MISC;
672 csp->segtype = SEG_SKIP;
673 break;
675 case 0x5A:
676 rb->snprintf(seg_desc, DESC_LEN,"Tapefile Concatenation Point");
677 csp->type = ST_MISC;
678 csp->segtype = SEG_SKIP;
680 default:
681 csp->type = ST_MISC;
682 csp->segtype = SEG_SKIP;
683 rb->snprintf(seg_desc,DESC_LEN, "Unknown TZX block (id: %02X, version: %i.%02i)",
684 segid, tf_tpi.tzxmajver, tf_tpi.tzxminver);
685 break;
688 return 1;
691 static int interpret_header(byte *hb, struct seginfo *csp)
693 if(tf_tpi.type == TAP_TAP) {
694 normal_segment(csp);
695 csp->pause = DEF_LEAD_PAUSE;
697 return 1;
699 else if(tf_tpi.type == TAP_TZX)
700 return interpret_tzx_header(hb, csp);
702 return 0;
705 byte *tf_get_block(int i)
707 seg_desc[0] = '\0';
709 if(jump_to_segment(i, &tf_cseg)) {
710 tf_segoffs = ftell(tapefd);
712 if(read_header(rbuf, &tf_cseg) &&
713 interpret_header(rbuf, &tf_cseg)) return rbuf;
715 return NULL;
719 int next_byte(void)
721 playstate = PL_NONE;
722 return next_data();
725 #define DPULSE(v1,v2) (*impbuf++=(v1), *impbuf++=(v2), timelen-=(v1)+(v2))
726 #define PULSE(v) (*impbuf++=(v), currlev = !currlev, timelen-=(v))
728 int next_imps(unsigned short *impbuf, int buflen, long timelen)
730 static int toput;
731 static int bitrem;
732 static dbyte dirpulse;
733 unsigned short *impbufend, *impbufstart;
735 impbufstart = impbuf;
736 impbufend = impbuf + buflen;
738 while(impbuf < impbufend - 1 && timelen > 0) {
739 switch(playstate) {
741 case PL_PAUSE:
742 if(currlev && lead_pause) {
743 PULSE(IMP_1MS);
744 lead_pause --;
746 else if(lead_pause > 10) {
747 if(tapeopt.blanknoise && !(rb->rand() % 64))
748 DPULSE(IMP_1MS * 10 - 1000, 1000);
749 else
750 DPULSE(IMP_1MS * 10, 0);
751 lead_pause -= 10;
753 else if(lead_pause) {
754 DPULSE(IMP_1MS, 0);
755 lead_pause --;
757 else {
758 if(tf_cseg.num || tf_cseg.sync1p || tf_cseg.sync2p ||
759 tf_cseg.ptr != tf_cseg.len) finished = 0;
761 switch (tf_cseg.type) {
762 case ST_NORM: playstate = PL_LEADER; break;
763 case ST_DIRE: playstate = PL_DIRE; dirpulse = 0; break;
764 case ST_PSEQ: playstate = PL_PSEQ; break;
765 default: playstate = PL_NONE;
768 break;
770 case PL_LEADER:
771 if(tf_cseg.num >= 2) {
772 DPULSE(tf_cseg.pulse, tf_cseg.pulse);
773 tf_cseg.num -= 2;
775 else
776 if(tf_cseg.num) {
777 PULSE(tf_cseg.pulse);
778 tf_cseg.num --;
780 else { /* PL_SYNC */
781 if(tf_cseg.sync1p || tf_cseg.sync2p)
782 DPULSE(tf_cseg.sync1p, tf_cseg.sync2p);
783 bitrem = 0;
784 playstate = PL_DATA;
786 break;
788 case PL_DATA:
789 if(!bitrem) {
790 toput = next_data();
791 if(toput < 0) {
792 playstate = PL_END;
793 break;
795 if(tf_cseg.ptr != tf_cseg.len) {
796 if(timelen > 16 * max(tf_cseg.onep, tf_cseg.zerop) &&
797 impbuf <= impbufend - 16) {
798 int p1, p2, br, tp;
800 p1 = tf_cseg.onep;
801 p2 = tf_cseg.zerop;
802 br = 8;
803 tp = toput;
805 while(br) {
806 if(tp & 0x80) DPULSE(p1, p1);
807 else DPULSE(p2, p2);
808 br--;
809 tp <<= 1;
811 bitrem = 0;
812 break;
814 bitrem = 8;
816 else {
817 bitrem = tf_cseg.bused;
818 if(!bitrem) break;
821 if(toput & 0x80) DPULSE(tf_cseg.onep, tf_cseg.onep);
822 else DPULSE(tf_cseg.zerop, tf_cseg.zerop);
823 bitrem--, toput <<= 1;
824 break;
826 case PL_PSEQ:
828 int b1, b2;
829 dbyte pulse1, pulse2;
830 b1 = next_data();
831 b2 = next_data();
832 if(b1 < 0 || b2 < 0) {
833 playstate = PL_END;
834 break;
836 pulse1 = b1 + (b2 << 8);
838 b1 = next_data();
839 b2 = next_data();
840 if(b1 < 0 || b2 < 0) {
841 PULSE(pulse1);
842 playstate = PL_END;
843 break;
845 pulse2 = b1 + (b2 << 8);
846 DPULSE(pulse1, pulse2);
848 break;
850 case PL_DIRE:
851 for(;;) {
852 if(!bitrem) {
853 toput = next_data();
854 if(toput < 0) {
855 playstate = PL_END;
856 DPULSE(dirpulse, 0);
857 break;
859 if(tf_cseg.ptr != tf_cseg.len) bitrem = 8;
860 else {
861 bitrem = tf_cseg.bused;
862 if(!bitrem) break;
865 bitrem--;
866 toput <<= 1;
867 if(((toput & 0x0100) ^ (currlev ? 0x0100 : 0x00))) {
868 PULSE(dirpulse);
869 dirpulse = tf_cseg.pulse;
870 break;
872 dirpulse += tf_cseg.pulse;
873 if(dirpulse >= 0x8000) {
874 DPULSE(dirpulse, 0);
875 dirpulse = 0;
876 break;
879 break;
881 case PL_END:
882 if(tf_cseg.pause) {
883 PULSE(IMP_1MS);
884 tf_cseg.pause--;
885 if(currlev) PULSE(0);
886 finished = 1;
888 playstate = PL_NONE;
889 break;
891 case PL_NONE:
892 default:
893 return PTRDIFF(impbuf, impbufstart);
897 return PTRDIFF(impbuf, impbufstart);
901 int next_segment(void)
903 if(endnext) {
904 endnext = 0;
905 tf_cseg.segtype = endtype;
906 tf_cseg.pause = endpause;
907 playstate = endplay;
908 return tf_cseg.segtype;
911 seg_desc[0] = '\0';
912 lead_pause = tf_cseg.pause;
914 if(end_seg(&tf_cseg)) {
915 currsegi = segi;
916 if(read_header(rbuf, &tf_cseg)) interpret_header(rbuf, &tf_cseg);
919 if(tf_cseg.segtype >= SEG_DATA) {
920 playstate = PL_PAUSE;
921 if(lead_pause) finished = 1;
923 else playstate = PL_NONE;
925 if(tf_cseg.segtype <= SEG_STOP && !finished) {
926 endnext = 1;
927 endtype = tf_cseg.segtype;
928 endpause = tf_cseg.pause;
929 endplay = playstate;
930 if(lead_pause > 0) lead_pause--;
932 tf_cseg.pause = 1;
933 tf_cseg.segtype = SEG_VIRTUAL;
934 playstate = PL_END;
937 return tf_cseg.segtype;
940 int goto_segment(int at_seg)
942 int res;
944 res = jump_to_segment(at_seg, &tf_cseg);
945 tf_cseg.pause = DEF_LEAD_PAUSE;
947 return res;
950 unsigned segment_pos(void)
952 return currsegi;
955 void close_tapefile(void)
957 if(tapefd != -1) {
958 playstate = PL_NONE;
959 rb->close(tapefd);
960 tapefd = -1;
964 int open_tapefile(char *name, int type)
966 int res;
967 int ok;
969 seg_desc[0] = '\0';
970 currlev = 0;
972 if(type != TAP_TAP && type != TAP_TZX) {
973 rb->snprintf(seg_desc,DESC_LEN, "Illegal tape type");
974 return 0;
977 /*tapefp = fopen(name, "rb");*/
978 tapefd = rb->open(name, O_RDONLY);
979 if(tapefd < 0 ) {
980 /*rb->snprintf(seg_desc,DESC_LEN, "Could not open `%s': %s", name, strerror(errno));*/
981 return 0;
984 tf_tpi.type = type;
985 tf_cseg.pause = DEF_LEAD_PAUSE;
986 INITTAPEOPT(tapeopt);
988 currsegi = segi = 0;
989 isbeg();
991 firstseg_offs = 0;
993 ok = 1;
995 if(tf_tpi.type == TAP_TZX) {
997 firstseg_offs = 10;
998 res = readbuf(rbuf, 10, tapefd);
999 if(res == 10 && rb->strncasecmp((char *)rbuf, tzxheader, 8) == 0) {
1000 tf_tpi.tzxmajver = rbuf[8];
1001 tf_tpi.tzxminver = rbuf[9];
1003 if(tf_tpi.tzxmajver > TZXMAJPROG) {
1004 rb->snprintf(seg_desc, DESC_LEN,
1005 "Cannot handle TZX file version (%i.%02i)",
1006 tf_tpi.tzxmajver, tf_tpi.tzxminver);
1007 ok = 0;
1010 else {
1011 rb->snprintf(seg_desc,DESC_LEN, "Illegal TZX file header");
1012 ok = 0;
1016 if(!ok) {
1017 close_tapefile();
1018 return 0;
1020 endnext = 0;
1022 loopctr = 0;
1023 callctr = 0;
1025 return 1;
1028 int get_level(void)
1030 return currlev;
1033 long get_seglen(void)
1035 return tf_cseg.len;
1038 long get_segpos(void)
1040 return tf_cseg.ptr;
1043 void set_tapefile_options(struct tape_options *to)
1045 rb->memcpy(&tapeopt, to, sizeof(tapeopt));