diff --git a/ZXTapeReviver.pro b/ZXTapeReviver.pro
index 7389be2..dcd907c 100644
--- a/ZXTapeReviver.pro
+++ b/ZXTapeReviver.pro
@@ -20,6 +20,7 @@ SOURCES += \
sources/controls/waveformcontrol.cpp \
sources/core/waveformparser.cpp \
sources/core/wavreader.cpp \
+ sources/models/parsersettingsmodel.cpp \
sources/models/suspiciouspointsmodel.cpp
HEADERS += \
@@ -28,6 +29,7 @@ HEADERS += \
sources/controls/waveformcontrol.h \
sources/core/waveformparser.h \
sources/core/wavreader.h \
+ sources/models/parsersettingsmodel.h \
sources/models/suspiciouspointsmodel.h
RESOURCES += qml/qml.qrc
diff --git a/qml/Frequency.qml b/qml/Frequency.qml
new file mode 100644
index 0000000..ec9ba5c
--- /dev/null
+++ b/qml/Frequency.qml
@@ -0,0 +1,37 @@
+//*******************************************************************************
+// ZX Tape Reviver
+//-----------------
+//
+// Author: Leonid Golouz
+// E-mail: lgolouz@list.ru
+//*******************************************************************************
+
+import QtQuick 2.3
+import QtQuick.Controls 1.3
+import QtQuick.Dialogs 1.3
+
+Dialog {
+ id: frequencyDialog
+
+ property var frequency: 0
+
+ visible: false
+ title: "Measured frequency"
+ standardButtons: StandardButton.Ok
+ modality: Qt.WindowModal
+ width: 200
+ height: 120
+
+ Text {
+ id: textWithField
+ text: "Measured frequency:"
+ }
+
+ TextField {
+ id: textField
+ anchors.top: textWithField.bottom
+ anchors.topMargin: 5
+ width: parent.width
+ text: frequency
+ }
+}
diff --git a/qml/ParserSettings.qml b/qml/ParserSettings.qml
new file mode 100644
index 0000000..786ec00
--- /dev/null
+++ b/qml/ParserSettings.qml
@@ -0,0 +1,206 @@
+//*******************************************************************************
+// ZX Tape Reviver
+//-----------------
+//
+// Author: Leonid Golouz
+// E-mail: lgolouz@list.ru
+//*******************************************************************************
+
+import QtQuick 2.3
+import QtQuick.Controls 1.3
+import QtQuick.Dialogs 1.3
+import QtQuick.Layouts 1.15
+
+import com.models.zxtapereviver 1.0
+
+Dialog {
+ id: parserSettingsDialog
+
+ visible: false
+ title: "Parser settings"
+ standardButtons: StandardButton.Ok | StandardButton.RestoreDefaults
+ modality: Qt.WindowModal
+
+ Grid {
+ id: grid
+ columns: 4
+
+ GroupBox {
+ title: "Pilot-tone settings:"
+ ColumnLayout {
+ Layout.fillHeight: true
+ Text {
+ text: "Pilot half frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.pilotHalfFreq;
+ onTextChanged: {
+ ParserSettingsModel.pilotHalfFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Pilot frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.pilotFreq;
+ onTextChanged: {
+ ParserSettingsModel.pilotFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Pilot delta:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.pilotDelta
+ onTextChanged: {
+ ParserSettingsModel.pilotDelta = text;
+ }
+ }
+ }
+ }
+
+ GroupBox {
+ title: "Synchro signal settigns:"
+ ColumnLayout {
+ Text {
+ text: "Synchro first half frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.synchroFirstHalfFreq;
+ onTextChanged: {
+ ParserSettingsModel.synchroFirstHalfFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Synchro second half frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.synchroSecondHalfFreq;
+ onTextChanged: {
+ ParserSettingsModel.synchroSecondHalfFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Synchro frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.synchroFreq;
+ onTextChanged: {
+ ParserSettingsModel.synchroFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Synchro delta:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.synchroDelta
+ onTextChanged: {
+ ParserSettingsModel.synchroDelta = text;
+ }
+ }
+ }
+ }
+
+ GroupBox {
+ title: "Zero digit settings:"
+ ColumnLayout {
+ Text {
+ text: "Zero half frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.zeroHalfFreq;
+ onTextChanged: {
+ ParserSettingsModel.zeroHalfFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Zero frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.zeroFreq;
+ onTextChanged: {
+ ParserSettingsModel.zeroFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "Zero delta:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.zeroDelta
+ onTextChanged: {
+ ParserSettingsModel.zeroDelta = text;
+ }
+ }
+ }
+ }
+
+ GroupBox {
+ title: "One digit settings:"
+ ColumnLayout {
+ Text {
+ text: "One half frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.oneHalfFreq;
+ onTextChanged: {
+ ParserSettingsModel.oneHalfFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "One frequency:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.oneFreq;
+ onTextChanged: {
+ ParserSettingsModel.oneFreq = parseInt(text, 10);
+ }
+ }
+
+ Text {
+ text: "One delta:"
+ }
+
+ TextField {
+ text: ParserSettingsModel.oneDelta
+ onTextChanged: {
+ ParserSettingsModel.oneDelta = text;
+ }
+ }
+ }
+ }
+ }
+ CheckBox {
+ anchors.top: grid.bottom
+ anchors.topMargin: 5
+
+ text: "Check for abnormal sine when parsing"
+ checked: ParserSettingsModel.checkForAbnormalSine
+ onCheckedChanged: {
+ ParserSettingsModel.checkForAbnormalSine = checked;
+ }
+ }
+
+ onReset: {
+ ParserSettingsModel.restoreDefaultSettings();
+ }
+}
diff --git a/qml/main.qml b/qml/main.qml
index d0716a7..9bec988 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -129,6 +129,15 @@ ApplicationWindow {
MenuItem {
text: "Reparse"
}
+
+ MenuSeparator { }
+
+ MenuItem {
+ text: "Parser settings..."
+ onTriggered: {
+ parserSettingsDialog.open();
+ }
+ }
}
}
@@ -455,7 +464,7 @@ ApplicationWindow {
width: hZoomOutButton.width
onClicked: {
- gotoAddressDialogLoader.item.open();
+ gotoAddressDialog.open();
}
}
@@ -469,9 +478,37 @@ ApplicationWindow {
anchors.rightMargin: 5
width: hZoomOutButton.width
checkable: true
+ visible: !measurementModeToggleButton.checked
onCheckedChanged: {
- waveformControlCh0.selectionMode = waveformControlCh1.selectionMode = checked;
+ waveformControlCh0.operationMode = waveformControlCh1.operationMode = checked ? WaveformControlOperationModes.WaveformSelectionMode : WaveformControlOperationModes.WaveformRepairMode;
+ }
+ }
+
+ Button {
+ id: measurementModeToggleButton
+
+ text: "Measurement mode"
+ anchors {
+ right: parent.right
+ rightMargin: 5
+ bottom: selectionModeToggleButton.top
+ bottomMargin: 5
+ }
+ width: hZoomOutButton.width
+ checkable: true
+ visible: !selectionModeToggleButton.checked
+
+ onCheckedChanged: {
+ waveformControlCh0.operationMode = waveformControlCh1.operationMode = checked ? WaveformControlOperationModes.WaveformMeasurementMode : WaveformControlOperationModes.WaveformRepairMode;
+ }
+ }
+
+ states: State {
+ when: measurementModeToggleButton.checked
+ AnchorChanges {
+ target: measurementModeToggleButton
+ anchors.bottom: waveformControlCh1.bottom
}
}
@@ -710,14 +747,9 @@ ApplicationWindow {
}
}
- Loader {
- id: gotoAddressDialogLoader
- source: "GoToAddress.qml"
- }
-
- Connections {
- target: gotoAddressDialogLoader.item
- function onGotoAddress(adr) {
+ GoToAddress {
+ id: gotoAddressDialog
+ onGotoAddress: {
console.log("Goto address: " + adr);
var pos = WaveformParser.getPositionByAddress(channelsComboBox.currentIndex, parsedDataView.currentRow, adr);
if (pos !== 0) {
@@ -730,4 +762,17 @@ ApplicationWindow {
}
}
}
+
+ ParserSettings {
+ id: parserSettingsDialog
+ }
+
+ Frequency {
+ id: frequencyDialog
+ Component.onCompleted: {
+ var func = function(fr) { frequency = fr; frequencyDialog.open(); };
+ waveformControlCh0.frequency.connect(func);
+ waveformControlCh1.frequency.connect(func);
+ }
+ }
}
diff --git a/qml/qml.qrc b/qml/qml.qrc
index f939205..a3da466 100644
--- a/qml/qml.qrc
+++ b/qml/qml.qrc
@@ -2,5 +2,7 @@
main.qml
GoToAddress.qml
+ Frequency.qml
+ ParserSettings.qml
diff --git a/sources/controls/waveformcontrol.cpp b/sources/controls/waveformcontrol.cpp
index 8cda5d0..1b68044 100644
--- a/sources/controls/waveformcontrol.cpp
+++ b/sources/controls/waveformcontrol.cpp
@@ -26,13 +26,35 @@ WaveformControl::WaveformControl(QQuickItem* parent) :
m_yScaleFactor(80000),
m_clickState(WaitForFirstPress),
m_clickPosition(0),
- m_selectionMode(false),
- m_rangeSelected(false)
+ m_operationMode(WaveformControlOperationModes::WaveformRepairMode),
+ m_rangeSelected(false),
+ m_clickCount(0)
{
setAcceptedMouseButtons(Qt::AllButtons);
setEnabled(true);
}
+QColor WaveformControl::getBackgroundColor() const
+{
+ QColor r;
+ switch (m_operationMode)
+ {
+ case WaveformSelectionMode:
+ r = QColor(37, 37, 37);
+ break;
+
+ case WaveformMeasurementMode:
+ r = QColor(0, 17, 17);
+ break;
+
+ default:
+ r = QColor(7, 7, 36);
+ break;
+ }
+
+ return r;
+}
+
QWavVector* WaveformControl::getChannel(uint* chNum) const
{
const auto c = chNum ? *chNum : m_channelNumber;
@@ -54,7 +76,7 @@ int WaveformControl::getWavPositionByMouseX(int x, int* point, double* dx) const
void WaveformControl::paint(QPainter* painter)
{
- painter->setBackground(QBrush (QColor(m_selectionMode ? 37 : 7, m_selectionMode ? 37 : 7, 37)));
+ painter->setBackground(QBrush(getBackgroundColor()));
painter->setBackgroundMode(Qt::OpaqueMode);
painter->setPen(QColor(11, 60, 0));
const auto& bRect = boundingRect();
@@ -137,7 +159,7 @@ void WaveformControl::paint(QPainter* painter)
x += dx;
}
- if (m_selectionMode && m_rangeSelected) {
+ if (m_operationMode == WaveformSelectionMode && m_rangeSelected) {
painter->setBackground(QBrush(QColor(7, 7, 137, 128)));
auto bRect = boundingRect();
bRect.setX(m_selectionRange.first);
@@ -171,9 +193,9 @@ bool WaveformControl::getIsWaveformRepaired() const
return m_isWaveformRepaired;
}
-bool WaveformControl::getSelectionMode() const
+WaveformControl::WaveformControlOperationModes WaveformControl::getOperationMode() const
{
- return m_selectionMode;
+ return m_operationMode;
}
void WaveformControl::setWavePos(int32_t wavePos)
@@ -206,14 +228,15 @@ void WaveformControl::setYScaleFactor(double yScaleFactor)
}
}
-void WaveformControl::setSelectionMode(bool mode)
+void WaveformControl::setOperationMode(WaveformControlOperationModes mode)
{
- if (m_selectionMode != mode) {
- m_selectionMode = mode;
+ if (m_operationMode != mode) {
+ m_operationMode = mode;
m_rangeSelected = false;
+ m_clickCount = 0;
update();
- emit selectionModeChanged();
+ emit operationModeChanged();
}
}
@@ -245,21 +268,24 @@ void WaveformControl::mousePressEvent(QMouseEvent* event)
m_clickPosition = getWavPositionByMouseX(event->x(), &point, &dx);
event->accept();
- if (m_selectionMode) {
+ if (m_operationMode == WaveformSelectionMode) {
m_rangeSelected = true;
m_selectionRange = { event->x(), event->x() };
update();
}
if (dx <= 2.0) {
+ if (m_operationMode == WaveformMeasurementMode) {
+ emit cannotSetMeasurementPoint();
+ }
return;
}
double dpoint = point * dx;
const double waveHeight = boundingRect().height() - 100;
const double halfHeight = waveHeight / 2;
- if (!m_selectionMode) {
- if (event->button() == Qt::MiddleButton ) {
+ if (m_operationMode == WaveformRepairMode) {
+ if (event->button() == Qt::MiddleButton) {
//const auto p = point + getWavePos();
const auto d = getChannel()->operator[](m_clickPosition);
qDebug() << "Inserting point: " << m_clickPosition;
@@ -284,7 +310,7 @@ void WaveformControl::mousePressEvent(QMouseEvent* event)
}
}
}
- } // m_selectionMode
+ } // m_operationMode
}
}
@@ -301,19 +327,32 @@ void WaveformControl::mouseReleaseEvent(QMouseEvent* event)
auto now = QDateTime::currentDateTime();
qDebug() << "Click state: " << m_clickState << "; time: " << m_clickTime.msecsTo(now);
- if (m_selectionMode && m_rangeSelected && m_selectionRange.first == m_selectionRange.second) {
+ if (m_operationMode == WaveformSelectionMode && m_rangeSelected && m_selectionRange.first == m_selectionRange.second) {
m_rangeSelected = false;
}
- if (m_clickState == WaitForFirstRelease && m_clickTime.msecsTo(now) <= 500) {
- m_clickState = WaitForSecondPress;
- }
- else if (m_clickState == WaitForSecondRelease && m_clickTime.msecsTo(now) <= 500) {
- m_clickState = WaitForFirstPress;
- emit doubleClick(m_clickPosition);
+ if (m_operationMode == WaveformRepairMode || m_operationMode == WaveformSelectionMode) {
+ if ( m_clickState == WaitForFirstRelease && m_clickTime.msecsTo(now) <= 500) {
+ m_clickState = WaitForSecondPress;
+ }
+ else if (m_clickState == WaitForSecondRelease && m_clickTime.msecsTo(now) <= 500) {
+ m_clickState = WaitForFirstPress;
+ emit doubleClick(m_clickPosition);
+ }
+ else {
+ m_clickState = WaitForFirstPress;
+ }
}
- else {
- m_clickState = WaitForFirstPress;
+ else if (m_operationMode == WaveformMeasurementMode) {
+ auto& clickPoint = m_clickCount == 0 ? m_selectionRange.first : m_selectionRange.second;
+ clickPoint = getWavPositionByMouseX(event->x());
+ if (m_clickCount == 1) {
+ auto len = std::abs(m_selectionRange.first - m_selectionRange.second);
+ int freq = mWavReader.getSampleRate() / (len == 0 ? 1 : len);
+ qDebug() << "Frequency: " << freq;
+ emit frequency(freq);
+ }
+ m_clickCount = (m_clickCount + 1) % 2;
}
m_pointGrabbed = false;
@@ -335,7 +374,7 @@ void WaveformControl::mouseMoveEvent(QMouseEvent* event)
switch (event->buttons()) {
case Qt::LeftButton: {
- if (m_selectionMode && m_rangeSelected) {
+ if (m_operationMode == WaveformSelectionMode && m_rangeSelected) {
if (event->x() <= m_selectionRange.first) {
m_selectionRange.first = event->x();
}
@@ -343,7 +382,7 @@ void WaveformControl::mouseMoveEvent(QMouseEvent* event)
m_selectionRange.second = event->x();
}
}
- else {
+ else if (m_operationMode == WaveformRepairMode) {
const auto* ch = getChannel();
if (!ch) {
return;
@@ -430,7 +469,7 @@ void WaveformControl::shiftWaveform()
void WaveformControl::copySelectedToAnotherChannel()
{
- if (m_selectionMode && m_rangeSelected) {
+ if (m_operationMode == WaveformSelectionMode && m_rangeSelected) {
uint destChNum = getChannelNumber() == 0 ? 1 : 0;
const auto sourceChannel = getChannel();
const auto destChannel = getChannel(&destChNum);
diff --git a/sources/controls/waveformcontrol.h b/sources/controls/waveformcontrol.h
index f02fb2e..8e9e9be 100644
--- a/sources/controls/waveformcontrol.h
+++ b/sources/controls/waveformcontrol.h
@@ -24,12 +24,21 @@ class WaveformControl : public QQuickPaintedItem
Q_PROPERTY(double xScaleFactor READ getXScaleFactor WRITE setXScaleFactor NOTIFY xScaleFactorChanged)
Q_PROPERTY(double yScaleFactor READ getYScaleFactor WRITE setYScaleFactor NOTIFY yScaleFactorChanged)
Q_PROPERTY(bool isWaveformRepaired READ getIsWaveformRepaired NOTIFY isWaveformRepairedChanged)
- Q_PROPERTY(bool selectionMode READ getSelectionMode WRITE setSelectionMode NOTIFY selectionModeChanged)
+ Q_PROPERTY(WaveformControlOperationModes operationMode READ getOperationMode WRITE setOperationMode NOTIFY operationModeChanged)
WavReader& mWavReader;
WaveformParser& mWavParser;
+ QColor getBackgroundColor() const;
+
public:
+ enum WaveformControlOperationModes {
+ WaveformRepairMode,
+ WaveformSelectionMode,
+ WaveformMeasurementMode
+ };
+ Q_ENUM(WaveformControlOperationModes)
+
explicit WaveformControl(QQuickItem* parent = nullptr);
uint getChannelNumber() const;
@@ -38,13 +47,13 @@ class WaveformControl : public QQuickPaintedItem
double getXScaleFactor() const;
double getYScaleFactor() const;
bool getIsWaveformRepaired() const;
- bool getSelectionMode() const;
+ WaveformControlOperationModes getOperationMode() const;
void setChannelNumber(uint chNum);
void setWavePos(int wavPos);
void setXScaleFactor(double xScaleFactor);
void setYScaleFactor(double yScaleFactor);
- void setSelectionMode(bool mode);
+ void setOperationMode(WaveformControlOperationModes mode);
virtual void paint(QPainter* painter) override;
virtual void mousePressEvent(QMouseEvent* event) override;
@@ -66,9 +75,11 @@ class WaveformControl : public QQuickPaintedItem
void xScaleFactorChanged();
void yScaleFactorChanged();
void isWaveformRepairedChanged();
- void selectionModeChanged();
+ void operationModeChanged();
void doubleClick(int idx);
+ void cannotSetMeasurementPoint();
+ void frequency(int freq);
private:
enum ClickStates {
@@ -89,9 +100,10 @@ class WaveformControl : public QQuickPaintedItem
ClickStates m_clickState;
QDateTime m_clickTime;
int m_clickPosition;
- bool m_selectionMode;
+ WaveformControlOperationModes m_operationMode;
bool m_rangeSelected;
QPair m_selectionRange;
+ int m_clickCount;
QWavVector* getChannel(uint* chNum = nullptr) const;
int getWavPositionByMouseX(int x, int* point = nullptr, double* dx = nullptr) const;
diff --git a/sources/core/waveformparser.cpp b/sources/core/waveformparser.cpp
index 5af5bc6..187c5b9 100644
--- a/sources/core/waveformparser.cpp
+++ b/sources/core/waveformparser.cpp
@@ -7,6 +7,7 @@
//*******************************************************************************
#include "waveformparser.h"
+#include "sources/models/parsersettingsmodel.h"
#include
#include
#include
@@ -45,13 +46,22 @@ void WaveformParser::parse(uint chNum)
uint8_t bit = 0;
uint8_t parity = 0;
+ const auto& parserSettings = ParserSettingsModel::instance()->getParserSettings();
+ auto isSineNormal = [&parserSettings, sampleRate](const WaveformPart& b, const WaveformPart& e, bool zeroCheck) -> bool {
+ if (parserSettings.checkForAbnormalSine) {
+ return isFreqFitsInDelta(sampleRate, b.length, zeroCheck ? parserSettings.zeroHalfFreq : parserSettings.oneHalfFreq, zeroCheck ? parserSettings.zeroDelta : parserSettings.oneDelta, 0.5) &&
+ isFreqFitsInDelta(sampleRate, e.length, zeroCheck ? parserSettings.zeroHalfFreq : parserSettings.oneHalfFreq, zeroCheck ? parserSettings.zeroDelta : parserSettings.oneDelta, 0.5);
+ }
+ return true;
+ };
+
while (currentState != NO_MORE_DATA) {
auto prevIt = it;
switch (currentState) {
case SEARCH_OF_PILOT_TONE:
- it = std::find_if(it, parsed.end(), [sampleRate, chNum, this](const WaveformPart& p) {
+ it = std::find_if(it, parsed.end(), [&parserSettings, sampleRate, chNum, this](const WaveformPart& p) {
fillParsedWaveform(chNum, p, 0);
- return isFreqFitsInDelta(sampleRate, p.length, SignalFrequencies::PILOT_HALF_FREQ, pilotDelta, 2.0);
+ return isFreqFitsInDelta(sampleRate, p.length, parserSettings.pilotHalfFreq, parserSettings.pilotDelta, 2.0);
});
if (it != parsed.end()) {
currentState = PILOT_TONE;
@@ -59,9 +69,9 @@ void WaveformParser::parse(uint chNum)
break;
case PILOT_TONE:
- it = std::find_if(it, parsed.end(), [sampleRate, chNum, this](const WaveformPart& p) {
+ it = std::find_if(it, parsed.end(), [&parserSettings, sampleRate, chNum, this](const WaveformPart& p) {
fillParsedWaveform(chNum, p, pilotTone ^ sequenceMiddle);
- return isFreqFitsInDelta(sampleRate, p.length, SignalFrequencies::SYNCHRO_FIRST_HALF_FREQ, synchroDelta);
+ return isFreqFitsInDelta(sampleRate, p.length, parserSettings.synchroFirstHalfFreq, parserSettings.synchroDelta);
});
if (it != parsed.end()) {
auto eIt = std::prev(it);
@@ -84,7 +94,8 @@ void WaveformParser::parse(uint chNum)
case SYNCHRO_SIGNAL:
it = std::next(it);
if (it != parsed.end()) {
- if ((isFreqFitsInDelta(sampleRate, it->length, SignalFrequencies::SYNCHRO_SECOND_HALF, synchroDelta)) && (isFreqFitsInDelta(sampleRate, it->length + prevIt->length, SignalFrequencies::SYNCHRO_FREQ, synchroDelta, 2.0))) {
+ if ((isFreqFitsInDelta(sampleRate, it->length, parserSettings.synchroSecondHalfFreq, parserSettings.synchroDelta)) &&
+ (isFreqFitsInDelta(sampleRate, it->length + prevIt->length, parserSettings.synchroFreq, parserSettings.synchroDelta, 2.0))) {
fillParsedWaveform(chNum, *prevIt, synchroSignal ^ sequenceMiddle);
fillParsedWaveform(chNum, *it, synchroSignal ^ sequenceMiddle);
parsedWaveform[prevIt->begin] = synchroSignal ^ sequenceBegin;
@@ -118,7 +129,7 @@ void WaveformParser::parse(uint chNum)
it = std::next(it);
if (it != parsed.end()) {
const auto len = it->length + prevIt->length;
- if (isFreqFitsInDelta(sampleRate, len, SignalFrequencies::ZERO_FREQ, zeroDelta)) { //ZERO
+ if (isFreqFitsInDelta(sampleRate, len, parserSettings.zeroFreq, parserSettings.zeroDelta) && isSineNormal(*prevIt, *it, true)) { //ZERO
fillParsedWaveform(chNum, *prevIt, zeroBit ^ sequenceMiddle);
fillParsedWaveform(chNum, *it, zeroBit ^ sequenceMiddle);
parsedWaveform[prevIt->begin] = zeroBit ^ sequenceBegin;
@@ -146,7 +157,7 @@ void WaveformParser::parse(uint chNum)
bit ^= bit;
}
}
- else if (isFreqFitsInDelta(sampleRate, len, SignalFrequencies::ONE_FREQ, oneDelta)) { //ONE
+ else if (isFreqFitsInDelta(sampleRate, len, parserSettings.oneFreq, parserSettings.oneDelta) && isSineNormal(*prevIt, *it, false)) { //ONE
fillParsedWaveform(chNum, *prevIt, oneBit ^ sequenceMiddle);
fillParsedWaveform(chNum, *it, oneBit ^ sequenceMiddle);
parsedWaveform[prevIt->begin] = oneBit ^ sequenceBegin;
@@ -351,6 +362,6 @@ QVariantList WaveformParser::getParsedChannel1() const
WaveformParser* WaveformParser::instance()
{
- static WaveformParser p;
- return &p;
+ static QScopedPointer p { new WaveformParser() };
+ return p.get();
}
diff --git a/sources/core/wavreader.cpp b/sources/core/wavreader.cpp
index ac77de8..6c3edf5 100644
--- a/sources/core/wavreader.cpp
+++ b/sources/core/wavreader.cpp
@@ -8,6 +8,7 @@
#include "wavreader.h"
#include "sources/models/suspiciouspointsmodel.h"
+#include "sources/models/parsersettingsmodel.h"
#include
#include
#include
@@ -390,6 +391,8 @@ void WavReader::normalizeWaveform2(uint chNum)
return lessThanZero(o1) == lessThanZero(o2);
};
+ const auto& parserSettings = ParserSettingsModel::instance()->getParserSettings();
+
//Trying to find a sine
auto bIt = ch.begin();
@@ -440,7 +443,7 @@ void WavReader::normalizeWaveform2(uint chNum)
if (it != ch.end()) {
bIt = it;
double freq = getSampleRate() / std::distance(peaks[0], peaks[3]);
- if (freq <= ZERO_HALF_FREQ) {
+ if (freq <= parserSettings.zeroHalfFreq) {
auto it = peaks[2];
for (int i = 0; i < 2 && it != ch.end(); ++i, ++it) {
auto val = *it;
@@ -470,6 +473,6 @@ WavReader::~WavReader()
WavReader* WavReader::instance()
{
- static WavReader w;
- return &w;
+ static QScopedPointer w { new WavReader() };
+ return w.get();
}
diff --git a/sources/defines.h b/sources/defines.h
index 476637e..19d4ea9 100644
--- a/sources/defines.h
+++ b/sources/defines.h
@@ -21,14 +21,18 @@ enum SignalFrequencies {
PILOT_HALF_FREQ = 1620,
PILOT_FREQ = 810,
SYNCHRO_FIRST_HALF_FREQ = 4900,
- SYNCHRO_SECOND_HALF = 5500,
+ SYNCHRO_SECOND_HALF_FREQ = 5500,
SYNCHRO_FREQ = 2600,
ZERO_HALF_FREQ = 4090,
+ ZERO_FIRST_HALF_FREQ = 0,
+ ZERO_SECOND_HALF_FREQ = 0,
ZERO_FREQ = 2050,
ONE_HALF_FREQ = 2045,
ONE_FREQ = 1023
};
+const bool checkForAbnormalSine = true;
+
const double pilotDelta = 0.1;
const double synchroDelta = 0.3;
const double zeroDelta = 0.3;//0.3;//0.18;
diff --git a/sources/main.cpp b/sources/main.cpp
index 151786a..17aec7a 100644
--- a/sources/main.cpp
+++ b/sources/main.cpp
@@ -12,11 +12,13 @@
#include "sources/core/waveformparser.h"
#include "sources/models/fileworkermodel.h"
#include "sources/models/suspiciouspointsmodel.h"
+#include "sources/models/parsersettingsmodel.h"
void registerTypes()
{
qmlRegisterUncreatableType("com.enums.zxtapereviver", 1, 0, "FileWorkerResults", QString());
qmlRegisterUncreatableType("com.enums.zxtapereviver", 1, 0, "ErrorCodesEnum", QString());
+ qmlRegisterUncreatableType("com.enums.zxtapereviver", 1, 0, "WaveformControlOperationModes", QString());
qmlRegisterType("WaveformControl", 1, 0, "WaveformControl");
qmlRegisterSingletonType("com.models.zxtapereviver", 1, 0, "FileWorkerModel", [](QQmlEngine* engine, QJSEngine* scriptEngine) -> QObject* {
@@ -27,6 +29,7 @@ void registerTypes()
qmlRegisterSingletonInstance("com.models.zxtapereviver", 1, 0, "SuspiciousPointsModel", SuspiciousPointsModel::instance());
qmlRegisterSingletonInstance("com.core.zxtapereviver", 1, 0, "WavReader", WavReader::instance());
qmlRegisterSingletonInstance("com.core.zxtapereviver", 1, 0, "WaveformParser", WaveformParser::instance());
+ qmlRegisterSingletonInstance("com.models.zxtapereviver", 1, 0, "ParserSettingsModel", ParserSettingsModel::instance());
}
int main(int argc, char *argv[])
diff --git a/sources/models/parsersettingsmodel.cpp b/sources/models/parsersettingsmodel.cpp
new file mode 100644
index 0000000..8a13755
--- /dev/null
+++ b/sources/models/parsersettingsmodel.cpp
@@ -0,0 +1,243 @@
+//*******************************************************************************
+// ZX Tape Reviver
+//-----------------
+//
+// Author: Leonid Golouz
+// E-mail: lgolouz@list.ru
+//*******************************************************************************
+
+#include "parsersettingsmodel.h"
+#include "sources/defines.h"
+#include
+
+ParserSettingsModel::ParserSettingsModel(QObject* parent) :
+ QObject(parent),
+ m_parserSettings {
+ SignalFrequencies::PILOT_HALF_FREQ,
+ SignalFrequencies::PILOT_FREQ,
+ SignalFrequencies::SYNCHRO_FIRST_HALF_FREQ,
+ SignalFrequencies::SYNCHRO_SECOND_HALF_FREQ,
+ SignalFrequencies::SYNCHRO_FREQ,
+ SignalFrequencies::ZERO_HALF_FREQ,
+ SignalFrequencies::ZERO_FREQ,
+ SignalFrequencies::ONE_HALF_FREQ,
+ SignalFrequencies::ONE_FREQ,
+ pilotDelta,
+ synchroDelta,
+ zeroDelta,
+ oneDelta,
+ checkForAbnormalSine }
+{
+
+}
+
+void ParserSettingsModel::restoreDefaultSettings()
+{
+ setPilotHalfFreq(SignalFrequencies::PILOT_HALF_FREQ);
+ setPilotFreq(SignalFrequencies::PILOT_FREQ);
+ setSynchroFirstHalfFreq(SignalFrequencies::SYNCHRO_FIRST_HALF_FREQ);
+ setSynchroSecondHalfFreq(SignalFrequencies::SYNCHRO_SECOND_HALF_FREQ);
+ setSynchroFreq(SignalFrequencies::SYNCHRO_FREQ);
+ setZeroHalfFreq(SignalFrequencies::ZERO_HALF_FREQ);
+ setZeroFreq(SignalFrequencies::ZERO_FREQ);
+ setOneHalfFreq(SignalFrequencies::ONE_HALF_FREQ);
+ setOneFreq(SignalFrequencies::ONE_FREQ);
+ setPilotDelta(pilotDelta);
+ setSynchroDelta(synchroDelta);
+ setZeroDelta(zeroDelta);
+ setOneDelta(oneDelta);
+ setCheckForAbnormalSine(checkForAbnormalSine);
+}
+
+const ParserSettingsModel::ParserSettings& ParserSettingsModel::getParserSettings() const
+{
+ return m_parserSettings;
+}
+
+int ParserSettingsModel::getPilotHalfFreq() const
+{
+ return m_parserSettings.pilotHalfFreq;
+}
+
+int ParserSettingsModel::getPilotFreq() const
+{
+ return m_parserSettings.pilotFreq;
+}
+
+int ParserSettingsModel::getSynchroFirstHalfFreq() const
+{
+ return m_parserSettings.synchroFirstHalfFreq;
+}
+
+int ParserSettingsModel::getSynchroSecondHalfFreq() const
+{
+ return m_parserSettings.synchroSecondHalfFreq;
+}
+
+int ParserSettingsModel::getSynchroFreq() const
+{
+ return m_parserSettings.synchroFreq;
+}
+
+int ParserSettingsModel::getZeroHalfFreq() const
+{
+ return m_parserSettings.zeroHalfFreq;
+}
+
+int ParserSettingsModel::getZeroFreq() const
+{
+ return m_parserSettings.zeroFreq;
+}
+
+int ParserSettingsModel::getOneHalfFreq() const
+{
+ return m_parserSettings.oneHalfFreq;
+}
+
+int ParserSettingsModel::getOneFreq() const
+{
+ return m_parserSettings.oneFreq;
+}
+
+double ParserSettingsModel::getPilotDelta() const
+{
+ return m_parserSettings.pilotDelta;
+}
+
+double ParserSettingsModel::getSynchroDelta() const
+{
+ return m_parserSettings.synchroDelta;
+}
+
+double ParserSettingsModel::getZeroDelta() const
+{
+ return m_parserSettings.zeroDelta;
+}
+
+double ParserSettingsModel::getOneDelta() const
+{
+ return m_parserSettings.oneDelta;
+}
+
+bool ParserSettingsModel::getCheckForAbnormalSine() const
+{
+ return m_parserSettings.checkForAbnormalSine;
+}
+
+void ParserSettingsModel::setPilotHalfFreq(int freq)
+{
+ if (m_parserSettings.pilotHalfFreq != freq) {
+ m_parserSettings.pilotHalfFreq = freq;
+ emit pilotHalfFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setPilotFreq(int freq)
+{
+ if (m_parserSettings.pilotFreq != freq) {
+ m_parserSettings.pilotFreq = freq;
+ emit pilotFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setSynchroFirstHalfFreq(int freq)
+{
+ if (m_parserSettings.synchroFirstHalfFreq != freq) {
+ m_parserSettings.synchroFirstHalfFreq = freq;
+ emit synchroFirstHalfFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setSynchroSecondHalfFreq(int freq)
+{
+ if (m_parserSettings.synchroSecondHalfFreq != freq) {
+ m_parserSettings.synchroSecondHalfFreq = freq;
+ emit synchroSecondHalfFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setSynchroFreq(int freq)
+{
+ if (m_parserSettings.synchroFreq != freq) {
+ m_parserSettings.synchroFreq = freq;
+ emit synchroFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setZeroHalfFreq(int freq)
+{
+ if (m_parserSettings.zeroHalfFreq != freq) {
+ m_parserSettings.zeroHalfFreq = freq;
+ emit zeroHalfFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setZeroFreq(int freq)
+{
+ if (m_parserSettings.zeroFreq != freq) {
+ m_parserSettings.zeroFreq = freq;
+ emit zeroFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setOneHalfFreq(int freq)
+{
+ if (m_parserSettings.oneHalfFreq != freq) {
+ m_parserSettings.oneHalfFreq = freq;
+ emit oneHalfFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setOneFreq(int freq)
+{
+ if (m_parserSettings.oneFreq != freq) {
+ m_parserSettings.oneFreq = freq;
+ emit oneFreqChanged();
+ }
+}
+
+void ParserSettingsModel::setPilotDelta(double delta)
+{
+ if (m_parserSettings.pilotDelta != delta) {
+ m_parserSettings.pilotDelta = delta;
+ emit pilotDeltaChanged();
+ }
+}
+
+void ParserSettingsModel::setSynchroDelta(double delta)
+{
+ if (m_parserSettings.synchroDelta != delta) {
+ m_parserSettings.synchroDelta = delta;
+ emit synchroDeltaChanged();
+ }
+}
+
+void ParserSettingsModel::setZeroDelta(double delta)
+{
+ if (m_parserSettings.zeroDelta != delta) {
+ m_parserSettings.zeroDelta = delta;
+ emit zeroDeltaChanged();
+ }
+}
+
+void ParserSettingsModel::setOneDelta(double delta)
+{
+ if (m_parserSettings.oneDelta != delta) {
+ m_parserSettings.oneDelta = delta;
+ emit oneDeltaChanged();
+ }
+}
+
+void ParserSettingsModel::setCheckForAbnormalSine(bool check)
+{
+ if (m_parserSettings.checkForAbnormalSine != check) {
+ m_parserSettings.checkForAbnormalSine = check;
+ emit checkForAbnormalSineChanged();
+ }
+}
+
+ParserSettingsModel* ParserSettingsModel::instance()
+{
+ static QScopedPointer m { new ParserSettingsModel() };
+ return m.get();
+}
diff --git a/sources/models/parsersettingsmodel.h b/sources/models/parsersettingsmodel.h
new file mode 100644
index 0000000..25160be
--- /dev/null
+++ b/sources/models/parsersettingsmodel.h
@@ -0,0 +1,111 @@
+//*******************************************************************************
+// ZX Tape Reviver
+//-----------------
+//
+// Author: Leonid Golouz
+// E-mail: lgolouz@list.ru
+//*******************************************************************************
+
+#ifndef PARSERSETTINGSMODEL_H
+#define PARSERSETTINGSMODEL_H
+
+#include
+
+class ParserSettingsModel : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int pilotHalfFreq READ getPilotHalfFreq WRITE setPilotHalfFreq NOTIFY pilotHalfFreqChanged)
+ Q_PROPERTY(int pilotFreq READ getPilotFreq WRITE setPilotFreq NOTIFY pilotFreqChanged)
+ Q_PROPERTY(int synchroFirstHalfFreq READ getSynchroFirstHalfFreq WRITE setSynchroFirstHalfFreq NOTIFY synchroFirstHalfFreqChanged)
+ Q_PROPERTY(int synchroSecondHalfFreq READ getSynchroSecondHalfFreq WRITE setSynchroSecondHalfFreq NOTIFY synchroSecondHalfFreqChanged)
+ Q_PROPERTY(int synchroFreq READ getSynchroFreq WRITE setSynchroFreq NOTIFY synchroFreqChanged)
+ Q_PROPERTY(int zeroHalfFreq READ getZeroHalfFreq WRITE setZeroHalfFreq NOTIFY zeroHalfFreqChanged)
+ Q_PROPERTY(int zeroFreq READ getZeroFreq WRITE setZeroFreq NOTIFY zeroFreqChanged)
+ Q_PROPERTY(int oneHalfFreq READ getOneHalfFreq WRITE setOneHalfFreq NOTIFY oneHalfFreqChanged)
+ Q_PROPERTY(int oneFreq READ getOneFreq WRITE setOneFreq NOTIFY oneFreqChanged)
+ Q_PROPERTY(double pilotDelta READ getPilotDelta WRITE setPilotDelta NOTIFY pilotDeltaChanged)
+ Q_PROPERTY(double synchroDelta READ getSynchroDelta WRITE setSynchroDelta NOTIFY synchroDeltaChanged)
+ Q_PROPERTY(double zeroDelta READ getZeroDelta WRITE setZeroDelta NOTIFY zeroDeltaChanged)
+ Q_PROPERTY(double oneDelta READ getOneDelta WRITE setOneDelta NOTIFY oneDeltaChanged)
+ Q_PROPERTY(bool checkForAbnormalSine READ getCheckForAbnormalSine WRITE setCheckForAbnormalSine NOTIFY checkForAbnormalSineChanged)
+
+public:
+ struct ParserSettings {
+ int32_t pilotHalfFreq;
+ int32_t pilotFreq;
+ int32_t synchroFirstHalfFreq;
+ int32_t synchroSecondHalfFreq;
+ int32_t synchroFreq;
+ int32_t zeroHalfFreq;
+ int32_t zeroFreq;
+ int32_t oneHalfFreq;
+ int32_t oneFreq;
+ double pilotDelta;
+ double synchroDelta;
+ double zeroDelta;
+ double oneDelta;
+ bool checkForAbnormalSine;
+ };
+
+ explicit ParserSettingsModel(QObject* parent = nullptr);
+ virtual ~ParserSettingsModel() = default;
+ const ParserSettings& getParserSettings() const;
+
+ static ParserSettingsModel* instance();
+
+ Q_INVOKABLE void restoreDefaultSettings();
+
+ //Getters
+ int getPilotHalfFreq() const;
+ int getPilotFreq() const;
+ int getSynchroFirstHalfFreq() const;
+ int getSynchroSecondHalfFreq() const;
+ int getSynchroFreq() const;
+ int getZeroHalfFreq() const;
+ int getZeroFreq() const;
+ int getOneHalfFreq() const;
+ int getOneFreq() const;
+ double getPilotDelta() const;
+ double getSynchroDelta() const;
+ double getZeroDelta() const;
+ double getOneDelta() const;
+ bool getCheckForAbnormalSine() const;
+
+ //Setters
+ void setPilotHalfFreq(int freq);
+ void setPilotFreq(int freq);
+ void setSynchroFirstHalfFreq(int freq);
+ void setSynchroSecondHalfFreq(int freq);
+ void setSynchroFreq(int freq);
+ void setZeroHalfFreq(int freq);
+ void setZeroFreq(int freq);
+ void setOneHalfFreq(int freq);
+ void setOneFreq(int freq);
+ void setPilotDelta(double delta);
+ void setSynchroDelta(double delta);
+ void setZeroDelta(double delta);
+ void setOneDelta(double delta);
+ void setCheckForAbnormalSine(bool check);
+
+signals:
+ void pilotHalfFreqChanged();
+ void pilotFreqChanged();
+ void synchroFirstHalfFreqChanged();
+ void synchroSecondHalfFreqChanged();
+ void synchroFreqChanged();
+ void zeroHalfFreqChanged();
+ void zeroFreqChanged();
+ void oneHalfFreqChanged();
+ void oneFreqChanged();
+ void pilotDeltaChanged();
+ void synchroDeltaChanged();
+ void zeroDeltaChanged();
+ void oneDeltaChanged();
+ void checkForAbnormalSineChanged();
+
+private:
+ ParserSettings m_parserSettings;
+};
+
+#endif // PARSERSETTINGSMODEL_H
diff --git a/sources/models/suspiciouspointsmodel.cpp b/sources/models/suspiciouspointsmodel.cpp
index b58bf75..61f4887 100644
--- a/sources/models/suspiciouspointsmodel.cpp
+++ b/sources/models/suspiciouspointsmodel.cpp
@@ -82,6 +82,6 @@ void SuspiciousPointsModel::setSuspiciousPoints(const QVariantList& m)
SuspiciousPointsModel* SuspiciousPointsModel::instance()
{
- static SuspiciousPointsModel m;
- return &m;
+ static QScopedPointer m { new SuspiciousPointsModel() };
+ return m.get();
}