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}/PulseProcTzxPulseSequence.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/PulseProcTzxPureData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/PulseProcBitStream.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) :
|
||||
_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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -16,7 +16,8 @@ private:
|
||||
PulseProcTzxIndex _pptIndex;
|
||||
PulseProcTzxBlock _pptBlock;
|
||||
uint32_t _tsPerMs;
|
||||
|
||||
PulseProcPauseMillis _lastPause;
|
||||
|
||||
public:
|
||||
|
||||
PulseProcTzx(
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
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(
|
||||
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;
|
||||
|
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