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
->strlcpy(seg_desc
+blen
, (char *) rbuf
, (unsigned) csp
->len
+ 1);
518 rb
->snprintf(seg_desc
,DESC_LEN
, "End Group");
520 csp
->segtype
= SEG_GRP_END
;
524 offs
= (signed short) DBYTE(hip
, 0x00);
526 rb
->snprintf(seg_desc
,DESC_LEN
, "Infinite loop");
528 csp
->segtype
= SEG_STOP
;
532 csp
->segtype
= SEG_SKIP
;
533 rb
->snprintf(seg_desc
,DESC_LEN
, "Jump to %i", segi
+offs
);
534 jump_to_segment(segi
+ offs
, csp
);
539 loopctr
= DBYTE(hip
, 0x00);
540 rb
->snprintf(seg_desc
,DESC_LEN
, "Loop %i times", loopctr
);
543 csp
->segtype
= SEG_SKIP
;
548 csp
->segtype
= SEG_SKIP
;
549 if(loopctr
) 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");
559 csp
->segtype
= SEG_SKIP
;
560 dtmp
= DBYTE(hip
, 0x00);
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
);
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
);
580 rb
->snprintf(seg_desc
,DESC_LEN
, "Call Sequence End");
586 csp
->segtype
= SEG_SKIP
;
587 rb
->snprintf(seg_desc
,DESC_LEN
, "Return");
588 if(callctr
> 0) jump_to_segment(callbeg
, csp
);
592 rb
->snprintf(seg_desc
,DESC_LEN
, "Selection (Not yet supported)");
594 csp
->segtype
= SEG_SKIP
;
598 if(tapeopt
.machine
== MACHINE_48
) {
599 rb
->snprintf(seg_desc
,DESC_LEN
, "Stop the Tape in 48k Mode (Stopped)");
601 csp
->segtype
= SEG_STOP
;
604 rb
->snprintf(seg_desc
,DESC_LEN
, "Stop the Tape in 48k Mode (Not Stopped)");
606 csp
->segtype
= SEG_SKIP
;
613 csp
->segtype
= SEG_SKIP
;
614 res
= readbuf(rbuf
, csp
->len
, tapefd
);
615 if(res
!= (int) csp
->len
) {
619 csp
->ptr
+= csp
->len
;
620 rb
->strlcpy(seg_desc
, (char *) rbuf
, (unsigned) csp
->len
+ 1);
625 csp
->segtype
= SEG_SKIP
;
630 numstr
= next_data();
631 for(;numstr
> 0; numstr
--) {
636 if(tid
< 0 || tlen
< 0) return 0;
638 for(; tlen
; tlen
--) {
643 seg_desc
[i
++] = '\n';
650 rb
->snprintf(seg_desc
,DESC_LEN
, "Hardware Information (Not yet supported)");
652 csp
->segtype
= SEG_SKIP
;
656 rb
->snprintf(seg_desc
, DESC_LEN
,"Emulation Information (Not yet supported)");
658 csp
->segtype
= SEG_SKIP
;
662 rb
->snprintf(seg_desc
,DESC_LEN
, "Custom Information (Not yet supported)");
664 csp
->segtype
= SEG_SKIP
;
668 rb
->snprintf(seg_desc
, DESC_LEN
,"Snapshot (Not yet supported)");
670 csp
->segtype
= SEG_SKIP
;
674 rb
->snprintf(seg_desc
, DESC_LEN
,"Tapefile Concatenation Point");
676 csp
->segtype
= SEG_SKIP
;
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
);
689 static int interpret_header(byte
*hb
, struct seginfo
*csp
)
691 if(tf_tpi
.type
== TAP_TAP
) {
693 csp
->pause
= DEF_LEAD_PAUSE
;
697 else if(tf_tpi
.type
== TAP_TZX
)
698 return interpret_tzx_header(hb
, csp
);
703 byte
*tf_get_block(int i
)
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
;
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
)
730 static dbyte dirpulse
;
731 unsigned short *impbufend
, *impbufstart
;
733 impbufstart
= impbuf
;
734 impbufend
= impbuf
+ buflen
;
736 while(impbuf
< impbufend
- 1 && timelen
> 0) {
740 if(currlev
&& lead_pause
) {
744 else if(lead_pause
> 10) {
745 if(tapeopt
.blanknoise
&& !(rb
->rand() % 64))
746 DPULSE(IMP_1MS
* 10 - 1000, 1000);
748 DPULSE(IMP_1MS
* 10, 0);
751 else if(lead_pause
) {
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
;
769 if(tf_cseg
.num
>= 2) {
770 DPULSE(tf_cseg
.pulse
, tf_cseg
.pulse
);
775 PULSE(tf_cseg
.pulse
);
779 if(tf_cseg
.sync1p
|| tf_cseg
.sync2p
)
780 DPULSE(tf_cseg
.sync1p
, tf_cseg
.sync2p
);
793 if(tf_cseg
.ptr
!= tf_cseg
.len
) {
794 if(timelen
> 16 * max(tf_cseg
.onep
, tf_cseg
.zerop
) &&
795 impbuf
<= impbufend
- 16) {
804 if(tp
& 0x80) DPULSE(p1
, p1
);
815 bitrem
= tf_cseg
.bused
;
819 if(toput
& 0x80) DPULSE(tf_cseg
.onep
, tf_cseg
.onep
);
820 else DPULSE(tf_cseg
.zerop
, tf_cseg
.zerop
);
821 bitrem
--, toput
<<= 1;
827 dbyte pulse1
, pulse2
;
830 if(b1
< 0 || b2
< 0) {
834 pulse1
= b1
+ (b2
<< 8);
838 if(b1
< 0 || b2
< 0) {
843 pulse2
= b1
+ (b2
<< 8);
844 DPULSE(pulse1
, pulse2
);
857 if(tf_cseg
.ptr
!= tf_cseg
.len
) bitrem
= 8;
859 bitrem
= tf_cseg
.bused
;
865 if(((toput
& 0x0100) ^ (currlev
? 0x0100 : 0x00))) {
867 dirpulse
= tf_cseg
.pulse
;
870 dirpulse
+= tf_cseg
.pulse
;
871 if(dirpulse
>= 0x8000) {
883 if(currlev
) PULSE(0);
891 return PTRDIFF(impbuf
, impbufstart
);
895 return PTRDIFF(impbuf
, impbufstart
);
899 int next_segment(void)
903 tf_cseg
.segtype
= endtype
;
904 tf_cseg
.pause
= endpause
;
906 return tf_cseg
.segtype
;
910 lead_pause
= tf_cseg
.pause
;
912 if(end_seg(&tf_cseg
)) {
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
) {
925 endtype
= tf_cseg
.segtype
;
926 endpause
= tf_cseg
.pause
;
928 if(lead_pause
> 0) lead_pause
--;
931 tf_cseg
.segtype
= SEG_VIRTUAL
;
935 return tf_cseg
.segtype
;
938 int goto_segment(int at_seg
)
942 res
= jump_to_segment(at_seg
, &tf_cseg
);
943 tf_cseg
.pause
= DEF_LEAD_PAUSE
;
948 unsigned segment_pos(void)
953 void close_tapefile(void)
962 int open_tapefile(char *name
, int type
)
970 if(type
!= TAP_TAP
&& type
!= TAP_TZX
) {
971 rb
->snprintf(seg_desc
,DESC_LEN
, "Illegal tape type");
975 /*tapefp = fopen(name, "rb");*/
976 tapefd
= rb
->open(name
, O_RDONLY
);
978 /*rb->snprintf(seg_desc,DESC_LEN, "Could not open `%s': %s", name, strerror(errno));*/
983 tf_cseg
.pause
= DEF_LEAD_PAUSE
;
984 INITTAPEOPT(tapeopt
);
993 if(tf_tpi
.type
== TAP_TZX
) {
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
);
1009 rb
->snprintf(seg_desc
,DESC_LEN
, "Illegal TZX file header");
1031 long get_seglen(void)
1036 long get_segpos(void)
1041 void set_tapefile_options(struct tape_options
*to
)
1043 rb
->memcpy(&tapeopt
, to
, sizeof(tapeopt
));