From 74d7f258c6a559dfb6c6f5bc833d79ffb6afb530 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 30 Oct 2022 15:20:25 +0000 Subject: [PATCH] TZX block 11 - Turbo --- src/CMakeLists.txt | 1 + src/PulseProcBitStream.cpp | 35 ++++++++++++ src/PulseProcBitStream.h | 32 +++++++++++ src/PulseProcStdByte.cpp | 8 +-- src/PulseProcStdByteStream.cpp | 3 +- src/PulseProcTzx.cpp | 3 +- src/PulseProcTzx.h | 3 +- src/PulseProcTzxBlock.cpp | 8 +-- src/PulseProcTzxDirectRecording.cpp | 85 ++++++++++++++++++++++++++++ src/PulseProcTzxDirectRecording.h | 35 ++++++++++++ src/PulseProcTzxTurbo.cpp | 4 +- test/tzx-test-block-11.tzx | Bin 0 -> 7232 bytes 12 files changed, 203 insertions(+), 14 deletions(-) create mode 100644 src/PulseProcBitStream.cpp create mode 100644 src/PulseProcBitStream.h create mode 100644 src/PulseProcTzxDirectRecording.cpp create mode 100644 src/PulseProcTzxDirectRecording.h create mode 100644 test/tzx-test-block-11.tzx diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b661390..bbdc0e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ set(zxspectrum_common_src ${CMAKE_CURRENT_LIST_DIR}/PulseProcPulseStream.cpp ${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPulseSequence.cpp ${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPureData.cpp + ${CMAKE_CURRENT_LIST_DIR}/PulseProcBitStream.cpp ${CMAKE_CURRENT_LIST_DIR}/ZxSpectrumFile.cpp diff --git a/src/PulseProcBitStream.cpp b/src/PulseProcBitStream.cpp new file mode 100644 index 0000000..9904dfc --- /dev/null +++ b/src/PulseProcBitStream.cpp @@ -0,0 +1,35 @@ +#include "PulseProcBitStream.h" + +PulseProcBitStream::PulseProcBitStream(PulseProcTone* ppTone) : + _ppTone(ppTone), + _l(0) +{} + +void PulseProcBitStream::init( + PulseProc *nxt, + uint32_t l, + uint32_t tspb, + uint32_t blb) { + next(nxt); + _l = l; + _tspb = tspb; + _blb = blb > 8 ? 8 : blb; + _b = 0x10000; +} + +int32_t __not_in_flash_func(PulseProcBitStream::advance)( + InputStream *is, + bool *pstate, + PulseProc **top +) { + if (_l == 0) return PP_COMPLETE; + if (_b & 0x10000) { + int32_t r = is->readByte(); + if (r < 0) return PP_ERROR; + _b = r | (1 << (_l == 1 ? (16 - _blb) : 8)); + } + *pstate = (_b >> 7) & 1; + *top = _ppTone; + _b <<= 1; + return _tspb; +} diff --git a/src/PulseProcBitStream.h b/src/PulseProcBitStream.h new file mode 100644 index 0000000..1704cf2 --- /dev/null +++ b/src/PulseProcBitStream.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include "PulseProc.h" +#include "PulseProcTone.h" + +class PulseProcBitStream : public PulseProc { +private: + + PulseProcTone* _ppTone; + uint32_t _l; + uint32_t _tspb; + uint32_t _blb; + uint32_t _b; + +public: + + PulseProcBitStream(PulseProcTone* ppTone); + + void init( + PulseProc *next, + uint32_t l, + uint32_t tspb, + uint32_t blb + ); + + virtual int32_t __not_in_flash_func(advance)( + InputStream *is, + bool *pstate, + PulseProc **top + ); +}; diff --git a/src/PulseProcStdByte.cpp b/src/PulseProcStdByte.cpp index 4948aa7..ce266a5 100644 --- a/src/PulseProcStdByte.cpp +++ b/src/PulseProcStdByte.cpp @@ -2,12 +2,12 @@ PulseProcStdByte::PulseProcStdByte(PulseProcTone* t1) : _t1(t1), - _b(0x10000) + _b(0x10000UL) {} void PulseProcStdByte::init(PulseProc *nxt, uint32_t b) { next(nxt); - _b = b | 0x100; + _b = b | 0x100UL; _ts[0] = 855; _ts[1] = 1710; } @@ -20,7 +20,7 @@ void __not_in_flash_func(PulseProcStdByte::init)( uint32_t ts1 ) { next(nxt); - _b = b | (1 << (16 - (n > 8 ? 8 : n))); + _b = b | (1UL << (16 - (n > 8 ? 8 : n))); _ts[0] = ts0; _ts[1] = ts1; } @@ -30,7 +30,7 @@ int32_t __not_in_flash_func(PulseProcStdByte::advance)( bool *pstate, PulseProc **top ) { - if (_b & 0x10000) return PP_COMPLETE; + if (_b & 0x10000UL) return PP_COMPLETE; _t1->init(this, _ts[(_b >> 7) & 1], 2); _b <<= 1; *top = _t1; diff --git a/src/PulseProcStdByteStream.cpp b/src/PulseProcStdByteStream.cpp index db16bd4..85fe154 100644 --- a/src/PulseProcStdByteStream.cpp +++ b/src/PulseProcStdByteStream.cpp @@ -38,11 +38,10 @@ int32_t __not_in_flash_func(PulseProcStdByteStream::advance)( _ppb->init( this, r, - _l == 1 ? _blb : 8, + --_l == 0 ? _blb : 8, _ts0, _ts1 ); - --_l; *top = _ppb; return PP_CONTINUE; } diff --git a/src/PulseProcTzx.cpp b/src/PulseProcTzx.cpp index fc9ee0c..0dc2c75 100644 --- a/src/PulseProcTzx.cpp +++ b/src/PulseProcTzx.cpp @@ -30,7 +30,8 @@ int32_t PulseProcTzx::advance( _pptHeader.init(&_pptIndex); _pptIndex.init(&_pptBlock, &_bi); - _pptBlock.init(next(), &_bi, _tsPerMs); + _pptBlock.init(&_lastPause, &_bi, _tsPerMs); + _lastPause.init(next(), 1000, _tsPerMs); *top = &_pptHeader; return PP_CONTINUE; diff --git a/src/PulseProcTzx.h b/src/PulseProcTzx.h index 5947d48..a0e7888 100644 --- a/src/PulseProcTzx.h +++ b/src/PulseProcTzx.h @@ -16,7 +16,8 @@ private: PulseProcTzxIndex _pptIndex; PulseProcTzxBlock _pptBlock; uint32_t _tsPerMs; - + PulseProcPauseMillis _lastPause; + public: PulseProcTzx( diff --git a/src/PulseProcTzxBlock.cpp b/src/PulseProcTzxBlock.cpp index 5b4f0d9..a97356d 100644 --- a/src/PulseProcTzxBlock.cpp +++ b/src/PulseProcTzxBlock.cpp @@ -72,7 +72,7 @@ int32_t PulseProcTzxBlock::doStandardSpeedData(InputStream *is, PulseProc **top) */ int32_t PulseProcTzxBlock::doTurboSpeedData(InputStream *is, PulseProc **top) { _ppTzxTurbo.init(this, _tsPerMs); - *top = _ppTap; + *top = &_ppTzxTurbo; return PP_CONTINUE; } @@ -82,7 +82,7 @@ int32_t PulseProcTzxBlock::doTurboSpeedData(InputStream *is, PulseProc **top) { */ int32_t PulseProcTzxBlock::doPureTone(InputStream *is, PulseProc **top) { _ppTzxPureTone.init(this); - *top = _ppTap; + *top = &_ppTzxPureTone; return PP_CONTINUE; } @@ -92,7 +92,7 @@ int32_t PulseProcTzxBlock::doPureTone(InputStream *is, PulseProc **top) { */ int32_t PulseProcTzxBlock::doSequence(InputStream *is, PulseProc **top) { _ppTzxPulseSequence.init(this); - *top = _ppTap; + *top = &_ppTzxPulseSequence; return PP_CONTINUE; } @@ -107,7 +107,7 @@ int32_t PulseProcTzxBlock::doSequence(InputStream *is, PulseProc **top) { */ int32_t PulseProcTzxBlock::doPureData(InputStream *is, PulseProc **top) { _ppTzxPureData.init(this, _tsPerMs); - *top = _ppTap; + *top = &_ppTzxPureData; return PP_CONTINUE; } diff --git a/src/PulseProcTzxDirectRecording.cpp b/src/PulseProcTzxDirectRecording.cpp new file mode 100644 index 0000000..f58e0d6 --- /dev/null +++ b/src/PulseProcTzxDirectRecording.cpp @@ -0,0 +1,85 @@ +#include "PulseProcTzxDirectRecording.h" + + +PulseProcTzxDirectRecording::PulseProcTzxDirectRecording( + PulseProcBitStream* data, + PulseProcTone* end, + PulseProcPauseMillis* pause +) : + _data(data), + _end(end), + _pause(pause) +{ +} + +void PulseProcTzxDirectRecording::init( + PulseProc *nxt, + uint32_t tsPerMs +) { + next(nxt); + _tsPerMs = tsPerMs; +} + +/** + * ID 15 - Direct Recording + * + * length: [05,06,07]+08 + * + * Offset Value Type Description + * 0x00 - WORD Number of T-states per sample (bit of data) + * 0x02 - WORD Pause after this block in milliseconds (ms.) + * 0x04 - BYTE Used bits (samples) in last byte of data (1-8) + * (e.g. if this is 2, only first two samples of the last byte will be played) + * 0x05 N BYTE[3] Length of samples' data + * 0x08 - BYTE[N] Samples data. Each bit represents a state on the EAR port (i.e. one sample). + * MSb is played first. +*/ +int32_t __not_in_flash_func(PulseProcTzxDirectRecording::advance)( + InputStream *is, + bool *pstate, + PulseProc **top +) { + DBG_PULSE("PulseProcTzxDirectRecording: \n"); + + const int8_t l[] = { //TODO + 2, // 0. WORD Number of T-states per sample (bit of data) + 2, // 1. WORD Pause after this block in milliseconds (ms.) + 1, // 2. BYTE Used bits (samples) in last byte of data (1-8) + 3 // 3. BYTE[3] Length of samples' data + }; + + uint32_t h[5]; + int32_t r = is->decodeLsbf(h, l, 5); + + if (r < 0) { + DBG_PULSE("PulseProcTzxDirectRecording: Error (%ld) reading pure data header\n", r); + return PP_ERROR; + } + else { + + DBG_PULSE("PulseProcTzxDirectRecording: Length of ZERO bit pulse %ld\n", h[0]); + DBG_PULSE("PulseProcTzxDirectRecording: Length of ONE bit pulse %ld\n", h[1]); + DBG_PULSE("PulseProcTzxDirectRecording: Used bits in the last byte %ld\n", h[2]); + DBG_PULSE("PulseProcTzxDirectRecording: Pause after this block %ld\n", h[3]); + DBG_PULSE("PulseProcTzxDirectRecording: Length of data that follow %ld\n", h[4]); + + _data->init( + _end, + h[4], // 4. BYTE[3] Length of data that follow + h[0], // 0. WORD Length of ZERO bit pulse {855} + h[4], // 4. WORD Length of ONE bit pulse {1710} + h[2] // 2. BYTE Used bits in the last byte + ); + + _end->init(_pause, 0, 1); + + _pause->init( + next(), + h[3], // 3. WORD Pause after this block (ms.) {1000} + _tsPerMs + ); + + *top = _data; + return PP_CONTINUE; + } +} diff --git a/src/PulseProcTzxDirectRecording.h b/src/PulseProcTzxDirectRecording.h new file mode 100644 index 0000000..11027ca --- /dev/null +++ b/src/PulseProcTzxDirectRecording.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include "PulseProc.h" +#include "PulseProcTone.h" +#include "PulseProcBitStream.h" +#include "PulseProcPauseMillis.h" + +class PulseProcTzxDirectRecording : public PulseProc { +private: + + PulseProcBitStream* _data; + PulseProcTone* _end; + PulseProcPauseMillis* _pause; + uint32_t _tsPerMs; + +public: + + PulseProcTzxDirectRecording( + PulseProcBitStream* data, + PulseProcTone* end, + PulseProcPauseMillis* pause + ); + + void init( + PulseProc *nxt, + uint32_t tsPerMs + ); + + virtual int32_t __not_in_flash_func(advance)( + InputStream *is, + bool *pstate, + PulseProc **top + ); +}; diff --git a/src/PulseProcTzxTurbo.cpp b/src/PulseProcTzxTurbo.cpp index ac6a845..7dd8185 100644 --- a/src/PulseProcTzxTurbo.cpp +++ b/src/PulseProcTzxTurbo.cpp @@ -99,8 +99,8 @@ int32_t __not_in_flash_func(PulseProcTzxTurbo::advance)( _pause->init( next(), - h[7], // 7. WORD Pause after this block (ms.) {1000} - _tsPerMs + h[7], // 7. WORD Pause after this block (ms.) {1000} + _tsPerMs ); *top = _header; diff --git a/test/tzx-test-block-11.tzx b/test/tzx-test-block-11.tzx new file mode 100644 index 0000000000000000000000000000000000000000..0015094d964c9935f0b8e2a405fb7994038fe151 GIT binary patch literal 7232 zcmd^@&ug4T7{{MwTlXcfNlGn>L3dk07pe74G`be)3LdIn>cK-Ol~S|^L8u5ys$c^Z z#FPF3Vm)~A6v2xZ^|dFXmWVlch+!8a-FWG{F~v0OzB4}0Jnzi=X5M$+;4PcXy!kQD zXP#%~JMX;nyt`*-UcT_=#iRF?s^e?r!vOHo>#tsV^z2N%UOx>Za2kBHzW@?Ost`T# z^yKv9D1iJPs&Mx`aC_?UCntS0oID4|r>3U~0ip*ELU`=hd=(m_uoaNk6e0+q`T>tp ze&f=G*Dk(=gVaAG``j;R{~YAXQF!(cOx(CPm|qg_%rA?ZHBoE)yRb1jasuvx8y^OZ zO@C%q9BKBr^|${bwf;PQ{r-S0zxΝrah?Yr%g6Tg|^N-#T#SL`m5w$XEX1Qxo6( zeB`(D!OGjP^5Dd~UtfPEIQjg!o0TQeUwEi~>dLaH{d(ZXFTeQdqu}zbhnK{erxu<& z^vA(ZO7-&X(pq_~?4hCw{2A_2nY%Mqa6v^Dmf;qUv;Uv^MTx6kl;PL^>DFSwW#9in znd{!s|6M;UxNQA*DqQ!g{@xhZ{i?rH<2p3@E32Yaa6x4yY8PDg{tsGQ_m2L8#X)52 zpS!}<=(qACzW=D|;2N*Xb?(9Od#$)-ykQJ29e`Pie{C@eBmAqqxicAHwp0$Ia8T}H z{|pwff4jSd{u!+N&HQt)9-qd`!OCp>sU_|7D7UYl!72UFk}_<|tJ}Sm{!r`xctHA% zH;tr<)*tnIn>kqN$N25ljc%0nmU8YHwZ0T952Lvg>vLdBpS07X#SPw&TS@@(Qdi&rFPWqN9+A8mP$Xy4?C6RDC3PWt_q_+4`YvB ztlxnxebP>k7Ef@{VhMozSN6l+`+aODSSsG;`H3I8ViEPHFgq*#&=RYgqTA16rJv$& zu6DnTGTs;?r9Tg2k7lgjfh~Q~PLCE(u)4n(-!t>WMuK^NX#K1&g|ROcr60F0uTSF5 zl(|{oES7P6)jbE3-HY`*u%%Dh>Cxf|R?j!aZ_@nK{=`OtU>PRW6b*lC#5n8BRiFutVxnuB$Ip>R2v%v!$#8}3Mt$m92mLH=8q;f}YoUH|!#&j(j}MEwOX zmx%U=eph-#{RJN`5$*c>yVC^u{=3rSe$nqrkNZWxD?OtAf-jd4?X7&ueZg-$8honZE5Kf}`)d(%Zl^E6KT$N%SGGcW9thsiV6;ljuZmp9g? JCOVwI{sTnVIr9Jj literal 0 HcmV?d00001