Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / apps / plugins / zxbox / sptape.c
blob80921a0afd126f90e899b49d13ec2903947866eb
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.
20 #include "zxmisc.h"
22 #include "sptape.h"
23 #include "tapefile.h"
25 #include "spperif.h"
26 #include "z80.h"
27 #include "interf.h"
28 #include "spconf.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
35 #define MAXLINELEN 256
37 int spt_auto_stop = 1;
39 static int playing = 0;
40 static int paused = 0;
42 static char tapename[MAXFILENAME];
43 static int tapetype;
45 #define EARBIT 0x40
47 #define IMPBUFLEN 1024
49 static int ingroup;
50 static int segtype;
52 static int lastdatak;
54 static int currseg;
56 static void stop_playing(void)
58 if(playing) close_tapefile();
59 playing = 0;
62 static void pause_playing(void)
64 if(playing) {
65 paused = 1;
66 playing = 0;
70 static void unpause_playing(void)
72 if(paused) {
73 paused = 0;
74 playing = 1;
75 segtype = SEG_END;
79 #define MAXDESCLEN 256
81 static void put_seg_desc(void)
83 if(segtype != SEG_VIRTUAL) {
84 if(segtype > SEG_END) {
85 if(!ingroup) {
86 long len;
87 int i, ml;
88 char *me;
90 len = get_seglen();
92 me = msgbuf;
93 rb->snprintf(me,MAXDESCLEN, "%4d: ", currseg);
94 me = me+rb->strlen(me);
95 if(segtype >= SEG_DATA && len) {
96 rb->snprintf(me,MAXDESCLEN, "%5ld bytes, ", len);
97 me = me+rb->strlen(me);
100 ml = 0;
101 for(i = 0; seg_desc[i]; i++) {
102 if(seg_desc[i] == '\n') {
103 *me = '\0';
104 put_msg(msgbuf);
106 me = msgbuf;
107 rb->snprintf(me,MAXDESCLEN, " ");
108 me = me+rb->strlen(me);
109 ml = 0;
111 else {
112 if(ml < MAXDESCLEN) *me++ = seg_desc[i];
113 ml++;
116 *me = '\0';
117 put_msg(msgbuf);
119 else {
120 rb->snprintf(msgbuf,MAXDESCLEN, "%4d:", currseg);
121 put_tmp_msg(msgbuf);
124 else put_msg(seg_desc);
126 #ifdef DEBUG_TAPE
127 else fprintf(stderr, "virtual segment\n");
128 #endif
131 static void get_next_segment(void)
133 int propseg;
135 do {
136 propseg = 1;
138 segtype = next_segment();
139 currseg = segment_pos();
141 put_seg_desc();
143 switch(segtype) {
144 case SEG_ERROR:
145 case SEG_END:
146 stop_playing();
147 break;
149 case SEG_STOP:
150 pause_playing();
151 put_msg(" * Tape paused; Press Ctrl-o to restart * ");
152 break;
154 case SEG_SKIP:
155 propseg = 0;
156 break;
158 case SEG_GRP_BEG:
159 ingroup = 1;
160 propseg = 0;
161 break;
163 case SEG_GRP_END:
164 ingroup = 0;
165 propseg = 0;
166 break;
168 } while(!propseg);
170 lastdatak = 0;
174 void play_tape(void)
176 static dbyte impbuf[IMPBUFLEN];
178 static int clevel;
179 static dbyte *impbufp;
180 static int impbufrem;
181 static long imprem;
183 static int cleared_buffers = 1;
185 int tsn;
186 dbyte *ibp;
187 byte *tsp;
188 int ibr;
189 long ir;
190 int cl;
191 signed char *op;
192 int ov;
193 int ca;
195 tsp = sp_tape_impinfo;
196 op = sp_tape_sound;
197 tsn = TMNUM;
199 if(!playing) {
200 if(cleared_buffers) return;
202 sp_playing_tape = 0;
204 if(!clevel) {
205 ca = CHKTICK;
206 clevel = ~clevel;
208 else {
209 ca = 0;
210 cleared_buffers = 1;
212 imprem = CHKTICK * TMNUM;
214 else if(!sp_playing_tape) {
215 sp_playing_tape = 1;
216 cleared_buffers = 0;
218 impbufrem = 0;
219 imprem = 0;
220 clevel = get_level() ? ~(0) : 0;
221 if(clevel) ca = 0;
222 else ca = 1;
224 else ca = 0;
226 #ifdef DEBUG_TAPE
227 if(((clevel ? 1 : 0) ^
228 (DANM(ula_inport) & EARBIT ? 1 : 0) ^
229 (DANM(imp_change) ? 1 : 0) ^
230 (ca ? 1 : 0)) == 0)
231 fprintf(stderr, "Levels don't match %i %i\n", imprem, impbufrem);
232 #endif
234 cl = clevel;
235 ibr = impbufrem;
236 ir = imprem;
237 ibp = impbufp;
239 if(cl) ov = CHKTICK/2;
240 else ov = -(CHKTICK/2);
242 do {
243 if(ir > 0) {
244 *tsp++ = ca;
245 *op++ = ov;
246 ir -= CHKTICK;
247 tsn--;
248 if(!tsn) goto done;
250 if(cl) ov = CHKTICK/2;
251 else ov = -(CHKTICK/2);
253 while(ir > 0) {
254 *tsp++ = 0;
255 *op++ = ov;
256 ir -= CHKTICK;
257 tsn--;
258 if(!tsn) goto done;
260 ca = 0;
262 if(ibr) {
263 if(!ca) {
264 if(cl) {
265 ov += ir;
266 ca = (CHKTICK/2) - ov + 1;
268 else {
269 ov -= ir;
270 ca = ov + (CHKTICK/2) + 1;
273 else {
274 ca = 0;
275 if(cl) ov += ir;
276 else ov -= ir;
278 ir += *ibp++;
279 ibr--;
280 cl = ~cl;
282 else {
283 ibp = impbuf;
284 do {
285 ibr = next_imps(impbuf, IMPBUFLEN, CHKTICK * tsn);
286 if(ibr) break;
287 get_next_segment();
288 if(!playing) {
289 if(!cl) {
290 if(ca) ca = 0;
291 else ca = CHKTICK;
292 cl = ~cl;
294 ir = tsn*CHKTICK;
295 ov = -(CHKTICK/2);
296 break;
298 } while(1);
301 } while(1);
303 done:
305 clevel = cl;
306 impbufrem = ibr;
307 imprem = ir;
308 impbufp = ibp;
310 if(segtype >= SEG_DATA) {
311 int datak;
313 datak = (int) (get_segpos() / 1000);
314 if(datak > lastdatak) {
315 if(ingroup) rb->snprintf(msgbuf,MAXDESCLEN, "%4d: ", currseg);
316 else rb->snprintf(msgbuf,MAXDESCLEN, " ");
317 rb->snprintf(msgbuf+rb->strlen(msgbuf),MAXDESCLEN, "%3dk", datak);
318 put_tmp_msg(msgbuf);
320 lastdatak = datak;
327 2168
328 2168 (9-10)
331 735 (2-4)
334 855 (3-5)
336 1710
337 1710 (7-9)
339 945 (4-5)
341 hosszu: 7..9
342 rovid: 2..5
346 #define MICBIT 0x08
349 #define RC_NONE 0
350 #define RC_LEADER 1
351 #define RC_SYNC 2
352 #define RC_DATA 3
354 #define MAXLEN TMNUM
356 #define LEADER_MIN 9
357 #define LEADER_MAX 10
358 #define SYNC_MIN 2
359 #define SYNC_MAX 4
361 #define BIT0_MIN 3
362 #define BIT0_MAX 5
363 #define BIT1_MIN 7
364 #define BIT1_MAX 9
366 #define LEADER_MIN_COUNT 512
367 #if 0
368 static int rec_segment;
369 static int rec_state = RC_NONE;
370 static byte *recbuf = NULL;
371 static const char *waitchars = "-\\|/";
372 #endif
373 static int recording = 0;
377 void rec_tape(void)
379 #if 0
380 static byte lastmic = 0;
381 static int lastlen = 0;
382 static int whole;
383 static int leadercount;
384 static byte data;
385 static byte parity;
386 static int bitnum;
387 static int bytecount;
388 static int recbufsize;
389 static int firsthalf;
390 static int frameswait = 0;
392 int tsl;
393 byte *fep;
394 int thishalf;
397 if(!recording) return;
399 for(fep = sp_fe_outport_time, tsl = TMNUM; tsl; fep++, tsl--) {
400 lastlen++;
401 if((*fep & MICBIT) == lastmic) {
402 if(lastlen < MAXLEN) continue;
404 else lastmic = ~lastmic & MICBIT;
406 switch(rec_state) {
407 case RC_NONE:
408 if(lastlen >= LEADER_MIN && lastlen <= LEADER_MAX) {
409 rec_state = RC_LEADER;
411 leadercount = 0;
412 break;
414 if((frameswait++ & 15)) break;
415 frameswait &= 0x3F;
416 sprintf(msgbuf, " %s: WAITING %c",
417 tapename, waitchars[(frameswait >> 4)]);
418 put_tmp_msg(msgbuf);
419 break;
420 case RC_LEADER:
421 if(lastlen >= LEADER_MIN && lastlen <= LEADER_MAX) {
422 leadercount++;
423 if(leadercount == LEADER_MIN_COUNT) {
424 sprintf(msgbuf, " %s: LEADER", tapename);
425 put_tmp_msg(msgbuf);
427 break;
429 if(leadercount >= LEADER_MIN_COUNT &&
430 lastlen >= SYNC_MIN && lastlen <= SYNC_MAX) rec_state = RC_SYNC;
431 else rec_state = RC_NONE;
432 break;
433 case RC_SYNC:
434 if(lastlen >= SYNC_MIN && lastlen <= SYNC_MAX) {
435 rec_state = RC_DATA;
436 whole = 0;
437 data = 0;
438 bitnum = 0;
439 bytecount = 0;
440 recbuf = NULL;
441 recbufsize = 0;
442 parity = 0;
444 sprintf(msgbuf, " %s: DATA", tapename);
445 put_tmp_msg(msgbuf);
447 else rec_state = RC_NONE;
448 break;
449 case RC_DATA:
450 thishalf = -1;
451 if(lastlen >= BIT0_MIN && lastlen <= BIT0_MAX) thishalf = 0;
452 else if(lastlen >= BIT1_MIN && lastlen <= BIT1_MAX) thishalf = 1;
454 if(thishalf < 0 || (whole && firsthalf != thishalf)) {
455 char filename[11];
456 int filesize;
457 int filetype;
459 sprintf(msgbuf, "%s: %03d", tapename, rec_segment);
460 if(bytecount >= 1) {
461 sprintf(msgbuf+strlen(msgbuf),
462 " %02X %5d %3s", recbuf[0], bytecount-2,
463 parity == 0 ? "OK" : "ERR");
464 if(recbuf[0] == 0 && bytecount - 2 >= 17) {
465 filetype = recbuf[1];
466 strncpy(filename, (char*) recbuf+2, 10);
467 filename[10] = '\0';
468 filesize = recbuf[12] + (recbuf[13] << 8);
470 sprintf(msgbuf+strlen(msgbuf),
471 " %02X %10s %5i", filetype, filename, filesize);
474 put_msg(msgbuf);
476 putc(bytecount & 0xFF, tapefp);
477 putc((bytecount >> 8) & 0xFF, tapefp);
479 fwrite(recbuf, 1, (size_t) bytecount, tapefp);
480 fflush(tapefp);
482 rec_segment++;
483 free(recbuf);
484 recbuf = NULL;
485 rec_state = RC_NONE;
486 break;
489 if(!whole) {
490 whole = 1;
491 firsthalf = thishalf;
493 else {
494 whole = 0;
495 data |= thishalf;
496 bitnum++;
498 if(bitnum == 8) {
499 bitnum = 0;
500 if(recbufsize <= bytecount) {
501 recbufsize += 1024;
502 recbuf = realloc(recbuf, (size_t) recbufsize);
503 if(recbuf == NULL) {
504 //fprintf(stderr, "Out of memory\n");
505 exit(1);
508 recbuf[bytecount] = data;
509 parity = parity ^ data;
510 data = 0;
511 bytecount++;
513 if(!(bytecount & 1023)) {
514 sprintf(msgbuf, " %s: DATA %i kB",
515 tapename, bytecount >> 10);
516 put_tmp_msg(msgbuf);
519 data <<= 1;
521 break;
524 lastlen = 0;
526 #endif
529 static void stop_recording(void)
531 #if 0
532 if(recording) {
533 recording = 0;
534 free(recbuf);
535 recbuf = NULL;
537 rb->close(tapefp);
539 #endif
542 static void restart_playing(void)
544 int res;
545 struct tape_options tapeopt;
547 if(tapetype < 0) {
548 tapetype = TAP_TZX;
549 res = open_tapefile(tapename, tapetype);
550 if(!res) {
551 tapetype = TAP_TAP;
552 res = open_tapefile(tapename, tapetype);
555 else res = open_tapefile(tapename, tapetype);
557 if(!res) {
558 put_msg(seg_desc);
559 return;
562 INITTAPEOPT(tapeopt);
563 #ifndef DEBUG_Z80
564 tapeopt.blanknoise = 1;
565 #endif
566 set_tapefile_options(&tapeopt);
568 if(currseg) {
569 res = goto_segment(currseg);
570 if(!res) {
571 put_msg(seg_desc);
572 return;
576 playing = 1;
577 segtype = SEG_END;
581 void pause_play(void)
583 if(playing) {
584 pause_playing();
585 put_msg(" * Tape paused * ");
586 goto_segment(currseg);
588 else unpause_playing();
592 void start_play_file_type(char *name, int seg, int type)
594 int filetype = FT_TAPEFILE;
596 rb->strlcpy(tapename, name, MAXFILENAME-10 + 1);
598 currseg = seg;
599 tapetype = type;
601 spcf_find_file_type(tapename, &filetype, &tapetype);
602 if(currseg < 0) currseg = 0;
604 ingroup = 0;
605 restart_playing();
608 void start_play(void)
610 char *name;
611 int t;
612 int seg;
614 if(playing || paused || recording) {
615 put_msg(" * Stop the tape first! * ");
616 return;
619 put_msg("Enter tape file path:");
620 name = spif_get_tape_fileinfo(&seg, &t);
621 if(name == NULL) return;
623 start_play_file_type(name, seg, -1);
627 void stop_play(void)
630 if(playing || paused) {
631 put_msg(" * Stopped playing * ");
633 if(playing) stop_playing();
634 if(paused) paused = 0;
636 else if(recording) {
637 #if 0
638 sprintf(msgbuf, " * Stopped recording tape `%s' * ", tapename);
639 put_msg(msgbuf);
640 #endif
641 stop_recording();
645 void start_rec(void)
647 #if 0
648 char *name;
650 if(playing || paused || recording) return;
652 put_msg("Enter tape file to record (default: '.tap'):");
654 name = spif_get_filename();
655 if(name == NULL) return;
657 strncpy(tapename, name, MAXFILENAME-10);
658 tapename[MAXFILENAME-10] = '\0';
660 if(!check_ext(tapename, "tap")) add_extension(tapename, "tap");
662 tapefp = fopen(tapename, "ab");
663 if(tapefp == NULL) {
664 sprintf(msgbuf, "Could not open tape file `%s', %s",
665 tapename, strerror(errno));
666 put_msg(msgbuf);
667 return;
670 recording = 1;
671 rec_segment = 0;
672 rec_state = RC_NONE;
674 sprintf(msgbuf,
675 "Recordind tape file `%s'. To stop press Ctrl-s", tapename);
676 put_msg(msgbuf);
677 #endif
680 #include "spkey_p.h"
682 #define CF 0x01
683 #define ZF 0x40
685 void qload(void)
687 byte type, parity;
688 dbyte length, dest, dtmp;
689 int verify, success, firstbyte;
690 int nextdata;
692 if(recording) {
693 put_msg("Can't quick load tape, because recording");
694 return;
697 do {
698 if(!playing) {
699 if(paused) unpause_playing();
700 else {
701 start_play();
704 if(!playing) {
705 put_msg("Not quick loading tape");
706 return;
708 while(playing && (segtype != SEG_DATA || get_segpos() > 0))
709 get_next_segment();
711 } while(!playing);
713 dtmp = AFBK;
714 AFBK = AF;
715 AF = dtmp;
717 type = RA;
718 verify = !(RF & CF);
719 length = DE;
720 firstbyte = !(RF & ZF);
721 dest = IX;
723 parity = 0;
724 success = 0;
726 do {
727 nextdata = next_byte();
728 if(nextdata < 0) break;
730 parity ^= nextdata;
732 if(!length) {
733 if(!parity) success = 1;
734 break;
737 if(firstbyte) {
738 firstbyte = 0;
739 if(nextdata != type) break;
741 else {
742 if(!verify) {
743 if(dest >= 0x4000) DANM(mem)[dest] = nextdata;
745 else {
746 if(DANM(mem)[dest] != nextdata) break;
748 dest++;
749 length--;
751 } while(1);
753 if(success) RF |= (CF | ZF);
754 else RF &= ~(CF | ZF);
755 IX = dest;
756 DE = length;
758 PC = SA_LD_RET;
759 DANM(iff1) = DANM(iff2) = 1;
760 DANM(haltstate) = 1;
762 sp_init_screen_mark();
764 if(spt_auto_stop) pause_playing();