diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 344d673d92a5c212a988e98af60d39e4e00a9673..8c13506a4cc26a10c93fff19343d3a58b6f1989c 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,29 +25,29 @@ find_package(Qt5PrintSupport REQUIRED) if(UNIX AND NOT APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro") # rpath rules option(OBS_SUSE_QUIRKS "Must be ON for Suse machines in Open Build Services" OFF) - set(NOOTKA_LIB_PATH "${CMAKE_INSTALL_PREFIX}/lib/nootka") - set(CMAKE_SKIP_BUILD_RPATH FALSE) # use, i.e. don't skip the full RPATH for the build tree - if(OBS_SUSE_QUIRKS) + set(NOOTKA_LIB_PATH "${CMAKE_INSTALL_PREFIX}/lib/nootka") + set(CMAKE_SKIP_BUILD_RPATH FALSE) # use, i.e. don't skip the full RPATH for the build tree + if(OBS_SUSE_QUIRKS) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) message("Build for Suse OBS") else(OBS_SUSE_QUIRKS) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # when building, don't use the install RPATH already (but later on when installing) endif(OBS_SUSE_QUIRKS) - set(CMAKE_INSTALL_RPATH "${NOOTKA_LIB_PATH}") - # add the automatically determined parts of the RPATH - # which point to directories outside the build tree to the install RPATH - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) - - # the RPATH to be used when installing, but only if it's not a system directory - list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${NOOTKA_LIB_PATH}" isSystemDir) - if("${isSystemDir}" STREQUAL "-1") - set(CMAKE_INSTALL_RPATH "${NOOTKA_LIB_PATH}") - endif("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${NOOTKA_LIB_PATH}") + # add the automatically determined parts of the RPATH + # which point to directories outside the build tree to the install RPATH + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + + # the RPATH to be used when installing, but only if it's not a system directory + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${NOOTKA_LIB_PATH}" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${NOOTKA_LIB_PATH}") + endif("${isSystemDir}" STREQUAL "-1") endif(UNIX AND NOT APPLE) if (APPLE) # Mac RPath @@ -87,7 +87,7 @@ qt5_add_resources(NOOTKA_SRC nootka.qrc) add_executable(nootka WIN32 ${NOOTKA_SRC} ${NOOTKA_EXE_ICON}) target_link_libraries(nootka NootkaCore -# NootkaScore + NootkaSound Qt5::Core Qt5::Widgets Qt5::Qml @@ -96,12 +96,12 @@ target_link_libraries(nootka ) -if(UNIX AND NOT APPLE) # Linux path for Nootka binary +if(UNIX AND NOT APPLE) # Linux path for Nootka binary install(TARGETS nootka DESTINATION bin) else(UNIX AND NOT APPLE) - if(WIN32) # Windows + if(WIN32) # Windows install(TARGETS nootka DESTINATION .) - else(WIN32) # MacOs + else(WIN32) # MacOs install(TARGETS nootka DESTINATION "${CMAKE_INSTALL_PREFIX}/nootka.app/Contents/MacOs") install( CODE " execute_process(COMMAND echo copying info.plist ) diff --git a/src/libs/core/ttickcolors.cpp b/src/libs/core/ttickcolors.cpp index f08a4858ae54aadc505f40e00fa2960985447cbf..7afb8ad50988ce0c1ebc0873843723d315ea2e94 100644 --- a/src/libs/core/ttickcolors.cpp +++ b/src/libs/core/ttickcolors.cpp @@ -28,38 +28,47 @@ QColor TtickColors::disabledColor = Qt::gray; TtickColors::TtickColors(QObject* parent) : - QObject(parent) -{ + QObject(parent), + m_divisor(6.0) +{} + +void TtickColors::setWidth(qreal w) { + if (w != m_width) { + m_width = w; + resize(m_width); + emit widthChanged(); + } +} + + +void TtickColors::setDivisor(qreal d) { + if (d != m_divisor) { + m_divisor = d; + resize(m_width); + emit divisorChanged(); + } } void TtickColors::resize(qreal w) { - int m_ticksCount = qFloor(w / 6); -// m_hiTickStep = ((float)height() * 0.66) / m_ticksCount; + int m_ticksCount = qFloor(w / m_divisor) + 1; m_tickColors.clear(); for (int i = 0; i < m_ticksCount; i++) { - if (i <= m_ticksCount * 0.2) - m_tickColors << startColor; - else if (i <= m_ticksCount * 0.5) - m_tickColors << gradColorAtPoint(w * 0.2, w * 0.55, startColor, middleColor, - (i + 1) * (w / m_ticksCount)); - else if (i <= m_ticksCount * 0.6) - m_tickColors << middleColor; - else if ( i <= m_ticksCount * 0.8) - m_tickColors << gradColorAtPoint(w * 0.6, w * 0.82, - middleColor, endColor, (i + 1) * (w / m_ticksCount)); - else - m_tickColors << gradColorAtPoint(w * 0.8, w, - endColor, totalColor, (i + 1) * (w / m_ticksCount)); - } + if (i < qFloor(m_ticksCount * 0.3)) + m_tickColors << gradColorAtPoint(0.0, w * 0.3, startColor, middleColor, (i) * (w / m_ticksCount)); + else if (i < qFloor(m_ticksCount * 0.9)) + m_tickColors << gradColorAtPoint(w * 0.3, w * 0.9, middleColor, endColor, (i) * (w / m_ticksCount)); + else + m_tickColors << gradColorAtPoint(w * 0.9, w, endColor, totalColor, (i) * (w / m_ticksCount)); + } } -QColor TtickColors::gradColorAtPoint(float lineX1, float lineX2, QColor startC, QColor endC, float posC) { - float segmentLength = qSqrt((lineX2 - lineX1) * (lineX2 - lineX1)); - double pdist = qSqrt((posC - lineX1) * (posC - lineX1)); - double ratio = pdist / segmentLength; +QColor TtickColors::gradColorAtPoint(qreal lineX1, qreal lineX2, const QColor& startC, const QColor& endC, qreal posC) { + qreal segmentLength = qSqrt((lineX2 - lineX1) * (lineX2 - lineX1)); + qreal pdist = qSqrt((posC - lineX1) * (posC - lineX1)); + qreal ratio = pdist / segmentLength; int red = qBound(0, (int)(ratio * endC.red() + ( 1 - ratio) * startC.red()), 255); int green = qBound(0, (int)(ratio * endC.green() + (1 - ratio) * startC.green()), 255); int blue = qBound(0, (int)(ratio * endC.blue() + (1 - ratio) * startC.blue()), 255); diff --git a/src/libs/core/ttickcolors.h b/src/libs/core/ttickcolors.h index 6fb9c2446887cce37989981e5d6025095fe1797c..17fa889245ee3b21b1f713c502702e6bf338730e 100644 --- a/src/libs/core/ttickcolors.h +++ b/src/libs/core/ttickcolors.h @@ -26,29 +26,57 @@ #include <QtCore/QDebug> +/** + * @class TtickColors generates list of gradient colors in a line of declared @p width(). + * Number of ticks is obtained by @p width() divided by @p divisor(). + * Then gradient values of @p startColor -> @p middleColor -> @p endColor -> @p totalColor + * are stored in the list accessible by @p colorAt(tickNr) + */ class NOOTKACORE_EXPORT TtickColors : public QObject { Q_OBJECT + Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged) + Q_PROPERTY(qreal divisor READ divisor WRITE setDivisor NOTIFY divisorChanged) + public: TtickColors(QObject* parent = nullptr); - Q_INVOKABLE void resize(qreal w); + qreal width() const { return m_width; } + void setWidth(qreal w); + + /** + * This is the sum of tick width and gap distance in pixels + */ + qreal divisor() const { return m_divisor; } + void setDivisor(qreal d); + + void resize(qreal w); Q_INVOKABLE QColor colorAt(int nr) { if (nr < 0 || nr > m_tickColors.count() - 1) { - qDebug() << "wrong color number" << nr; + qDebug() << "[TtickColors] WRONG COLOR NUMBER!" << nr; return QColor(); } return m_tickColors[qBound(0, nr, m_tickColors.count() - 1)]; } - QColor gradColorAtPoint(float lineX1, float lineX2, QColor startC, QColor endC, float posC); + /** + * Calculates color at point @p posC on the line of X points from @p lineX1 to @p lineX2 + * of gradient with colors @p startC to @p endColor. @p posC has to be inside @p lineX1 and @p lineX2 + */ + QColor gradColorAtPoint(qreal lineX1, qreal lineX2, const QColor& startC, const QColor& endC, qreal posC); static QColor startColor, middleColor, endColor, totalColor, disabledColor; +signals: + void widthChanged(); + void divisorChanged(); + private: QList<QColor> m_tickColors; + qreal m_width; + qreal m_divisor; }; #endif diff --git a/src/libs/sound/tartiniparams.h b/src/libs/sound/tartiniparams.h index 4b3fe9c451a82f535c5fe992f64c7b093932eb4c..b75368903e2926f87d7353619086825fc297283a 100644 --- a/src/libs/sound/tartiniparams.h +++ b/src/libs/sound/tartiniparams.h @@ -35,22 +35,22 @@ enum EanalysisModes { e_MPM = 0, e_AUTOCORRELATION = 1, e_MPM_MODIFIED_CEPSTRUM class NOOTKASOUND_EXPORT TartiniParams { public: - quint32 rate; - quint8 chanells; - quint32 windowSize; - quint32 framesPerChunk; /** in mono signal frames are the same as samples */ - double dBFloor; - bool equalLoudness; - bool doingFreqAnalysis; - bool doingAutoNoiseFloor; - bool doingHarmonicAnalysis; - bool firstTimeThrough; - bool doingDetailedPitch; - int threshold; /** threshold of lowest loudness in [dB] */ - EanalysisModes analysisType; - double topPitch; /** The highest possible note pitch allowed (lowest possible is 0 in Tartini) */ - qint16 loPitch; /** The lowest possible note. Filtered in searchIn() method */ - double ampThresholds[7][2]; + quint32 rate; + quint8 chanells; + quint32 windowSize; + quint32 framesPerChunk; /**< in mono signal frames are the same as samples */ + double dBFloor; + bool equalLoudness; + bool doingFreqAnalysis; + bool doingAutoNoiseFloor; + bool doingHarmonicAnalysis; + bool firstTimeThrough; + bool doingDetailedPitch; + int threshold; /**< threshold of lowest loudness in [dB] */ + EanalysisModes analysisType; + double topPitch; /**< The highest possible note pitch allowed (lowest possible is 0 in Tartini) */ + qint16 loPitch; /**< The lowest possible note. Filtered in searchIn() method */ + double ampThresholds[7][2]; }; diff --git a/src/libs/sound/tcommonlistener.cpp b/src/libs/sound/tcommonlistener.cpp index 727d98b103f5d7c04a1449eb518d1d123a9bdd5c..89fe77383af3e0ac1272fb36367c18773a475f6f 100644 --- a/src/libs/sound/tcommonlistener.cpp +++ b/src/libs/sound/tcommonlistener.cpp @@ -74,11 +74,6 @@ TcommonListener::~TcommonListener() { } -void TcommonListener::startListening() {} /* virtual */ -void TcommonListener::stopListening() {} /* virtual */ - - - void TcommonListener::setAudioInParams() { setDetectionMethod(m_audioParams->detectMethod); setMinimalVolume(m_audioParams->minimalVol); diff --git a/src/libs/sound/tcommonlistener.h b/src/libs/sound/tcommonlistener.h index 45e500d445fdcbd74c457897236aab4c944dbb7f..21d9213099ed7b78f0403be8b176f4b0ce9d5110 100644 --- a/src/libs/sound/tcommonlistener.h +++ b/src/libs/sound/tcommonlistener.h @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ + #ifndef TCOMMONLISTENER_H #define TCOMMONLISTENER_H @@ -50,7 +51,8 @@ public: ~TcommonListener(); - /** State of input audio device: + /** + * State of input audio device: * @p e_listening - when input captures data and emits signals * @p e_paused - when data is capturing but signals about detected pitches are not emitting * @p e_stopped - capturing data is stopped. @@ -58,62 +60,105 @@ public: */ enum Estate { e_detecting = 0, e_paused = 1, e_stopped = 2 }; - /** Stops emitting signals about pitch detection, but detection is still performed. - * It also resets last chunk pitch to ignore detection - * It helps to sniff whole sound/note from begin to its end. */ + /** + * Stops emitting signals about pitch detection, but detection is still performed. + * It also resets last chunk pitch to ignore detection + * It helps to sniff whole sound/note from begin to its end. + */ void pause() { m_LastChunkPitch = 0.0; if (m_state == e_detecting) setState(e_paused); } - /** Starts emitting @p noteStarted() and @p noteFinished() signals again. */ + /** + * Starts emitting @p noteStarted() and @p noteFinished() signals again. + */ void unPause() { if (m_state == e_paused) setState(e_detecting); } bool isPaused() { return m_state == e_paused; } bool isStoped() { return m_state == e_stopped; } Estate detectingState() { return m_state; } - /** Current volume of detecting sound or 0 if silence */ + /** + * Current volume of detecting sound or 0 if silence + */ float volume() { return m_volume; } - /** Volume of raw PCM signal */ + /** + * Volume of raw PCM signal + */ qreal pcmVolume(); - /** Sets device parameters stores in structure SaudioInParams. - * SaudioInParams::deviceName is ignored. It have to be set separately. */ + /** + * Sets device parameters stores in structure SaudioInParams. + * SaudioInParams::deviceName is ignored. It have to be set separately. + */ virtual void setAudioInParams(); - /** Sets minimal volume needed that note will be detected. Overrides global setting. */ + /** + * Sets minimal volume needed that note will be detected. Overrides global setting. + */ void setMinimalVolume(float minVol); float minimalVolume(); + /** + * Sets range of notes which are detected. Others are ignored. + */ + void setAmbitus(Tnote loNote, Tnote hiNote); + + /** + * Returns lower boundary note of ambitus + */ + Tnote& loNote() { return m_loNote; } - void setAmbitus(Tnote loNote, Tnote hiNote); /**< Sets range of notes which are detected. Others are ignored. */ - Tnote& loNote() { return m_loNote; } /**< Returns lower boundary note of ambitus */ - Tnote& hiNote() { return m_hiNote; } /**< Returns upper boundary note of ambitus */ + /** + * Returns upper boundary note of ambitus + */ + Tnote& hiNote() { return m_hiNote; } - qreal lastNotePitch() { return m_lastNote.pitchF; } /**< Pitch of last detected note in double precision. */ - TnoteStruct& lastNote() { return m_lastNote; } /**< Pitch, frequency and duration of the last detected note. */ + /** + * Pitch of last detected note in double precision. + */ + qreal lastNotePitch() { return m_lastNote.pitchF; } + + /** + * Pitch, frequency and duration of the last detected note. + */ + TnoteStruct& lastNote() { return m_lastNote; } float lastChunkPitch() { return m_LastChunkPitch; } + /** + * Returns @p TRUE when @p pitch is in ambitus + */ bool inRange(qreal pitch) { if (pitch >= m_loPitch && pitch <= m_hiPitch) return true; else return false; - } /** Returns @p TRUE when @p pitch is in ambitus */ + } bool noteWasStarted() { return m_noteWasStarted; } /**< @p TRUE when note started but not finished. */ - /** Sets pitch detection method. Currently three are available: + /** + * Sets pitch detection method. Currently three are available: * 0 - MPM (Philip McLeod Method) - default * 1 - auto-correlation * 2 - MPM modified cepstrum. - * Currently set value is available through global. */ + * Currently set value is available through global. + */ void setDetectionMethod(int method); - /** Stores user action when he stopped sniffing himself. */ + /** + * Stores user action when he stopped sniffing himself. + */ void setStoppedByUser(bool userStop) { m_stoppedByUser = userStop; } bool stoppedByUser() { return m_stoppedByUser; } - quint8 intonationAccuracy(); /**< Returns intonation accuracy sets in global audio settings. */ - void setIntonationAccuracy(qint8 intAcc); /**< Sets global value of intonation accuracy. It doesn't refresh intonation view. */ + /** + * Returns intonation accuracy sets in global audio settings. + */ + quint8 intonationAccuracy(); + + /** + * Sets global value of intonation accuracy. It doesn't refresh intonation view. + */ + void setIntonationAccuracy(qint8 intAcc); int detectionRange() { return m_currentRange; } /**< Integer value of @p TpitchFinder::Erange */ #if !defined (Q_OS_ANDROID) @@ -122,28 +167,50 @@ public: signals: - /** Emitted when note was played and its duration is longer than minimal duration */ + /** + * Emitted when note was played and its duration is longer than minimal duration + */ void noteStarted(const TnoteStruct&); - /** When already started note fade out and finished */ + /** + * When already started note fade out and finished + */ void noteFinished(const TnoteStruct&); - /** When device changes its state. It can be cast on @p Estate enumeration. */ + /** + * When device changes its state. It can be cast on @p Estate enumeration. + */ void stateChanged(int); - /** Emitted when raw PCM volume is too high or too low for a few detected notes */ + /** + * Emitted when raw PCM volume is too high or too low for a few detected notes + */ void lowPCMvolume(); void hiPCMvolume(); public slots: - virtual void startListening(); /**< This virtual method is responsible for starting audio input */ - virtual void stopListening(); /**< This virtual method is responsible for stopping audio input */ + /** + * This virtual method is responsible for starting audio input + */ + virtual void startListening() = 0; + + /** + * This virtual method is responsible for stopping audio input + */ + virtual void stopListening() = 0; protected: - TpitchFinder* finder() { return m_pitchFinder; } /**< Instance of @p TpitchFinder */ - void resetVolume() { m_volume = 0.0; } /**< Sets volume to 0 */ + /** + * Instance of @p TpitchFinder + */ + TpitchFinder* finder() { return m_pitchFinder; } + + /** + * Sets volume to 0 + */ + void resetVolume() { m_volume = 0.0; } void resetChunkPitch() { m_LastChunkPitch = 0.0; } diff --git a/src/libs/sound/tsound.cpp b/src/libs/sound/tsound.cpp index 5a706f4fffd6f001cf5ac90c920752057a97741b..604c8496a11e602a0c9b15740f9608842bd17b0a 100755 --- a/src/libs/sound/tsound.cpp +++ b/src/libs/sound/tsound.cpp @@ -33,10 +33,13 @@ #include <QtCore/qdebug.h> + /* static */ Tsound* Tsound::m_instance = nullptr; +#define INT_FACTOR (1.2) + Tsound::Tsound(QObject* parent) : QObject(parent), player(0), @@ -64,6 +67,8 @@ Tsound::Tsound(QObject* parent) : } else { sniffer = 0; } + + QTimer::singleShot(750, [=]{ sniffer->startListening(); }); } Tsound::~Tsound() @@ -114,6 +119,19 @@ void Tsound::playMelody(Tmelody* mel) { } +qreal Tsound::inputVol() { + return sniffer ? sniffer->volume() : 0.0; +} + + +qreal Tsound::pitchDeviation() { + if (sniffer) + return static_cast<qreal>(qBound(-0.49, (sniffer->lastChunkPitch() - static_cast<float>(qRound(sniffer->lastChunkPitch()))) * INT_FACTOR, 0.49)); + else + return 0.0; +} + + void Tsound::acceptSettings() { bool doParamsUpdated = false; // for output diff --git a/src/libs/sound/tsound.h b/src/libs/sound/tsound.h index 0c5db527ee9eebbf2d27a6fa6baee39cc706065a..f9303290bf3fd36ba6bc4d05d08cf8ef6eca4a46 100644 --- a/src/libs/sound/tsound.h +++ b/src/libs/sound/tsound.h @@ -65,6 +65,17 @@ public: bool isSniffable() { return (sniffer ? true : false) ; } bool melodyIsPlaying() { return m_melodyNoteIndex > -1; } + /** + * Normalized volume of detected note + */ + Q_INVOKABLE qreal inputVol(); + + /** + * Value representing fractional part of the pitch in current chunk, + * it expressing a clearness of the pitch + */ + Q_INVOKABLE qreal pitchDeviation(); + // TpitchView* pitchView() { return m_pitchView; } /**< First instance existing in main window */ /** diff --git a/src/main.cpp b/src/main.cpp index 0bdb3e9447f5b3b3b464d1a7a87db0ef8da4b5e2..6a9b61db582ccb06102e479643533e6b9b4731ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,14 +32,18 @@ #include "tpath.h" #include "tnootkaqml.h" +#include <tsound.h> #if defined (Q_OS_ANDROID) #include <Android/tandroid.h> #endif + static QString logFile; -/** It allows to grab all debug messages into nootka-log.txt file */ +/** + * It allows to grab all debug messages into nootka-log.txt file + */ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_UNUSED(context) Q_UNUSED(type) @@ -109,10 +113,13 @@ int main(int argc, char *argv[]) a->setWindowIcon(QIcon(Tpath::img("nootka"))); + Tsound sound; + // creating main window e = new QQmlApplicationEngine; e->rootContext()->setContextProperty(QStringLiteral("GLOB"), GLOB); e->rootContext()->setContextProperty(QStringLiteral("Noo"), &nooObj); + e->rootContext()->setContextProperty(QStringLiteral("SOUND"), &sound); if (GLOB->isFirstRun) { e->load(QUrl(QStringLiteral("qrc:/wizard/Wizard.qml"))); exitCode = a->exec(); @@ -120,6 +127,7 @@ int main(int argc, char *argv[]) e = new QQmlApplicationEngine; e->rootContext()->setContextProperty(QStringLiteral("GLOB"), GLOB); e->rootContext()->setContextProperty(QStringLiteral("Noo"), &nooObj); + e->rootContext()->setContextProperty(QStringLiteral("SOUND"), &sound); GLOB->isFirstRun = false; } e->load(QUrl(QStringLiteral("qrc:/MainWindow.qml"))); diff --git a/src/qml/TtoolBar.qml b/src/qml/TtoolBar.qml index 9649156152bc66bcb764b2325a73caff3f0cd0c2..4909ee9ea849bdd3c55738f9c8c3d647d3a866ef 100644 --- a/src/qml/TtoolBar.qml +++ b/src/qml/TtoolBar.qml @@ -4,15 +4,14 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 -import QtQuick.Window 2.2 ToolBar { id: toolBar - height: settAct.height property alias scoreAct: scoreAct + height: settAct.height background: Rectangle { anchors.fill: parent; color: activPal.window } Row { @@ -21,13 +20,23 @@ ToolBar { HeadButton { id: scoreAct; action: nootkaWindow.scoreAct } HeadButton { action: nootkaWindow.examAct } } + PitchView { - x: lab.x - parent.width * 0.41; y: parent.height * 0.05 + id: pitchView + x: label.x - parent.width * 0.41; y: parent.height * 0.05 height: parent.height * 0.9 width: parent.width * 0.4 + Timer { + repeat: true; interval: 75; running: true + onTriggered: { + pitchView.volume = SOUND.inputVol() + pitchView.deviation = SOUND.pitchDeviation() + } + } } + NootkaLabel { - id: lab + id: label anchors.right: parent.right height: toolBar.height onClicked: nootkaWindow.aboutAct.trigger() diff --git a/src/qml/sound/IntonationBar.qml b/src/qml/sound/IntonationBar.qml index 2a0f6a6732449b8cc02ed84926dff71ed4334f46..31e118a5e5fc3d64e68417de3c90aa046aac09f0 100644 --- a/src/qml/sound/IntonationBar.qml +++ b/src/qml/sound/IntonationBar.qml @@ -3,7 +3,6 @@ * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ import QtQuick 2.9 -import QtGraphicalEffects 1.0 import Nootka 1.0 @@ -11,21 +10,15 @@ import Nootka 1.0 Item { id: intoBar - property real pitch: 0.1 + property real deviation: 0.0 - onWidthChanged: tc.resize(intoBar.width - noteText.width * 3) - - TtickColors { id: tc } + TtickColors { id: tc; width: (intoBar.width - noteText.width * 3) / 2; divisor: pitchView.tickGap + pitchView.tickWidth } Repeater { id: iRepLeft - model: (intoBar.width - noteText.width * 3) / 2 / (pitchView.tickGap + pitchView.tickWidth) - 1 + model: tc.width / tc.divisor Rectangle { - color: activPal.text -// color: { -// var tickNr = iRep.model * index / 100 -// tickNr <= volBar.volume * 100 ? tc.colorAt(tickNr) : disdPal.text -// } + color: deviation < 0 && iRepLeft.model - index <= (deviation * -2 * iRepLeft.model) ? tc.colorAt(iRepLeft.model - index) : activPal.text width: pitchView.tickWidth radius: pitchView.tickWidth / 2 height: pitchView.tickWidth * 1.5 + ((intoBar.height - pitchView.tickWidth * 4) / iRepLeft.model) * (iRepLeft.model - index) @@ -47,13 +40,9 @@ Item { Repeater { id: iRepRight - model: (intoBar.width - noteText.width * 3) / 2 / (pitchView.tickGap + pitchView.tickWidth) - 1 + model: tc.width / tc.divisor Rectangle { - color: activPal.text -// color: { -// var tickNr = iRep.model * index / 100 -// tickNr <= volBar.volume * 100 ? tc.colorAt(tickNr) : disdPal.text -// } + color: deviation > 0 && index <= (deviation * 2 * iRepRight.model) ? tc.colorAt(index) : activPal.text width: pitchView.tickWidth radius: pitchView.tickWidth / 2 height: pitchView.tickWidth * 1.5 + ((intoBar.height - pitchView.tickWidth * 4) / iRepRight.model) * index diff --git a/src/qml/sound/PitchView.qml b/src/qml/sound/PitchView.qml index 53ee3d3e8f002171c389c82491a8d7a37296570c..c4c7a796c3017196404a367d7b64202a5143e1c7 100644 --- a/src/qml/sound/PitchView.qml +++ b/src/qml/sound/PitchView.qml @@ -9,18 +9,26 @@ import QtQuick.Window 2.2 Item { id: pitchView + property alias volume : volBar.volume + property alias minVol : volBar.minVol + property alias deviation : intoBar.deviation + + // private property real tickWidth: Screen.pixelDensity * 0.5 property real tickGap: tickWidth * 1.25 IntonationBar { + id: intoBar + y: parent.height * 0.05 width: parent.width - height: parent.height / 2 + height: parent.height * 0.45 } VolumeBar { - y: parent.height / 2 + id: volBar + y: parent.height * 0.55 width: parent.width - height: parent.height / 2 + height: parent.height * 0.45 } } diff --git a/src/qml/sound/VolumeBar.qml b/src/qml/sound/VolumeBar.qml index 17221aa28b94c42a80e2f301ab7990aaee41c052..c3f724a87eeae81bffdafff09ea29804360e7187 100644 --- a/src/qml/sound/VolumeBar.qml +++ b/src/qml/sound/VolumeBar.qml @@ -14,34 +14,38 @@ Item { property real volume: 0.05 property real minVol: 0.4 - onWidthChanged: tc.resize(volBar.width - minText.width - noteText.width * 2) - TtickColors { id: tc } + TtickColors { id: tc; width: volBar.width - minText.width - noteText.width * 2; divisor: pitchView.tickGap + pitchView.tickWidth } - Rectangle { - id: bgRect - anchors.fill: parent - color: activPal.window + MouseArea { + id: area + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton + onPositionChanged: { + if (pressedButtons && mouseX > vRep.itemAt(1).x && mouseX < vRep.itemAt(vRep.model - 2).x) { + var mv = (mouseX - minText.width) / tc.width + if (mv > 0.1 && mv < 0.9) + minVol = mv + } + } } Text { id: minText - anchors.top: parent.Top - anchors.left: parent.Left - anchors.verticalCenter: parent.verticalCenter + anchors { top: parent.Top; left: parent.Left; verticalCenter: parent.verticalCenter } text: " " + Math.round(minVol * 100) + "% " color: activPal.text + font.pixelSize: parent.height / 2 + width: parent.height * 1.2 } Repeater { id: vRep - model: (volBar.width - minText.width - noteText.width * 2) / (pitchView.tickGap + pitchView.tickWidth) + model: tc.width / tc.divisor Rectangle { - color: { - var tickNr = vRep.model * index / 100 - tickNr <= volBar.volume * 100 ? tc.colorAt(tickNr) : disdPal.text - } - width: (index * 9) < minVol * (volBar.width - minText.width - noteText.width * 1.5) ? pitchView.tickWidth / 2 : pitchView.tickWidth + color: index <= volume * vRep.model ? tc.colorAt(index) : activPal.text + width: index <= minVol * vRep.model ? pitchView.tickWidth / 2 : pitchView.tickWidth radius: pitchView.tickWidth / 2 height: pitchView.tickWidth * 1.5 + ((volBar.height - pitchView.tickWidth * 4) / vRep.model) * index y: (parent.height - height) / 2 @@ -51,13 +55,18 @@ Item { Text { id: noteText - anchors.top: parent.Top x: volBar.width - width * 1.5 anchors.verticalCenter: parent.verticalCenter font.family: "Nootka" font.pixelSize: volBar.height text: "r" color: activPal.text + MouseArea { + anchors.fill: parent + hoverEnabled: true + onEntered: noteText.color = activPal.highlight + onExited: noteText.color = activPal.text + } } DropShadow { @@ -68,12 +77,12 @@ Item { color: activPal.shadow radius: 8.0 source: knob - visible: false + visible: area.pressed || area.containsMouse } Rectangle { id: knob - x: minVol * volBar.width + x: minText.width + minVol * tc.width - radius y: (volBar.height - height) / 2 visible: false height: volBar.height * 0.9 @@ -89,25 +98,4 @@ Item { } } - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton - - onEntered: { - knobShad.visible = true - } - onPositionChanged: { - if (pressedButtons && mouseX > vRep.itemAt(1).x && mouseX < vRep.itemAt(vRep.model - 2).x) { - var mv = mouseX / volBar.width - if (mv > 0.1 && mv < 0.9) { - minVol = (mouseX - knob.width) / volBar.width - knob.x = mouseX - knob.width / 2 - } - } - } - onExited: { - knobShad.visible = false - } - } }