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(); }