From 6d8859357e4dcbff4e2aa8be40c47e4bec4b87cc Mon Sep 17 00:00:00 2001 From: kub Date: Sat, 1 Feb 2025 11:46:02 +0100 Subject: [PATCH] sms, add SC-3000 lower layers for tape writing suppurt (wav, bit) no UI, as there's currently no possibility to enter file names in libpicofe --- pico/sms.c | 117 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 40 deletions(-) diff --git a/pico/sms.c b/pico/sms.c index 0bbf1f69..c70b8b04 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -353,23 +353,45 @@ static void tape_write(int cycle, int data) pt->poll_cycles += cycles; // write samples to file. Stop if the sample doesn't change for more than 2s - if (pt->wavsample && pt->poll_cycles <= OSC_NTSC/15*2) { - samples = ((u64)cycles * pt->cycles_mult) >> 32; - while (samples-- > 0 && !ferror(pt->ftape)) - fwrite(&pt->wavsample, 1, sizeof(s16), pt->ftape); - if (ferror(pt->ftape)) { - fclose(pt->ftape); - pt->ftape = NULL; + if (pt->isbit) { + pt->poll_count += (data >= 0); + if (data >= 0 && pt->poll_cycles >= pt->cycles_sample*15/16) { + // determine bit, either 2400Hz, or 1200Hz, or bust + switch (pt->poll_count) { + case 4: pt->bitsample = '1'; break; // 2*2400Hz + case 2: pt->bitsample = '0'; break; // 1*1200Hz + default: pt->bitsample = ' '; break; // ignore everything else + } + + if (pt->poll_cycles < OSC_NTSC/15*2) { + samples = ((u64)pt->poll_cycles * pt->cycles_mult + 0x80000000LL) >> 32; + while (samples-- > 0 && !ferror(pt->ftape)) + fwrite(&pt->bitsample, 1, sizeof(u8), pt->ftape); + } + + pt->poll_count = pt->poll_cycles = 0; + } + } else { + if (pt->wavsample && pt->poll_cycles < OSC_NTSC/15*2) { + samples = ((u64)cycles * pt->cycles_mult) >> 32; + while (samples-- > 0 && !ferror(pt->ftape)) + fwrite(&pt->wavsample, 1, sizeof(s16), pt->ftape); } - } - // current sample value in little endian, for writing next time - if (data != -1) { - pt->wavsample = (data ? 0x7ff8 : 0x8008); + // current sample value in little endian, for writing next time + if (data != -1) { + pt->wavsample = (data ? 0x7ff8 : 0x8008); #if ! CPU_IS_LE - pt->wavsample = (u8)(pt->wavsample >> 8) | (pt->wavsample << 8); + pt->wavsample = (u8)(pt->wavsample >> 8) | (pt->wavsample << 8); #endif - pt->poll_cycles = 0; + pt->poll_cycles = 0; + } + } + + // catch write errors + if (ferror(pt->ftape)) { + fclose(pt->ftape); + pt->ftape = NULL; } } @@ -1319,30 +1341,39 @@ int PicoPlayTape(const char *fname) // open tape file for writing, and write WAV hdr (44KHz, mono, 16 bit samples) int PicoRecordTape(const char *fname) { + const char *ext = strrchr(fname, '.'); struct tape *pt = &tape; - int i; - - // WAV header "riffraff" for PCM 44KHz mono, 16 bit samples. - u8 hdr[44] = { // file and data size updated on file close - 'R','I','F','F', 0,0,0,0, 'W','A','V','E', // "RIFF", file size, "WAVE" - // "fmt ", hdr size, type, chans, rate, bytes/sec, bytes/sample, bits/sample - 'f','m','t',' ', 16,0,0,0, 1,0, 1,0, 68,172,0,0, 136,88,1,0, 2,0, 16,0, - 'd','a','t','a', 0,0,0,0 }; // "data", data size + int rate, i; if (pt->ftape) PicoCloseTape(); pt->ftape = fopen(fname, "wb"); if (pt->ftape == NULL) return 1; pt->mode = 'w'; - pt->isbit = 0; - pt->wavsample = 0; // Marker for "don't write yet" - pt->fsize = sizeof(s16); - - fwrite(hdr, 1, sizeof(hdr), pt->ftape); - for (i = 0; i < 44100; i++) - fwrite(&pt->wavsample, 1, sizeof(s16), pt->ftape); + pt->isbit = ext && ! memcmp(ext, ".bit", 4); + if (! pt->isbit) { + // WAV header "riffraff" for PCM 44KHz mono, 16 bit samples. + u8 hdr[44] = { // file and data size updated on file close + 'R','I','F','F', 0,0,0,0, 'W','A','V','E', // "RIFF", file size, "WAVE" + // "fmt ", hdr size, type, chans, rate, bytes/sec,bytes/sample,bits/sample + 'f','m','t',' ', 16,0,0,0, 1,0, 1,0, 68,172,0,0, 136,88,1,0, 2,0, 16,0, + 'd','a','t','a', 0,0,0,0 }; // "data", data size + + rate = 44100; + pt->wavsample = 0; // Marker for "don't write yet" + pt->fsize = sizeof(s16); + + fwrite(hdr, 1, sizeof(hdr), pt->ftape); + for (i = 0; i < 44100; i++) + fwrite(&pt->wavsample, 1, sizeof(s16), pt->ftape); + } else { + rate = 1200; + pt->bitsample = ' '; // Marker for "don't write yet" + for (i = 0; i < 1200; i++) + fwrite(&pt->bitsample, 1, sizeof(u8), pt->ftape); + } - pt->cycles_sample = (Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15) / 44100; + pt->cycles_sample = (Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15) / rate; pt->cycles_mult = (1LL<<32) / pt->cycles_sample; pt->cycle = Pico.t.z80c_aim; pt->phase = Pico.t.z80c_aim; @@ -1353,24 +1384,30 @@ int PicoRecordTape(const char *fname) void PicoCloseTape(void) { struct tape *pt = &tape; + int i, le; // if recording, write last data, and update length in header if (pt->mode == 'w') { - int i, le; - for (i = 0; i < 44100; i++) - fwrite(&pt->wavsample, 1, sizeof(s16), pt->ftape); - le = i = ftell(pt->ftape); + if (! pt->isbit) { + for (i = 0; i < 44100; i++) + fwrite(&pt->wavsample, 1, sizeof(s16), pt->ftape); + le = i = ftell(pt->ftape); #if ! CPU_IS_LE - le = (u8)(le>>24) | ((u8)le<<24) | ((u8)(le>>16)<<8) | ((u8)(le>>8)<<16); + le = (u8)(le>>24) | ((u8)le<<24) | ((u8)(le>>16)<<8) | ((u8)(le>>8)<<16); #endif - fseek(pt->ftape, 4, SEEK_SET); - fwrite(&le, 1, 4, pt->ftape); - le = i-44; + fseek(pt->ftape, 4, SEEK_SET); + fwrite(&le, 1, 4, pt->ftape); + le = i-44; #if ! CPU_IS_LE - le = (u8)(le>>24) | ((u8)le<<24) | ((u8)(le>>16)<<8) | ((u8)(le>>8)<<16); + le = (u8)(le>>24) | ((u8)le<<24) | ((u8)(le>>16)<<8) | ((u8)(le>>8)<<16); #endif - fseek(pt->ftape, 40, SEEK_SET); - fwrite(&le, 1, 4, pt->ftape); + fseek(pt->ftape, 40, SEEK_SET); + fwrite(&le, 1, 4, pt->ftape); + } else { + pt->bitsample = ' '; + for (i = 0; i < 1200; i++) + fwrite(&pt->bitsample, 1, sizeof(u8), pt->ftape); + } } if (pt->ftape) fclose(pt->ftape); -- 2.39.5