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. */
32 #include <sys/types.h>
35 #define max(x, y) ((x) > (y) ? (x) : (y))
39 char seg_desc
[DESC_LEN
];
44 /*static FILE *tapefp = NULL;*/
47 static dbyte segi
, currsegi
;
50 static int endtype
, endnext
, endplay
;
51 static dbyte endpause
;
54 static long firstseg_offs
;
56 static struct tape_options tapeopt
;
59 struct tapeinfo tf_tpi
;
61 static dbyte loopctr
, loopbeg
;
62 static dbyte callctr
, callbeg
;
79 static dbyte lead_pause
;
80 static int playstate
= PL_NONE
;
83 #define DEF_LEAD_PAUSE 2000
85 struct seginfo tf_cseg
;
94 #define NUMBLOCKID 0x60
95 /* changed NONE because of warinigs */
104 static byte rbuf
[RBUFLEN
];
106 /* Table containing information on TZX blocks */
108 static struct tzxblock tzxb
[NUMBLOCKID
] = {
109 { NONE
}, /* ID: 00 */
118 { NONE
}, /* ID: 08 */
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 },
136 { NONE
}, /* ID: 18 */
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 */
156 { STAN
, 0, 1, 0x00 },
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 },
172 { NONE
}, /* ID: 38 */
181 { COMM
, 3, 1, 0x04 }, /* ID: 40 */
190 { NONE
}, /* ID: 48 */
199 { NONE
}, /* ID: 50 */
208 { NONE
}, /* ID: 58 */
210 { COMM
, 0, 1, 0x09 },
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
)
239 int lenoffs
, lenbytes
, lenmul
, lenadd
;
244 segid
= getc(tapefd
);
246 csp
->segtype
= SEG_END
;
247 rb
->snprintf(seg_desc
,DESC_LEN
, "End of Tape");
251 hb
[0] = (byte
) segid
;
253 if(segid
< NUMBLOCKID
) seght
= tzxb
[segid
].type
;
254 else seght
= 0; /* was NONE here*/
257 lenbytes
= tzxb
[segid
].lenbytes
;
258 lenmul
= tzxb
[segid
].lenmul
;
259 hlen
= tzxb
[segid
].hlen
;
261 lenoffs
= hlen
- lenbytes
;
271 if(seght
== STAN
) hlen
+= tzxb
[segid
].hlen
;
274 res
= readbuf(hip
, hlen
, tapefd
);
280 for(;lenbytes
; lenbytes
--)
281 length
= (length
<< 8) + hip
[lenoffs
+ lenbytes
- 1];
283 length
= (length
* lenmul
) + lenadd
- hlen
;
289 static int read_tap_header(byte
*hb
, struct seginfo
*csp
)
293 res
= readbuf(hb
, 2, tapefd
);
296 csp
->segtype
= SEG_END
;
297 rb
->snprintf(seg_desc
,DESC_LEN
, "End of Tape");
302 csp
->len
= DBYTE(hb
, 0);
306 static int read_header(byte
*hb
, struct seginfo
*csp
)
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
);
320 static void isbeg(void)
323 tf_cseg
.len
= tf_cseg
.ptr
= 0;
327 static int end_seg(struct seginfo
*csp
)
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
) {
347 static int jump_to_segment(int newsegi
, struct seginfo
*csp
)
349 if(newsegi
<= segi
) {
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;
365 static int next_data(void)
368 if(tf_cseg
.ptr
== tf_cseg
.len
) return DAT_END
;
372 rb
->snprintf(seg_desc
, DESC_LEN
,"Premature end of segment");
380 static void normal_segment(struct seginfo
*csp
)
382 rb
->snprintf(seg_desc
,DESC_LEN
, "Data");
384 csp
->segtype
= SEG_DATA
;
385 csp
->pulse
= 2168; /* 2016 */
389 csp
->zerop
= 855; /* 672 */
390 csp
->onep
= 1710; /* 1568 */
395 static int interpret_tzx_header(byte
*hb
, struct seginfo
*csp
)
409 csp
->pause
= DBYTE(hip
, 0x00);
413 rb
->snprintf(seg_desc
,DESC_LEN
, "Turbo Data");
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);
427 rb
->snprintf(seg_desc
,DESC_LEN
, "Pure Tone");
429 csp
->segtype
= SEG_OTHER
;
430 csp
->pulse
= DBYTE(hip
, 0x00);
431 csp
->num
= DBYTE(hip
, 0x02);
441 rb
->snprintf(seg_desc
,DESC_LEN
, "Pulse Sequence");
443 csp
->segtype
= SEG_OTHER
;
448 rb
->snprintf(seg_desc
,DESC_LEN
, "Pure Data");
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);
462 rb
->snprintf(seg_desc
,DESC_LEN
, "Direct Recording");
464 csp
->segtype
= SEG_OTHER
;
465 csp
->pulse
= DBYTE(hip
, 0x00);
466 csp
->pause
= DBYTE(hip
, 0x02);
467 csp
->bused
= BYTE(hip
, 0x04);
471 dtmp
= DBYTE(hip
, 0x00);
473 if(!tapeopt
.stoppause
) {
475 csp
->segtype
= SEG_STOP
;
478 csp
->pause
= tapeopt
.stoppause
* 1000;
480 csp
->segtype
= SEG_PAUSE
;
482 rb
->snprintf(seg_desc
,DESC_LEN
, "Stop the Tape Mark");
487 csp
->segtype
= SEG_PAUSE
;
488 rb
->snprintf(seg_desc
,DESC_LEN
, "Pause for %i.%03is",
489 csp
->pause
/ 1000, csp
->pause
% 1000);
502 csp
->segtype
= SEG_GRP_BEG
;
503 res
= readbuf(rbuf
, csp
->len
, tapefd
);
504 if(res
!= (int) csp
->len
) {
508 csp
->ptr
+= csp
->len
;
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';
519 rb
->snprintf(seg_desc
,DESC_LEN
, "End Group");
521 csp
->segtype
= SEG_GRP_END
;
525 offs
= (signed short) DBYTE(hip
, 0x00);
527 rb
->snprintf(seg_desc
,DESC_LEN
, "Infinite loop");
529 csp
->segtype
= SEG_STOP
;
533 csp
->segtype
= SEG_SKIP
;
534 rb
->snprintf(seg_desc
,DESC_LEN
, "Jump to %i", segi
+offs
);
535 jump_to_segment(segi
+ offs
, csp
);
540 loopctr
= DBYTE(hip
, 0x00);
541 rb
->snprintf(seg_desc
,DESC_LEN
, "Loop %i times", loopctr
);
544 csp
->segtype
= SEG_SKIP
;
549 csp
->segtype
= SEG_SKIP
;
550 if(loopctr
) 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");
560 csp
->segtype
= SEG_SKIP
;
561 dtmp
= DBYTE(hip
, 0x00);
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
);
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
);
581 rb
->snprintf(seg_desc
,DESC_LEN
, "Call Sequence End");
587 csp
->segtype
= SEG_SKIP
;
588 rb
->snprintf(seg_desc
,DESC_LEN
, "Return");
589 if(callctr
> 0) jump_to_segment(callbeg
, csp
);
593 rb
->snprintf(seg_desc
,DESC_LEN
, "Selection (Not yet supported)");
595 csp
->segtype
= SEG_SKIP
;
599 if(tapeopt
.machine
== MACHINE_48
) {
600 rb
->snprintf(seg_desc
,DESC_LEN
, "Stop the Tape in 48k Mode (Stopped)");
602 csp
->segtype
= SEG_STOP
;
605 rb
->snprintf(seg_desc
,DESC_LEN
, "Stop the Tape in 48k Mode (Not Stopped)");
607 csp
->segtype
= SEG_SKIP
;
614 csp
->segtype
= SEG_SKIP
;
615 res
= readbuf(rbuf
, csp
->len
, tapefd
);
616 if(res
!= (int) csp
->len
) {
620 csp
->ptr
+= csp
->len
;
621 rb
->strncpy(seg_desc
, (char *) rbuf
, (unsigned) csp
->len
);
622 seg_desc
[csp
->len
] = '\0';
627 csp
->segtype
= SEG_SKIP
;
632 numstr
= next_data();
633 for(;numstr
> 0; numstr
--) {
638 if(tid
< 0 || tlen
< 0) return 0;
640 for(; tlen
; tlen
--) {
645 seg_desc
[i
++] = '\n';
652 rb
->snprintf(seg_desc
,DESC_LEN
, "Hardware Information (Not yet supported)");
654 csp
->segtype
= SEG_SKIP
;
658 rb
->snprintf(seg_desc
, DESC_LEN
,"Emulation Information (Not yet supported)");
660 csp
->segtype
= SEG_SKIP
;
664 rb
->snprintf(seg_desc
,DESC_LEN
, "Custom Information (Not yet supported)");
666 csp
->segtype
= SEG_SKIP
;
670 rb
->snprintf(seg_desc
, DESC_LEN
,"Snapshot (Not yet supported)");
672 csp
->segtype
= SEG_SKIP
;
676 rb
->snprintf(seg_desc
, DESC_LEN
,"Tapefile Concatenation Point");
678 csp
->segtype
= SEG_SKIP
;
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
);
691 static int interpret_header(byte
*hb
, struct seginfo
*csp
)
693 if(tf_tpi
.type
== TAP_TAP
) {
695 csp
->pause
= DEF_LEAD_PAUSE
;
699 else if(tf_tpi
.type
== TAP_TZX
)
700 return interpret_tzx_header(hb
, csp
);
705 byte
*tf_get_block(int i
)
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
;
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
)
732 static dbyte dirpulse
;
733 unsigned short *impbufend
, *impbufstart
;
735 impbufstart
= impbuf
;
736 impbufend
= impbuf
+ buflen
;
738 while(impbuf
< impbufend
- 1 && timelen
> 0) {
742 if(currlev
&& lead_pause
) {
746 else if(lead_pause
> 10) {
747 if(tapeopt
.blanknoise
&& !(rb
->rand() % 64))
748 DPULSE(IMP_1MS
* 10 - 1000, 1000);
750 DPULSE(IMP_1MS
* 10, 0);
753 else if(lead_pause
) {
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
;
771 if(tf_cseg
.num
>= 2) {
772 DPULSE(tf_cseg
.pulse
, tf_cseg
.pulse
);
777 PULSE(tf_cseg
.pulse
);
781 if(tf_cseg
.sync1p
|| tf_cseg
.sync2p
)
782 DPULSE(tf_cseg
.sync1p
, tf_cseg
.sync2p
);
795 if(tf_cseg
.ptr
!= tf_cseg
.len
) {
796 if(timelen
> 16 * max(tf_cseg
.onep
, tf_cseg
.zerop
) &&
797 impbuf
<= impbufend
- 16) {
806 if(tp
& 0x80) DPULSE(p1
, p1
);
817 bitrem
= tf_cseg
.bused
;
821 if(toput
& 0x80) DPULSE(tf_cseg
.onep
, tf_cseg
.onep
);
822 else DPULSE(tf_cseg
.zerop
, tf_cseg
.zerop
);
823 bitrem
--, toput
<<= 1;
829 dbyte pulse1
, pulse2
;
832 if(b1
< 0 || b2
< 0) {
836 pulse1
= b1
+ (b2
<< 8);
840 if(b1
< 0 || b2
< 0) {
845 pulse2
= b1
+ (b2
<< 8);
846 DPULSE(pulse1
, pulse2
);
859 if(tf_cseg
.ptr
!= tf_cseg
.len
) bitrem
= 8;
861 bitrem
= tf_cseg
.bused
;
867 if(((toput
& 0x0100) ^ (currlev
? 0x0100 : 0x00))) {
869 dirpulse
= tf_cseg
.pulse
;
872 dirpulse
+= tf_cseg
.pulse
;
873 if(dirpulse
>= 0x8000) {
885 if(currlev
) PULSE(0);
893 return PTRDIFF(impbuf
, impbufstart
);
897 return PTRDIFF(impbuf
, impbufstart
);
901 int next_segment(void)
905 tf_cseg
.segtype
= endtype
;
906 tf_cseg
.pause
= endpause
;
908 return tf_cseg
.segtype
;
912 lead_pause
= tf_cseg
.pause
;
914 if(end_seg(&tf_cseg
)) {
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
) {
927 endtype
= tf_cseg
.segtype
;
928 endpause
= tf_cseg
.pause
;
930 if(lead_pause
> 0) lead_pause
--;
933 tf_cseg
.segtype
= SEG_VIRTUAL
;
937 return tf_cseg
.segtype
;
940 int goto_segment(int at_seg
)
944 res
= jump_to_segment(at_seg
, &tf_cseg
);
945 tf_cseg
.pause
= DEF_LEAD_PAUSE
;
950 unsigned segment_pos(void)
955 void close_tapefile(void)
964 int open_tapefile(char *name
, int type
)
972 if(type
!= TAP_TAP
&& type
!= TAP_TZX
) {
973 rb
->snprintf(seg_desc
,DESC_LEN
, "Illegal tape type");
977 /*tapefp = fopen(name, "rb");*/
978 tapefd
= rb
->open(name
, O_RDONLY
);
980 /*rb->snprintf(seg_desc,DESC_LEN, "Could not open `%s': %s", name, strerror(errno));*/
985 tf_cseg
.pause
= DEF_LEAD_PAUSE
;
986 INITTAPEOPT(tapeopt
);
995 if(tf_tpi
.type
== TAP_TZX
) {
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
);
1011 rb
->snprintf(seg_desc
,DESC_LEN
, "Illegal TZX file header");
1033 long get_seglen(void)
1038 long get_segpos(void)
1043 void set_tapefile_options(struct tape_options
*to
)
1045 rb
->memcpy(&tapeopt
, to
, sizeof(tapeopt
));