mirror of
https://github.com/fruit-bat/pico-zxspectrum.git
synced 2025-04-19 00:04:01 +03:00
TZX block 11 - Turbo
This commit is contained in:
parent
a5f9d99d0e
commit
74d7f258c6
@ -30,6 +30,7 @@ set(zxspectrum_common_src
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/PulseProcPulseStream.cpp
|
${CMAKE_CURRENT_LIST_DIR}/PulseProcPulseStream.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPulseSequence.cpp
|
${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPulseSequence.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPureData.cpp
|
${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPureData.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/PulseProcBitStream.cpp
|
||||||
|
|
||||||
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ZxSpectrumFile.cpp
|
${CMAKE_CURRENT_LIST_DIR}/ZxSpectrumFile.cpp
|
||||||
|
35
src/PulseProcBitStream.cpp
Normal file
35
src/PulseProcBitStream.cpp
Normal file
@ -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;
|
||||||
|
}
|
32
src/PulseProcBitStream.h
Normal file
32
src/PulseProcBitStream.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
#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
|
||||||
|
);
|
||||||
|
};
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
PulseProcStdByte::PulseProcStdByte(PulseProcTone* t1) :
|
PulseProcStdByte::PulseProcStdByte(PulseProcTone* t1) :
|
||||||
_t1(t1),
|
_t1(t1),
|
||||||
_b(0x10000)
|
_b(0x10000UL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void PulseProcStdByte::init(PulseProc *nxt, uint32_t b) {
|
void PulseProcStdByte::init(PulseProc *nxt, uint32_t b) {
|
||||||
next(nxt);
|
next(nxt);
|
||||||
_b = b | 0x100;
|
_b = b | 0x100UL;
|
||||||
_ts[0] = 855;
|
_ts[0] = 855;
|
||||||
_ts[1] = 1710;
|
_ts[1] = 1710;
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ void __not_in_flash_func(PulseProcStdByte::init)(
|
|||||||
uint32_t ts1
|
uint32_t ts1
|
||||||
) {
|
) {
|
||||||
next(nxt);
|
next(nxt);
|
||||||
_b = b | (1 << (16 - (n > 8 ? 8 : n)));
|
_b = b | (1UL << (16 - (n > 8 ? 8 : n)));
|
||||||
_ts[0] = ts0;
|
_ts[0] = ts0;
|
||||||
_ts[1] = ts1;
|
_ts[1] = ts1;
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ int32_t __not_in_flash_func(PulseProcStdByte::advance)(
|
|||||||
bool *pstate,
|
bool *pstate,
|
||||||
PulseProc **top
|
PulseProc **top
|
||||||
) {
|
) {
|
||||||
if (_b & 0x10000) return PP_COMPLETE;
|
if (_b & 0x10000UL) return PP_COMPLETE;
|
||||||
_t1->init(this, _ts[(_b >> 7) & 1], 2);
|
_t1->init(this, _ts[(_b >> 7) & 1], 2);
|
||||||
_b <<= 1;
|
_b <<= 1;
|
||||||
*top = _t1;
|
*top = _t1;
|
||||||
|
@ -38,11 +38,10 @@ int32_t __not_in_flash_func(PulseProcStdByteStream::advance)(
|
|||||||
_ppb->init(
|
_ppb->init(
|
||||||
this,
|
this,
|
||||||
r,
|
r,
|
||||||
_l == 1 ? _blb : 8,
|
--_l == 0 ? _blb : 8,
|
||||||
_ts0,
|
_ts0,
|
||||||
_ts1
|
_ts1
|
||||||
);
|
);
|
||||||
--_l;
|
|
||||||
*top = _ppb;
|
*top = _ppb;
|
||||||
return PP_CONTINUE;
|
return PP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@ int32_t PulseProcTzx::advance(
|
|||||||
|
|
||||||
_pptHeader.init(&_pptIndex);
|
_pptHeader.init(&_pptIndex);
|
||||||
_pptIndex.init(&_pptBlock, &_bi);
|
_pptIndex.init(&_pptBlock, &_bi);
|
||||||
_pptBlock.init(next(), &_bi, _tsPerMs);
|
_pptBlock.init(&_lastPause, &_bi, _tsPerMs);
|
||||||
|
_lastPause.init(next(), 1000, _tsPerMs);
|
||||||
*top = &_pptHeader;
|
*top = &_pptHeader;
|
||||||
|
|
||||||
return PP_CONTINUE;
|
return PP_CONTINUE;
|
||||||
|
@ -16,7 +16,8 @@ private:
|
|||||||
PulseProcTzxIndex _pptIndex;
|
PulseProcTzxIndex _pptIndex;
|
||||||
PulseProcTzxBlock _pptBlock;
|
PulseProcTzxBlock _pptBlock;
|
||||||
uint32_t _tsPerMs;
|
uint32_t _tsPerMs;
|
||||||
|
PulseProcPauseMillis _lastPause;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PulseProcTzx(
|
PulseProcTzx(
|
||||||
|
@ -72,7 +72,7 @@ int32_t PulseProcTzxBlock::doStandardSpeedData(InputStream *is, PulseProc **top)
|
|||||||
*/
|
*/
|
||||||
int32_t PulseProcTzxBlock::doTurboSpeedData(InputStream *is, PulseProc **top) {
|
int32_t PulseProcTzxBlock::doTurboSpeedData(InputStream *is, PulseProc **top) {
|
||||||
_ppTzxTurbo.init(this, _tsPerMs);
|
_ppTzxTurbo.init(this, _tsPerMs);
|
||||||
*top = _ppTap;
|
*top = &_ppTzxTurbo;
|
||||||
return PP_CONTINUE;
|
return PP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ int32_t PulseProcTzxBlock::doTurboSpeedData(InputStream *is, PulseProc **top) {
|
|||||||
*/
|
*/
|
||||||
int32_t PulseProcTzxBlock::doPureTone(InputStream *is, PulseProc **top) {
|
int32_t PulseProcTzxBlock::doPureTone(InputStream *is, PulseProc **top) {
|
||||||
_ppTzxPureTone.init(this);
|
_ppTzxPureTone.init(this);
|
||||||
*top = _ppTap;
|
*top = &_ppTzxPureTone;
|
||||||
return PP_CONTINUE;
|
return PP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ int32_t PulseProcTzxBlock::doPureTone(InputStream *is, PulseProc **top) {
|
|||||||
*/
|
*/
|
||||||
int32_t PulseProcTzxBlock::doSequence(InputStream *is, PulseProc **top) {
|
int32_t PulseProcTzxBlock::doSequence(InputStream *is, PulseProc **top) {
|
||||||
_ppTzxPulseSequence.init(this);
|
_ppTzxPulseSequence.init(this);
|
||||||
*top = _ppTap;
|
*top = &_ppTzxPulseSequence;
|
||||||
return PP_CONTINUE;
|
return PP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ int32_t PulseProcTzxBlock::doSequence(InputStream *is, PulseProc **top) {
|
|||||||
*/
|
*/
|
||||||
int32_t PulseProcTzxBlock::doPureData(InputStream *is, PulseProc **top) {
|
int32_t PulseProcTzxBlock::doPureData(InputStream *is, PulseProc **top) {
|
||||||
_ppTzxPureData.init(this, _tsPerMs);
|
_ppTzxPureData.init(this, _tsPerMs);
|
||||||
*top = _ppTap;
|
*top = &_ppTzxPureData;
|
||||||
return PP_CONTINUE;
|
return PP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
85
src/PulseProcTzxDirectRecording.cpp
Normal file
85
src/PulseProcTzxDirectRecording.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
35
src/PulseProcTzxDirectRecording.h
Normal file
35
src/PulseProcTzxDirectRecording.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
#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
|
||||||
|
);
|
||||||
|
};
|
@ -99,8 +99,8 @@ int32_t __not_in_flash_func(PulseProcTzxTurbo::advance)(
|
|||||||
|
|
||||||
_pause->init(
|
_pause->init(
|
||||||
next(),
|
next(),
|
||||||
h[7], // 7. WORD Pause after this block (ms.) {1000}
|
h[7], // 7. WORD Pause after this block (ms.) {1000}
|
||||||
_tsPerMs
|
_tsPerMs
|
||||||
);
|
);
|
||||||
|
|
||||||
*top = _header;
|
*top = _header;
|
||||||
|
BIN
test/tzx-test-block-11.tzx
Normal file
BIN
test/tzx-test-block-11.tzx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user