Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / zxbox / tapefile.c
blob92f4ea69f6b2757058fb189f2e0f7a0bc157b939
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 "inttypes.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->strlcpy(seg_desc+blen, (char *) rbuf, (unsigned) csp->len + 1);
515 break;
517 case 0x22:
518 rb->snprintf(seg_desc,DESC_LEN, "End Group");
519 csp->type = ST_MISC;
520 csp->segtype = SEG_GRP_END;
521 break;
523 case 0x23:
524 offs = (signed short) DBYTE(hip, 0x00);
525 if(offs == 0) {
526 rb->snprintf(seg_desc,DESC_LEN, "Infinite loop");
527 csp->type = ST_MISC;
528 csp->segtype = SEG_STOP;
530 else {
531 csp->type = ST_MISC;
532 csp->segtype = SEG_SKIP;
533 rb->snprintf(seg_desc,DESC_LEN, "Jump to %i", segi+offs);
534 jump_to_segment(segi + offs, csp);
536 break;
538 case 0x24:
539 loopctr = DBYTE(hip, 0x00);
540 rb->snprintf(seg_desc,DESC_LEN, "Loop %i times", loopctr);
541 loopbeg = segi+1;
542 csp->type = ST_MISC;
543 csp->segtype = SEG_SKIP;
544 break;
546 case 0x25:
547 csp->type = ST_MISC;
548 csp->segtype = SEG_SKIP;
549 if(loopctr) loopctr--;
550 if(loopctr) {
551 jump_to_segment(loopbeg, csp);
552 rb->snprintf(seg_desc,DESC_LEN, "Loop to: %i", loopbeg);
554 else rb->snprintf(seg_desc,DESC_LEN, "Loop End");
555 break;
557 case 0x26:
558 csp->type = ST_MISC;
559 csp->segtype = SEG_SKIP;
560 dtmp = DBYTE(hip, 0x00);
561 if(callctr < dtmp) {
562 int offset;
563 callbeg = segi;
564 /*fseek(tapefp, callctr*2, SEEK_CUR);*/
565 rb->lseek(tapefd, callctr*2, SEEK_CUR);
566 csp->ptr += callctr*2;
567 res = readbuf(rbuf, 2, tapefd);
568 if(res != 2) {
569 premature(csp);
570 return 0;
572 csp->ptr += 2;
573 offset = (signed short) DBYTE(rbuf, 0x00);
574 rb->snprintf(seg_desc,DESC_LEN, "Call to %i", segi+offset);
575 jump_to_segment(segi+offset, csp);
576 callctr++;
578 else {
579 callctr = 0;
580 rb->snprintf(seg_desc,DESC_LEN, "Call Sequence End");
582 break;
584 case 0x27:
585 csp->type = ST_MISC;
586 csp->segtype = SEG_SKIP;
587 rb->snprintf(seg_desc,DESC_LEN, "Return");
588 if(callctr > 0) jump_to_segment(callbeg, csp);
589 break;
591 case 0x28:
592 rb->snprintf(seg_desc,DESC_LEN, "Selection (Not yet supported)");
593 csp->type = ST_MISC;
594 csp->segtype = SEG_SKIP;
595 break;
597 case 0x2A:
598 if(tapeopt.machine == MACHINE_48) {
599 rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape in 48k Mode (Stopped)");
600 csp->type = ST_MISC;
601 csp->segtype = SEG_STOP;
603 else {
604 rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape in 48k Mode (Not Stopped)");
605 csp->type = ST_MISC;
606 csp->segtype = SEG_SKIP;
608 break;
610 case 0x31:
611 case 0x30:
612 csp->type = ST_MISC;
613 csp->segtype = SEG_SKIP;
614 res = readbuf(rbuf, csp->len, tapefd);
615 if(res != (int) csp->len) {
616 premature(csp);
617 return 0;
619 csp->ptr += csp->len;
620 rb->strlcpy(seg_desc, (char *) rbuf, (unsigned) csp->len + 1);
621 break;
623 case 0x32:
624 csp->type = ST_MISC;
625 csp->segtype = SEG_SKIP;
627 int numstr, i;
629 i = 0;
630 numstr = next_data();
631 for(;numstr > 0; numstr--) {
632 int tlen, tid, b;
634 tid = next_data();
635 tlen = next_data();
636 if(tid < 0 || tlen < 0) return 0;
638 for(; tlen; tlen--) {
639 b = next_data();
640 if(b < 0) return 0;
641 seg_desc[i++] = b;
643 seg_desc[i++] = '\n';
645 seg_desc[i] = '\0';
647 break;
649 case 0x33:
650 rb->snprintf(seg_desc,DESC_LEN, "Hardware Information (Not yet supported)");
651 csp->type = ST_MISC;
652 csp->segtype = SEG_SKIP;
653 break;
655 case 0x34:
656 rb->snprintf(seg_desc, DESC_LEN,"Emulation Information (Not yet supported)");
657 csp->type = ST_MISC;
658 csp->segtype = SEG_SKIP;
659 break;
661 case 0x35:
662 rb->snprintf(seg_desc,DESC_LEN, "Custom Information (Not yet supported)");
663 csp->type = ST_MISC;
664 csp->segtype = SEG_SKIP;
665 break;
667 case 0x40:
668 rb->snprintf(seg_desc, DESC_LEN,"Snapshot (Not yet supported)");
669 csp->type = ST_MISC;
670 csp->segtype = SEG_SKIP;
671 break;
673 case 0x5A:
674 rb->snprintf(seg_desc, DESC_LEN,"Tapefile Concatenation Point");
675 csp->type = ST_MISC;
676 csp->segtype = SEG_SKIP;
678 default:
679 csp->type = ST_MISC;
680 csp->segtype = SEG_SKIP;
681 rb->snprintf(seg_desc,DESC_LEN, "Unknown TZX block (id: %02X, version: %i.%02i)",
682 segid, tf_tpi.tzxmajver, tf_tpi.tzxminver);
683 break;
686 return 1;
689 static int interpret_header(byte *hb, struct seginfo *csp)
691 if(tf_tpi.type == TAP_TAP) {
692 normal_segment(csp);
693 csp->pause = DEF_LEAD_PAUSE;
695 return 1;
697 else if(tf_tpi.type == TAP_TZX)
698 return interpret_tzx_header(hb, csp);
700 return 0;
703 byte *tf_get_block(int i)
705 seg_desc[0] = '\0';
707 if(jump_to_segment(i, &tf_cseg)) {
708 tf_segoffs = ftell(tapefd);
710 if(read_header(rbuf, &tf_cseg) &&
711 interpret_header(rbuf, &tf_cseg)) return rbuf;
713 return NULL;
717 int next_byte(void)
719 playstate = PL_NONE;
720 return next_data();
723 #define DPULSE(v1,v2) (*impbuf++=(v1), *impbuf++=(v2), timelen-=(v1)+(v2))
724 #define PULSE(v) (*impbuf++=(v), currlev = !currlev, timelen-=(v))
726 int next_imps(unsigned short *impbuf, int buflen, long timelen)
728 static int toput;
729 static int bitrem;
730 static dbyte dirpulse;
731 unsigned short *impbufend, *impbufstart;
733 impbufstart = impbuf;
734 impbufend = impbuf + buflen;
736 while(impbuf < impbufend - 1 && timelen > 0) {
737 switch(playstate) {
739 case PL_PAUSE:
740 if(currlev && lead_pause) {
741 PULSE(IMP_1MS);
742 lead_pause --;
744 else if(lead_pause > 10) {
745 if(tapeopt.blanknoise && !(rb->rand() % 64))
746 DPULSE(IMP_1MS * 10 - 1000, 1000);
747 else
748 DPULSE(IMP_1MS * 10, 0);
749 lead_pause -= 10;
751 else if(lead_pause) {
752 DPULSE(IMP_1MS, 0);
753 lead_pause --;
755 else {
756 if(tf_cseg.num || tf_cseg.sync1p || tf_cseg.sync2p ||
757 tf_cseg.ptr != tf_cseg.len) finished = 0;
759 switch (tf_cseg.type) {
760 case ST_NORM: playstate = PL_LEADER; break;
761 case ST_DIRE: playstate = PL_DIRE; dirpulse = 0; break;
762 case ST_PSEQ: playstate = PL_PSEQ; break;
763 default: playstate = PL_NONE;
766 break;
768 case PL_LEADER:
769 if(tf_cseg.num >= 2) {
770 DPULSE(tf_cseg.pulse, tf_cseg.pulse);
771 tf_cseg.num -= 2;
773 else
774 if(tf_cseg.num) {
775 PULSE(tf_cseg.pulse);
776 tf_cseg.num --;
778 else { /* PL_SYNC */
779 if(tf_cseg.sync1p || tf_cseg.sync2p)
780 DPULSE(tf_cseg.sync1p, tf_cseg.sync2p);
781 bitrem = 0;
782 playstate = PL_DATA;
784 break;
786 case PL_DATA:
787 if(!bitrem) {
788 toput = next_data();
789 if(toput < 0) {
790 playstate = PL_END;
791 break;
793 if(tf_cseg.ptr != tf_cseg.len) {
794 if(timelen > 16 * max(tf_cseg.onep, tf_cseg.zerop) &&
795 impbuf <= impbufend - 16) {
796 int p1, p2, br, tp;
798 p1 = tf_cseg.onep;
799 p2 = tf_cseg.zerop;
800 br = 8;
801 tp = toput;
803 while(br) {
804 if(tp & 0x80) DPULSE(p1, p1);
805 else DPULSE(p2, p2);
806 br--;
807 tp <<= 1;
809 bitrem = 0;
810 break;
812 bitrem = 8;
814 else {
815 bitrem = tf_cseg.bused;
816 if(!bitrem) break;
819 if(toput & 0x80) DPULSE(tf_cseg.onep, tf_cseg.onep);
820 else DPULSE(tf_cseg.zerop, tf_cseg.zerop);
821 bitrem--, toput <<= 1;
822 break;
824 case PL_PSEQ:
826 int b1, b2;
827 dbyte pulse1, pulse2;
828 b1 = next_data();
829 b2 = next_data();
830 if(b1 < 0 || b2 < 0) {
831 playstate = PL_END;
832 break;
834 pulse1 = b1 + (b2 << 8);
836 b1 = next_data();
837 b2 = next_data();
838 if(b1 < 0 || b2 < 0) {
839 PULSE(pulse1);
840 playstate = PL_END;
841 break;
843 pulse2 = b1 + (b2 << 8);
844 DPULSE(pulse1, pulse2);
846 break;
848 case PL_DIRE:
849 for(;;) {
850 if(!bitrem) {
851 toput = next_data();
852 if(toput < 0) {
853 playstate = PL_END;
854 DPULSE(dirpulse, 0);
855 break;
857 if(tf_cseg.ptr != tf_cseg.len) bitrem = 8;
858 else {
859 bitrem = tf_cseg.bused;
860 if(!bitrem) break;
863 bitrem--;
864 toput <<= 1;
865 if(((toput & 0x0100) ^ (currlev ? 0x0100 : 0x00))) {
866 PULSE(dirpulse);
867 dirpulse = tf_cseg.pulse;
868 break;
870 dirpulse += tf_cseg.pulse;
871 if(dirpulse >= 0x8000) {
872 DPULSE(dirpulse, 0);
873 dirpulse = 0;
874 break;
877 break;
879 case PL_END:
880 if(tf_cseg.pause) {
881 PULSE(IMP_1MS);
882 tf_cseg.pause--;
883 if(currlev) PULSE(0);
884 finished = 1;
886 playstate = PL_NONE;
887 break;
889 case PL_NONE:
890 default:
891 return PTRDIFF(impbuf, impbufstart);
895 return PTRDIFF(impbuf, impbufstart);
899 int next_segment(void)
901 if(endnext) {
902 endnext = 0;
903 tf_cseg.segtype = endtype;
904 tf_cseg.pause = endpause;
905 playstate = endplay;
906 return tf_cseg.segtype;
909 seg_desc[0] = '\0';
910 lead_pause = tf_cseg.pause;
912 if(end_seg(&tf_cseg)) {
913 currsegi = segi;
914 if(read_header(rbuf, &tf_cseg)) interpret_header(rbuf, &tf_cseg);
917 if(tf_cseg.segtype >= SEG_DATA) {
918 playstate = PL_PAUSE;
919 if(lead_pause) finished = 1;
921 else playstate = PL_NONE;
923 if(tf_cseg.segtype <= SEG_STOP && !finished) {
924 endnext = 1;
925 endtype = tf_cseg.segtype;
926 endpause = tf_cseg.pause;
927 endplay = playstate;
928 if(lead_pause > 0) lead_pause--;
930 tf_cseg.pause = 1;
931 tf_cseg.segtype = SEG_VIRTUAL;
932 playstate = PL_END;
935 return tf_cseg.segtype;
938 int goto_segment(int at_seg)
940 int res;
942 res = jump_to_segment(at_seg, &tf_cseg);
943 tf_cseg.pause = DEF_LEAD_PAUSE;
945 return res;
948 unsigned segment_pos(void)
950 return currsegi;
953 void close_tapefile(void)
955 if(tapefd != -1) {
956 playstate = PL_NONE;
957 rb->close(tapefd);
958 tapefd = -1;
962 int open_tapefile(char *name, int type)
964 int res;
965 int ok;
967 seg_desc[0] = '\0';
968 currlev = 0;
970 if(type != TAP_TAP && type != TAP_TZX) {
971 rb->snprintf(seg_desc,DESC_LEN, "Illegal tape type");
972 return 0;
975 /*tapefp = fopen(name, "rb");*/
976 tapefd = rb->open(name, O_RDONLY);
977 if(tapefd < 0 ) {
978 /*rb->snprintf(seg_desc,DESC_LEN, "Could not open `%s': %s", name, strerror(errno));*/
979 return 0;
982 tf_tpi.type = type;
983 tf_cseg.pause = DEF_LEAD_PAUSE;
984 INITTAPEOPT(tapeopt);
986 currsegi = segi = 0;
987 isbeg();
989 firstseg_offs = 0;
991 ok = 1;
993 if(tf_tpi.type == TAP_TZX) {
995 firstseg_offs = 10;
996 res = readbuf(rbuf, 10, tapefd);
997 if(res == 10 && rb->strncasecmp((char *)rbuf, tzxheader, 8) == 0) {
998 tf_tpi.tzxmajver = rbuf[8];
999 tf_tpi.tzxminver = rbuf[9];
1001 if(tf_tpi.tzxmajver > TZXMAJPROG) {
1002 rb->snprintf(seg_desc, DESC_LEN,
1003 "Cannot handle TZX file version (%i.%02i)",
1004 tf_tpi.tzxmajver, tf_tpi.tzxminver);
1005 ok = 0;
1008 else {
1009 rb->snprintf(seg_desc,DESC_LEN, "Illegal TZX file header");
1010 ok = 0;
1014 if(!ok) {
1015 close_tapefile();
1016 return 0;
1018 endnext = 0;
1020 loopctr = 0;
1021 callctr = 0;
1023 return 1;
1026 int get_level(void)
1028 return currlev;
1031 long get_seglen(void)
1033 return tf_cseg.len;
1036 long get_segpos(void)
1038 return tf_cseg.ptr;
1041 void set_tapefile_options(struct tape_options *to)
1043 rb->memcpy(&tapeopt, to, sizeof(tapeopt));