├── .gitattributes
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── CMakeLists.txt
├── CockHeroine.pro
├── CockHeroine.pro.user
├── LICENSING.txt
├── README.md
├── Resources
├── CMakeLists.txt
├── CockHeroine.desktop
├── WandIcon.png
└── resources.qrc
├── Source
├── .buttplugdeviceconfigdialog.ui.un~
├── abstractbeatinterval.cpp
├── abstractbeatinterval.h
├── abstractnewbeatvaluewidget.cpp
├── abstractnewbeatvaluewidget.h
├── adddialog.cpp
├── adddialog.h
├── adddialog.ui
├── adjustdialog.cpp
├── adjustdialog.h
├── adjustdialog.ui
├── analysisoptionsdialog.cpp
├── analysisoptionsdialog.h
├── analysisoptionsdialog.ui
├── beatanalysis.cpp
├── beatanalysis.h
├── beatdatamodel.cpp
├── beatdatamodel.h
├── beatinterval.cpp
├── beatinterval.h
├── beatmeter
│ ├── editorgridline.cpp
│ └── editorgridline.h
├── beatoptimisation.cpp
├── beatoptimisation.h
├── beatpattern.cpp
├── beatpattern.h
├── beattimestamp.cpp
├── beattimestamp.h
├── beatvalue.cpp
├── beatvalue.h
├── beatvaluewidget.cpp
├── beatvaluewidget.h
├── buttplug
│ ├── buttplugdevice.cpp
│ ├── buttplugdevice.h
│ ├── buttplugdevicefeature.cpp
│ ├── buttplugdevicefeature.h
│ ├── buttpluginterface.cpp
│ └── buttpluginterface.h
├── buttplugdeviceconfigdialog.cpp
├── buttplugdeviceconfigdialog.h
├── buttplugdeviceconfigdialog.ui
├── buttplugdeviceconfigdialog.ui~
├── buttplugdispatcher.cpp
├── buttplugdispatcher.h
├── buttplugfeatureparams.cpp
├── buttplugfeatureparams.h
├── chmlhandler.cpp
├── chmlhandler.h
├── config.h
├── croppedvideosurface.cpp
├── croppedvideosurface.h
├── customeventaction.cpp
├── customeventaction.h
├── deletedialog.cpp
├── deletedialog.h
├── deletedialog.ui
├── editorwindow.cpp
├── editorwindow.h
├── editorwindow.ui
├── enableidentifyintervalsdialog.cpp
├── enableidentifyintervalsdialog.h
├── enableidentifyintervalsdialog.ui
├── event.cpp
├── event.h
├── eventdatamodel.cpp
├── eventdatamodel.h
├── eventdataproxymodel.cpp
├── eventdataproxymodel.h
├── eventdispatcher.cpp
├── eventdispatcher.h
├── eventmetadata.cpp
├── eventmetadata.h
├── eventtabledelegate.cpp
├── eventtabledelegate.h
├── exportbeatmeterdialog.cpp
├── exportbeatmeterdialog.h
├── exportbeatmeterdialog.ui
├── funscriptwriter.cpp
├── funscriptwriter.h
├── globals.cpp
├── globals.h
├── graphicsscenevideodialog.cpp
├── graphicsscenevideodialog.h
├── graphicsscenevideodialog.ui
├── handycsvwriter.cpp
├── handycsvwriter.h
├── helperfunctions.cpp
├── helperfunctions.h
├── intervaldatamodel.cpp
├── intervaldatamodel.h
├── keyboardshortcutsdialog.cpp
├── keyboardshortcutsdialog.h
├── keyboardshortcutsdialog.ui
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── midifilereader.cpp
├── midifilereader.h
├── midifilewriter.cpp
├── midifilewriter.h
├── newbeatvaluewidget.cpp
├── newbeatvaluewidget.h
├── newcustombeatvaluewidget.cpp
├── newcustombeatvaluewidget.h
├── optimisationoptionsdialog.cpp
├── optimisationoptionsdialog.h
├── optimisationoptionsdialog.ui
├── optionsdialog.cpp
├── optionsdialog.h
├── optionsdialog.ui
├── patterndatamodel.cpp
├── patterndatamodel.h
├── pch.h
├── playbackassociatedaction.cpp
├── playbackassociatedaction.h
├── playbackassociatedactions
│ ├── pregenerateestimsignalaction.cpp
│ └── pregenerateestimsignalaction.h
├── preplaybackactionmanager.cpp
├── preplaybackactionmanager.h
├── preplaybackinfodialog.cpp
├── preplaybackinfodialog.h
├── preplaybackinfodialog.ui
├── seektotimecodedialog.cpp
├── seektotimecodedialog.h
├── seektotimecodedialog.ui
├── splitdialog.cpp
├── splitdialog.h
├── splitdialog.ui
├── stimsignal
│ ├── dualchannelsignalgenerator.cpp
│ ├── dualchannelsignalgenerator.h
│ ├── estimwavfilewriter.cpp
│ ├── estimwavfilewriter.h
│ ├── modifiers
│ │ ├── boostfaststrokesmodifier.cpp
│ │ ├── boostfaststrokesmodifier.h
│ │ ├── breaksoftenermodifier.cpp
│ │ ├── breaksoftenermodifier.h
│ │ ├── channelbalancemodifier.cpp
│ │ ├── channelbalancemodifier.h
│ │ ├── fadefromcoldmodifier.cpp
│ │ ├── fadefromcoldmodifier.h
│ │ ├── phaseinvertermodifier.cpp
│ │ ├── phaseinvertermodifier.h
│ │ ├── phasesettermodifier.cpp
│ │ ├── phasesettermodifier.h
│ │ ├── progressincreasemodifier.cpp
│ │ ├── progressincreasemodifier.h
│ │ ├── singlechannelbeatproximitymodifier.cpp
│ │ ├── singlechannelbeatproximitymodifier.h
│ │ ├── triphasebeatproximitymodifier.cpp
│ │ ├── triphasebeatproximitymodifier.h
│ │ ├── triphasemodifier.cpp
│ │ ├── triphasemodifier.h
│ │ ├── waypoint.cpp
│ │ ├── waypoint.h
│ │ ├── waypointfollowermodifier.cpp
│ │ ├── waypointfollowermodifier.h
│ │ ├── waypointlist.cpp
│ │ └── waypointlist.h
│ ├── monostimsignalsample.cpp
│ ├── monostimsignalsample.h
│ ├── multithreadedsamplepipelineprocessor.cpp
│ ├── multithreadedsamplepipelineprocessor.h
│ ├── separatelnrsignalgenerator.cpp
│ ├── separatelnrsignalgenerator.h
│ ├── singlechannelsignalgenerator.cpp
│ ├── singlechannelsignalgenerator.h
│ ├── stereostimsignalsample.cpp
│ ├── stereostimsignalsample.h
│ ├── stimsignalfile.cpp
│ ├── stimsignalfile.h
│ ├── stimsignalgenerator.cpp
│ ├── stimsignalgenerator.h
│ ├── stimsignalmodifier.cpp
│ ├── stimsignalmodifier.h
│ ├── stimsignalsample.cpp
│ ├── stimsignalsample.h
│ ├── stimsignalsamplefactory.cpp
│ ├── stimsignalsamplefactory.h
│ ├── stimsignalsource.cpp
│ ├── stimsignalsource.h
│ ├── stimsignalworker.cpp
│ ├── stimsignalworker.h
│ ├── triphasesignalgenerator.cpp
│ └── triphasesignalgenerator.h
├── syncfilewriter.cpp
├── syncfilewriter.h
├── uniquebeatinterval.cpp
├── uniquebeatinterval.h
├── valuedatamodel.cpp
├── valuedatamodel.h
├── valuetablekeyboardeventhandler.cpp
├── valuetablekeyboardeventhandler.h
├── vibratorpulsefeatureparams.cpp
├── vibratorpulsefeatureparams.h
├── wavefileexporter.cpp
└── wavefileexporter.h
├── notes_on_deploying.txt
└── release64.bat
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 | * text=auto
3 |
4 | # Explicitly declare text files you want to always be normalized and converted
5 | # to native line endings on checkout.
6 | *.cpp text
7 | *.h text
8 | *.ui text
9 | *.pro text
10 | *.md text
11 | *.txt text
12 |
13 | # Declare files that will always have CRLF line endings on checkout.
14 | # None, yet...
15 |
16 | # Denote all files that are truly binary and should not be modified.
17 | *.png binary
18 | *.qrc binary
19 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: ${{ matrix.os }}
12 | strategy:
13 | fail-fast: false
14 | matrix:
15 | include:
16 | - os: windows-2022
17 | name: Windows64
18 | - os: ubuntu-20.04 # needs to be 20.04 or else linuxdeployqt will not work
19 | name: Linux
20 | - os: macos-latest
21 | name: macOS
22 |
23 | steps:
24 | - name: Checkout repository
25 | uses: actions/checkout@v2
26 |
27 | - name: Install Qt 5.15.2 on Windows64
28 | if: matrix.name == 'Windows64'
29 | uses: jurplel/install-qt-action@v4
30 | with:
31 | version: '5.15.2'
32 | arch: 'win64_msvc2019_64'
33 |
34 | - name: Install Qt 5.15.2 on Linux
35 | if: matrix.name == 'Linux'
36 | uses: jurplel/install-qt-action@v4
37 | with:
38 | version: '5.15.2'
39 | arch: 'gcc_64'
40 |
41 | - name: Install Qt5 on macOS
42 | if: matrix.name == 'macOS'
43 | run: |
44 | brew install qt5
45 |
46 | - name: Build on Windows64
47 | if: matrix.name == 'Windows64'
48 | run: |
49 | mkdir build
50 | cd build
51 | cmake .. -G"Visual Studio 17 2022" -DQt5_DIR="$env:QT_ROOT_DIR\lib\cmake\Qt5"
52 | cmake --build . --target CockHeroine --config Release
53 |
54 | - name: Build on Linux
55 | if: matrix.name == 'Linux'
56 | run: |
57 | mkdir build
58 | cd build
59 | cmake .. -G"Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
60 | make -j$(nproc)
61 |
62 | - name: Build on macOS
63 | if: matrix.name == 'macOS'
64 | run: |
65 | mkdir build
66 | cd build
67 | cmake .. -G"Unix Makefiles" -DQt5_DIR=$(brew --prefix qt5)/lib/cmake/Qt5
68 | make -j4
69 |
70 | - name: Deploy Qt libraries on Windows64
71 | if: matrix.name == 'Windows64'
72 | run: |
73 | cd $env:QT_ROOT_DIR\bin
74 | windeployqt --release $env:GITHUB_WORKSPACE\build\Release\CockHeroine.exe
75 |
76 | #- name: Deploy on Linux
77 | # if: matrix.name == 'Linux'
78 | # run: |
79 | # sudo apt-get install libfuse2
80 | # cd $GITHUB_WORKSPACE/build
81 | # wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
82 | # chmod a+x linuxdeployqt-continuous-x86_64.AppImage
83 | # make install DESTDIR=AppDir ; find AppDir/
84 | # ./linuxdeployqt-continuous-x86_64.AppImage ./AppDir/usr/share/applications/CockHeroine.desktop -appimage
85 | # mv ./CockHeroine*.AppImage CockHeroine-x86_64.AppImage
86 | # ls -lF
87 |
88 | - name: Zip Windows64 artifacts
89 | if: matrix.name == 'Windows64'
90 | run: |
91 | Compress-Archive -Path $env:GITHUB_WORKSPACE\build\Release\* -DestinationPath $env:GITHUB_WORKSPACE\build\CockHeroine.zip
92 |
93 | - name: Upload artifacts on Windows64
94 | if: matrix.name == 'Windows64'
95 | uses: actions/upload-artifact@v4
96 | with:
97 | name: CockHeroine-Windows64
98 | path: ${{ github.workspace }}/build/CockHeroine.zip
99 |
100 | #- name: Upload artifacts on Linux
101 | # if: matrix.name == 'Linux'
102 | # uses: actions/upload-artifact@v4
103 | # with:
104 | # name: CockHeroine-Linux
105 | # path: ${{ github.workspace }}/build/CockHeroine-x86_64.AppImage
106 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs
2 | build
3 | *.pro.user
4 |
--------------------------------------------------------------------------------
/Resources/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | if (UNIX AND NOT APPLE)
3 | install(FILES CockHeroine.desktop DESTINATION share/applications)
4 | install(FILES WandIcon.png DESTINATION share/icons/hicolor/150x150/apps)
5 | endif()
6 |
--------------------------------------------------------------------------------
/Resources/CockHeroine.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=CockHeroine
3 | Comment=A tool for recording and editing beat patterns for cock hero videos
4 | Exec=CockHeroine
5 | Icon=WandIcon
6 | Type=Application
7 | Categories=Utility;
8 |
--------------------------------------------------------------------------------
/Resources/WandIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/memmaa/cock-heroine/02dcbdd5e2b31b6f09d8af28e2db7248fe6181ff/Resources/WandIcon.png
--------------------------------------------------------------------------------
/Resources/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | WandIcon.png
4 |
5 |
--------------------------------------------------------------------------------
/Source/.buttplugdeviceconfigdialog.ui.un~:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/memmaa/cock-heroine/02dcbdd5e2b31b6f09d8af28e2db7248fe6181ff/Source/.buttplugdeviceconfigdialog.ui.un~
--------------------------------------------------------------------------------
/Source/abstractbeatinterval.cpp:
--------------------------------------------------------------------------------
1 | #include "abstractbeatinterval.h"
2 | #include "helperfunctions.h"
3 | #include
4 | #include
5 | #include "config.h"
6 | #include "globals.h"
7 |
8 | AbstractBeatInterval::AbstractBeatInterval()
9 | {
10 | }
11 |
12 | AbstractBeatInterval::~AbstractBeatInterval()
13 | {
14 | }
15 |
16 | bool AbstractBeatInterval::matchesThisInterval(int otherInterval) const
17 | {
18 | return isWithinXPercentOf(getLength(),otherInterval,BeatAnalysis::Configuration::maxPercentAcceptableBeatError);
19 | }
20 |
21 | bool AbstractBeatInterval::matchesThisInterval(AbstractBeatInterval &otherInterval) const
22 | {
23 | return matchesThisInterval(otherInterval.getLength());
24 | }
25 |
26 | bool AbstractBeatInterval::matchesThisInterval(BeatValue & otherValue, double atTempo) const
27 | {
28 | return matchesThisInterval(roundToInt(otherValue.getLength(atTempo)));
29 | }
30 |
31 | void AbstractBeatInterval::calculateValue() const
32 | {
33 | if (beatValues.size() == 0)
34 | {
35 | qDebug() << "Warning: Trying to calculate value of interval before beat values are initialised!";
36 | value = 0;
37 | return;
38 | }
39 |
40 | if (BeatAnalysis::Configuration::tempoEstablished == false)
41 | {
42 | qDebug() << "Warning: Trying to calculate value of interval before tempo is calculated!";
43 | value = 0;
44 | return;
45 | }
46 |
47 | value = nearestValue(true);
48 | }
49 |
50 | float AbstractBeatInterval::deviationFromNearestKnownBeatValue() const
51 | {
52 | if ( ! value )
53 | calculateValue();
54 |
55 | if ( ! value )
56 | return FLT_MAX;
57 |
58 | return percentageDifferenceBetween(value->getLength(),getLength());
59 | }
60 |
61 | float AbstractBeatInterval::absoluteDifferenceFromNearestKnownBeatValue() const
62 | {
63 | if ( ! value )
64 | calculateValue();
65 |
66 | if ( ! value )
67 | return FLT_MAX;
68 |
69 | return absoluteDifferenceBetween(getLength(), value->getLength());
70 | }
71 |
72 | bool AbstractBeatInterval::isKnownBeatValue(double tempo) const
73 | {
74 | bool acceptableProportion = (deviationFromNearestKnownBeatValue() <= BeatAnalysis::Configuration::maxPercentAcceptableBeatError);
75 | if (!acceptableProportion)
76 | return false; //return early as access to 'value->' below may NPE in this case
77 | double tempoInterval = tempoToBeatLength(tempo);
78 | float absoluteDifference = absoluteDifferenceFromNearestKnownBeatValue();
79 | float partialBeatLength = tempoInterval / (BeatAnalysis::Configuration::allowHalfBeatsInBreaks ? 4.0 : 2.0);
80 | bool acceptableError = absoluteDifference <= partialBeatLength;
81 | return acceptableError; // && acceptableProportion (we wouldn't be here otherwise)
82 | }
83 |
84 | BeatValue const * AbstractBeatInterval::getValue() const
85 | {
86 | if (isKnownBeatValue())
87 | return value;
88 | else
89 | return NULL;
90 | }
91 |
92 | const BeatValue *AbstractBeatInterval::nearestValue(bool mustBeActive) const
93 | {
94 | float valueDifference = 100.0;
95 | const BeatValue * nearestValue = nullptr;
96 | if (BeatAnalysis::Configuration::tempoEstablished == false)
97 | {
98 | return nearestValue;
99 | }
100 | for (int i = 0; i < beatValues.size(); ++i)
101 | {
102 | if ((beatValues.at(i).active || !mustBeActive) &&
103 | percentageDifferenceBetween(getLength(), beatValues.at(i).value() * BeatAnalysis::Configuration::tempoInterval()) < valueDifference)
104 | {
105 | valueDifference = percentageDifferenceBetween(getLength(), beatValues.at(i).value() * BeatAnalysis::Configuration::tempoInterval());
106 | nearestValue = &beatValues.at(i);
107 | }
108 | }
109 | return nearestValue;
110 | }
111 |
--------------------------------------------------------------------------------
/Source/abstractbeatinterval.h:
--------------------------------------------------------------------------------
1 | #ifndef ABSTRACTBEATINTERVAL_H
2 | #define ABSTRACTBEATINTERVAL_H
3 |
4 | #include "beatvalue.h"
5 | #include "globals.h"
6 |
7 | class AbstractBeatInterval
8 | {
9 | public:
10 | AbstractBeatInterval();
11 | virtual ~AbstractBeatInterval();
12 |
13 | virtual float getLength() const = 0;
14 |
15 | bool matchesThisInterval(int otherInterval) const;
16 | bool matchesThisInterval(AbstractBeatInterval &otherInterval) const;
17 | bool matchesThisInterval(BeatValue & otherValue, double atTempo = BeatAnalysis::Configuration::currentBPM) const;
18 |
19 | void calculateValue() const;
20 | float deviationFromNearestKnownBeatValue() const;
21 | float absoluteDifferenceFromNearestKnownBeatValue() const;
22 | bool isKnownBeatValue(double atTempo = BeatAnalysis::Configuration::currentBPM) const;
23 | const BeatValue * getValue() const;
24 |
25 | protected:
26 | mutable BeatValue const * value = NULL;
27 | const BeatValue * nearestValue(bool mustBeActive) const;
28 | };
29 |
30 | #endif // ABSTRACTBEATINTERVAL_H
31 |
--------------------------------------------------------------------------------
/Source/abstractnewbeatvaluewidget.h:
--------------------------------------------------------------------------------
1 | #ifndef ABSTRACTNEWBEATVALUEWIDGET_H
2 | #define ABSTRACTNEWBEATVALUEWIDGET_H
3 |
4 | #include
5 |
6 | class QVBoxLayout;
7 | class QHBoxLayout;
8 | class QRadioButton;
9 |
10 | class AbstractNewBeatValueWidget : public QFrame
11 | {
12 | Q_OBJECT
13 | public:
14 | AbstractNewBeatValueWidget(float valueInBeats, QWidget * parent = nullptr);
15 | virtual void updateForValue(float);
16 | virtual QString getName();
17 | virtual float getMatchResistance() = 0;
18 | void select();
19 | void deselect();
20 | virtual int getNumerator() = 0;
21 | virtual int getDivisor() = 0;
22 | virtual float getCurrentValue();
23 | //!
24 | //! \brief poopness returns a higher number if it's a poor match.
25 | //! \return 0 = perfect match, 1 = exceptionallly poor match, anything higher is not a match at all
26 | //!
27 | float poopness();
28 | //!
29 | //! \brief matchness the opposite of poopness. If this is not a match, matchness will be 0
30 | //! \return between 0 (not a match) and 100 (perfect match)
31 | //!
32 | float matchness();
33 | //!
34 | //! \brief isAMatch is this value a possible (but not necessarily the best) match for the interval?
35 | //! It only has to be within the maximum allowed deviation to count
36 | //! \return true if it could be a match
37 | //!
38 | bool isAMatch();
39 | bool isSelected();
40 | signals:
41 | void selected();
42 | void selected(AbstractNewBeatValueWidget *);
43 | protected:
44 | float valueInBeats;
45 | QVBoxLayout * valueLayout;
46 | QHBoxLayout * valueFractionLayout;
47 | QHBoxLayout * valueNameLayout;
48 | QRadioButton * valueNameRadioButton;
49 | virtual void updateBackground();
50 |
51 | private slots:
52 | void on_selected(bool on_selected);
53 | };
54 |
55 | #endif // ABSTRACTNEWBEATVALUEWIDGET_H
56 |
--------------------------------------------------------------------------------
/Source/adddialog.h:
--------------------------------------------------------------------------------
1 | #ifndef ADDDIALOG_H
2 | #define ADDDIALOG_H
3 |
4 | #define SHORTCUT_ADD_INSERT_BEFORE_SELECTION "SHORTCUT_ADD_INSERT_BEFORE_SELECTION"
5 | #define SHORTCUT_ADD_INSERT_AFTER_SELECTION "SHORTCUT_ADD_INSERT_AFTER_SELECTION"
6 | #define SHORTCUT_ADD_MOVE_OTHERS_BACK "SHORTCUT_ADD_MOVE_OTHERS_BACK"
7 | #define SHORTCUT_ADD_MOVE_OTHERS_FORWARD "SHORTCUT_ADD_MOVE_OTHERS_FORWARD"
8 |
9 | #include
10 | class QShortcut;
11 | class BeatValue;
12 |
13 | namespace Ui {
14 | class AddDialog;
15 | }
16 |
17 | class AddDialog : public QDialog
18 | {
19 | Q_OBJECT
20 |
21 | public:
22 | explicit AddDialog(QWidget *parent = nullptr);
23 | ~AddDialog();
24 |
25 | virtual void accept() override;
26 |
27 | private slots:
28 | void on_beforeRadioButton_toggled(bool checked);
29 |
30 | void on_afterRadioButton_toggled(bool checked);
31 |
32 | void on_shiftBackRadioButton_toggled(bool checked);
33 |
34 | void on_shiftForwardRadioButton_toggled(bool checked);
35 |
36 | void newValueSelected(BeatValue * newValue);
37 |
38 | void ensureSingleSelection();
39 |
40 | private:
41 | Ui::AddDialog *ui;
42 | void setShortcuts();
43 | void setLabels();
44 | void showEditorAddPage();
45 | void setButtonState();
46 | QShortcut * addBeforeShortcut;
47 | QShortcut * addAfterShortcut;
48 | QShortcut * moveBackShortcut;
49 | QShortcut * moveForwardShortcut;
50 | QShortcut * doneShortcut;
51 | };
52 |
53 | #endif // ADDDIALOG_H
54 |
--------------------------------------------------------------------------------
/Source/adddialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | AddDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Add Interval
15 |
16 |
17 | -
18 |
19 |
20 | QFrame::StyledPanel
21 |
22 |
23 | QFrame::Raised
24 |
25 |
26 |
27 |
28 | -
29 |
30 |
31 | QFrame::StyledPanel
32 |
33 |
34 | QFrame::Raised
35 |
36 |
37 |
-
38 |
39 |
40 | Add interval...
41 |
42 |
43 |
-
44 |
45 |
46 | (K) Before selected interval(s)
47 |
48 |
49 |
50 | -
51 |
52 |
53 | (J) After selected interval(s)
54 |
55 |
56 |
57 |
58 |
59 |
60 | -
61 |
62 |
63 | Move other intervals...
64 |
65 |
66 |
-
67 |
68 |
69 | (L) Back (right)
70 |
71 |
72 |
73 | -
74 |
75 |
76 | (H) Forward (left)
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | -
87 |
88 |
89 | Qt::Horizontal
90 |
91 |
92 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | buttonBox
102 | accepted()
103 | AddDialog
104 | accept()
105 |
106 |
107 | 248
108 | 254
109 |
110 |
111 | 157
112 | 274
113 |
114 |
115 |
116 |
117 | buttonBox
118 | rejected()
119 | AddDialog
120 | reject()
121 |
122 |
123 | 316
124 | 260
125 |
126 |
127 | 286
128 | 274
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/Source/adjustdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef ADJUSTDIALOG_H
2 | #define ADJUSTDIALOG_H
3 |
4 | #define SHORTCUT_ADJUST_MOVE_BEGINNING "SHORTCUT_ADJUST_MOVE_BEGINNING"
5 | #define SHORTCUT_ADJUST_MOVE_END "SHORTCUT_ADJUST_MOVE_END"
6 | #define SHORTCUT_ADJUST_MOVE_BOTH "SHORTCUT_ADJUST_MOVE_BOTH"
7 | #define SHORTCUT_ADJUST_SMART_ADJUST "SHORTCUT_ADJUST_SMART_ADJUST"
8 | #define SHORTCUT_ADJUST_OVERWRITE_OTHERS "SHORTCUT_ADJUST_OVERWIRTE_OTHERS"
9 |
10 | #include
11 | class QShortcut;
12 | class BeatValue;
13 |
14 | namespace Ui {
15 | class AdjustDialog;
16 | }
17 |
18 | class AdjustDialog : public QDialog
19 | {
20 | Q_OBJECT
21 |
22 | public:
23 | explicit AdjustDialog(QWidget *parent = nullptr);
24 | AdjustDialog(BeatValue presetValue, QWidget *parent = nullptr);
25 | ~AdjustDialog();
26 |
27 | virtual void accept() override;
28 |
29 | private slots:
30 | void newValueSelected(BeatValue * newValue);
31 |
32 | void ensureSingleSelection();
33 |
34 | void on_moveBeginningRadioButton_toggled(bool checked);
35 |
36 | void on_moveEndRadioButton_toggled(bool checked);
37 |
38 | void on_moveBothRadioButton_toggled(bool checked);
39 |
40 | void on_smartAdjustRadioButton_toggled(bool checked);
41 |
42 | void on_allowOverwritesCheckBox_toggled(bool checked);
43 |
44 | private:
45 | Ui::AdjustDialog *ui;
46 | void setShortcuts();
47 | void setLabels();
48 | void showEditorAdjustPage();
49 | void populateValues();
50 | void populateSingleValue(BeatValue value);
51 | void clearValues();
52 | void setButtonState();
53 | QVector valueShortcuts;
54 | QShortcut * moveEndShortcut;
55 | QShortcut * moveBeginningShortcut;
56 | QShortcut * moveBothShortcut;
57 | QShortcut * smartAdjustShortcut;
58 | QShortcut * overwriteOthersShortcut;
59 | QShortcut * doneShortcut;
60 | };
61 |
62 | #endif // ADJUSTDIALOG_H
63 |
--------------------------------------------------------------------------------
/Source/adjustdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | AdjustDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Adjust Interval
15 |
16 |
17 | -
18 |
19 |
20 | QFrame::StyledPanel
21 |
22 |
23 | QFrame::Raised
24 |
25 |
26 |
-
27 |
28 |
29 | Allow overwriting other timestamps
30 |
31 |
32 |
33 | -
34 |
35 |
36 | Move beginning
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Move end
44 |
45 |
46 |
47 | -
48 |
49 |
50 | Move both equally
51 |
52 |
53 |
54 | -
55 |
56 |
57 | Smart adjust
58 |
59 |
60 |
61 |
62 |
63 |
64 | -
65 |
66 |
67 | QFrame::StyledPanel
68 |
69 |
70 | QFrame::Raised
71 |
72 |
73 |
74 |
75 | -
76 |
77 |
78 | Qt::Horizontal
79 |
80 |
81 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | buttonBox
91 | accepted()
92 | AdjustDialog
93 | accept()
94 |
95 |
96 | 248
97 | 254
98 |
99 |
100 | 157
101 | 274
102 |
103 |
104 |
105 |
106 | buttonBox
107 | rejected()
108 | AdjustDialog
109 | reject()
110 |
111 |
112 | 316
113 | 260
114 |
115 |
116 | 286
117 | 274
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/Source/analysisoptionsdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef ANALYSISOPTIONSDIALOG_H
2 | #define ANALYSISOPTIONSDIALOG_H
3 |
4 | #include
5 |
6 | class QTime;
7 | class QTimer;
8 |
9 | namespace Ui {
10 | class AnalysisOptionsDialog;
11 | }
12 |
13 | class AnalysisOptionsDialog : public QDialog
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | explicit AnalysisOptionsDialog(QWidget *parent = 0);
19 | ~AnalysisOptionsDialog();
20 |
21 | private slots:
22 | void on_useProvidedTempoRadioButton_clicked();
23 |
24 | void on_automaticTempoRadioButton_clicked();
25 |
26 | void on_preferLongPatternsCheckBox_clicked();
27 |
28 | void on_buttons_accepted();
29 |
30 | void on_matchPatternMembersByActualValueCheckBox_clicked();
31 |
32 | void on_matchPatternMembersByNearestKnownValueCheckBox_clicked();
33 |
34 | void on_tapTempoInputButton_clicked();
35 |
36 | void onTempoTimeout();
37 |
38 |
39 | void on_tapTempoResetButton_clicked();
40 |
41 | private:
42 | Ui::AnalysisOptionsDialog *ui;
43 | QSettings settings;
44 | short tapTempoCounter;
45 | float previousTempo;
46 | QTime * tapTempoTimer;
47 | QTimer * tempoTimeoutTimer;
48 | };
49 |
50 | #endif // ANALYSISOPTIONSDIALOG_H
51 |
--------------------------------------------------------------------------------
/Source/beatdatamodel.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATDATAMODEL_H
2 | #define BEATDATAMODEL_H
3 |
4 | #include
5 | #include
6 | class EventDataProxyModel;
7 | class Event;
8 | class BeatTimestamp;
9 |
10 | class BeatDataModel : public QAbstractTableModel
11 | {
12 | Q_OBJECT
13 | public:
14 | explicit BeatDataModel(QObject *parent = 0);
15 | int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
16 | int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
17 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
18 | Qt::ItemFlags flags(const QModelIndex &index) const;
19 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
20 |
21 | //! \param deleted almost always false - only true if restoring pre-deleted timestamps from an undo snapshot
22 | void addEvent(const Event &newEvent, int index = -1);
23 | void addBeat(const QModelIndex & index);
24 | void addBeats(EventDataProxyModel * model, const QModelIndexList & indexList);
25 | void addEventsFromSnapshot(EditorWin::RollbackSnapshot snapshot);
26 |
27 | Event eventFromRow(int row);
28 | void changeEventAt(int index, const Event & event);
29 | void changeTimestampAt(int index, long newTimestamp);
30 |
31 | void removeBeat(int index);
32 | bool removeRows (int row, int count, const QModelIndex &);
33 |
34 | BeatTimestamp & operator[](int index);
35 |
36 | void cancelQueuedDeletions();
37 | void writeChangesToOriginalModel();
38 |
39 | private:
40 | EventDataProxyModel * originModel;
41 | QVector indexesToDelete;
42 |
43 | friend void EditorWindow::createRollbackSnapshot();
44 | friend void EditorWindow::applySnapshot(EditorWin::RollbackSnapshot);
45 |
46 | signals:
47 |
48 | public slots:
49 |
50 | };
51 |
52 | #endif // BEATDATAMODEL_H
53 |
--------------------------------------------------------------------------------
/Source/beatinterval.cpp:
--------------------------------------------------------------------------------
1 | #include "beatinterval.h"
2 | #include "beattimestamp.h"
3 | #include "globals.h"
4 |
5 | BeatInterval::BeatInterval()
6 | :
7 | index(-1)
8 | {
9 | //nothing here
10 | }
11 |
12 | BeatInterval::BeatInterval(int index)
13 | :
14 | index(index)
15 | {
16 | //nothing here
17 | }
18 |
19 | BeatInterval::~BeatInterval()
20 | {
21 | }
22 |
23 | int BeatInterval::startsAtTimestamp()
24 | {
25 | return beatTimestamps.at(index).eventData.timestamp;
26 | }
27 |
28 | int BeatInterval::endsAtTimestamp()
29 | {
30 | return beatTimestamps.at(index + 1).eventData.timestamp;
31 | }
32 |
33 | float BeatInterval::getLength() const
34 | {
35 | return (float) getIntLength();
36 | }
37 |
38 | int BeatInterval::getIntLength() const
39 | {
40 | return beatTimestamps.at(index + 1).eventData.timestamp - beatTimestamps.at(index).eventData.timestamp;
41 | }
42 |
--------------------------------------------------------------------------------
/Source/beatinterval.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATINTERVAL_H
2 | #define BEATINTERVAL_H
3 |
4 | #include "abstractbeatinterval.h"
5 |
6 | class BeatTimestamp;
7 |
8 | class BeatInterval : public AbstractBeatInterval
9 | {
10 | public:
11 | BeatInterval();
12 | BeatInterval(int index);
13 | ~BeatInterval();
14 |
15 | BeatInterval * prev = NULL;
16 | BeatInterval * next = NULL;
17 |
18 | int index;
19 | int startsAtTimestamp();
20 | int endsAtTimestamp();
21 |
22 | float getLength() const;
23 | int getIntLength() const;
24 | };
25 |
26 | #endif // BEATINTERVAL_H
27 |
--------------------------------------------------------------------------------
/Source/beatmeter/editorgridline.cpp:
--------------------------------------------------------------------------------
1 | #include "editorgridline.h"
2 | #include
3 | #include "beatanalysis.h"
4 | #include "optionsdialog.h"
5 |
6 | EditorGridLine::EditorGridLine(float beatsFromNow, float opacity, QGraphicsItem * parent)
7 | :
8 | QGraphicsLineItem(parent),
9 | beatsFromNow(beatsFromNow)
10 | {
11 | reposition();
12 |
13 | setOpacity(opacity);
14 |
15 | QPen pen;
16 | pen.setWidth(1);
17 | setPen(pen);
18 | }
19 |
20 | void EditorGridLine::reposition()
21 | {
22 | qreal xCoordinate = beatsFromNow * getPixelsPerBeat();
23 | int yHalfLength = (qreal) OptionsDialog::getBeatMeterHeight() / 2;
24 | QLineF line(xCoordinate, yHalfLength, xCoordinate, -yHalfLength);
25 | setLine(line);
26 | }
27 |
28 | float EditorGridLine::value()
29 | {
30 | return beatsFromNow;
31 | }
32 |
33 | qreal EditorGridLine::getPixelsPerBeat()
34 | {
35 | if (false == BeatAnalysis::Configuration::tempoEstablished)
36 | return (qreal) OptionsDialog::getBeatMeterSpeed() / 2;
37 | return (BeatAnalysis::Configuration::tempoInterval() * OptionsDialog::getBeatMeterSpeed()) / 1000;
38 | }
39 |
--------------------------------------------------------------------------------
/Source/beatmeter/editorgridline.h:
--------------------------------------------------------------------------------
1 | #ifndef EDITORGRIDLINE_H
2 | #define EDITORGRIDLINE_H
3 |
4 | #include
5 |
6 | class EditorGridLine : public QGraphicsLineItem
7 | {
8 | // Q_OBJECT
9 | public:
10 | EditorGridLine(float beatsFromNow, float opacity, QGraphicsItem *parent = nullptr);
11 | void reposition();
12 | float value();
13 | private:
14 | float beatsFromNow;
15 | qreal getPixelsPerBeat();
16 | };
17 |
18 | #endif // EDITORGRIDLINE_H
19 |
--------------------------------------------------------------------------------
/Source/beatoptimisation.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATOPTIMISATION_H
2 | #define BEATOPTIMISATION_H
3 |
4 | struct BeatOptimisation
5 | {
6 | static void optimiseBeats();
7 | static void applyBeats();
8 |
9 | struct Configuration
10 | {
11 | static bool outputTempoProvided;
12 | static double providedOutputTempo;
13 | static bool startingTimestampProvided;
14 | static long providedStartingTimestamp;
15 | static bool roundToNearestBPM;
16 | static bool roundToEvenBPM;
17 | static float outputTempoInterval();
18 | static void setImprovedValuesFromProvided();
19 | };
20 |
21 | private:
22 | static long shiftWhenWorking;
23 | static float improvedStartTimestamp;
24 | static float improvedTempoInterval;
25 | static QVector targetTimestamps;
26 | static QVector trialTimestamps;
27 | static char lastProgressChar;
28 | static short outputCharCounter;
29 |
30 | static void configureTrialTimestamps(float start, float interval);
31 | static double compareTrialTimestamps();
32 | static void outputProgressChar(char progressChar);
33 |
34 | friend class BeatDataModel;
35 | friend class EditorWindow;
36 | };
37 |
38 | #endif // BEATOPTIMISATION_H
39 |
--------------------------------------------------------------------------------
/Source/beatpattern.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATPATTERN_H
2 | #define BEATPATTERN_H
3 |
4 | class BeatValue;
5 |
6 | class BeatPattern
7 | {
8 | public:
9 | BeatPattern();
10 | BeatPattern(int startBeat);
11 |
12 | //all forward to underlying vector
13 | void clear();
14 | void append(const BeatValue * const &t);
15 | int size() const;
16 | bool isEmpty() const;
17 | void remove(int i);
18 | void removeLast();
19 | const BeatValue * const & at(int i) const;
20 | const BeatValue *& operator[](int i);
21 | const BeatValue * takeFirst();
22 | void resize (int i);
23 |
24 | int startsAtBeat() const;
25 | void setStartBeat(int );
26 |
27 | int lengthInStrokes() const;
28 | bool containsUnknownIntervals() const;
29 | float lengthInBeats() const;
30 | float lengthInMsAtTempo();
31 |
32 | void reduceToShortestForm();
33 |
34 | int totalStrokesCovered() const;
35 | void setTotalStrokesCovered(int count);
36 | float totalBeatsCovered() const;
37 | int repetitions() const;
38 | int framesRequiredPerBeat() const;
39 |
40 | QVector listOfDenominators() const;
41 |
42 | QString name() const;
43 |
44 | bool operator==(const BeatPattern & other) const;
45 | bool cyclesTheSameAs(const BeatPattern &other) const;
46 |
47 | static BeatPattern * byName(QString name);
48 |
49 | private:
50 | QVector vector;
51 | int startsAt;
52 | int strokesCovered;
53 | };
54 |
55 | #endif // BEATPATTERN_H
56 |
--------------------------------------------------------------------------------
/Source/beattimestamp.cpp:
--------------------------------------------------------------------------------
1 | #include "beattimestamp.h"
2 |
3 | BeatTimestamp::BeatTimestamp()
4 | :
5 | originalRowIndex(-1),
6 | isDeleted(false)
7 | {
8 | }
9 |
10 | BeatTimestamp::BeatTimestamp(int index, Event event, bool deleted)
11 | :
12 | originalRowIndex(index),
13 | eventData(event),
14 | isDeleted(deleted)
15 | {
16 | }
17 |
--------------------------------------------------------------------------------
/Source/beattimestamp.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATTIMESTAMP_H
2 | #define BEATTIMESTAMP_H
3 |
4 | #include "event.h"
5 |
6 | class BeatTimestamp
7 | {
8 | public:
9 | BeatTimestamp();
10 | //!
11 | //! \brief BeatTimestamp
12 | //! \param index
13 | //! \param event
14 | //! \param deleted almost always false - only true if restoring pre-deleted timestamps from an undo snapshot
15 | //!
16 | BeatTimestamp(int index, Event event, bool deleted = false);
17 |
18 | int originalRowIndex;
19 | Event eventData;
20 | bool isDeleted;
21 | };
22 |
23 | #endif // BEATTIMESTAMP_H
24 |
--------------------------------------------------------------------------------
/Source/beatvalue.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "beatvalue.h"
4 | #include "globals.h"
5 | #include "config.h"
6 | #include "uniquebeatinterval.h"
7 | #include "helperfunctions.h"
8 |
9 | float BeatValue::value() const
10 | {
11 | return ((float)numerator / (float)denominator);
12 | }
13 |
14 | float BeatValue::getLength(double atTempo) const
15 | {
16 | return value() * tempoToBeatLength(atTempo);
17 | }
18 |
19 | bool BeatValue::isBestEnabledMatchFor(int intervalInMs, double tempo)
20 | {
21 | BeatValue * nearestValue = nullptr;
22 | double beatLength = tempoToBeatLength(tempo);
23 | double valueDifference = 100.0;
24 | for (int i = 0; i < beatValues.size(); ++i)
25 | {
26 | if (beatValues.at(i).active &&
27 | percentageDifferenceBetween(intervalInMs, beatValues.at(i).value() * beatLength) < valueDifference)
28 | {
29 | valueDifference = percentageDifferenceBetween(intervalInMs, beatValues.at(i).value() * beatLength);
30 | nearestValue = &beatValues[i];
31 | }
32 | }
33 | return *nearestValue == *this;
34 | }
35 |
36 | bool BeatValue::isBestPossibleMatchFor(int intervalInMs, double tempo)
37 | {
38 | BeatValue * nearestValue = nullptr;
39 | double beatLength = tempoToBeatLength(tempo);
40 | double valueDifference = 100.0;
41 | for (int i = 0; i < beatValues.size(); ++i)
42 | {
43 | if (percentageDifferenceBetween(intervalInMs, beatValues.at(i).value() * beatLength) < valueDifference)
44 | {
45 | valueDifference = percentageDifferenceBetween(intervalInMs, beatValues.at(i).value() * beatLength);
46 | nearestValue = &beatValues[i];
47 | }
48 | }
49 | return *nearestValue == *this;
50 | }
51 |
52 | bool BeatValue::isPossibleMatchFor(int intervalInMs, double tempo)
53 | {
54 | float deviationFromValue = percentageDifferenceBetween(getLength(tempo),intervalInMs);
55 | bool acceptableProportion = (deviationFromValue <= BeatAnalysis::Configuration::maxPercentAcceptableBeatError);
56 | if (!acceptableProportion)
57 | return false; //return early as access to 'value->' below may NPE in this case
58 | double tempoInterval = tempoToBeatLength(tempo);
59 | float absoluteDifference = abs(getLength(tempo) - intervalInMs);
60 | float partialBeatLength = tempoInterval / (BeatAnalysis::Configuration::allowHalfBeatsInBreaks ? 4.0 : 2.0);
61 | bool acceptableError = absoluteDifference <= partialBeatLength;
62 | return acceptableError; // && acceptableProportion (we wouldn't be here otherwise)
63 | }
64 |
65 | bool BeatValue::operator==(const BeatValue & other)
66 | {
67 | return numerator == other.numerator &&
68 | denominator == other.denominator &&
69 | name == other.name;
70 | }
71 |
--------------------------------------------------------------------------------
/Source/beatvalue.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATVALUE_H
2 | #define BEATVALUE_H
3 |
4 | #include
5 | #include "beatanalysis.h"
6 |
7 | class BeatValue
8 | {
9 | public:
10 |
11 | BeatValue() : active(false) {} //Because of QVector's annoying requirement for a default ctr.
12 | BeatValue(unsigned short numerator,
13 | unsigned char denominator,
14 | QString name,
15 | bool active = true,
16 | bool preset = false)
17 | : numerator(numerator),
18 | denominator(denominator),
19 | name(name),
20 | active(active),
21 | preset(preset)
22 | {
23 | //nothing
24 | }
25 | unsigned short numerator;
26 | unsigned char denominator;
27 | QString name;
28 | bool active;
29 | bool preset;
30 | //!
31 | //! \brief value the number of beats in this value. For example, 'Four Beats' is 4.0, 'Five Semisquavers' is 1.25.
32 | //! \return
33 | //!
34 | float value() const;
35 | float getLength(double atTempo = BeatAnalysis::Configuration::currentBPM) const;
36 | //!
37 | //! \brief isBestEnabledMatchFor is this value the one that would be given if asked for the best match for the given length of time
38 | //! \param intervalInMs
39 | //! \return true if it's the best match
40 | //!
41 | bool isBestEnabledMatchFor(int intervalInMs, double tempo = BeatAnalysis::Configuration::currentBPM);
42 | //!
43 | //! \brief isBestPossibleMatchFor is this value the best match for the given length of time (even if it's not active/enabled)
44 | //! \param intervalInMs
45 | //! \return true if it's the best match
46 | //!
47 | bool isBestPossibleMatchFor(int intervalInMs, double tempo = BeatAnalysis::Configuration::currentBPM);
48 | //!
49 | //! \brief isBestPossibleMatchFor would this value match the given length of time (if it were enabled and unmasked by any other better matches)
50 | //! \param intervalInMs
51 | //! \return true if it's a possible match
52 | //!
53 | bool isPossibleMatchFor(int intervalInMs, double tempo = BeatAnalysis::Configuration::currentBPM);
54 |
55 | bool operator==(const BeatValue & other);
56 | };
57 |
58 | #endif // BEATVALUE_H
59 |
--------------------------------------------------------------------------------
/Source/beatvaluewidget.cpp:
--------------------------------------------------------------------------------
1 | #include "beatvaluewidget.h"
2 | #include
3 | #include "beatvalue.h"
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | BeatValueWidget::BeatValueWidget(QWidget *parent, BeatValue value, SelectionMode mode)
10 | :
11 | QFrame(parent),
12 | value(value),
13 | layout(new QVBoxLayout(this)),
14 | label(new QLabel(value.name, this)),
15 | selectionMode(mode)
16 | {
17 | setFrameShape(QFrame::StyledPanel);
18 | setFrameShadow(QFrame::Raised);
19 | switch (mode)
20 | {
21 | case RepeatableSelection:
22 | selectionButton = new QPushButton(tr("Add"),this);
23 | connect(selectionButton, SIGNAL(clicked(bool)), this, SLOT(on_selected(bool)));
24 | break;
25 | case SingleSelection:
26 | selectionButton = new QRadioButton(parent);
27 | connect(selectionButton, SIGNAL(clicked(bool)), this, SLOT(on_selected(bool)));
28 | break;
29 | case NoSelection:
30 | selectionButton = nullptr;
31 | break;
32 | }
33 |
34 | layout->addWidget(label);
35 | layout->addWidget(selectionButton);
36 | }
37 |
38 | void BeatValueWidget::select()
39 | {
40 | switch (selectionMode) {
41 | case SingleSelection:
42 | if (!selectionButton->isChecked())
43 | selectionButton->click();
44 | selectionButton->setChecked(true);
45 | break;
46 | case RepeatableSelection:
47 | selectionButton->click();
48 | break;
49 | default:
50 | break;
51 | }
52 | }
53 |
54 | void BeatValueWidget::deselect()
55 | {
56 | switch (selectionMode) {
57 | case SingleSelection:
58 | selectionButton->setChecked(false);
59 | break;
60 | default:
61 | break;
62 | }
63 | }
64 |
65 | void BeatValueWidget::on_selected(bool is_selected)
66 | {
67 | if (is_selected || selectionMode == RepeatableSelection)
68 | {
69 | emit selected();
70 | emit selected(&value);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Source/beatvaluewidget.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATVALUEWIDGET_H
2 | #define BEATVALUEWIDGET_H
3 |
4 | #include
5 | #include "beatvalue.h"
6 | class QVBoxLayout;
7 | class QLabel;
8 | class QAbstractButton;
9 |
10 | class BeatValueWidget : public QFrame
11 | {
12 | public:
13 | enum SelectionMode {
14 | RepeatableSelection,
15 | SingleSelection,
16 | NoSelection
17 | };
18 | private:
19 | Q_OBJECT
20 | public:
21 | explicit BeatValueWidget(QWidget *parent, BeatValue value, SelectionMode mode);
22 | void deselect();
23 | BeatValue getValue() {return value;};
24 |
25 | signals:
26 | void selected();
27 | void selected(BeatValue * value);
28 |
29 | public slots:
30 | void select();
31 |
32 | private slots:
33 | void on_selected(bool on_selected);
34 |
35 | private:
36 | BeatValue value;
37 | QVBoxLayout * layout;
38 | QLabel * label;
39 | SelectionMode selectionMode;
40 | QAbstractButton * selectionButton;
41 | };
42 |
43 | #endif // BEATVALUEWIDGET_H
44 |
--------------------------------------------------------------------------------
/Source/buttplug/buttplugdevice.cpp:
--------------------------------------------------------------------------------
1 | #include "buttplugdevice.h"
2 | #include "buttplugdevicefeature.h"
3 | #include "buttpluginterface.h"
4 |
5 | int ButtplugDevice::eventCollationTime = 1;
6 |
7 | ButtplugDevice::ButtplugDevice(QObject * parent)
8 | :
9 | QObject(parent)
10 | {
11 |
12 | }
13 |
14 | ButtplugDevice::ButtplugDevice(ButtplugInterface * parent)
15 | :
16 | QObject(parent),
17 | parent(parent),
18 | name(""),
19 | index(0),
20 | supportsStop(false),
21 | supportsVibrate(false),
22 | numVibrators(0),
23 | vibrationLevels(0),
24 | supportsLinear(false),
25 | numLinearAxes(0),
26 | supportsRotate(false),
27 | numRotationalAxes(0),
28 | supportsBatteryLevel(false),
29 | supportsSignalStrength(false),
30 | vibrateCmdTimer(this)
31 | {
32 | }
33 |
34 | ButtplugDevice::ButtplugDevice(ButtplugInterface * parent,
35 | QString name,
36 | int index,
37 | bool supportsStop,
38 | QVector vibratorLevels,
39 | int linearAxes,
40 | int rotaionalAxes,
41 | bool supportsBatteryLevel,
42 | bool supportsSignalStrength)
43 | :
44 | QObject(parent),
45 | parent(parent),
46 | name(name),
47 | index(index),
48 | supportsStop(supportsStop),
49 | supportsVibrate(!vibratorLevels.isEmpty()),
50 | numVibrators(vibratorLevels.size()),
51 | vibrationLevels(vibratorLevels),
52 | supportsLinear(linearAxes > 0),
53 | numLinearAxes(linearAxes),
54 | supportsRotate(rotaionalAxes > 0),
55 | numRotationalAxes(rotaionalAxes),
56 | supportsBatteryLevel(supportsBatteryLevel),
57 | supportsSignalStrength(supportsSignalStrength),
58 | vibrateCmdTimer(this)
59 | {
60 | populateFeatureList();
61 | vibrateCmdTimer.setSingleShot(true);
62 | vibrateCmdTimer.setTimerType(Qt::PreciseTimer);
63 | connect(&vibrateCmdTimer, &QTimer::timeout, this, &ButtplugDevice::sendVibrationCommand);
64 | }
65 |
66 | ButtplugDevice::~ButtplugDevice()
67 | {
68 |
69 | }
70 |
71 | int ButtplugDevice::totalFeatures()
72 | {
73 | return numVibrators + numLinearAxes + numRotationalAxes;
74 | }
75 |
76 | void ButtplugDevice::populateFeatureList()
77 | {
78 | for (int index = 0; index < numVibrators; ++index)
79 | {
80 | currentVibratorIntensities.append(0);
81 | ButtplugDeviceFeature * feature = new ButtplugDeviceFeature(this, ButtplugDeviceFeatureType::VibratorMotor, index, vibrationLevels[index]);
82 | featureList.append(feature);
83 | }
84 |
85 | for (int index = 0; index < numLinearAxes; ++index)
86 | {
87 | ButtplugDeviceFeature * feature = new ButtplugDeviceFeature(this, ButtplugDeviceFeatureType::StrokerAxis, index);
88 | featureList.append(feature);
89 | }
90 |
91 | for (int index = 0; index < numRotationalAxes; ++index)
92 | {
93 | currentRotationalIntensities.append(0);
94 | ButtplugDeviceFeature * feature = new ButtplugDeviceFeature(this, ButtplugDeviceFeatureType::RotatorMotor, index);
95 | featureList.append(feature);
96 | }
97 | }
98 |
99 | void ButtplugDevice::setVibration(int idx, double intensity)
100 | {
101 | currentVibratorIntensities[idx] = intensity;
102 | vibrateCmdTimer.start(eventCollationTime);
103 | }
104 |
105 | void ButtplugDevice::sendVibrationCommand()
106 | {
107 | parent->sendVibrateCmd(index, currentVibratorIntensities);
108 | }
109 |
--------------------------------------------------------------------------------
/Source/buttplug/buttplugdevice.h:
--------------------------------------------------------------------------------
1 | #ifndef BUTTPLUGDEVICE_H
2 | #define BUTTPLUGDEVICE_H
3 |
4 | #include
5 |
6 | class ButtplugInterface;
7 | class ButtplugDeviceFeature;
8 |
9 | class ButtplugDevice : public QObject
10 | {
11 | Q_OBJECT
12 |
13 | public:
14 | ButtplugDevice(QObject * parent = nullptr);
15 | ButtplugDevice(ButtplugInterface * parent = nullptr);
16 | ButtplugDevice(ButtplugInterface * parent,
17 | QString name,
18 | int index,
19 | bool supportsStop,
20 | QVector vibratorLevels,
21 | int linearAxes,
22 | int rotaionalAxes,
23 | bool supportsBatteryLevel,
24 | bool supportsSignalStrength);
25 | ~ButtplugDevice();
26 |
27 | static int eventCollationTime;
28 |
29 | ButtplugInterface * parent;
30 | QString name;
31 |
32 | int index;
33 | bool supportsStop;
34 | bool supportsVibrate;
35 | int numVibrators;
36 | QVector vibrationLevels;
37 | bool supportsLinear;
38 | int numLinearAxes;
39 | bool supportsRotate;
40 | int numRotationalAxes;
41 | bool supportsBatteryLevel;
42 | bool supportsSignalStrength;
43 |
44 | QVector featureList;
45 | int totalFeatures();
46 | void populateFeatureList();
47 |
48 | QVector currentVibratorIntensities;
49 | // QVector currentStrokerSpeeds; //needed?
50 | QVector currentRotationalIntensities;
51 |
52 | void setVibration(int index, double intensity);
53 | void setRotation(int index, double intensity);
54 | QTimer vibrateCmdTimer;
55 |
56 | private slots:
57 | void sendVibrationCommand();
58 | };
59 |
60 | #endif // BUTTPLUGDEVICE_H
61 |
--------------------------------------------------------------------------------
/Source/buttplug/buttplugdevicefeature.cpp:
--------------------------------------------------------------------------------
1 | #include "buttplugdevicefeature.h"
2 | #include "buttplugfeatureparams.h"
3 | #include "buttplugdeviceconfigdialog.h"
4 | #include
5 | #include "buttplugdevice.h"
6 |
7 | ButtplugDeviceFeature::ButtplugDeviceFeature(ButtplugDevice * device, ButtplugDeviceFeatureType type, int index, int featureLevels)
8 | :
9 | device(device),
10 | type(type),
11 | index(index),
12 | levels(featureLevels)
13 | {
14 | //nothing here
15 | }
16 |
17 | ButtplugDeviceFeature::~ButtplugDeviceFeature()
18 | {
19 | //or here
20 | }
21 |
22 | QString ButtplugDeviceFeature::getName()
23 | {
24 | if (device->totalFeatures() == 1)
25 | return device->name;
26 | switch (type)
27 | {
28 | case VibratorMotor:
29 | if (device->numVibrators == 1)
30 | return QString("%1 (Vibrator)").arg(device->name);
31 | else
32 | return QString("%1 (Vibrator %2)").arg(device->name).arg(index + 1);
33 | case StrokerAxis:
34 | if (device->numLinearAxes == 1)
35 | return QString("%1 (Stroker)").arg(device->name);
36 | else
37 | return QString("%1 (Axis %2)").arg(device->name).arg(index + 1);
38 | case RotatorMotor:
39 | if (device->numRotationalAxes == 1)
40 | return QString("%1 (Rotation)").arg(device->name);
41 | else
42 | return QString("%1 (Rotator %2)").arg(device->name).arg(index + 1);
43 | }
44 | return QString("Wat.");
45 | }
46 |
47 | void ButtplugDeviceFeature::dispatch(Event event)
48 | {
49 | ButtplugFeatureParams * params = getParamsFor(event);
50 | if (params == nullptr)
51 | {
52 | return;
53 | }
54 |
55 | params->handleEvent(event, this);
56 | }
57 |
58 | ButtplugFeatureParams * ButtplugDeviceFeature::getParamsFor(Event event)
59 | {
60 | ButtplugFeatureParams * featureDefault = nullptr;
61 | ButtplugFeatureParams * deviceFeatureDefault = nullptr;
62 | ButtplugFeatureParams * specificFeatureEvent = nullptr;
63 | for (ButtplugFeatureParams * params : ButtplugDeviceConfigDialog::entries)
64 | {
65 | if (params->featureType == type) //ignore params for incompatible types of feature
66 | {
67 | if (params->isDefaultParams())
68 | featureDefault = params;
69 | else if (params->featureName == getName())
70 | {
71 | if (params->eventType == -1)
72 | deviceFeatureDefault = params;
73 | else if (params->eventType == event.type())
74 | specificFeatureEvent = params;
75 | //TODO: This is temporary - really params should have a type that is correct
76 | else
77 | specificFeatureEvent = params;
78 | }
79 | }
80 | }
81 | if (specificFeatureEvent != nullptr)
82 | return specificFeatureEvent;
83 | else if (deviceFeatureDefault != nullptr)
84 | return deviceFeatureDefault;
85 | if (featureDefault == nullptr)
86 | qDebug() << "Oh dear... something went wrong: Can't find parameters for event " << event.toAsciiString() << " on feature " << getName();
87 | return featureDefault;
88 | }
89 |
90 | void ButtplugDeviceFeature::setVibration(double level)
91 | {
92 | device->setVibration(index, level);
93 | }
94 |
--------------------------------------------------------------------------------
/Source/buttplug/buttplugdevicefeature.h:
--------------------------------------------------------------------------------
1 | #ifndef BUTTPLUGDEVICEFEATURE_H
2 | #define BUTTPLUGDEVICEFEATURE_H
3 |
4 | #include "event.h"
5 | class ButtplugDevice;
6 | class ButtplugFeatureParams;
7 |
8 | enum ButtplugDeviceFeatureType
9 | {
10 | VibratorMotor,
11 | StrokerAxis,
12 | RotatorMotor
13 | };
14 |
15 | class ButtplugDeviceFeature : public QObject
16 | {
17 | Q_OBJECT
18 |
19 | public:
20 | ButtplugDeviceFeature();
21 | ButtplugDeviceFeature(ButtplugDevice *device, ButtplugDeviceFeatureType type, int index, int featureLevels = 1);
22 | ~ButtplugDeviceFeature();
23 |
24 | ButtplugDevice * device;
25 | ButtplugDeviceFeatureType type;
26 | int index;
27 | int levels;
28 |
29 | QString getName();
30 | void dispatch(Event event);
31 | ButtplugFeatureParams * getParamsFor(Event event);
32 | void setVibration(double level);
33 | };
34 |
35 | #endif // BUTTPLUGDEVICEFEATURE_H
36 |
--------------------------------------------------------------------------------
/Source/buttplug/buttpluginterface.h:
--------------------------------------------------------------------------------
1 | #ifndef BUTTPLUGINTERFACE_H
2 | #define BUTTPLUGINTERFACE_H
3 |
4 | #include
5 | #include
6 |
7 | class ButtplugDeviceFeature;
8 | class ButtplugDevice;
9 |
10 | class ButtplugInterface : public QObject
11 | {
12 | Q_OBJECT
13 | public:
14 | explicit ButtplugInterface(QObject *parent = nullptr);
15 | void openSocket(QString address = "ws://127.0.0.1:12345");
16 | void closeSocket();
17 | QVector getAllFeatures();
18 | ButtplugDeviceFeature * getFeatureByName(const QString & name);
19 |
20 | public slots:
21 | void serverConnected();
22 | void serverDisconnected();
23 | void serverError(QAbstractSocket::SocketError error);
24 | void processTextMessage(QString message);
25 | void processDataMessage(QByteArray message);
26 | void startScanning();
27 | void stopScanning();
28 | void stopAllDevices();
29 | void sendStopDeviceCmd(int deviceIndex);
30 | //!
31 | //! \brief sendVibrateCmd vibrates all the vibrators on...
32 | //! \param deviceIndex ..the specified device (by id) at...
33 | //! \param intensity ...the specified intensity (0.0-1.0).
34 | //!
35 | void sendVibrateCmdAll(int deviceIndex, double intensity);
36 | void sendVibrateCmd(int deviceIndex, QVector intensities);
37 | void vibrateAll(double intensity);
38 |
39 | signals:
40 | void connected();
41 | void disconnected();
42 | void error(QAbstractSocket::SocketError error, QString message);
43 | void deviceAdded(int deviceIndex);
44 | void deviceRemoved(int deviceIndex);
45 |
46 | private:
47 | void sendTextMessage(QString message);
48 | int getNewRequestId();
49 | void registerRequestSent(unsigned int id, QJsonObject request);
50 | QJsonObject registerResponseReceived(unsigned int id);
51 | void handleOk(QJsonObject payload);
52 | void handleError(QJsonObject payload);
53 | QJsonObject createMessageWithPayload(QString messageType, QJsonObject payload);
54 | QJsonObject sendMessageWithPayload(QString messageType, QJsonObject payload);
55 | void sendPing();
56 | void sendHandshake();
57 | void handleServerInfo(QJsonObject payload);
58 | void handleScanningFinished();
59 | void requestDeviceList();
60 | void handleDeviceList(QJsonObject payload);
61 | void handleDeviceAdded(QJsonObject payload);
62 | void handleNewDeviceInfo(QJsonObject deviceJson);
63 | void handleDeviceRemoved(QJsonObject payload);
64 |
65 | QWebSocket socket;
66 | QMap activeRequests;
67 | //!
68 | //! \brief currentlyConnected are we currently connected to the server?
69 | //!
70 | bool currentlyConnected = false;
71 | //!
72 | //! \brief currentlyScanning are we currently scanning on bluetooth or the like?
73 | //!
74 | bool currentlyScanning = false;
75 | QMap attachedDevicesById;
76 | QMap attachedDevicesByName;
77 | };
78 |
79 | #endif // BUTTPLUGINTERFACE_H
80 |
--------------------------------------------------------------------------------
/Source/buttplugdeviceconfigdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef BUTTPLUGDEVICECONFIGDIALOG_H
2 | #define BUTTPLUGDEVICECONFIGDIALOG_H
3 |
4 | #include
5 |
6 | namespace Ui {
7 | class ButtplugDeviceConfigDialog;
8 | }
9 |
10 | class VibratorPulseFeatureParams;
11 | class ButtplugFeatureParams;
12 | class ButtplugDeviceFeature;
13 |
14 | class ButtplugDeviceConfigDialog : public QDialog
15 | {
16 | Q_OBJECT
17 |
18 | public:
19 | explicit ButtplugDeviceConfigDialog(QWidget *parent = nullptr);
20 | ~ButtplugDeviceConfigDialog();
21 | static QVector entries;
22 | static void readInConfigs();
23 | static VibratorPulseFeatureParams *getDefaultVibratorParams();
24 | void writeOutConfigs();
25 |
26 | public slots:
27 | void refreshFeatureList();
28 | void saveAndClose();
29 | void deleteParams(ButtplugFeatureParams *);
30 |
31 | private slots:
32 | void on_addButton_clicked();
33 |
34 | private:
35 | Ui::ButtplugDeviceConfigDialog *ui;
36 | QHash nonDefaultPanels;
37 | void createNewVibratorParams(ButtplugDeviceFeature * feature);
38 | };
39 |
40 | #endif // BUTTPLUGDEVICECONFIGDIALOG_H
41 |
--------------------------------------------------------------------------------
/Source/buttplugdispatcher.cpp:
--------------------------------------------------------------------------------
1 | #include "buttplugdispatcher.h"
2 | #include "buttplugfeatureparams.h"
3 | //#include "vibratorpulsefeatureparams.h"
4 | //#include "buttplugdeviceconfigdialog.h"
5 | #include "buttplug/buttpluginterface.h"
6 |
7 | ButtplugDispatcher::ButtplugDispatcher(ButtplugInterface * nterface, QObject * parent)
8 | :
9 | EventDispatcher(parent),
10 | nterface(nterface)
11 | {
12 |
13 | }
14 |
15 | void ButtplugDispatcher::dispatch(Event event)
16 | {
17 | for (ButtplugDeviceFeature * feature : nterface->getAllFeatures())
18 | feature->dispatch(event);
19 |
20 | // float intensity = getIntensity(event);
21 | // nterface->vibrateAll(intensity);
22 | // QTimer::singleShot(180, nterface, SLOT(stopAllDevices()));
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/Source/buttplugdispatcher.h:
--------------------------------------------------------------------------------
1 | #ifndef BUTTPLUGDISPATCHER_H
2 | #define BUTTPLUGDISPATCHER_H
3 |
4 | #include "eventdispatcher.h"
5 |
6 | class ButtplugInterface;
7 |
8 | class ButtplugDispatcher : public EventDispatcher
9 | {
10 | public:
11 | ButtplugDispatcher(ButtplugInterface * nterface, QObject * parent = nullptr);
12 | void dispatch(Event event);
13 |
14 | private:
15 | //!
16 | //! \brief nterface can't call it 'interface' because that seems to be defined to 'struct' :-o
17 | //!
18 | ButtplugInterface * nterface;
19 |
20 | void triggerEventNow(Event event);
21 | };
22 |
23 | #endif // BUTTPLUGDISPATCHER_H
24 |
--------------------------------------------------------------------------------
/Source/buttplugfeatureparams.h:
--------------------------------------------------------------------------------
1 | #ifndef BUTTPLUGDEVICEPARAMS_H
2 | #define BUTTPLUGDEVICEPARAMS_H
3 |
4 | #include "buttplug/buttplugdevicefeature.h"
5 |
6 | #define PARAMS_TYPE_SETTING "Params type"
7 | #define PARAMS_ENABLED_SETTING "Parameters enabled"
8 | #define DEVICE_NAME_SETTING "Device name"
9 | #define FEATURE_NAME_SETTING "Feature name"
10 | #define SYNC_ADJUST_SETTING "Synchronisation adjustment"
11 |
12 | class QHBoxLayout;
13 | class QCheckBox;
14 | class QComboBox;
15 | class QSpinBox;
16 | class QBoxLayout;
17 | class QToolButton;
18 |
19 | namespace ButtplugDeviceParameter {
20 | enum Type {
21 | VibratorPulse,
22 | StrokerRange,
23 | RotatorBurst
24 | };
25 | }
26 |
27 | class ButtplugFeatureParams : public QObject
28 | {
29 | Q_OBJECT
30 | public:
31 | explicit ButtplugFeatureParams(QObject *parent, ButtplugDeviceFeatureType featureType, ButtplugDeviceParameter::Type type, bool enabled = true, short syncAdjust = 0);
32 | explicit ButtplugFeatureParams(QObject *parent, ButtplugDeviceFeature * feature, ButtplugDeviceParameter::Type type, bool enabled = true, short syncAdjust = 0);
33 | ButtplugDeviceFeatureType featureType;
34 | ButtplugDeviceParameter::Type paramsType;
35 | bool enabled;
36 | QString deviceName;
37 | QString featureName;
38 | int eventType;
39 | short syncAdjust = 0;
40 | //!
41 | //! \brief isDefaultParams are these parameters intended for new or uncustomised devices/features?
42 | //! \return true for yes
43 | //!
44 | bool isDefaultParams();
45 |
46 | virtual void writeSettingsGroup(QSettings & settings);
47 | //!
48 | //! \brief fromSettingsGroup creates an instance of a ButtplugFeatureParams from a QSettings group
49 | //! \param settings the QSettings. It is expected that 'beginGroup' has been called on this QSettings so that
50 | //! the values of the parameters can be accessed directly using 'value()'.
51 | //! \return
52 | //!
53 | static ButtplugFeatureParams * fromSettingsGroup(QSettings & settings);
54 | virtual void readSettingsGroup(QSettings & settings);
55 |
56 | //this should really belong to a separate class like ButtplugFeatureBehaviour
57 | virtual void handleEvent(Event event, ButtplugDeviceFeature * feature) = 0;
58 |
59 | signals:
60 | void aboutToDelete(ButtplugFeatureParams *);
61 |
62 | protected:
63 | virtual void setUiEnabled(bool enabled) = 0;
64 | QHBoxLayout * layout;
65 | QCheckBox *enableCheckBox;
66 | QComboBox *eventTypeComboBox;
67 | QSpinBox *syncAdjustSpinBox;
68 |
69 | QToolButton *deleteButton;
70 | public:
71 | virtual void createUi(QWidget *parentWidget, QBoxLayout *parentLayout);
72 | void addDeleteButton(QWidget *parent, QHBoxLayout * layout);
73 | void adoptUi(QHBoxLayout *layout, QCheckBox *enableCheckBox, QComboBox *eventTypeComboBox, QSpinBox *syncAdjustSpinBox);
74 | virtual void adoptUiValues();
75 | virtual void connectWidgetSignals();
76 | virtual void updateUiFromData();
77 | virtual void copyParamsFrom(ButtplugFeatureParams * other);
78 |
79 | public slots:
80 | void newEnabledState(bool enabled);
81 | void newEventType(int eventType);
82 | void deleteRequested();
83 |
84 | private slots:
85 | void on_SyncAdjustChanged(int newValue);
86 | };
87 |
88 | #endif // BUTTPLUGDEVICEPARAMS_H
89 |
--------------------------------------------------------------------------------
/Source/chmlhandler.cpp:
--------------------------------------------------------------------------------
1 | #include "chmlhandler.h"
2 | #include
3 | #include "globals.h"
4 | #include "mainwindow.h"
5 |
6 | CHMLHandler::CHMLHandler()
7 | {
8 | }
9 |
10 | bool CHMLHandler::startDocument()
11 | {
12 | inEventsSection = inEvent = false;
13 | currentEventProperty = "none";
14 | return true;
15 | }
16 |
17 | bool CHMLHandler::startElement( const QString &, const QString & name, const QString &, const QXmlAttributes &atts)
18 | {
19 | if (name == "events")
20 | {
21 | inEventsSection = true;
22 | }
23 | else if (name == "event")
24 | {
25 | currentEvent = new Event;
26 | inEvent = true;
27 | }
28 | else if (name == "timestamp" ||
29 | name == "type" ||
30 | name == "value")
31 | {
32 | currentEventProperty = name;
33 | }
34 | else if (name == "metadata")
35 | {
36 | inMetadata = true;
37 | currentEvent->metadata = new EventMetadata;
38 | }
39 | else if (name == "tempo" ||
40 | name == "numerator" ||
41 | name == "denominator" ||
42 | name == "startsNewPattern" ||
43 | name == "startsNewRound" ||
44 | name == "endsRound")
45 | {
46 | currentEventProperty = name;
47 | }
48 | else if (name == "pattern")
49 | {
50 | currentEvent->metadata->patternIndex = atts.value(QString(),"patternIndex").toInt();
51 | currentEventProperty = name;
52 | }
53 | else
54 | {
55 | qDebug() << name << " is not a recognised XML node.";
56 | return false;
57 | }
58 |
59 | return true;
60 | }
61 |
62 | bool CHMLHandler::characters ( const QString & text )
63 | {
64 | if (inEventsSection && inEvent && currentEventProperty != "none")
65 | {
66 | if (currentEventProperty == "timestamp")
67 | currentEvent->timestamp = text.toLong();
68 | else if (currentEventProperty == "type")
69 | currentEvent->setTypeRaw(text.toInt());
70 | else if (currentEventProperty == "value")
71 | currentEvent->value = text.toInt();
72 | else if (inMetadata)
73 | {
74 | if (currentEventProperty == "tempo")
75 | currentEvent->metadata->tempo = text.toFloat();
76 | else if (currentEventProperty == "numerator")
77 | currentEvent->metadata->valueNumerator = text.toInt();
78 | else if (currentEventProperty == "denominator")
79 | currentEvent->metadata->valueDenominator = text.toInt();
80 | else if (currentEventProperty == "startsNewPattern")
81 | currentEvent->metadata->startsNewPattern = text == "true";
82 | else if (currentEventProperty == "startsNewRound")
83 | currentEvent->metadata->startsNewRound = text == "true";
84 | else if (currentEventProperty == "endsRound")
85 | currentEvent->metadata->endsRound = text == "true";
86 | else if (currentEventProperty == "pattern")
87 | currentEvent->metadata->patternName = text;
88 | }
89 | }
90 |
91 | return true;
92 | }
93 |
94 | bool CHMLHandler::endElement( const QString & , const QString & name, const QString &)
95 | {
96 | if (name == "events")
97 | {
98 | inEventsSection = false;
99 | }
100 | else if (name == "event")
101 | {
102 | mainWindow->addEventToTable(*currentEvent);
103 | delete currentEvent;
104 | currentEvent = NULL;
105 | inEvent = false;
106 | }
107 | else if (name == "metadata")
108 | {
109 | inMetadata = false;
110 | }
111 | else if (name == "timestamp" ||
112 | name == "type" ||
113 | name == "value" ||
114 | name == "tempo" ||
115 | name == "numerator" ||
116 | name == "denominator" ||
117 | name == "startsNewPattern" ||
118 | name == "startsNewRound" ||
119 | name == "endsRound" ||
120 | name == "pattern")
121 | {
122 | currentEventProperty = "none";
123 | }
124 | else
125 | {
126 | qDebug() << name << " is not a recognised XML node.";
127 | return false;
128 | }
129 |
130 | return true;
131 | }
132 |
--------------------------------------------------------------------------------
/Source/chmlhandler.h:
--------------------------------------------------------------------------------
1 | #ifndef CHMLHANDLER_H
2 | #define CHMLHANDLER_H
3 |
4 | #include
5 |
6 | class Event;
7 |
8 | class CHMLHandler : public QXmlDefaultHandler
9 | {
10 | public:
11 | CHMLHandler();
12 |
13 | bool startDocument();
14 |
15 | bool startElement( const QString & namespaceURI, const QString & name, const QString & qName, const QXmlAttributes & atts );
16 |
17 | bool characters ( const QString & text );
18 |
19 | bool endElement( const QString & namespaceURI, const QString & name, const QString & qName );
20 |
21 | private:
22 | bool inEventsSection;
23 | bool inEvent;
24 | bool inMetadata;
25 | QString currentEventProperty;
26 | Event * currentEvent;
27 |
28 | };
29 |
30 | #endif // CHMLHANDLER_H
31 |
--------------------------------------------------------------------------------
/Source/config.h:
--------------------------------------------------------------------------------
1 | #ifndef CONFIG_H
2 | #define CONFIG_H
3 |
4 | #include "beatanalysis.h"
5 |
6 | #define SEMIQUAVER (1.0/4.0)
7 | #define QUAVER_TRIPLET (1.0/3.0)
8 | #define QUAVER (1.0/2.0)
9 | #define CROCHET_TRIPLET (2.0/3.0)
10 | #define THREE_SEMIQUAVERS (3.0/4.0)
11 | #define CROCHET 1
12 | #define FIVE_SEMIQUAVERS (5.0/4.0)
13 | #define TWO_CROCHET_TRIPLETS (4.0/3.0)
14 | #define THREE_QUAVERS (3.0/2.0)
15 | #define TWO_BEATS 2
16 | #define THREE_BEATS 3
17 | #define FOUR_BEATS 4
18 | #define FIVE_BEATS 5
19 | #define SIX_BEATS 6
20 | #define SEVEN_BEATS 7
21 | #define EIGHT_BEATS 8
22 | //replaced by 'break length detection':
23 | //#define TWELVE_BEATS 12
24 | //#define SIXTEEN_BEATS 16
25 | //#define TWENTY_FOUR_BEATS 24
26 | //#define THIRTY_TWO_BEATS 32
27 |
28 | #ifdef CH_GROOVE
29 | #define SEVEN_SEMIQUAVERS (7.0/4.0)
30 | #define NINE_SEMIQUAVERS (9.0/4.0)
31 | #define SEVENTEEN_SEMIQUAVERS (17.0/4.0)
32 | #endif
33 |
34 |
35 |
36 | #endif // CONFIG_H
37 |
--------------------------------------------------------------------------------
/Source/croppedvideosurface.h:
--------------------------------------------------------------------------------
1 | #ifndef CROPPEDVIDEOSURFACE_H
2 | #define CROPPEDVIDEOSURFACE_H
3 |
4 | #include
5 | #include
6 |
7 | class CroppedVideoSurface : public QVideoWidget, public QAbstractVideoSurface
8 | {
9 | public:
10 | CroppedVideoSurface(QWidget *widget, QObject *parent = 0);
11 | QList supportedPixelFormats(
12 | QAbstractVideoBuffer::HandleType handleType) const;
13 | bool present(const QVideoFrame &frame);
14 |
15 | public:
16 | bool isFormatSupported(const QVideoSurfaceFormat &format) const;
17 |
18 | bool start(const QVideoSurfaceFormat &format);
19 | void stop();
20 |
21 | QRect videoRect() const { return targetRect; }
22 | void updateVideoRect();
23 |
24 | void paint(QPainter *painter);
25 |
26 | private:
27 | QWidget *widget;
28 | QImage::Format imageFormat;
29 | QRect targetRect;
30 | QSize imageSize;
31 | QRect sourceRect;
32 | };
33 |
34 | #endif // CROPPEDVIDEOSURFACE_H
35 |
--------------------------------------------------------------------------------
/Source/customeventaction.h:
--------------------------------------------------------------------------------
1 | #ifndef CUSTOMEVENTACTION_H
2 | #define CUSTOMEVENTACTION_H
3 |
4 | #include
5 | class QHBoxLayout;
6 | class QKeySequenceEdit;
7 | class QSpinBox;
8 | class QCheckBox;
9 | class QWidget;
10 |
11 | #include "event.h"
12 |
13 | class CustomEventAction : public QAction
14 | {
15 | Q_OBJECT
16 | public:
17 | bool operator== (const CustomEventAction & other) const;
18 | CustomEventAction(Event event, bool trigger, bool record, QObject *parent);
19 | CustomEventAction(bool trigger, bool record, QObject *parent);
20 | QHBoxLayout * createGuiEditorLayout(QWidget *parent);
21 | QKeySequenceEdit * getPrimaryKeySequenceEdit() {return primaryKeySequenceEdit;}
22 | QKeySequenceEdit * getSecondaryKeySequenceEdit() {return secondaryKeySequenceEdit;}
23 | QString getCustomActionID();
24 | QString getPrimaryShortcutID();
25 | QString getSecondaryShortcutID();
26 | static CustomEventAction * fromString(const QString & string, QObject *parent);
27 | void addShortcut(QKeySequence newShortcut);
28 |
29 | public slots:
30 | void newTriggerValue(int newValue);
31 | void newRecordValue(int newValue);
32 | void newEventType(int newValue);
33 | void newEventValue(int newValue);
34 | void performAction(bool checked);
35 |
36 | private:
37 | Event actionEvent;
38 | bool shouldTrigger;
39 | bool shouldRecord;
40 | bool useSelectedEventValues;
41 | QWidget * originatingWidget = nullptr;
42 | QSpinBox * eventTypeBox;
43 | QSpinBox * eventValueBox;
44 | QCheckBox * triggerCheckbox;
45 | QCheckBox * recordCheckbox;
46 | QKeySequenceEdit * primaryKeySequenceEdit;
47 | QKeySequenceEdit * secondaryKeySequenceEdit;
48 | };
49 |
50 | #endif // CUSTOMEVENTACTION_H
51 |
--------------------------------------------------------------------------------
/Source/deletedialog.h:
--------------------------------------------------------------------------------
1 | #ifndef DELETEDIALOG_H
2 | #define DELETEDIALOG_H
3 |
4 | #include
5 | class EditorWindow;
6 | class QShortcut;
7 |
8 | namespace Ui {
9 | class DeleteDialog;
10 | }
11 |
12 | class DeleteDialog : public QDialog
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit DeleteDialog(EditorWindow *parent = nullptr);
18 | ~DeleteDialog();
19 |
20 | virtual void accept() override;
21 |
22 | private slots:
23 | void on_deleteIntervalMergeWithFollowingRadioButton_toggled(bool checked);
24 |
25 | void on_deleteIntervalMergeWithPreceedingRadioButton_toggled(bool checked);
26 |
27 | void on_deleteIntervalMergePreceedingWithFollowingRadioButton_toggled(bool checked);
28 |
29 | void on_deleteIntervalMoveLaterIntervalsRadioButton_toggled(bool checked);
30 |
31 | void on_deleteIntervalMoveEarlierIntervalsRadioButton_toggled(bool checked);
32 |
33 | private:
34 | Ui::DeleteDialog *ui;
35 | EditorWindow * editor;
36 | void showEditorDeletePage();
37 | void setLabels();
38 | void setShortcuts();
39 | void setButtonState();
40 | QShortcut * mergeFollowingShortcut;
41 | QShortcut * mergePrecedingShortcut;
42 | QShortcut * mergeBothShortcut;
43 | QShortcut * moveLaterShortcut;
44 | QShortcut * moveEarlierShortcut;
45 | QShortcut * doneShortcut;
46 | };
47 |
48 | #endif // DELETEDIALOG_H
49 |
--------------------------------------------------------------------------------
/Source/deletedialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | DeleteDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 493
10 | 156
11 |
12 |
13 |
14 | Delete Interval
15 |
16 |
17 | -
18 |
19 |
20 | Merge with following interval (remove the beat at the end of interval)
21 |
22 |
23 | true
24 |
25 |
26 |
27 | -
28 |
29 |
30 | Merge with preceeding interval (remove the beat at the beginning of interval)
31 |
32 |
33 |
34 | -
35 |
36 |
37 | Merge preceeding interval with following interval (remove both ends of interval)
38 |
39 |
40 |
41 | -
42 |
43 |
44 | Move later beats to fill the gap (all beats to the right of the selected beat will be moved left)
45 |
46 |
47 |
48 | -
49 |
50 |
51 | Move earlier beats to fill the gap (all beats to the left of the selected beat will be moved right)
52 |
53 |
54 |
55 | -
56 |
57 |
58 | Qt::Horizontal
59 |
60 |
61 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | buttonBox
71 | accepted()
72 | DeleteDialog
73 | accept()
74 |
75 |
76 | 248
77 | 254
78 |
79 |
80 | 157
81 | 274
82 |
83 |
84 |
85 |
86 | buttonBox
87 | rejected()
88 | DeleteDialog
89 | reject()
90 |
91 |
92 | 316
93 | 260
94 |
95 |
96 | 286
97 | 274
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/Source/enableidentifyintervalsdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef ENABLEIDENTIFYINTERVALSDIALOG_H
2 | #define ENABLEIDENTIFYINTERVALSDIALOG_H
3 |
4 | #include
5 |
6 | class AbstractNewBeatValueWidget;
7 | class NewCustomBeatValueWidget;
8 | class BeatValue;
9 |
10 | namespace Ui {
11 | class EnableIdentifyIntervalsDialog;
12 | }
13 |
14 | class EnableIdentifyIntervalsDialog : public QDialog
15 | {
16 | Q_OBJECT
17 |
18 | public:
19 | explicit EnableIdentifyIntervalsDialog(int valueInMs, double currentTempo, QWidget *parent = nullptr);
20 | ~EnableIdentifyIntervalsDialog();
21 |
22 | public slots:
23 | void accept() override;
24 |
25 | private slots:
26 | void on_tempoSpinBox_valueChanged(double arg1);
27 | void on_intervalNumeratorSpinBox_valueChanged(int);
28 | AbstractNewBeatValueWidget * selectBestMatch();
29 | void ensureSingleSelection();
30 | void newValueSelected(AbstractNewBeatValueWidget *);
31 |
32 | void on_intervalNameEdit_textChanged(const QString &arg1);
33 |
34 | void on_originalTempoButton_clicked();
35 |
36 | void on_perfectMatchTempoButton_clicked();
37 |
38 | void on_minimumNecessaryChangeTempoButton_clicked();
39 |
40 | void on_updateTempoCheckBox_stateChanged(int arg1);
41 |
42 | void on_openAdjustDialogCheckBox_stateChanged(int);
43 |
44 | void on_openAdjustDialogCheckBox_clicked();
45 |
46 | private:
47 | Ui::EnableIdentifyIntervalsDialog *ui;
48 | int valueInMs;
49 | double tempo;
50 | const double originalTempo;
51 | double lastNonOriginalTempo;
52 | double valueInBeats;
53 | QVector valueWidgets;
54 | NewCustomBeatValueWidget * customValueWidget;
55 | AbstractNewBeatValueWidget * currentlySelectedWidget;
56 | void calculateValueInBeats();
57 | double getSelectedValueInBeats();
58 | void updateDescriptiveText(AbstractNewBeatValueWidget *);
59 | void updateCheckboxes();
60 | static BeatValue * getExistingMatchingValue(float value);
61 | static bool hasExistingMatchingValue(float value);
62 | BeatValue getSelectedValue();
63 | BeatValue createSelectedValue();
64 | double getPerfectMatchTempo();
65 | QVector getMaskingValues();
66 | QString getMaskingValuesString();
67 | bool selectedValueIsMasked();
68 | bool tempoChangedLots();
69 | QString askAboutBadMatch();
70 | bool askAboutBigTempoChange();
71 | bool confirmChoiceToDisableMaskingValues();
72 | QString askAboutMaskingValues();
73 | };
74 |
75 | #endif // ENABLEIDENTIFYINTERVALSDIALOG_H
76 |
--------------------------------------------------------------------------------
/Source/event.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTSTRUCT_H
2 | #define EVENTSTRUCT_H
3 |
4 | #include "eventmetadata.h"
5 | #include "globals.h"
6 |
7 | enum e_eventType
8 | {
9 | EVENT_RESET_TIMECODE,
10 | EVENT_NORMAL_WAND_PULSE,
11 | EVENT_NORMAL_WAND_PULSE_END,
12 | EVENT_TIMED_WAND_PULSE,
13 | EVENT_TIMED_WAND_PULSE_END,
14 | EVENT_EDGE_BEGIN,
15 | EVENT_EDGE_END,
16 | EVENT_ANAL_VIBRATOR_PULSE,
17 | EVENT_ANAL_VIBRATOR_PULSE_END,
18 | EVENT_INFLATABLE_BUTT_PLUG_INFLATE,
19 | EVENT_INFLATABLE_BUTT_PLUG_DEFLATE,
20 | EVENT_AIR_PUMP_ON,
21 | EVENT_AIR_PUMP_OFF,
22 | EVENT_RECORDING_MISTAKE,
23 | EVENT_UNUSED,
24 | EVENT_STROKER_WAYPOINT, //for things like handy, launch etc.
25 | EVENT_STROKE_UP, //A stroke moving from the base of the penis towards the tip
26 | EVENT_STROKE_DOWN, //A stroke moving from the tip of the penis towards the base
27 | EVENT_ENUM_SIZE
28 | };
29 |
30 | class Event
31 | {
32 | public:
33 | Event();
34 | Event(long timestamp, unsigned char type, short value);
35 | Event(long timestamp, unsigned char type, short value, bool optional);
36 | Event(long timestamp, unsigned char type, short value, EventMetadata metadata);
37 |
38 | bool operator==(const Event &) const;
39 |
40 | QString toAsciiString();
41 | QString toBinary();
42 | //! used for hashing the events table to detect changes
43 | int toHash();
44 |
45 | long timestamp;
46 |
47 | static bool writeAllToXml(QString filename);
48 |
49 | private:
50 | char typeData;
51 | public:
52 | unsigned char type() const;
53 | QString typeName() const;
54 | void setType(unsigned char newType);
55 | void setTypeRaw(char newTypeData);
56 | short value;
57 | short maxPossibleValue();
58 | bool optional() const;
59 | bool isOptional() const;
60 | void setOptional(bool optionality);
61 | EventMetadata * metadata;
62 | };
63 |
64 | #endif // EVENTSTRUCT_H
65 |
--------------------------------------------------------------------------------
/Source/eventdatamodel.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTDATAMODEL_H
2 | #define EVENTDATAMODEL_H
3 |
4 | #include
5 | class Event;
6 |
7 | class eventDataModel : public QAbstractTableModel
8 | {
9 | Q_OBJECT
10 | public:
11 | explicit eventDataModel(QObject *parent = 0);
12 | int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
13 | int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
14 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
15 | Qt::ItemFlags flags(const QModelIndex &index) const;
16 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
17 | bool setData(const QModelIndex &index, const QVariant &value, int role);
18 | Event eventFromIndex(const QModelIndex &index);
19 | void setEventAtIndex(const QModelIndex & indexToChange, const Event & event);
20 | void addEvent(const Event eventToAdd);
21 | void removeEvent(int index);
22 | //bool removeRow();
23 | //bool insertRows(int row, int count, const QModelIndex &parent);
24 | bool removeRows ( int row, int count, const QModelIndex & parent = QModelIndex() );
25 |
26 | signals:
27 |
28 | public slots:
29 |
30 | };
31 |
32 | #endif // EVENTDATAMODEL_H
33 |
--------------------------------------------------------------------------------
/Source/eventdataproxymodel.cpp:
--------------------------------------------------------------------------------
1 | #include "eventdataproxymodel.h"
2 | #include "eventdatamodel.h"
3 | #include "event.h"
4 |
5 | EventDataProxyModel::EventDataProxyModel(QObject *parent) :
6 | QSortFilterProxyModel(parent)
7 | {
8 | source = static_cast(sourceModel());
9 | }
10 |
11 | Event EventDataProxyModel::eventFromIndex(const QModelIndex &index)
12 | {
13 | if (!source)
14 | source = static_cast(sourceModel());
15 | return source->eventFromIndex(mapToSource(index));
16 | }
17 |
18 | void EventDataProxyModel::setEventAtIndex(const QModelIndex & indexToChange, const Event & event)
19 | {
20 | if (!source)
21 | source = static_cast(sourceModel());
22 | source->setEventAtIndex(mapToSource(indexToChange),event);
23 | }
24 |
25 | void EventDataProxyModel::addEvent(const Event eventToAdd)
26 | {
27 | if (!source)
28 | source = static_cast(sourceModel());
29 | source->addEvent(eventToAdd);
30 | }
31 |
32 | void EventDataProxyModel::removeEvent(int indexToDelete)
33 | {
34 | if (!source)
35 | source = static_cast(sourceModel());
36 | int otherRow = mapToSource(index(indexToDelete,0)).row();
37 | source->removeEvent(otherRow);
38 | }
39 |
--------------------------------------------------------------------------------
/Source/eventdataproxymodel.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTDATAPROXYMODEL_H
2 | #define EVENTDATAPROXYMODEL_H
3 |
4 | #include
5 |
6 | class Event;
7 | class eventDataModel;
8 |
9 | class EventDataProxyModel : public QSortFilterProxyModel
10 | {
11 | Q_OBJECT
12 | public:
13 | explicit EventDataProxyModel(QObject *parent = 0);
14 |
15 | Event eventFromIndex(const QModelIndex & index);
16 | void setEventAtIndex(const QModelIndex & indexToChange, const Event & event);
17 | void addEvent(const Event eventToAdd);
18 | void removeEvent(int indexToDelete);
19 |
20 | signals:
21 |
22 | public slots:
23 |
24 | private:
25 | eventDataModel * source;
26 | };
27 |
28 | #endif // EVENTDATAPROXYMODEL_H
29 |
--------------------------------------------------------------------------------
/Source/eventdispatcher.cpp:
--------------------------------------------------------------------------------
1 | #include "eventdispatcher.h"
2 |
3 | EventDispatcher::EventDispatcher(QObject *parent) : QObject(parent)
4 | {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/Source/eventdispatcher.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTDISPATCHER_H
2 | #define EVENTDISPATCHER_H
3 |
4 | #include "event.h"
5 |
6 | class EventDispatcher : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit EventDispatcher(QObject *parent = nullptr);
11 | virtual void dispatch(Event event) = 0;
12 |
13 | signals:
14 |
15 | };
16 |
17 | #endif // EVENTDISPATCHER_H
18 |
--------------------------------------------------------------------------------
/Source/eventmetadata.cpp:
--------------------------------------------------------------------------------
1 | #include "eventmetadata.h"
2 |
3 | EventMetadata::EventMetadata()
4 | :
5 | tempo(0),
6 | valueNumerator(0),
7 | valueDenominator(0),
8 | startsNewPattern(false),
9 | startsNewRound(false),
10 | endsRound(false),
11 | patternName(QString()),
12 | patternIndex(0)
13 | {
14 | //just the LIST above...
15 | }
16 |
--------------------------------------------------------------------------------
/Source/eventmetadata.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTMETADATA_H
2 | #define EVENTMETADATA_H
3 |
4 | struct EventMetadata
5 | {
6 | EventMetadata();
7 | float tempo;
8 | unsigned char valueNumerator;
9 | unsigned char valueDenominator;
10 | bool startsNewPattern;
11 | bool startsNewRound;
12 | bool endsRound;
13 | QString patternName;
14 | unsigned char patternIndex;
15 | };
16 |
17 | #endif // EVENTMETADATA_H
18 |
--------------------------------------------------------------------------------
/Source/eventtabledelegate.cpp:
--------------------------------------------------------------------------------
1 | #include "eventtabledelegate.h"
2 | #include
3 | #include
4 | #include
5 |
6 | EventTableDelegate::EventTableDelegate(QObject *parent) :
7 | QStyledItemDelegate(parent)
8 | {
9 | }
10 |
11 | QWidget * EventTableDelegate::createEditor(QWidget *parent,
12 | const QStyleOptionViewItem & option,
13 | const QModelIndex & index) const
14 | {
15 | if (index.column() == 1 ||
16 | index.column() == 2 ||
17 | index.column() == 3)
18 | {
19 | QSpinBox * editor = new QSpinBox(parent);
20 | editor->setMinimum(0);
21 | if (index.column() == 1)
22 | editor->setMaximum(INT_MAX);
23 | else if (index.column() == 2)
24 | editor->setMaximum(0xFF);
25 | else if (index.column() == 3)
26 | editor->setMaximum(0xFFFF);
27 |
28 | int value = index.data(Qt::EditRole).toInt();
29 | editor->setValue(value);
30 |
31 | return editor;
32 | }
33 | else if (index.column() == 4)
34 | {
35 | QCheckBox * editor = new QCheckBox(parent);
36 | return editor;
37 | }
38 | else
39 | return QStyledItemDelegate::createEditor(parent, option, index);
40 | }
41 |
42 | void EventTableDelegate::setEditorData(QWidget *editor,
43 | const QModelIndex &index) const
44 | {
45 | if (index.column() == 1 ||
46 | index.column() == 2 ||
47 | index.column() == 3 )
48 | {
49 | int value = index.model()->data(index, Qt::EditRole).toInt();
50 | QSpinBox * thisEditor = qobject_cast(editor);
51 | thisEditor->setValue(value);
52 | }
53 | else if (index.column() == 4)
54 | {
55 | bool value = index.model()->data(index, Qt::EditRole).toBool();
56 | QCheckBox * thisEditor = qobject_cast(editor);
57 | thisEditor->setChecked(value);
58 | }
59 | else
60 | QStyledItemDelegate::setEditorData(editor, index);
61 | }
62 |
63 | void EventTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
64 | const QModelIndex &index) const
65 | {
66 | if (index.column() == 1 ||
67 | index.column() == 2 ||
68 | index.column() == 3 )
69 | {
70 | QSpinBox *spinBox = static_cast(editor);
71 | spinBox->interpretText();
72 | int value = spinBox->value();
73 |
74 | model->setData(index, value, Qt::EditRole);
75 | }
76 | else if (index.column() == 4)
77 | {
78 | QCheckBox *checkBox = static_cast(editor);
79 | bool value = checkBox->isChecked();
80 |
81 | model->setData(index, value, Qt::EditRole);
82 | }
83 | else
84 | QStyledItemDelegate::setModelData(editor, model, index);
85 | }
86 |
87 | void EventTableDelegate::updateEditorGeometry(QWidget *editor,
88 | const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
89 | {
90 | editor->setGeometry(option.rect);
91 | }
92 |
--------------------------------------------------------------------------------
/Source/eventtabledelegate.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTTABLEDELEGATE_H
2 | #define EVENTTABLEDELEGATE_H
3 |
4 | #include
5 |
6 | class EventTableDelegate : public QStyledItemDelegate
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit EventTableDelegate(QObject *parent = 0);
11 |
12 | QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
13 | const QModelIndex &index) const;
14 |
15 | void setEditorData(QWidget *editor, const QModelIndex &index) const;
16 | void setModelData(QWidget *editor, QAbstractItemModel *model,
17 | const QModelIndex &index) const;
18 |
19 | void updateEditorGeometry(QWidget *editor,
20 | const QStyleOptionViewItem &option, const QModelIndex &index) const;
21 |
22 | signals:
23 |
24 | public slots:
25 |
26 | };
27 |
28 | #endif // EVENTTABLEDELEGATE_H
29 |
--------------------------------------------------------------------------------
/Source/exportbeatmeterdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "exportbeatmeterdialog.h"
2 | #include "ui_exportbeatmeterdialog.h"
3 | #include
4 | #include
5 | #include "event.h"
6 | #include "optionsdialog.h"
7 | #include
8 |
9 | ExportBeatMeterDialog::ExportBeatMeterDialog(QWidget *parent) :
10 | QDialog(parent),
11 | ui(new Ui::ExportBeatMeterDialog),
12 | scene(new QGraphicsScene(this))
13 | {
14 | ui->setupUi(this);
15 | ui->strokeMeter->setScene(scene);
16 | }
17 |
18 | ExportBeatMeterDialog::~ExportBeatMeterDialog()
19 | {
20 | delete ui;
21 | }
22 |
23 | void ExportBeatMeterDialog::on_updateButton_clicked()
24 | {
25 | updateScene();
26 | }
27 |
28 | void ExportBeatMeterDialog::updateScene()
29 | {
30 | while (!strokeMarkers.isEmpty())
31 | {
32 | QAbstractGraphicsShapeItem * removeMe = strokeMarkers.last();
33 | scene->removeItem(removeMe);
34 | strokeMarkers.removeLast();
35 | delete removeMe;
36 | }
37 |
38 | int markerHeight = OptionsDialog::getBeatMarkerHeight();
39 | int markerWidth = OptionsDialog::getBeatMarkerWidth();
40 | for (Event event : events) {
41 | int hOffset = ((event.timestamp * OptionsDialog::getBeatMeterSpeed()) / 1000) - markerWidth / 2;//offset by half the width so the markers are centered horizontally on their timestamps
42 | int vOffset = 0 - (markerHeight / 2); //offset by half the height so the markers are centered vertically on 0
43 | QRectF rectLocation(hOffset,vOffset,markerWidth,markerHeight);
44 | QAbstractGraphicsShapeItem * marker;
45 | if (OptionsDialog::useSquareBeatMarkers())
46 | marker = new QGraphicsRectItem(rectLocation);
47 | else
48 | marker = new QGraphicsEllipseItem(rectLocation);
49 | QPen pen;
50 | pen.setWidth(2);
51 | marker->setPen(pen);
52 | QColor color = getColor(event);
53 | QBrush brush(color);
54 | marker->setBrush(brush);
55 | strokeMarkers.append(marker);
56 | scene->addItem(marker);
57 | }
58 |
59 | int width = OptionsDialog::getBeatMeterWidth();
60 | QRectF bounds = scene->itemsBoundingRect();
61 | bounds.setLeft(bounds.left() - width);
62 | bounds.setRight(bounds.right() + width);
63 | scene->setSceneRect(bounds);
64 | scene->update();
65 | }
66 |
67 | QColor ExportBeatMeterDialog::getColor(Event)
68 | {
69 | //TODO: Implement some fun colouring here
70 | return QColor(Qt::lightGray);
71 | }
72 |
73 | void ExportBeatMeterDialog::on_exportButton_clicked()
74 | {
75 | QString exportFilenamePrefix = QFileDialog::getSaveFileName(this, tr("Select image sequence base filename"),
76 | "~/Pictures",
77 | tr("Portable Network Graphics (*.png)"));
78 | if (exportFilenamePrefix.isEmpty())
79 | return; //save cancelled
80 | if (exportFilenamePrefix.endsWith(".png"))
81 | {
82 | exportFilenamePrefix.chop(4);
83 | }
84 | int height = OptionsDialog::getBeatMeterHeight();
85 | int width = OptionsDialog::getBeatMeterWidth();
86 | int pixelsPerSecond = OptionsDialog::getBeatMeterSpeed();
87 | double fps = OptionsDialog::getBeatMeterFrameRate();
88 | long frameCounter = 0;
89 | qreal beginning = scene->itemsBoundingRect().left() - width;
90 | qreal end = scene->itemsBoundingRect().right();
91 | qreal top = 0 - (float) height / 2;
92 | qreal hPos = beginning;
93 |
94 | while (hPos < end)
95 | {
96 | ++frameCounter;
97 | hPos = beginning + (frameCounter * pixelsPerSecond) / fps;
98 | scene->setSceneRect(QRectF(hPos, top, width, height));
99 | QImage image(scene->sceneRect().size().toSize(), QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
100 | image.fill(Qt::transparent); // Start all pixels transparent
101 |
102 | QPainter painter(&image);
103 | scene->render(&painter);
104 | image.save(QString("%1_%2.png").arg(exportFilenamePrefix).arg(frameCounter));
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Source/exportbeatmeterdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef EXPORTBEATMETERDIALOG_H
2 | #define EXPORTBEATMETERDIALOG_H
3 |
4 | #include
5 | #include "event.h"
6 |
7 | class QGraphicsScene;
8 | class QAbstractGraphicsShapeItem;
9 |
10 | namespace Ui {
11 | class ExportBeatMeterDialog;
12 | }
13 |
14 | class ExportBeatMeterDialog : public QDialog
15 | {
16 | Q_OBJECT
17 |
18 | public:
19 | explicit ExportBeatMeterDialog(QWidget *parent = nullptr);
20 | ~ExportBeatMeterDialog();
21 |
22 | private slots:
23 | void on_updateButton_clicked();
24 |
25 | void on_exportButton_clicked();
26 |
27 | private:
28 | Ui::ExportBeatMeterDialog *ui;
29 | QGraphicsScene * scene;
30 | QVector strokeMarkers;
31 | QColor getColor(Event event);
32 |
33 | void updateScene();
34 | };
35 |
36 | #endif // EXPORTBEATMETERDIALOG_H
37 |
--------------------------------------------------------------------------------
/Source/exportbeatmeterdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ExportBeatMeterDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 879
10 | 141
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 | Export
23 |
24 |
25 |
26 | -
27 |
28 |
29 | Update
30 |
31 |
32 |
33 | -
34 |
35 |
36 | Cancel
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Qt::Horizontal
44 |
45 |
46 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
47 |
48 |
49 |
50 |
51 |
52 | -
53 |
54 |
55 | QPainter::Antialiasing|QPainter::TextAntialiasing
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | buttonBox
65 | accepted()
66 | ExportBeatMeterDialog
67 | accept()
68 |
69 |
70 | 248
71 | 254
72 |
73 |
74 | 157
75 | 274
76 |
77 |
78 |
79 |
80 | buttonBox
81 | rejected()
82 | ExportBeatMeterDialog
83 | reject()
84 |
85 |
86 | 316
87 | 260
88 |
89 |
90 | 286
91 | 274
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Source/funscriptwriter.cpp:
--------------------------------------------------------------------------------
1 | #include "funscriptwriter.h"
2 | #include "optionsdialog.h"
3 | #include
4 |
5 | FunscriptWriter::FunscriptWriter(QFile & file, QObject * parent)
6 | :
7 | SyncFileWriter(file, parent)
8 | {
9 |
10 | }
11 |
12 | void FunscriptWriter::writeHeader()
13 | {
14 | //TODO: This whole class could be rewritten using proper JSON handling, but hey, it works...
15 | int topOfRange = OptionsDialog::getRangeTop();
16 | int bottomOfRange = OptionsDialog::getRangeBottom();
17 | int rangeAnchor = OptionsDialog::getRangeAnchor();
18 | int proportionalLength = OptionsDialog::getStrokeLengthProportion();
19 | QString fileHeader = QString("{\"export_comment\":\"Exported from Cock Heroine using range %1%% to %2%%, %3%% anchor point and %4%% proportional stroke length. "
20 | "Exporting tempo, beat values and non-standard stroke events such as edging and butt plug control events not supported at time of writing.\","
21 | "\"version\":\"1.0\",\"inverted\":false,\"range\":100,\"actions\":[")
22 | .arg(bottomOfRange)
23 | .arg(topOfRange)
24 | .arg(rangeAnchor)
25 | .arg(proportionalLength);
26 | file.write(fileHeader.toLatin1());
27 | needPreceedingComma = false;
28 | }
29 |
30 | void FunscriptWriter::addEvent(long timestamp, int position)
31 | {
32 | if (needPreceedingComma)
33 | file.write(",");
34 | QString eventString = funscriptEntryString(timestamp, position);
35 | file.write(eventString.toLatin1());
36 | needPreceedingComma = true;
37 | }
38 |
39 | void FunscriptWriter::writeFooter()
40 | {
41 | file.write("]}");
42 | }
43 |
44 | QString FunscriptWriter::funscriptEntryString(long timestamp, int targetLocation)
45 | {
46 | return QString("{\"pos\":%1,\"at\":%2}").arg(targetLocation).arg(timestamp);
47 | }
48 |
--------------------------------------------------------------------------------
/Source/funscriptwriter.h:
--------------------------------------------------------------------------------
1 | #ifndef FUNSCRIPTWRITER_H
2 | #define FUNSCRIPTWRITER_H
3 |
4 | #include "syncfilewriter.h"
5 |
6 | class FunscriptWriter : public SyncFileWriter
7 | {
8 | Q_OBJECT
9 | public:
10 | FunscriptWriter(QFile &, QObject * parent = nullptr);
11 | virtual void writeHeader();
12 | virtual void addEvent(long timestamp, int position);
13 | virtual void writeFooter();
14 | QString funscriptEntryString(long timestamp, int targetLocation);
15 | private:
16 | bool needPreceedingComma = false;
17 | };
18 |
19 | #endif // FUNSCRIPTWRITER_H
20 |
--------------------------------------------------------------------------------
/Source/globals.h:
--------------------------------------------------------------------------------
1 | #ifndef GLOBALS_H
2 | #define GLOBALS_H
3 |
4 | #include "beatpattern.h"
5 |
6 | class QTime;
7 | class QTimer;
8 | class Event;
9 | class BeatTimestamp;
10 | class BeatValue;
11 | class BeatInterval;
12 | class UniqueBeatInterval;
13 | class QMediaPlayer;
14 | class EditorWindow;
15 | class MainWindow;
16 | class QLCDNumber;
17 | class EventDispatcher;
18 |
19 | extern QVector events;
20 | QVector filteredEvents(const QList & types, const QVector & eventsToFilter = events);
21 | extern QVector beatTimestamps;
22 | //!
23 | //! \brief beatValues a list of all the possible 'types' of interval length we recognise.
24 | //! At time of writing these are populated in the beat analysis code, but they could (also) be
25 | //! loaded from a save file. New types of value are added via the editor (values table).
26 | //! Also can be enabled or created from the Enable/Identify Values Dialog.
27 | //!
28 | extern QVector beatValues;
29 | //!
30 | //! \brief beatIntervals This is just a list of the 'spaces' between the beats (BeatTimestamps).
31 | //!
32 | extern QVector beatIntervals;
33 | //!
34 | //! \brief uniqueBeatIntervals If you were to create a graph for all the intervals, with interval length
35 | //! as the x axis and abundance as the y axis, then the idea is you have one uniqueBeatInterval for
36 | //! each peak on that graph.
37 | //!
38 | extern QList uniqueBeatIntervals;
39 | extern QVector beatPatterns;
40 | extern const char * defaultValueShortcuts[2][10];
41 |
42 | extern QString loadedVideo;
43 | extern QString loadedScript;
44 |
45 | extern QTimer * refreshTimer;
46 | extern QMediaPlayer * videoPlayer;
47 | extern QMediaPlayer * stimSignalPlayer;
48 | extern MainWindow * mainWindow;
49 | extern EditorWindow * editor;
50 | extern QTime * timecode;
51 | extern long timecodeLastStopped;
52 | extern bool currentlyPlaying;
53 | extern long currentTimecode();
54 | extern void seekToTimestamp (long seekTo);
55 | QVector listOfTimestampDenominators();
56 | QVector listOfMetadataDenominators();
57 | extern QLCDNumber * lcdDisplay; //so seekToTimestamp can update it
58 | void setLcdDisplay(int millis);
59 |
60 | BeatValue * getBeatValueByName(const QString & name);
61 | BeatValue * getBeatValueFromMsLength(int length);
62 | BeatValue * getBeatValueFromLengthInBeats(float length);
63 | BeatValue * getBeatValueFromDropdownEntry(const QString & entry);
64 | QString millisToTimecode(unsigned int millis);
65 |
66 | extern QVector dispatchers;
67 |
68 | double tempoToBeatLength(double tempo);
69 | double beatLengthToTempo(double beatLength);
70 |
71 | #endif // GLOBALS_H
72 |
--------------------------------------------------------------------------------
/Source/graphicsscenevideodialog.h:
--------------------------------------------------------------------------------
1 | #ifndef GRAPHICSSCENEVIDEODIALOG_H
2 | #define GRAPHICSSCENEVIDEODIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | namespace Ui {
9 | class GraphicsSceneVideoDialog;
10 | }
11 |
12 | class GraphicsSceneVideoDialog : public QDialog
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit GraphicsSceneVideoDialog(QWidget *parent = 0);
18 | ~GraphicsSceneVideoDialog();
19 | void takeVideoOutput();
20 | QGraphicsScene * videoScene;
21 | QGraphicsVideoItem * videoItem;
22 | void closeEvent(QCloseEvent *);
23 | void resizeEvent(QResizeEvent*);
24 | void handleResize();
25 | void mousePressEvent(QMouseEvent *);
26 | void keyPressEvent(QKeyEvent *);
27 | bool eventFilter(QObject *obj, QEvent *event);
28 | void toggleFullscreen();
29 | void show();
30 |
31 | public slots:
32 | void maskBeatMeter(bool dark = false);
33 | void setMaskOrNot (bool);
34 |
35 | private:
36 | Ui::GraphicsSceneVideoDialog *ui;
37 | QGraphicsRectItem * maskingRectangle;
38 | QGraphicsView * graphicsView;
39 | };
40 |
41 | #endif // GRAPHICSSCENEVIDEODIALOG_H
42 |
--------------------------------------------------------------------------------
/Source/graphicsscenevideodialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | GraphicsSceneVideoDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 | -
18 |
19 |
20 | QFrame::NoFrame
21 |
22 |
23 | QFrame::Plain
24 |
25 |
26 | 0
27 |
28 |
29 | Qt::ScrollBarAlwaysOff
30 |
31 |
32 | Qt::ScrollBarAlwaysOff
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Qt::Horizontal
40 |
41 |
42 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | buttonBox
52 | accepted()
53 | GraphicsSceneVideoDialog
54 | accept()
55 |
56 |
57 | 248
58 | 254
59 |
60 |
61 | 157
62 | 274
63 |
64 |
65 |
66 |
67 | buttonBox
68 | rejected()
69 | GraphicsSceneVideoDialog
70 | reject()
71 |
72 |
73 | 316
74 | 260
75 |
76 |
77 | 286
78 | 274
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/Source/handycsvwriter.cpp:
--------------------------------------------------------------------------------
1 | #include "handycsvwriter.h"
2 | #include
3 |
4 | HandyCsvWriter::HandyCsvWriter(QFile & file, QObject * parent)
5 | :
6 | SyncFileWriter(file, parent)
7 | {
8 |
9 | }
10 |
11 | void HandyCsvWriter::writeHeader()
12 | {
13 | QString fileHeader = QString("#Handy sync file. Exported from Cock Heroine\n");
14 | file.write(fileHeader.toLatin1());
15 | }
16 |
17 | void HandyCsvWriter::addEvent(long timestamp, int position)
18 | {
19 | QString eventString = csvEntryString(timestamp, position);
20 | file.write(eventString.toLatin1());
21 | }
22 |
23 | void HandyCsvWriter::writeFooter()
24 | {
25 | //A CSV file needs no footer
26 | }
27 |
28 | QString HandyCsvWriter::csvEntryString(long timestamp, int targetLocation)
29 | {
30 | return QString("%1,%2\n").arg(timestamp).arg(targetLocation);
31 | }
32 |
--------------------------------------------------------------------------------
/Source/handycsvwriter.h:
--------------------------------------------------------------------------------
1 | #ifndef HANDYCSVWRITER_H
2 | #define HANDYCSVWRITER_H
3 |
4 | #include "syncfilewriter.h"
5 |
6 | class HandyCsvWriter : public SyncFileWriter
7 | {
8 | Q_OBJECT
9 | public:
10 | HandyCsvWriter(QFile &, QObject * parent = nullptr);
11 | virtual void writeHeader();
12 | virtual void addEvent(long timestamp, int position);
13 | virtual void writeFooter();
14 | QString csvEntryString(long timestamp, int targetLocation);
15 | };
16 |
17 | #endif // HANDYCSVWRITER_H
18 |
--------------------------------------------------------------------------------
/Source/helperfunctions.h:
--------------------------------------------------------------------------------
1 | #ifndef HELPERFUNCTIONS_H
2 | #define HELPERFUNCTIONS_H
3 |
4 | #include
5 | class QTableView;
6 | class BeatValue;
7 |
8 | bool isWholeNumber(float numberToCheck);
9 | long int roundToInt(double numberToRound);
10 | float absoluteDifferenceBetween(const double initialValue, const double newValue);
11 | float percentageDifferenceBetween(const double initialValue, const double newValue);
12 | bool isWithinXPercentOf(const double initialValue, const double newValue, const short percentageDifference);
13 | int isPowerOfTwo (unsigned int x);
14 |
15 | int greatestCommonDivisor(int a, int b);
16 | int lowestCommonMultiple(int a, int b);
17 | int lowestCommonMultiple(const QVector & listOfNumbers);
18 | int lowestCommonMultiple(const QVector & listOfNumbers);
19 |
20 | void setColumWidthsFromModel(QTableView * table);
21 | bool multipleRowsSelected(const QModelIndexList & indexList);
22 | bool containsNonContiguousRows(const QModelIndexList & indexList);
23 | void identifyFirstAndLastRows(const QModelIndexList & indexList, int & result_first, int & result_last);
24 | BeatValue * calculateShortestActiveBeatValue();
25 |
26 | bool midiCanUseTempo();
27 | void reportTempoGaps();
28 |
29 | #endif // HELPERFUNCTIONS_H
30 |
--------------------------------------------------------------------------------
/Source/intervaldatamodel.h:
--------------------------------------------------------------------------------
1 | #ifndef INTERVALDATAMODEL_H
2 | #define INTERVALDATAMODEL_H
3 |
4 | #include
5 |
6 | class BeatInterval;
7 |
8 | class IntervalDataModel : public QAbstractTableModel
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit IntervalDataModel(QObject *parent = 0);
13 | int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
14 | int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
15 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
16 | Qt::ItemFlags flags(const QModelIndex &index) const;
17 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
18 | bool containsUnknownIntervals();
19 | bool containsPoorlyMatchedIntervals (float threshold = 40);
20 |
21 | signals:
22 |
23 | public slots:
24 |
25 | };
26 |
27 | #endif // INTERVALDATAMODEL_H
28 |
--------------------------------------------------------------------------------
/Source/keyboardshortcutsdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef KEYBOARDSHORTCUTSDIALOG_H
2 | #define KEYBOARDSHORTCUTSDIALOG_H
3 |
4 | #include
5 | class QKeySequenceEdit;
6 |
7 | namespace Ui {
8 | class KeyboardShortcutsDialog;
9 | }
10 |
11 | class KeyboardShortcutsDialog : public QDialog
12 | {
13 | Q_OBJECT
14 |
15 | public:
16 | explicit KeyboardShortcutsDialog(QWidget *parent = 0);
17 | ~KeyboardShortcutsDialog();
18 | void applyShortcutPrefsFromUi();
19 | static void applyActionShortcutsFromPrefs();
20 | void accept();
21 |
22 | public slots:
23 | void on_addCustomShortcutButtonClicked();
24 |
25 | private:
26 | Ui::KeyboardShortcutsDialog *ui;
27 | QList * allActions;
28 | QList allPrimaryShortcuts;
29 | QList allSecondaryShortcuts;
30 | static QList *createActionsList();
31 | void createWidgetList();
32 | static QString getActionID(QAction * action);
33 | static QString getActionContext(QAction * action);
34 | static QString getActionPrimaryShortcutID(QAction * action);
35 | static QString getActionSecondaryShortcutID(QAction * action);
36 | };
37 |
38 | #endif // KEYBOARDSHORTCUTSDIALOG_H
39 |
--------------------------------------------------------------------------------
/Source/keyboardshortcutsdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | KeyboardShortcutsDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 801
10 | 527
11 |
12 |
13 |
14 | Keyboard Shortcuts
15 |
16 |
17 | -
18 |
19 |
20 | true
21 |
22 |
23 |
24 |
25 | 0
26 | 0
27 | 781
28 | 478
29 |
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 | Qt::Horizontal
39 |
40 |
41 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | buttonBox
51 | accepted()
52 | KeyboardShortcutsDialog
53 | accept()
54 |
55 |
56 | 248
57 | 254
58 |
59 |
60 | 157
61 | 274
62 |
63 |
64 |
65 |
66 | buttonBox
67 | rejected()
68 | KeyboardShortcutsDialog
69 | reject()
70 |
71 |
72 | 316
73 | 260
74 |
75 |
76 | 286
77 | 274
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/Source/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | QCoreApplication::setOrganizationName("Flooble");
8 | QCoreApplication::setOrganizationDomain("unknown");
9 | QCoreApplication::setApplicationName("Cock Heroine");
10 | MainWindow w;
11 | w.setWindowIcon(QIcon(":/WandIcon"));
12 | w.setWindowTitle(QString("Cock Heroine"));
13 | w.show();
14 |
15 | return a.exec();
16 | }
17 |
--------------------------------------------------------------------------------
/Source/midifilereader.h:
--------------------------------------------------------------------------------
1 | #ifndef MIDIFILEREADER_H
2 | #define MIDIFILEREADER_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class MidiFileReader : public QObject
9 | {
10 | public:
11 | MidiFileReader(QString filename, QObject *parent);
12 | quint32 readVariableLengthQuantity();
13 | void printAsVariableLengthQuantity(unsigned int value);
14 | bool readFile();
15 | bool handleNewTempo();
16 | void configureIntegerDivisionCompensation();
17 | bool handleMidiNoteOn(unsigned char statusByte);
18 | bool createEventNow(unsigned char key, unsigned char velocity, unsigned char channel);
19 | bool handleMetaEvent();
20 | bool ignoreVariableQuantity();
21 | bool ignoreFixedQuantity(unsigned int bytesToIgnore);
22 | void advanceCurrentTimeByDivisions(unsigned int numberOfDivisions);
23 |
24 | QFile inputMidiFile;
25 | QDataStream inputMidiData;
26 |
27 | long currentMicroseconds;
28 |
29 | bool usingSMTPE;
30 |
31 | int microsecondsPerBeat;
32 | int microsecondsPerDivision;
33 |
34 | quint8 framesPerSecond;
35 | quint8 ticksPerFrame;
36 | unsigned int ticksPerSecond;
37 | unsigned int framesPerBeat;
38 |
39 | int extraMicroseconds;
40 | int extraMicrosecondsCounter;
41 | int addExtraMicrosecondsEvery;
42 |
43 | quint8 runningStatus;
44 |
45 | static const int firstTrackSizePos;
46 | };
47 |
48 | #endif // MIDIFILEREADER_H
49 |
--------------------------------------------------------------------------------
/Source/midifilewriter.h:
--------------------------------------------------------------------------------
1 | #ifndef MIDIFILEWRITER_H
2 | #define MIDIFILEWRITER_H
3 |
4 | #include
5 | #include
6 |
7 | class MidiFileWriter : public QObject
8 | {
9 | Q_OBJECT
10 | public:
11 | explicit MidiFileWriter(QString filename, QObject *parent = 0);
12 |
13 | bool writeHeader(bool useSMPTE, qint16 framesPerBeat = 0);
14 | quint8 writeVariableLengthQuantity(quint32 value);
15 | quint16 writeTitle(QString title);
16 | bool writeTimeSignature(quint8 numerator, quint8 denominator, quint8 clocksPerMetronomeClick = 24, quint8 demisemiquaversPerCrochet = 8);
17 | bool writeTempo(quint16 BPM, int afterFrames = 0);
18 | bool writeTempo(double BPM, int afterFrames = 0);
19 | bool writeTempo_usPerBeat(quint32 microsecondsPerBeat, int afterFrames = 0);
20 | bool writePatchChange(quint8 channel, quint8 patchNo);
21 | void writeBeat(quint32 timestampInMiliseconds, quint8 note = defaultDrumNote, quint8 channel = 9 /*drums*/, quint8 velocity = 127 /*full whack*/);
22 | void writeBeat_frameDelta(quint32 framesSinceLastBeat, quint8 note = defaultDrumNote, quint8 channel = 9 /*drums*/, quint8 velocity = 127 /*full whack*/);
23 | void writeBeatNow(quint8 note = defaultDrumNote, quint8 channel = 9 /*drums*/, quint8 velocity = 127 /*full whack*/);
24 | void writeEndOfTrack();
25 |
26 | signals:
27 |
28 | public slots:
29 |
30 | private:
31 | QFile outputMidiFile;
32 | QDataStream outputMidiData;
33 |
34 | long lastPositionWritten;
35 | quint8 runningStatus;
36 |
37 | static const char * const headerTag;
38 | static const char * const trackTag;
39 | static const int firstTrackSizePos;
40 | static quint8 defaultDrumNote;
41 | };
42 |
43 | #define BASS_DRUM_1 36
44 | #define SIDE_STICK 37
45 | #define ACOUSTIC_SNARE 38
46 | #define ELECTRIC_SNARE 40
47 | #define CLOSED_HIHAT 41
48 | #define OPEN_HIHAT 46
49 |
50 | #endif // MIDIFILEWRITER_H
51 |
--------------------------------------------------------------------------------
/Source/newbeatvaluewidget.cpp:
--------------------------------------------------------------------------------
1 | #include "newbeatvaluewidget.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "globals.h"
8 | #include "uniquebeatinterval.h"
9 | #include "beatanalysis.h"
10 |
11 | NewBeatValueWidget::NewBeatValueWidget(QWidget *parent, float valueInBeats, int divisor)
12 | :
13 | AbstractNewBeatValueWidget(valueInBeats, parent),
14 | numerator(1),
15 | divisor(divisor)
16 | {
17 | valueNumeratorLabel = new QLabel(this);
18 | valueNumeratorLabel->setObjectName(QString::fromUtf8("valueNumeratorLabel"));
19 | valueNumeratorLabel->setAlignment(Qt::AlignCenter);
20 |
21 | valueFractionLayout->addWidget(valueNumeratorLabel);
22 |
23 | QLabel * valueSlashLabel = new QLabel(this);
24 | valueSlashLabel->setObjectName(QString::fromUtf8("valueSlashLabel"));
25 | valueSlashLabel->setAlignment(Qt::AlignCenter);
26 | valueSlashLabel->setText(QApplication::translate("EnableIdentifyIntervalsDialog", "/", nullptr));
27 |
28 | valueFractionLayout->addWidget(valueSlashLabel);
29 |
30 | valueDivisorLabel = new QLabel(this);
31 | valueDivisorLabel->setObjectName(QString::fromUtf8("valueDivisorLabel"));
32 | valueDivisorLabel->setAlignment(Qt::AlignCenter);
33 | valueDivisorLabel->setText(QString::number(divisor));
34 |
35 | valueFractionLayout->addWidget(valueDivisorLabel);
36 |
37 |
38 | updateForValue(valueInBeats);
39 | }
40 |
41 | void NewBeatValueWidget::updateForValue(float newValueInBeats)
42 | {
43 | valueInBeats = newValueInBeats;
44 | calculateNumerator();
45 | updateName();
46 | updateBackground();
47 | }
48 |
49 | QString NewBeatValueWidget::getName()
50 | {
51 | if (hasExistingMatchingValue())
52 | {
53 | return AbstractNewBeatValueWidget::getName();
54 | }
55 | return QString();
56 | }
57 |
58 | float NewBeatValueWidget::getMatchResistance()
59 | {
60 | return poopness() * divisor;
61 | }
62 |
63 | int NewBeatValueWidget::getNumerator()
64 | {
65 | return numerator;
66 | }
67 |
68 | int NewBeatValueWidget::getDivisor()
69 | {
70 | return divisor;
71 | }
72 |
73 | void NewBeatValueWidget::calculateNumerator()
74 | {
75 | while(true)
76 | {
77 | float currentValue = getCurrentValue();
78 | float currentDiff = abs(valueInBeats - currentValue);
79 | int bigger = numerator + 1;
80 | float biggerValue = (float) bigger / divisor;
81 | float biggerDiff = abs(valueInBeats - biggerValue);
82 | if (biggerDiff < currentDiff)
83 | {
84 | ++numerator;
85 | continue;
86 | }
87 | if (numerator > 1)
88 | {
89 | int smaller = numerator - 1;
90 | float smallerValue = (float) smaller / divisor;
91 | float smallerDiff = abs(valueInBeats - smallerValue);
92 | if (smallerDiff < currentDiff)
93 | {
94 | --numerator;
95 | continue;
96 | }
97 | }
98 | //the numerator can't be improved by increasing or decreasing - we're done
99 | break;
100 | }
101 | valueNumeratorLabel->setText(QString::number(numerator));
102 | }
103 |
104 | bool NewBeatValueWidget::hasExistingMatchingValue()
105 | {
106 | for (auto value : beatValues)
107 | {
108 | float thisValue = value.value();
109 | float myValue = getCurrentValue();
110 | if (thisValue == myValue)
111 | {
112 | return true;
113 | }
114 | }
115 | return false;
116 | }
117 |
118 | void NewBeatValueWidget::updateName()
119 | {
120 | for (auto value : beatValues)
121 | {
122 | float thisValue = value.value();
123 | float myValue = getCurrentValue();
124 | if (thisValue == myValue)
125 | {
126 | valueNameRadioButton->setText(value.name);
127 | return;
128 | }
129 | }
130 | //no matches found - must be new
131 | valueNameRadioButton->setText(QApplication::translate("EnableIdentifyIntervalsDialog", "New value", nullptr));
132 | }
133 |
--------------------------------------------------------------------------------
/Source/newbeatvaluewidget.h:
--------------------------------------------------------------------------------
1 | #ifndef NEWBEATVALUEWIDGET_H
2 | #define NEWBEATVALUEWIDGET_H
3 |
4 | #include "abstractnewbeatvaluewidget.h"
5 |
6 | class QLabel;
7 |
8 | class NewBeatValueWidget : public AbstractNewBeatValueWidget
9 | {
10 | Q_OBJECT
11 | public:
12 | NewBeatValueWidget(QWidget * parent, float valueInBeats, int divisor);
13 | void updateForValue(float newValueInBeats) override;
14 | QString getName() override;
15 | float getMatchResistance() override;
16 | int getNumerator() override;
17 | int getDivisor() override;
18 | private:
19 | int numerator;
20 | int divisor;
21 | QLabel * valueNumeratorLabel;
22 | QLabel * valueDivisorLabel;
23 | void calculateNumerator();
24 | bool hasExistingMatchingValue();
25 | void updateName();
26 | };
27 |
28 | #endif // NEWBEATVALUEWIDGET_H
29 |
--------------------------------------------------------------------------------
/Source/newcustombeatvaluewidget.cpp:
--------------------------------------------------------------------------------
1 | #include "newcustombeatvaluewidget.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "globals.h"
9 | #include "uniquebeatinterval.h"
10 | #include "beatanalysis.h"
11 | #include
12 |
13 | NewCustomBeatValueWidget::NewCustomBeatValueWidget(float valueInBeats, QWidget *parent)
14 | :
15 | AbstractNewBeatValueWidget(valueInBeats, parent)
16 | {
17 | valueNumeratorSpinBox = new QSpinBox(this);
18 | valueNumeratorSpinBox->setObjectName(QString::fromUtf8("valueNumeratorSpinBox"));
19 | valueNumeratorSpinBox->setMinimum(1);
20 | valueNumeratorSpinBox->setMaximum(9999);
21 | valueNumeratorSpinBox->setValue(3);
22 |
23 | valueFractionLayout->addWidget(valueNumeratorSpinBox);
24 | connect(valueNumeratorSpinBox, SIGNAL(valueChanged(int)), this, SLOT(on_numeratorValueChanged(int)));
25 |
26 | QLabel * valueSlashLabel = new QLabel(this);
27 | valueSlashLabel->setObjectName(QString::fromUtf8("valueSlashLabel"));
28 | valueSlashLabel->setAlignment(Qt::AlignCenter);
29 | valueSlashLabel->setText(QApplication::translate("EnableIdentifyIntervalsDialog", "/", nullptr));
30 |
31 | valueFractionLayout->addWidget(valueSlashLabel);
32 |
33 | valueDivisorSpinBox = new QSpinBox(this);
34 | valueDivisorSpinBox->setObjectName(QString::fromUtf8("valueDivisorSpinBox"));
35 | valueDivisorSpinBox->setEnabled(false);
36 | valueDivisorSpinBox->setMinimum(1);
37 | valueDivisorSpinBox->setMaximum(9999);
38 |
39 | valueFractionLayout->addWidget(valueDivisorSpinBox);
40 |
41 |
42 | valueNameRadioButton->setText(QApplication::translate("EnableIdentifyIntervalsDialog", "Custom", nullptr));
43 |
44 |
45 | updateBackground();
46 | }
47 |
48 | void NewCustomBeatValueWidget::setValue(int numerator, int divisor)
49 | {
50 | const QSignalBlocker blocker(valueNumeratorSpinBox);
51 | valueNumeratorSpinBox->setValue(numerator);
52 | valueDivisorSpinBox->setValue(divisor);
53 | updateBackground();
54 | }
55 |
56 | QString NewCustomBeatValueWidget::getName()
57 | {
58 | return QString();
59 | }
60 |
61 | int NewCustomBeatValueWidget::getNumerator()
62 | {
63 | return valueNumeratorSpinBox->value();
64 | }
65 |
66 | int NewCustomBeatValueWidget::getDivisor()
67 | {
68 | return valueDivisorSpinBox->value();
69 | }
70 |
71 | void NewCustomBeatValueWidget::on_numeratorValueChanged(int)
72 | {
73 | if (!valueNameRadioButton->isChecked())
74 | valueNameRadioButton->setChecked(true);
75 | updateBackground();
76 | emit selected(this);
77 | }
78 |
79 | float NewCustomBeatValueWidget::getMatchResistance()
80 | {
81 | if (valueNameRadioButton->isChecked())
82 | {
83 | return 0;
84 | }
85 | return std::numeric_limits::max();
86 | }
87 |
88 | #include "helperfunctions.h"
89 | void NewCustomBeatValueWidget::updateBackground()
90 | {
91 | QColor color;
92 | bool fail = false;
93 | float deviation = percentageDifferenceBetween(getCurrentValue(), valueInBeats);
94 | bool acceptableProportion = (deviation <= BeatAnalysis::Configuration::maxPercentAcceptableBeatError);
95 | if (!acceptableProportion)
96 | {
97 | color = QColor("Dark Red");
98 | fail = true;
99 | }
100 | else
101 | {
102 | float beatsDifference = abs(valueInBeats - getCurrentValue());
103 | if (beatsDifference > 0.25 && BeatAnalysis::Configuration::allowHalfBeatsInBreaks)
104 | {
105 | color = QColor("Dark Red");
106 | fail = true;
107 | }
108 | else
109 | {
110 | float offness = deviation / BeatAnalysis::Configuration::maxPercentAcceptableBeatError;
111 | short hue = 120 - (offness * 120);
112 | color = QColor::fromHsl(hue,255,191);
113 | }
114 | }
115 |
116 | QString textColor;
117 | if (fail)
118 | {
119 | textColor = "white";
120 | }
121 | else
122 | {
123 | textColor = "black";
124 | }
125 | int r, g, b;
126 | color.getRgb(&r, &g, &b);
127 | QString rgbRep = QString("background-color: rgb(%1,%2,%3); color: %4").arg(r).arg(g).arg(b).arg(textColor);
128 | setStyleSheet(rgbRep);
129 | }
130 |
--------------------------------------------------------------------------------
/Source/newcustombeatvaluewidget.h:
--------------------------------------------------------------------------------
1 | #ifndef NEWCUSTOMBEATVALUEWIDGET_H
2 | #define NEWCUSTOMBEATVALUEWIDGET_H
3 |
4 | #include "abstractnewbeatvaluewidget.h"
5 |
6 | class QSpinBox;
7 |
8 | class NewCustomBeatValueWidget : public AbstractNewBeatValueWidget
9 | {
10 | Q_OBJECT
11 | public:
12 | NewCustomBeatValueWidget(float valueInBeats, QWidget * parent = nullptr);
13 | void setValue(int numerator, int divisor);
14 | QString getName() override;
15 | int getNumerator() override;
16 | int getDivisor() override;
17 | private slots:
18 | void on_numeratorValueChanged(int);
19 | private:
20 | QSpinBox * valueNumeratorSpinBox;
21 | QSpinBox * valueDivisorSpinBox;
22 | float getMatchResistance() override;
23 | void updateBackground() override;
24 | };
25 |
26 | #endif // NEWCUSTOMBEATVALUEWIDGET_H
27 |
--------------------------------------------------------------------------------
/Source/optimisationoptionsdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef OPTIMISATIONOPTIONSDIALOG_H
2 | #define OPTIMISATIONOPTIONSDIALOG_H
3 |
4 | #include
5 |
6 | #define BACKUP_WHEN_OPTIMISING_PREF "createBackupWhenOptimising"
7 |
8 | class EditorWindow;
9 |
10 | namespace Ui {
11 | class OptimisationOptionsDialog;
12 | }
13 |
14 | class OptimisationOptionsDialog : public QDialog
15 | {
16 | Q_OBJECT
17 |
18 | public:
19 | explicit OptimisationOptionsDialog(EditorWindow *parent);
20 | ~OptimisationOptionsDialog();
21 |
22 | private slots:
23 | void on_automaticOptimisationRadioButton_clicked();
24 |
25 | void on_useProvidedOutputTempoRadioButton_clicked();
26 |
27 | void on_manualStartTimestampCheckBox_toggled(bool checked);
28 |
29 | void on_buttons_accepted();
30 |
31 | void on_roundBPMCheckBox_clicked(bool checked);
32 |
33 | private:
34 | Ui::OptimisationOptionsDialog *ui;
35 | QSettings settings;
36 | };
37 |
38 | #endif // OPTIMISATIONOPTIONSDIALOG_H
39 |
--------------------------------------------------------------------------------
/Source/patterndatamodel.h:
--------------------------------------------------------------------------------
1 | #ifndef PATTERNDATAMODEL_H
2 | #define PATTERNDATAMODEL_H
3 |
4 | #include
5 |
6 | class PatternDataModel : public QAbstractTableModel
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit PatternDataModel(QObject *parent = 0);
11 | int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
12 | int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
13 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
14 | Qt::ItemFlags flags(const QModelIndex &index) const;
15 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
16 |
17 | signals:
18 |
19 | public slots:
20 |
21 | };
22 |
23 | #endif // PATTERNDATAMODEL_H
24 |
--------------------------------------------------------------------------------
/Source/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
--------------------------------------------------------------------------------
/Source/playbackassociatedaction.cpp:
--------------------------------------------------------------------------------
1 | #include "playbackassociatedaction.h"
2 |
3 | PlaybackAssociatedAction::PlaybackAssociatedAction(QString name, QObject *parent)
4 | :
5 | QObject(parent),
6 | name(name)
7 | {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/Source/playbackassociatedaction.h:
--------------------------------------------------------------------------------
1 | #ifndef PLAYBACKASSOCIATEDACTION_H
2 | #define PLAYBACKASSOCIATEDACTION_H
3 |
4 | class PlaybackAssociatedAction : public QObject
5 | {
6 | Q_OBJECT
7 | public:
8 | explicit PlaybackAssociatedAction(QString name, QObject *parent = nullptr);
9 | QString getName() {return name;};
10 |
11 | signals:
12 | void started(QString uniqueActionName);
13 | void completed(QString uniqueActionName);
14 | void failed(QString uniqueActionName, QString errorMessage);
15 |
16 | public slots:
17 | virtual void kickOff() = 0;
18 | virtual void abort() = 0;
19 |
20 | protected:
21 | QString name;
22 | };
23 |
24 | #endif // PLAYBACKASSOCIATEDACTION_H
25 |
--------------------------------------------------------------------------------
/Source/playbackassociatedactions/pregenerateestimsignalaction.cpp:
--------------------------------------------------------------------------------
1 | #include "pregenerateestimsignalaction.h"
2 | #include "mainwindow.h"
3 | #include
4 | #include "stimsignal/stimsignalsource.h"
5 |
6 | PregenerateEstimSignalAction::PregenerateEstimSignalAction()
7 | :
8 | PlaybackAssociatedAction(tr("Pre-generating E-stim Signal")),
9 | cancelRequested(false)
10 | {
11 |
12 | }
13 |
14 | PregenerateEstimSignalAction::~PregenerateEstimSignalAction()
15 | {
16 | writer->deleteLater();
17 | }
18 |
19 | void PregenerateEstimSignalAction::kickOff()
20 | {
21 | emit started(name);
22 | QString filename = calculateFilename();
23 | if (filename.isEmpty())
24 | {
25 | emit failed(name, QString(tr("Could not calculate a temporary filename to store the pre-generated estim signal. Please save the current project data, or load a video.")));
26 | return;
27 | }
28 | else if (QFileInfo(filename).exists())
29 | {
30 | //hooray - we can reuse this file, so nothing to do here.
31 | emit completed(name);
32 | return;
33 | }
34 | //OK, let's do this...
35 |
36 | writer = new EstimWavFileWriter(filename);
37 | if (writer->writeFile() || cancelRequested)
38 | {
39 | emit completed(name);
40 | return;
41 | }
42 | emit failed(name, "Something went wrong while writing the e-stim file. Sorry! :-(");
43 | }
44 |
45 | void PregenerateEstimSignalAction::abort()
46 | {
47 | cancelRequested = true;
48 | writer->requestCancel();
49 | }
50 |
51 | QString PregenerateEstimSignalAction::calculateFilename()
52 | {
53 | // if (!mainWindow->getLoadedScript().isEmpty())
54 | // {
55 | // QFileInfo fileInfo(mainWindow->getLoadedScript());
56 | //// QString textToRemove = fileInfo.completeSuffix();
57 | // QString textToRemove = fileInfo.suffix();
58 | // QString newBaseName = fileInfo.absoluteFilePath();
59 | // newBaseName.chop(textToRemove.length());
60 | // return newBaseName + "wav";
61 | // }
62 | // else if (!mainWindow->getLoadedVideo().isEmpty())
63 | // {
64 | // QFileInfo fileInfo(mainWindow->getLoadedVideo());
65 | // QString textToRemove = fileInfo.completeSuffix();
66 | //// QString textToRemove = fileInfo.suffix();
67 | // QString newBaseName = fileInfo.absoluteFilePath();
68 | // newBaseName.chop(textToRemove.length());
69 | // return newBaseName + "wav";
70 | // }
71 | // return "";
72 | return StimSignalSource::calculatePregeneratedStimFilename();
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/Source/playbackassociatedactions/pregenerateestimsignalaction.h:
--------------------------------------------------------------------------------
1 | #ifndef PREGENERATEESTIMSIGNALACTION_H
2 | #define PREGENERATEESTIMSIGNALACTION_H
3 | #include "playbackassociatedaction.h"
4 | #include "stimsignal/estimwavfilewriter.h"
5 |
6 | class PregenerateEstimSignalAction : public PlaybackAssociatedAction
7 | {
8 | public:
9 | PregenerateEstimSignalAction();
10 | ~PregenerateEstimSignalAction();
11 |
12 | void kickOff() override;
13 | void abort() override;
14 |
15 | private:
16 | QString calculateFilename();
17 | EstimWavFileWriter * writer;
18 | bool cancelRequested;
19 | };
20 |
21 | #endif // PREGENERATEESTIMSIGNALACTION_H
22 |
--------------------------------------------------------------------------------
/Source/preplaybackactionmanager.h:
--------------------------------------------------------------------------------
1 | #ifndef PREPLAYBACKACTIONMANAGER_H
2 | #define PREPLAYBACKACTIONMANAGER_H
3 |
4 | #include
5 | class QAbstractButton;
6 | class PlaybackAssociatedAction;
7 | class PrePlaybackInfoDialog;
8 |
9 | class PrePlaybackActionManager : public QObject
10 | {
11 | Q_OBJECT
12 | public:
13 | explicit PrePlaybackActionManager(QObject *parent = nullptr);
14 | ~PrePlaybackActionManager();
15 | bool waitForCompletion();
16 |
17 | signals:
18 |
19 | public slots:
20 | void startAll();
21 | void handleActionStarted(QString uniqueActionName);
22 | void handleActionCompleted(QString uniqueActionName);
23 | void handleActionFailed(QString uniqueActionName, QString errorMessage);
24 | void dialogCancelled();
25 |
26 | signals:
27 | void startAllJobs();
28 | void abortAllRemainingJobs();
29 |
30 | private:
31 | QMap actionMap;
32 | QList currentlyRunning;
33 | void connectUp(PlaybackAssociatedAction * action);
34 | bool someFailed = false;
35 | bool userRequestedAbort = false;
36 | bool allDone = false;
37 | void updateDialogContent();
38 | QString createDialogMessage();
39 | PrePlaybackInfoDialog * progressInfoDialog;
40 | QAbstractButton * cancelButton;
41 | };
42 |
43 | #endif // PREPLAYBACKACTIONMANAGER_H
44 |
--------------------------------------------------------------------------------
/Source/preplaybackinfodialog.cpp:
--------------------------------------------------------------------------------
1 | #include "preplaybackinfodialog.h"
2 | #include "ui_preplaybackinfodialog.h"
3 |
4 | PrePlaybackInfoDialog::PrePlaybackInfoDialog(QWidget *parent) :
5 | QDialog(parent),
6 | ui(new Ui::PrePlaybackInfoDialog)
7 | {
8 | ui->setupUi(this);
9 | }
10 |
11 | PrePlaybackInfoDialog::~PrePlaybackInfoDialog()
12 | {
13 | delete ui;
14 | }
15 |
16 | void PrePlaybackInfoDialog::displayList(QList list)
17 | {
18 | QString labelText;
19 | for (int i = 0; i < list.length(); i++)
20 | {
21 | if (i)
22 | labelText += "\n";
23 | labelText += list[i];
24 | }
25 | ui->listLabel->setText(labelText);
26 | }
27 |
--------------------------------------------------------------------------------
/Source/preplaybackinfodialog.h:
--------------------------------------------------------------------------------
1 | #ifndef PREPLAYBACKINFODIALOG_H
2 | #define PREPLAYBACKINFODIALOG_H
3 |
4 | #include
5 |
6 | namespace Ui {
7 | class PrePlaybackInfoDialog;
8 | }
9 |
10 | class PrePlaybackInfoDialog : public QDialog
11 | {
12 | Q_OBJECT
13 |
14 | public:
15 | explicit PrePlaybackInfoDialog(QWidget *parent = nullptr);
16 | ~PrePlaybackInfoDialog();
17 | void displayList(QList list);
18 |
19 | private:
20 | Ui::PrePlaybackInfoDialog *ui;
21 | };
22 |
23 | #endif // PREPLAYBACKINFODIALOG_H
24 |
--------------------------------------------------------------------------------
/Source/preplaybackinfodialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | PrePlaybackInfoDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 221
10 | 200
11 |
12 |
13 |
14 |
15 | 200
16 | 200
17 |
18 |
19 |
20 | Preparing for Playback
21 |
22 |
23 | -
24 |
25 |
26 |
27 | 0
28 | 0
29 |
30 |
31 |
32 | Waiting for the following jobs to complete:
33 |
34 |
35 |
36 |
37 | -
38 |
39 |
40 |
41 | 0
42 | 1
43 |
44 |
45 |
46 |
47 |
48 |
49 | Qt::AlignCenter
50 |
51 |
52 |
53 | -
54 |
55 |
-
56 |
57 |
58 | Skip
59 |
60 |
61 |
62 | -
63 |
64 |
65 | Cancel
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | cancelButton
77 | clicked()
78 | PrePlaybackInfoDialog
79 | reject()
80 |
81 |
82 | 162
83 | 131
84 |
85 |
86 | 110
87 | 76
88 |
89 |
90 |
91 |
92 | skipButton
93 | clicked()
94 | PrePlaybackInfoDialog
95 | accept()
96 |
97 |
98 | 58
99 | 131
100 |
101 |
102 | 110
103 | 76
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/Source/seektotimecodedialog.cpp:
--------------------------------------------------------------------------------
1 | #include "seektotimecodedialog.h"
2 | #include "ui_seektotimecodedialog.h"
3 |
4 | SeekToTimecodeDialog::SeekToTimecodeDialog(QWidget *parent) :
5 | QDialog(parent),
6 | ui(new Ui::SeekToTimecodeDialog)
7 | {
8 | ui->setupUi(this);
9 | }
10 |
11 | SeekToTimecodeDialog::~SeekToTimecodeDialog()
12 | {
13 | delete ui;
14 | }
15 |
16 | void SeekToTimecodeDialog::updateTimecode(int newTimecode)
17 | {
18 | QTime tempTime = QTime(0,0,0,0).addMSecs(newTimecode);
19 | ui->timeEdit->setTime(tempTime);
20 | }
21 |
22 | void SeekToTimecodeDialog::on_buttonBox_accepted()
23 | {
24 | QDialog::done( - ui->timeEdit->time().msecsTo(QTime(0,0,0,0)));
25 | }
26 |
27 | void SeekToTimecodeDialog::on_buttonBox_rejected()
28 | {
29 | QDialog::done(-1);
30 | }
31 |
--------------------------------------------------------------------------------
/Source/seektotimecodedialog.h:
--------------------------------------------------------------------------------
1 | #ifndef SEEKTOTIMECODEDIALOG_H
2 | #define SEEKTOTIMECODEDIALOG_H
3 |
4 | #include
5 |
6 | namespace Ui {
7 | class SeekToTimecodeDialog;
8 | }
9 |
10 | class SeekToTimecodeDialog : public QDialog
11 | {
12 | Q_OBJECT
13 |
14 | friend class BetterLCDNumber;
15 | public:
16 | explicit SeekToTimecodeDialog(QWidget *parent = 0);
17 | ~SeekToTimecodeDialog();
18 |
19 | void updateTimecode(int newTimecode);
20 |
21 | private slots:
22 | void on_buttonBox_accepted();
23 |
24 | void on_buttonBox_rejected();
25 |
26 | private:
27 | Ui::SeekToTimecodeDialog *ui;
28 | };
29 |
30 | #endif // SEEKTOTIMECODEDIALOG_H
31 |
--------------------------------------------------------------------------------
/Source/seektotimecodedialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | SeekToTimecodeDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 221
10 | 68
11 |
12 |
13 |
14 | Jump To Time
15 |
16 |
17 | true
18 |
19 |
20 |
21 |
22 | 7
23 | 3
24 | 208
25 | 61
26 |
27 |
28 |
29 | -
30 |
31 |
-
32 |
33 |
34 | Jump to time:
35 |
36 |
37 |
38 | -
39 |
40 |
41 | QDateTimeEdit::HourSection
42 |
43 |
44 | h:mm:ss.zzz
45 |
46 |
47 |
48 |
49 |
50 | -
51 |
52 |
53 | Qt::Horizontal
54 |
55 |
56 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
57 |
58 |
59 | true
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | buttonBox
70 | accepted()
71 | SeekToTimecodeDialog
72 | accept()
73 |
74 |
75 | 248
76 | 254
77 |
78 |
79 | 157
80 | 274
81 |
82 |
83 |
84 |
85 | buttonBox
86 | rejected()
87 | SeekToTimecodeDialog
88 | reject()
89 |
90 |
91 | 316
92 | 260
93 |
94 |
95 | 286
96 | 274
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Source/splitdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef SPLITDIALOG_H
2 | #define SPLITDIALOG_H
3 |
4 | #define SHORTCUT_ADD_INSERT_BEFORE_SELECTION "SHORTCUT_ADD_INSERT_BEFORE_SELECTION"
5 | #define SHORTCUT_ADD_INSERT_AFTER_SELECTION "SHORTCUT_ADD_INSERT_AFTER_SELECTION"
6 | #define SHORTCUT_ADD_MOVE_OTHERS_BACK "SHORTCUT_ADD_MOVE_OTHERS_BACK"
7 | #define SHORTCUT_ADD_MOVE_OTHERS_FORWARD "SHORTCUT_ADD_MOVE_OTHERS_FORWARD"
8 |
9 | #include
10 | class QShortcut;
11 | class BeatValue;
12 | class BeatPattern;
13 |
14 | namespace Ui {
15 | class SplitDialog;
16 | }
17 |
18 | class SplitDialog : public QDialog
19 | {
20 | Q_OBJECT
21 |
22 | public:
23 | explicit SplitDialog(QWidget *parent = nullptr);
24 | ~SplitDialog();
25 |
26 | virtual void accept() override;
27 |
28 | private slots:
29 | void newValueSelected(BeatValue * newValue);
30 |
31 | void on_deleteButton_clicked();
32 |
33 | private:
34 | Ui::SplitDialog *ui;
35 | void setShortcuts();
36 | void setLabels();
37 | void showEditorSplitPage();
38 | void setButtonState();
39 | void refreshPatternDisplay();
40 | QShortcut * addBeforeShortcut;
41 | QShortcut * addAfterShortcut;
42 | QShortcut * moveBackShortcut;
43 | QShortcut * moveForwardShortcut;
44 | QShortcut * doneShortcut;
45 | BeatPattern * pattern;
46 | };
47 |
48 | #endif // SPLITDIALOG_H
49 |
--------------------------------------------------------------------------------
/Source/stimsignal/dualchannelsignalgenerator.cpp:
--------------------------------------------------------------------------------
1 | #include "dualchannelsignalgenerator.h"
2 | #include "optionsdialog.h"
3 | #include "modifiers/phasesettermodifier.h"
4 | //#include "modifiers/singlechannelbeatproximitymodifier.h"
5 | #include "modifiers/waypointfollowermodifier.h"
6 | #include "modifiers/progressincreasemodifier.h"
7 | //#include "modifiers/boostfaststrokesmodifier.h"
8 | #include "modifiers/fadefromcoldmodifier.h"
9 | #include "modifiers/breaksoftenermodifier.h"
10 | #include "modifiers/channelbalancemodifier.h"
11 | #include "mainwindow.h"
12 | #include "stereostimsignalsample.h"
13 | #include "globals.h"
14 |
15 | #define LEFT_CHANNEL 0
16 | #define RIGHT_CHANNEL 1
17 |
18 | DualChannelSignalGenerator::DualChannelSignalGenerator(QAudioFormat audioFormat, QObject *parent)
19 | :
20 | StimSignalGenerator(audioFormat, parent)
21 | {
22 |
23 | }
24 |
25 | void DualChannelSignalGenerator::setModifiers()
26 | {
27 | modifiers.append(new PhaseSetterModifier(OptionsDialog::getEstimLeftChannelStartingFrequency(), OptionsDialog::getEstimLeftChannelEndingFrequency(), LEFT_CHANNEL));
28 | modifiers.append(new PhaseSetterModifier(OptionsDialog::getEstimRightChannelStartingFrequency(), OptionsDialog::getEstimRightChannelEndingFrequency(), RIGHT_CHANNEL));
29 | WaypointList * leftVolumeWaypoints = createWaypointList(OptionsDialog::getEstimLeftChannelStrokeStyle() == PREF_ESTIM_ENDS_ON_BEAT_STYLE,
30 | OptionsDialog::getEstimLeftChannelPeakPositionInCycle(),
31 | OptionsDialog::getEstimLeftChannelTroughLevel());
32 | modifiers.append(new WaypointFollowerModifier(leftVolumeWaypoints, LEFT_CHANNEL));
33 | WaypointList * rightVolumeWaypoints = createWaypointList(OptionsDialog::getEstimRightChannelStrokeStyle() == PREF_ESTIM_ENDS_ON_BEAT_STYLE,
34 | OptionsDialog::getEstimRightChannelPeakPositionInCycle(),
35 | OptionsDialog::getEstimRightChannelTroughLevel());
36 | modifiers.append(new WaypointFollowerModifier(rightVolumeWaypoints, RIGHT_CHANNEL));
37 | modifiers.append(new ProgressIncreaseModifier());
38 | modifiers.append(new FadeFromColdModifier());
39 | modifiers.append(new BreakSoftenerModifier());
40 | if (OptionsDialog::getEstimSignalPan())
41 | modifiers.append(new ChannelBalanceModifier());
42 | }
43 |
44 | long DualChannelSignalGenerator::getStopTimestamp()
45 | {
46 | return mainWindow->totalPlayTime() + std::max(OptionsDialog::getEstimLeftChannelFadeTime(), OptionsDialog::getEstimRightChannelFadeTime());
47 | }
48 |
49 | StimSignalSample *DualChannelSignalGenerator::createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp)
50 | {
51 | return new StereoStimSignalSample(wholeTimestamp, fractionalTimestamp);
52 | }
53 |
--------------------------------------------------------------------------------
/Source/stimsignal/dualchannelsignalgenerator.h:
--------------------------------------------------------------------------------
1 | #ifndef DUALCHANNELSIGNALGENERATOR_H
2 | #define DUALCHANNELSIGNALGENERATOR_H
3 |
4 | #include "stimsignalgenerator.h"
5 |
6 | class DualChannelSignalGenerator : public StimSignalGenerator
7 | {
8 | public:
9 | explicit DualChannelSignalGenerator(QAudioFormat audioFormat, QObject *parent = nullptr);
10 | protected:
11 | void setModifiers() override;
12 | long getStopTimestamp() override;
13 | StimSignalSample * createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp) override;
14 | };
15 |
16 | #endif // DUALCHANNELSIGNALGENERATOR_H
17 |
--------------------------------------------------------------------------------
/Source/stimsignal/estimwavfilewriter.h:
--------------------------------------------------------------------------------
1 | #ifndef ESTIMWAVFILEWRITER_H
2 | #define ESTIMWAVFILEWRITER_H
3 |
4 | #include
5 | class QProgressDialog;
6 |
7 | class EstimWavFileWriter : public QObject
8 | {
9 | Q_OBJECT
10 | public:
11 | explicit EstimWavFileWriter(QString filePath, QObject *parent = nullptr);
12 | bool writeFile();
13 | signals:
14 |
15 | public slots:
16 | void requestCancel();
17 |
18 | private:
19 | QFile file;
20 | bool cancelRequested = false;
21 | };
22 |
23 | #endif // ESTIMWAVFILEWRITER_H
24 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/boostfaststrokesmodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "boostfaststrokesmodifier.h"
2 | #include "optionsdialog.h"
3 | #include "globals.h"
4 | #include "mainwindow.h"
5 | #include "stimsignal/stimsignalsample.h"
6 |
7 | BoostFastStrokesModifier::BoostFastStrokesModifier()
8 | {
9 | maxBoostAmount = 0.01 * OptionsDialog::getEstimBoostShortStrokes();
10 | normalStrokeLength = OptionsDialog::getEstimMaxStrokeLength();
11 | }
12 |
13 | void BoostFastStrokesModifier::modify(StimSignalSample &sample)
14 | {
15 | qreal timestamp = sample.totalTimestamp();
16 | Event * before = mainWindow->getLastEventBefore(timestamp);
17 | Event * after = mainWindow->getNextEventAfter(timestamp);
18 | if (before == nullptr || after == nullptr)
19 | //can't (or shouldn't) help with this
20 | return;
21 | long length = after->timestamp - before->timestamp;
22 | if (length <= 0 || length > normalStrokeLength)
23 | //can't (or shouldn't) help with this
24 | return;
25 | qreal boostAmount = ((qreal) (normalStrokeLength - length) / normalStrokeLength) * maxBoostAmount;
26 | // XXX
27 | // Note that this will cause distortion if not combined with something which reduces the overall volume below 100%
28 | // At the time of writing, this role is done by the 'ProgressIncreaseModifier'
29 | for (int i = 0; i < sample.numberOfChannels(); ++i)
30 | sample.setAmplitude(i, sample.getAmplitude(i) * (1 + boostAmount));
31 | }
32 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/boostfaststrokesmodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef BOOSTFASTSTROKESMODIFIER_H
2 | #define BOOSTFASTSTROKESMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | //!
7 | //! \brief The BoostFastStrokesModifier class
8 | //! Note that this will cause distortion if not combined with something which reduces the overall volume below 100%
9 | //! At the time of writing, this role is done by the 'ProgressIncreaseModifier'
10 | //!
11 | class BoostFastStrokesModifier : public StimSignalModifier
12 | {
13 | public:
14 | BoostFastStrokesModifier();
15 | void modify(StimSignalSample &sample) override;
16 | qreal maxBoostAmount;
17 | int normalStrokeLength;
18 | };
19 |
20 | #endif // BOOSTFASTSTROKESMODIFIER_H
21 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/breaksoftenermodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "breaksoftenermodifier.h"
2 | #include "optionsdialog.h"
3 | #include "stimsignal/stimsignalsample.h"
4 |
5 | BreakSoftenerModifier::BreakSoftenerModifier(int checkThisChannel)
6 | :
7 | currentLevel(1),
8 | channel(checkThisChannel)
9 | {
10 | maxQuietening = qreal(OptionsDialog::getEstimCompressorStrength()) / 100;
11 | long samplesInQuieteningPeriod = OptionsDialog::getEstimSamplingRate() * OptionsDialog::getEstimCompressorBiteTime() + 0.5;
12 | long samplesInLoudeningPeriod = OptionsDialog::getEstimSamplingRate() * OptionsDialog::getEstimCompressorRelease() + 0.5;
13 | quieteningPerSilentSample = maxQuietening / samplesInQuieteningPeriod;
14 | loudeningPerActiveSample = maxQuietening / samplesInLoudeningPeriod;
15 |
16 | if (channel == -1)
17 | {
18 | if (OptionsDialog::getEstimChannelCount() == 1)
19 | channel = 0;
20 | else
21 | {
22 | if (OptionsDialog::getEstimLeftChannelFadeTime() > OptionsDialog::getEstimRightChannelFadeTime())
23 | channel = 1;
24 | else
25 | channel = 0;
26 | }
27 | }
28 | }
29 |
30 | void BreakSoftenerModifier::modify(StimSignalSample &sample)
31 | {
32 | if (sample.getAmplitude(channel) == 0)
33 | {
34 | if (!atMaxQuietening())
35 | currentLevel -= quieteningPerSilentSample;
36 | }
37 | else
38 | {
39 | if (!atMaxVolume())
40 | {
41 | currentLevel += loudeningPerActiveSample;
42 | }
43 | }
44 | for (int i = 0; i < sample.numberOfChannels(); ++i)
45 | sample.setAmplitude(i, sample.getAmplitude(i) * currentLevel);
46 | }
47 |
48 | bool BreakSoftenerModifier::atMaxQuietening()
49 | {
50 | return currentLevel <= maxQuietening;
51 | }
52 |
53 | bool BreakSoftenerModifier::atMaxVolume()
54 | {
55 | return currentLevel >= 1;
56 | }
57 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/breaksoftenermodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef BREAKSOFTENERMODIFIER_H
2 | #define BREAKSOFTENERMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class BreakSoftenerModifier : public StimSignalModifier
7 | {
8 | public:
9 | //!
10 | //! \brief BreakSoftenerModifier this modifier will apply quietning to the beginning of signals following a long break.
11 | //! It will always quieten all channels equally, but you can set the channel parameter to dictate which channel
12 | //! will be used to decide whether a break is happening (whether that channel is currently silent)
13 | //! \param channel set which channel will be checked to see whether the signal is currently silent (which
14 | //! is taken to mean now is a break). If omitted, a channel will be chosen based on which is most often
15 | //! silent (that is - the one with the shorter decay time)
16 | //!
17 | BreakSoftenerModifier(int channel = -1);
18 | void modify(StimSignalSample &sample) override;
19 |
20 | private:
21 | qreal currentLevel;
22 | qreal maxQuietening;
23 | qreal quieteningPerSilentSample;
24 | qreal loudeningPerActiveSample;
25 | int channel;
26 |
27 | bool atMaxQuietening();
28 | bool atMaxVolume();
29 | };
30 |
31 | #endif // BREAKSOFTENERMODIFIER_H
32 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/channelbalancemodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "channelbalancemodifier.h"
2 | #include "optionsdialog.h"
3 | #include "stimsignal/stimsignalsample.h"
4 |
5 | ChannelBalanceModifier::ChannelBalanceModifier()
6 | {
7 | int pan = OptionsDialog::getEstimSignalPan();
8 | panLeft = (pan < 0);
9 | attenuation = 1 - (0.01 * abs(pan));
10 | }
11 |
12 | void ChannelBalanceModifier::modify(StimSignalSample &sample)
13 | {
14 | if (panLeft)
15 | {
16 | sample.setAmplitude(1, sample.getAmplitude(1) * attenuation);
17 | }
18 | else
19 | {
20 | sample.setPrimaryAmplitude(sample.getPrimaryAmplitude() * attenuation);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/channelbalancemodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef CHANNELBALANCEMODIFIER_H
2 | #define CHANNELBALANCEMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class ChannelBalanceModifier : public StimSignalModifier
7 | {
8 | public:
9 | ChannelBalanceModifier();
10 | void modify(StimSignalSample &sample) override;
11 |
12 | private:
13 | bool panLeft;
14 | float attenuation;
15 |
16 | };
17 |
18 | #endif // CHANNELBALANCEMODIFIER_H
19 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/fadefromcoldmodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "fadefromcoldmodifier.h"
2 | #include "optionsdialog.h"
3 | #include "stimsignal/stimsignalsample.h"
4 |
5 | FadeFromColdModifier::FadeFromColdModifier()
6 | {
7 | int sampleRate = OptionsDialog::getEstimSamplingRate();
8 | totalSamples = (OptionsDialog::getEstimStartPlaybackFadeInTime() * sampleRate) / 1000;
9 | increment = 1.0 / totalSamples;
10 | }
11 |
12 | void FadeFromColdModifier::modify(StimSignalSample &sample)
13 | {
14 | if (sampleCounter < totalSamples)
15 | {
16 | runningTotal = sampleCounter * increment;
17 | for (int i = 0; i < sample.numberOfChannels(); ++i)
18 | sample.setAmplitude(i, sample.getAmplitude(i) * runningTotal);
19 | ++sampleCounter;
20 | }
21 | else
22 | {
23 | //remove self to save processing?
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/fadefromcoldmodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef FADEFROMCOLDMODIFIER_H
2 | #define FADEFROMCOLDMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class FadeFromColdModifier : public StimSignalModifier
7 | {
8 | public:
9 | FadeFromColdModifier();
10 | void modify(StimSignalSample &sample) override;
11 |
12 | private:
13 | long totalSamples;
14 | long sampleCounter = 0;
15 | qreal runningTotal = 0;
16 | qreal increment = 0;
17 | };
18 |
19 | #endif // FADEFROMCOLDMODIFIER_H
20 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/phaseinvertermodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "phaseinvertermodifier.h"
2 | #include "stimsignal/stimsignalsample.h"
3 |
4 | PhaseInverterModifier::PhaseInverterModifier()
5 | {
6 |
7 | }
8 |
9 | void PhaseInverterModifier::modify(StimSignalSample &sample)
10 | {
11 | sample.setPhase(1, sample.getPhase(1) + 0.5);
12 | }
13 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/phaseinvertermodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef PHASEINVERTERMODIFIER_H
2 | #define PHASEINVERTERMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class PhaseInverterModifier : public StimSignalModifier
7 | {
8 | public:
9 | PhaseInverterModifier();
10 | void modify(StimSignalSample &sample) override;
11 | };
12 |
13 | #endif // PHASEINVERTERMODIFIER_H
14 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/phasesettermodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "phasesettermodifier.h"
2 | #include "optionsdialog.h"
3 | #include "mainwindow.h"
4 | #include "stimsignal/stimsignalsample.h"
5 |
6 | PhaseSetterModifier::PhaseSetterModifier(int startFrequency, int endFrequency, int channel)
7 | :
8 | phase(0),
9 | step(0),
10 | startingFrequency(startFrequency),
11 | endingFrequency(endFrequency),
12 | updateCounter(OptionsDialog::getEstimSamplingRate()),
13 | frequencyUpdateInterval(OptionsDialog::getEstimSamplingRate()),
14 | channel(channel)
15 | {
16 |
17 | }
18 |
19 | void PhaseSetterModifier::modify(StimSignalSample &sample)
20 | {
21 | if (updateCounter >= frequencyUpdateInterval)
22 | setStep(sample.totalTimestamp());
23 | if (channel == -1)
24 | {
25 | for (int i = 0; i < sample.numberOfChannels(); ++i)
26 | sample.setPhase(i, phase);
27 | }
28 | else
29 | {
30 | sample.setPhase(channel, phase);
31 | }
32 | phase += step;
33 | }
34 |
35 | void PhaseSetterModifier::setStep(long timestamp)
36 | {
37 | qreal endPortion = mainWindow->progressThroughGame(timestamp);
38 | qreal beginningPortion = 1 - endPortion;
39 | int currentFrequency = (beginningPortion * startingFrequency) + (endPortion * endingFrequency);
40 | step = (qreal) currentFrequency / OptionsDialog::getEstimSamplingRate();
41 | phase -= (int) phase;
42 | updateCounter = 0;
43 | }
44 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/phasesettermodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef PHASESETTERMODIFIER_H
2 | #define PHASESETTERMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class PhaseSetterModifier : public StimSignalModifier
7 | {
8 | public:
9 | //!
10 | //! \brief PhaseSetterModifier
11 | //! \param startFrequency
12 | //! \param endFrequency
13 | //! \param channel by deafult this is 0, and will apply to the first channel. Set to -1 to apply to all channels
14 | //!
15 | PhaseSetterModifier(int startFrequency, int endFrequency, int channel = 0);
16 | void modify(StimSignalSample &sample) override;
17 |
18 | private:
19 | void setStep(long timestamp);
20 | qreal phase;
21 | qreal step;
22 | int startingFrequency;
23 | int endingFrequency;
24 | int updateCounter;
25 | int frequencyUpdateInterval;
26 | int channel;
27 | };
28 |
29 | #endif // PHASESETTERMODIFIER_H
30 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/progressincreasemodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "progressincreasemodifier.h"
2 | #include "optionsdialog.h"
3 | #include "mainwindow.h"
4 | #include "globals.h"
5 | #include "stimsignal/stimsignalsample.h"
6 |
7 | ProgressIncreaseModifier::ProgressIncreaseModifier()
8 | {
9 | int increasePercent = OptionsDialog::getEstimTotalSignalGrowth();
10 | //leave space for 'boosting' fast strokes
11 | qreal endingVolume = (qreal) 100 / (100 + OptionsDialog::getEstimBoostShortStrokes());
12 | initialValue = (endingVolume * 100) / (100 + increasePercent);
13 | totalIncrease = endingVolume - initialValue;
14 | }
15 |
16 | void ProgressIncreaseModifier::modify(StimSignalSample &sample)
17 | {
18 | qreal progress = mainWindow->progressThroughGame(sample.totalTimestamp());
19 | qreal scaleValue = initialValue + (progress * totalIncrease);
20 | for (int i = 0; i < sample.numberOfChannels(); ++i)
21 | sample.setAmplitude(i, sample.getAmplitude(i) * scaleValue);
22 | }
23 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/progressincreasemodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef PROGRESSINCREASEMODIFIER_H
2 | #define PROGRESSINCREASEMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class ProgressIncreaseModifier : public StimSignalModifier
7 | {
8 | public:
9 | ProgressIncreaseModifier();
10 | void modify(StimSignalSample &sample) override;
11 | qreal initialValue = 1;
12 | qreal totalIncrease = 0;
13 | };
14 |
15 | #endif // PROGRESSINCREASEMODIFIER_H
16 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/singlechannelbeatproximitymodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef SINGLECHANNELBEATPROXIMITYMODIFIER_H
2 | #define SINGLECHANNELBEATPROXIMITYMODIFIER_H
3 |
4 | #include "../stimsignalmodifier.h"
5 |
6 |
7 | class SingleChannelBeatProximityModifier : public StimSignalModifier
8 | {
9 | public:
10 | SingleChannelBeatProximityModifier(bool cycleStartsOnBeat, qreal peakPositionWithinCycle, qreal troughLevel, qreal fadeTime);
11 | void modify(StimSignalSample &sample) override;
12 |
13 | private:
14 | bool cycleStartsOnBeat;
15 | qreal peakPositionInCycle;
16 | qreal troughLevel;
17 | qreal fadeTime;
18 | int getFadeTime();
19 | int maxStrokeLength;
20 | qreal amountFadedInOneBeat;
21 | };
22 |
23 | #endif // SINGLECHANNELBEATPROXIMITYMODIFIER_H
24 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/triphasebeatproximitymodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "triphasebeatproximitymodifier.h"
2 | #include "mainwindow.h"
3 | #include "globals.h"
4 | #include "../stimsignalgenerator.h"
5 | #include "optionsdialog.h"
6 | #include "stimsignal/stimsignalsample.h"
7 |
8 | int TriphaseBeatProximityModifier::getFadeInTime()
9 | {
10 | return fadeInTime;
11 | }
12 |
13 | int TriphaseBeatProximityModifier::getFadeInAnticipation()
14 | {
15 | return fadeInAnticipation;
16 | }
17 |
18 | int TriphaseBeatProximityModifier::getFadeOutTime()
19 | {
20 | return fadeOutTime;
21 | }
22 |
23 | int TriphaseBeatProximityModifier::getFadeOutDelay()
24 | {
25 | return fadeOutDelay;
26 | }
27 |
28 | TriphaseBeatProximityModifier::TriphaseBeatProximityModifier()
29 | {
30 | fadeInTime = OptionsDialog::getEstimBeatFadeInTime();
31 | fadeInAnticipation = OptionsDialog::getEstimBeatFadeInAnticipationTime();
32 | fadeOutTime = OptionsDialog::getEstimBeatFadeOutTime();
33 | fadeOutDelay = OptionsDialog::getEstimBeatFadeOutDelay();
34 | }
35 |
36 | void TriphaseBeatProximityModifier::modify(StimSignalSample &sample)
37 | {
38 | //how close are we to the last event?
39 | Event * eventBefore = mainWindow->getLastEventBefore(sample.totalTimestamp());
40 | qreal volumeBefore = 0;
41 | if (eventBefore != nullptr)
42 | {
43 | qreal spaceBefore = abs(sample.distanceToTimestamp(eventBefore->timestamp));
44 | if (spaceBefore < getFadeOutDelay())
45 | volumeBefore = 1;
46 | else
47 | {
48 | spaceBefore -= getFadeOutDelay();
49 | if (spaceBefore <= getFadeOutTime())
50 | volumeBefore = (getFadeOutTime() - spaceBefore) / getFadeOutTime();
51 | }
52 | }
53 | //and how about the next event?
54 | Event * eventAfter = mainWindow->getNextEventAfter(sample.totalTimestamp());
55 | qreal volumeAfter = 0;
56 | if (eventAfter != nullptr)
57 | {
58 | qreal spaceAfter = abs(sample.distanceToTimestamp(eventAfter->timestamp));
59 | if (spaceAfter <= getFadeInAnticipation())
60 | volumeAfter = 1;
61 | else
62 | {
63 | spaceAfter -= getFadeInAnticipation();
64 | if (spaceAfter <= getFadeInTime())
65 | volumeAfter = (getFadeInTime() - spaceAfter) / getFadeInTime();
66 | }
67 | }
68 |
69 | qreal volume = qMax(volumeBefore, volumeAfter);
70 |
71 | for (int i = 0; i < sample.numberOfChannels(); ++i)
72 | sample.setAmplitude(i, sample.getAmplitude(i) * volume);
73 | }
74 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/triphasebeatproximitymodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef BEATPROXIMITYMODIFIER_H
2 | #define BEATPROXIMITYMODIFIER_H
3 |
4 | #include "../stimsignalmodifier.h"
5 |
6 | #define DEFAULT_STIM_FADE_IN_LENGTH 4000
7 | #define DEFAULT_STIM_FADE_OUT_LENGTH 4000
8 |
9 | class TriphaseBeatProximityModifier : public StimSignalModifier
10 | {
11 | public:
12 | TriphaseBeatProximityModifier();
13 | void modify(StimSignalSample &sample) override;
14 | private:
15 | int fadeInTime;
16 | int fadeInAnticipation;
17 | int fadeOutTime;
18 | int fadeOutDelay;
19 | int getFadeInTime();
20 | int getFadeInAnticipation();
21 | int getFadeOutTime();
22 | int getFadeOutDelay();
23 | };
24 |
25 | #endif // BEATPROXIMITYMODIFIER_H
26 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/triphasemodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "triphasemodifier.h"
2 | #include "mainwindow.h"
3 | #include "globals.h"
4 | #include "optionsdialog.h"
5 | #include "beatinterval.h"
6 | #include "stimsignal/stimsignalsample.h"
7 |
8 | TriphaseModifier::TriphaseModifier()
9 | {
10 | strokeLength = OptionsDialog::getEstimMaxStrokeLength();
11 | if (OptionsDialog::getEstimTriphaseStrokeStyle() == PREF_ESTIM_UP_DOWN_BEAT_STROKE_STYLE)
12 | style = UP_DOWN_BEAT;
13 | else
14 | style = DOWN_BEAT_UP;
15 | }
16 |
17 | int TriphaseModifier::getMaxTriphaseStrokeLength()
18 | {
19 | return strokeLength;
20 | }
21 |
22 | void TriphaseModifier::modify(StimSignalSample &sample)
23 | {
24 | qreal phaseDifference = 0;
25 |
26 | long nextEventTimestamp = 0;
27 | long previousEventTimestamp = 0;
28 | bool previousEventFound = false;
29 | bool nextEventFound = false;
30 | Event * nextEvent = mainWindow->getNextEventAfter(sample.totalTimestamp());
31 | if (nextEvent != nullptr)
32 | {
33 | nextEventFound = true;
34 | nextEventTimestamp = nextEvent->timestamp;
35 | }
36 | Event * previousEvent = mainWindow->getLastEventBefore(sample.totalTimestamp());
37 | if (previousEvent != nullptr)
38 | {
39 | previousEventFound = true;
40 | previousEventTimestamp = previousEvent->timestamp;
41 | }
42 | switch (style)
43 | {
44 | case UP_DOWN_BEAT:
45 | // mimic the behaviour of the handy and funscript output.
46 | // pros: it matches the stroker and funscript actions
47 | // cons: not sure if this is the best way to make stimulation
48 | // feel 'on the beat' as all action is before the beat. /////////////////////////
49 | // we primarily care about when the next beat is.
50 | if (nextEventFound && sample.distanceToTimestamp(nextEventTimestamp) <= getMaxTriphaseStrokeLength())
51 | {
52 | //now we're part way through a 'stroke', so calculate how far through we are.
53 | qlonglong startStrokeAt = 0;
54 | if ( !previousEventFound || std::abs(sample.distanceToTimestamp(previousEventTimestamp)) > getMaxTriphaseStrokeLength())
55 | {
56 | startStrokeAt = nextEventTimestamp - getMaxTriphaseStrokeLength();
57 | if (startStrokeAt < 0)
58 | {
59 | startStrokeAt = 0; //can't start a stroke before the beginning
60 | }
61 | }
62 | else
63 | {
64 | startStrokeAt = previousEventTimestamp;
65 | }
66 | int strokeLength = nextEventTimestamp - startStrokeAt;
67 | //distance to timestamp in the past is negative, so invert it
68 | phaseDifference = -sample.distanceToTimestamp(startStrokeAt) / strokeLength;
69 | }
70 | break; //case
71 | case DOWN_BEAT_UP:
72 | //this style defaults to 'up' rather than 'down' when not stroking
73 | qreal distance = 1; //i.e. nowhere near the beat (will get converted to 0.5, which is max distance from any integer)
74 | int strokeLength = getMaxTriphaseStrokeLength();
75 | if (nextEventFound && previousEventFound)
76 | strokeLength = nextEventTimestamp - previousEventTimestamp;
77 | int halfOfStrokeLength = strokeLength / 2;
78 |
79 | if (nextEventFound && sample.distanceToTimestamp(nextEventTimestamp) <= halfOfStrokeLength)
80 | {
81 | //now we're on a 'down stroke', calculate how far from the beat we are
82 | distance = sample.distanceToTimestamp(nextEventTimestamp) / halfOfStrokeLength;
83 | //distance is between 0 and 1
84 | }
85 | else if (previousEventFound && std::abs(sample.distanceToTimestamp(previousEventTimestamp)) <= halfOfStrokeLength)
86 | {
87 | //we're on an 'up stroke', calculate distance from beat, distance will be negative
88 | distance = sample.distanceToTimestamp(previousEventTimestamp) / halfOfStrokeLength;
89 | //distance is between 0 and -1
90 | }
91 | //constrain to between -0.5 and +0.5: phase 'wraps around' below 0 as well as above 1
92 | phaseDifference = 0.5 * distance;
93 | break; //case
94 | }
95 | sample.setPhase(1, sample.getPrimaryPhase() + phaseDifference);
96 | }
97 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/triphasemodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef TRIPHASEMODIFIER_H
2 | #define TRIPHASEMODIFIER_H
3 |
4 | #include "../stimsignalmodifier.h"
5 |
6 | enum StrokeStyle {
7 | UP_DOWN_BEAT,
8 | DOWN_BEAT_UP
9 | };
10 |
11 | class TriphaseModifier : public StimSignalModifier
12 | {
13 | public:
14 | TriphaseModifier();
15 | void modify(StimSignalSample &sample) override;
16 | private:
17 | int strokeLength;
18 | int getMaxTriphaseStrokeLength();
19 | StrokeStyle style;
20 | };
21 |
22 | #endif // TRIPHASEMODIFIER_H
23 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/waypoint.cpp:
--------------------------------------------------------------------------------
1 | #include "waypoint.h"
2 |
3 | Waypoint::Waypoint(long timestamp, qreal multiplier)
4 | :
5 | timestamp(timestamp),
6 | multiplier(multiplier),
7 | next(nullptr),
8 | previous(nullptr)
9 | {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/waypoint.h:
--------------------------------------------------------------------------------
1 | #ifndef WAYPOINT_H
2 | #define WAYPOINT_H
3 |
4 | #include
5 |
6 | class Waypoint
7 | {
8 | public:
9 | Waypoint(long timestamp, qreal multiplier);
10 |
11 | long timestamp;
12 | qreal multiplier;
13 | Waypoint * next;
14 | Waypoint * previous;
15 | };
16 |
17 | #endif // WAYPOINT_H
18 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/waypointfollowermodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "waypointfollowermodifier.h"
2 | #include "waypointlist.h"
3 | #include
4 | #include "stimsignal/stimsignalsample.h"
5 | #include "waypoint.h"
6 |
7 | WaypointFollowerModifier::WaypointFollowerModifier(WaypointList *waypoints, int channel)
8 | :
9 | waypoints(waypoints),
10 | nextWaypoint(waypoints->first()),
11 | channel(channel)
12 | {
13 | }
14 |
15 | WaypointFollowerModifier::~WaypointFollowerModifier()
16 | {
17 | delete waypoints;
18 | }
19 |
20 | void WaypointFollowerModifier::modify(StimSignalSample &sample)
21 | {
22 | if (sample.totalTimestamp() < waypoints->first()->timestamp || sample.totalTimestamp() >= waypoints->last()->timestamp)
23 | {
24 | if (channel == -1)
25 | {
26 | for (int i = 0; i < sample.numberOfChannels(); ++i)
27 | sample.setAmplitude(i, 0);
28 | }
29 | else
30 | {
31 | sample.setAmplitude(channel, 0);
32 | }
33 | return;
34 | }
35 | if (sample.totalTimestamp() >= nextWaypoint->timestamp)
36 | {
37 | lastWaypoint = nextWaypoint;
38 | nextWaypoint = lastWaypoint->next;
39 | }
40 | qreal distanceToLast = sample.totalTimestamp() - lastWaypoint->timestamp;
41 | qreal distanceToNext = nextWaypoint->timestamp - sample.totalTimestamp();
42 | qreal nextWeight = distanceToLast / (distanceToLast + distanceToNext);
43 | qreal totalMultiplier = calculateMultiplier(lastWaypoint->multiplier, nextWaypoint->multiplier, nextWeight);
44 | if (channel == -1)
45 | {
46 | for (int i = 0; i < sample.numberOfChannels(); ++i)
47 | sample.setAmplitude(i, totalMultiplier);
48 | }
49 | else
50 | {
51 | sample.setAmplitude(channel, totalMultiplier);
52 | }
53 | }
54 |
55 | qreal WaypointFollowerModifier::calculateMultiplier(qreal lastValue, qreal nextValue, qreal progress)
56 | {
57 | // qreal zeroToOne = (progress * nextValue) + ((1 - progress) * lastValue);
58 | //simple implementation:
59 | // return zeroToOne;
60 |
61 | //SINple implementation
62 | qreal difference = nextValue - lastValue;
63 | return lastValue + difference * (0.5 + (0.5 * qCos(M_PI + M_PI * progress)));
64 | }
65 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/waypointfollowermodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef WAYPOINTFOLLOWERMODIFIER_H
2 | #define WAYPOINTFOLLOWERMODIFIER_H
3 |
4 | #include "stimsignal/stimsignalmodifier.h"
5 |
6 | class WaypointList;
7 | class Waypoint;
8 |
9 | class WaypointFollowerModifier : public StimSignalModifier
10 | {
11 | public:
12 | WaypointFollowerModifier(WaypointList * waypoints, int channel = -1);
13 | ~WaypointFollowerModifier();
14 | void modify(StimSignalSample &sample) override;
15 |
16 | private:
17 | WaypointList * waypoints;
18 | Waypoint * lastWaypoint;
19 | Waypoint * nextWaypoint;
20 | int channel;
21 | qreal calculateMultiplier(qreal lastValue, qreal nextValue, qreal progress);
22 | };
23 |
24 | #endif // WAYPOINTFOLLOWERMODIFIER_H
25 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/waypointlist.cpp:
--------------------------------------------------------------------------------
1 | #include "waypointlist.h"
2 | #include "optionsdialog.h"
3 | #include "waypoint.h"
4 |
5 | WaypointList::WaypointList()
6 | :
7 | QList()
8 | {
9 |
10 | }
11 |
12 | WaypointList::~WaypointList()
13 | {
14 | while (!isEmpty())
15 | {
16 | delete takeLast();
17 | }
18 | }
19 |
20 | void WaypointList::plonkOnTheEnd(Waypoint * newValue)
21 | {
22 | Waypoint * oldEnd = nullptr;
23 | if (!isEmpty())
24 | {
25 | oldEnd = last();
26 | oldEnd->next = newValue;
27 | }
28 | newValue->previous = oldEnd;
29 | append(newValue);
30 | }
31 |
32 | void WaypointList::insertTroughs(qreal troughLevel)
33 | {
34 | double amountFadedInHalfAStrokeTime = 1 - troughLevel;
35 | double halfAStrokeTime = (double) OptionsDialog::getEstimMaxStrokeLength() / 2;
36 | double fadeTime = halfAStrokeTime / amountFadedInHalfAStrokeTime;
37 | int i = length() - 1;
38 | // Don't crash here by handling last waypoint
39 | plonkOnTheEnd(new Waypoint(at(i)->timestamp + fadeTime, 0));
40 | //iterate backwards because it means we don't have to skip values of i
41 | for (--i /* step back once, we did length - 1 already*/; i >= 0 ; --i)
42 | {
43 | //insert a trough _after_ this peak
44 | qreal lengthBetweenPeaks = (at(i+1)->timestamp - at(i)->timestamp);
45 | if (lengthBetweenPeaks > (fadeTime * 2))
46 | {
47 | //we've got time to completely fade out and back in, so we'll need a waypoint for the end of the fade-out and another for the beginning of the fade-in.
48 | qreal endOfFadeout = at(i)->timestamp + fadeTime;
49 | qreal beginningOfFadein = at(i+1)->timestamp - fadeTime;
50 | squeezeInBetween(i + 1, new Waypoint(beginningOfFadein, 0));
51 | //use i+1 again
52 | squeezeInBetween(i + 1, new Waypoint(endOfFadeout, 0));
53 | }
54 | else
55 | {
56 | //we just need a trough halfway between the peaks
57 | qreal troughPosition = (at(i)->timestamp + at(i+1)->timestamp) / 2;
58 | qreal troughValue = troughLevel;
59 | if (lengthBetweenPeaks < OptionsDialog::getEstimMaxStrokeLength())
60 | {
61 | troughValue = std::max(at(i)->multiplier, at(i+1)->multiplier) * troughLevel;
62 | }
63 | else
64 | {
65 | troughValue = (fadeTime*2 - lengthBetweenPeaks) / (fadeTime*2);
66 | }
67 | squeezeInBetween(i+1, new Waypoint(troughPosition, troughValue));
68 | }
69 | }
70 | //i is now -1. Insert the beginning of the fade-in that comes before the first waypoint
71 | if (at(0)->timestamp > 0)
72 | {
73 | qreal startOfFadeIn = 0;
74 | if (at(0)->timestamp - fadeTime > 0)
75 | startOfFadeIn = at(0)->timestamp - fadeTime;
76 | insert(0, new Waypoint(startOfFadeIn, 0));
77 | at(0)->next = at(1);
78 | at(1)->previous = at(0);
79 | }
80 | }
81 |
82 | void WaypointList::squeezeInBetween(int insertionIndex, Waypoint *newValue)
83 | {
84 | Q_ASSERT(insertionIndex < length() - 1);
85 | insert(insertionIndex, newValue);
86 | at(insertionIndex-1)->next = at(insertionIndex);
87 | at(insertionIndex)->previous = at(insertionIndex-1);
88 | at(insertionIndex)->next = at(insertionIndex+1);
89 | at(insertionIndex+1)->previous = at(insertionIndex);
90 | }
91 |
--------------------------------------------------------------------------------
/Source/stimsignal/modifiers/waypointlist.h:
--------------------------------------------------------------------------------
1 | #ifndef WAYPOINTLIST_H
2 | #define WAYPOINTLIST_H
3 |
4 | class Waypoint;
5 |
6 | class WaypointList : public QList
7 | {
8 | public:
9 | WaypointList();
10 | ~WaypointList();
11 |
12 | void plonkOnTheEnd(Waypoint *newValue);
13 | void insertTroughs(qreal troughLevel);
14 | void squeezeInBetween(int insertionIndex, Waypoint * newValue);
15 | };
16 |
17 | #endif // WAYPOINTLIST_H
18 |
--------------------------------------------------------------------------------
/Source/stimsignal/monostimsignalsample.cpp:
--------------------------------------------------------------------------------
1 | #include "monostimsignalsample.h"
2 |
3 | MonoStimSignalSample::MonoStimSignalSample(qlonglong wholeTimestamp, qreal fractionalTimestamp, QObject *parent)
4 | :
5 | StimSignalSample(1, wholeTimestamp, fractionalTimestamp, parent)
6 | {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/Source/stimsignal/monostimsignalsample.h:
--------------------------------------------------------------------------------
1 | #ifndef MONOSTIMSIGNALSAMPLE_H
2 | #define MONOSTIMSIGNALSAMPLE_H
3 |
4 | #include "stimsignalsample.h"
5 |
6 | class MonoStimSignalSample : public StimSignalSample
7 | {
8 | public:
9 | explicit MonoStimSignalSample(qlonglong wholeTimestamp, qreal fractionalTimestamp, QObject *parent = nullptr);
10 | };
11 |
12 | #endif // MONOSTIMSIGNALSAMPLE_H
13 |
--------------------------------------------------------------------------------
/Source/stimsignal/multithreadedsamplepipelineprocessor.h:
--------------------------------------------------------------------------------
1 | #ifndef MULTITHREADEDSAMPLEPIPELINEPROCESSOR_H
2 | #define MULTITHREADEDSAMPLEPIPELINEPROCESSOR_H
3 |
4 | #include "stereostimsignalsample.h"
5 | //class StimSignalWorkPackage;
6 | //#include
7 |
8 | class StimSignalWorker;
9 | class StimSignalModifier;
10 |
11 | class MultithreadedSamplePipelineProcessor : public QObject
12 | {
13 | Q_OBJECT
14 | public:
15 | explicit MultithreadedSamplePipelineProcessor(QList * modifiers, QObject *parent = nullptr);
16 | ~MultithreadedSamplePipelineProcessor();
17 | //!
18 | //! \brief processAll will run all the samples through all the modifiers and then return
19 | //!
20 | void processAll(QList * vector );
21 |
22 | signals:
23 | void runThroughAllWorkers(int index);
24 |
25 | public slots:
26 | void registerWorkComplete(int index);
27 |
28 | private:
29 | void setUpWorkers();
30 | QList * sampleVector;
31 | QList * modifiers;
32 | //belongs to old, slow method
33 | // QList workQueue;
34 | // int workAssigned;
35 | // QAtomicInt workComplete;
36 | QList workers;
37 | QList workerThreads;
38 | bool allDone = false;
39 | };
40 |
41 | #endif // MULTITHREADEDSAMPLEPIPELINEPROCESSOR_H
42 |
--------------------------------------------------------------------------------
/Source/stimsignal/separatelnrsignalgenerator.cpp:
--------------------------------------------------------------------------------
1 | #include "separatelnrsignalgenerator.h"
2 | #include "optionsdialog.h"
3 | #include "modifiers/phasesettermodifier.h"
4 | //#include "modifiers/singlechannelbeatproximitymodifier.h"
5 | #include "modifiers/waypointfollowermodifier.h"
6 | #include "modifiers/progressincreasemodifier.h"
7 | //#include "modifiers/boostfaststrokesmodifier.h"
8 | #include "modifiers/fadefromcoldmodifier.h"
9 | #include "modifiers/breaksoftenermodifier.h"
10 | #include "modifiers/channelbalancemodifier.h"
11 | #include "mainwindow.h"
12 | #include "stereostimsignalsample.h"
13 |
14 | #define LEFT_CHANNEL 0
15 | #define RIGHT_CHANNEL 1
16 |
17 | SeparateLnRSignalGenerator::SeparateLnRSignalGenerator(QAudioFormat audioFormat, QObject *parent)
18 | :
19 | StimSignalGenerator(audioFormat, parent)
20 | {
21 |
22 | }
23 |
24 | void SeparateLnRSignalGenerator::setModifiers()
25 | {
26 | modifiers.append(new PhaseSetterModifier(OptionsDialog::getEstimLeftChannelStartingFrequency(), OptionsDialog::getEstimLeftChannelEndingFrequency(), LEFT_CHANNEL));
27 | modifiers.append(new PhaseSetterModifier(OptionsDialog::getEstimRightChannelStartingFrequency(), OptionsDialog::getEstimRightChannelEndingFrequency(), RIGHT_CHANNEL));
28 |
29 | QList upstrokes{e_eventType::EVENT_STROKE_UP};
30 | QVector upEvents = filteredEvents(upstrokes);
31 | WaypointList * leftVolumeWaypoints = createWaypointList(false,
32 | 0,
33 | OptionsDialog::getEstimLeftChannelTroughLevel(),
34 | upEvents);
35 | modifiers.append(new WaypointFollowerModifier(leftVolumeWaypoints, LEFT_CHANNEL));
36 |
37 | QList downstrokes{e_eventType::EVENT_STROKE_DOWN};
38 | QVector downEvents = filteredEvents(downstrokes);
39 | WaypointList * rightVolumeWaypoints = createWaypointList(false,
40 | 0,
41 | OptionsDialog::getEstimRightChannelTroughLevel(),
42 | downEvents);
43 | modifiers.append(new WaypointFollowerModifier(rightVolumeWaypoints, RIGHT_CHANNEL));
44 |
45 | modifiers.append(new ProgressIncreaseModifier());
46 | modifiers.append(new FadeFromColdModifier());
47 | modifiers.append(new BreakSoftenerModifier());
48 | if (OptionsDialog::getEstimSignalPan())
49 | modifiers.append(new ChannelBalanceModifier());
50 | }
51 |
52 | long SeparateLnRSignalGenerator::getStopTimestamp()
53 | {
54 | return mainWindow->totalPlayTime() + std::max(OptionsDialog::getEstimLeftChannelFadeTime(), OptionsDialog::getEstimRightChannelFadeTime());
55 | }
56 |
57 | StimSignalSample *SeparateLnRSignalGenerator::createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp)
58 | {
59 | return new StereoStimSignalSample(wholeTimestamp, fractionalTimestamp);
60 | }
61 |
--------------------------------------------------------------------------------
/Source/stimsignal/separatelnrsignalgenerator.h:
--------------------------------------------------------------------------------
1 | #ifndef SEPARATELNRSIGNALGENERATOR_H
2 | #define SEPARATELNRSIGNALGENERATOR_H
3 |
4 | #include "stimsignalgenerator.h"
5 |
6 | class SeparateLnRSignalGenerator : public StimSignalGenerator
7 | {
8 | public:
9 | explicit SeparateLnRSignalGenerator(QAudioFormat audioFormat, QObject *parent = nullptr);
10 | protected:
11 | void setModifiers() override;
12 | long getStopTimestamp() override;
13 | StimSignalSample * createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp) override;
14 | };
15 |
16 | #endif // SEPARATELNRSIGNALGENERATOR_H
17 |
--------------------------------------------------------------------------------
/Source/stimsignal/singlechannelsignalgenerator.cpp:
--------------------------------------------------------------------------------
1 | #include "singlechannelsignalgenerator.h"
2 | #include "optionsdialog.h"
3 | #include "modifiers/phasesettermodifier.h"
4 | //#include "modifiers/singlechannelbeatproximitymodifier.h"
5 | #include "modifiers/waypointfollowermodifier.h"
6 | #include "modifiers/progressincreasemodifier.h"
7 | //#include "modifiers/boostfaststrokesmodifier.h"
8 | #include "modifiers/fadefromcoldmodifier.h"
9 | #include "modifiers/breaksoftenermodifier.h"
10 | #include "modifiers/channelbalancemodifier.h"
11 | #include "mainwindow.h"
12 | #include "monostimsignalsample.h"
13 |
14 | SingleChannelSignalGenerator::SingleChannelSignalGenerator(QAudioFormat audioFormat, QObject *parent)
15 | :
16 | StimSignalGenerator(audioFormat, parent)
17 | {
18 |
19 | }
20 |
21 | void SingleChannelSignalGenerator::setModifiers()
22 | {
23 | modifiers.append(new PhaseSetterModifier(OptionsDialog::getEstimLeftChannelStartingFrequency(), OptionsDialog::getEstimLeftChannelEndingFrequency()));
24 | WaypointList * volumeWaypoints = createWaypointList(OptionsDialog::getEstimLeftChannelStrokeStyle() == PREF_ESTIM_ENDS_ON_BEAT_STYLE,
25 | OptionsDialog::getEstimLeftChannelPeakPositionInCycle(),
26 | OptionsDialog::getEstimLeftChannelTroughLevel());
27 | modifiers.append(new WaypointFollowerModifier(volumeWaypoints));
28 | modifiers.append(new ProgressIncreaseModifier());
29 | modifiers.append(new FadeFromColdModifier());
30 | modifiers.append(new BreakSoftenerModifier());
31 | if (OptionsDialog::getEstimSignalPan())
32 | modifiers.append(new ChannelBalanceModifier());
33 | }
34 |
35 | long SingleChannelSignalGenerator::getStopTimestamp()
36 | {
37 | return mainWindow->totalPlayTime() + OptionsDialog::getEstimLeftChannelFadeTime();
38 | }
39 |
40 | StimSignalSample *SingleChannelSignalGenerator::createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp)
41 | {
42 | return new MonoStimSignalSample(wholeTimestamp, fractionalTimestamp);
43 | }
44 |
--------------------------------------------------------------------------------
/Source/stimsignal/singlechannelsignalgenerator.h:
--------------------------------------------------------------------------------
1 | #ifndef SINGLECHANNELSIGNALGENERATOR_H
2 | #define SINGLECHANNELSIGNALGENERATOR_H
3 |
4 | #include "stimsignalgenerator.h"
5 |
6 | class SingleChannelSignalGenerator : public StimSignalGenerator
7 | {
8 | public:
9 | explicit SingleChannelSignalGenerator(QAudioFormat audioFormat, QObject *parent = nullptr);
10 | protected:
11 | void setModifiers() override;
12 | long getStopTimestamp() override;
13 | StimSignalSample * createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp) override;
14 | };
15 |
16 | #endif // SINGLECHANNELSIGNALGENERATOR_H
17 |
--------------------------------------------------------------------------------
/Source/stimsignal/stereostimsignalsample.cpp:
--------------------------------------------------------------------------------
1 | #include "stereostimsignalsample.h"
2 | #include
3 |
4 | StereoStimSignalSample::StereoStimSignalSample(qlonglong wholeTimestamp, qreal fractionalTimestamp, QObject *parent)
5 | :
6 | StimSignalSample(2, wholeTimestamp, fractionalTimestamp, parent)
7 | {
8 |
9 | }
10 |
11 | qreal StereoStimSignalSample::getSecondaryPhase() const
12 | {
13 | return getPhase(1);
14 | }
15 |
16 | void StereoStimSignalSample::setSecondaryPhase(const qreal &value)
17 | {
18 | setPhase(1, value);
19 | }
20 |
21 | qreal StereoStimSignalSample::secondaryValue()
22 | {
23 | return value(1);
24 | }
25 |
26 | qint16 StereoStimSignalSample::secondaryPcm()
27 | {
28 | return realToPcm(secondaryValue());
29 | }
30 |
31 | qreal StereoStimSignalSample::getSecondaryAmplitude() const
32 | {
33 | return getAmplitude(1);
34 | }
35 |
36 | void StereoStimSignalSample::setSecondaryAmplitude(const qreal &value)
37 | {
38 | setAmplitude(1, value);
39 | }
40 |
--------------------------------------------------------------------------------
/Source/stimsignal/stereostimsignalsample.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALFRAME_H
2 | #define STIMSIGNALFRAME_H
3 |
4 | #include "stimsignalsample.h"
5 |
6 | class StereoStimSignalSample : public StimSignalSample
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit StereoStimSignalSample(qlonglong wholeTimestamp, qreal fractionalTimestamp, QObject *parent = nullptr);
11 |
12 | qreal secondaryValue();
13 |
14 | qint16 secondaryPcm();
15 |
16 | qreal getSecondaryAmplitude() const;
17 | void setSecondaryAmplitude(const qreal &value);
18 |
19 | qreal getSecondaryPhase() const;
20 | void setSecondaryPhase(const qreal &value);
21 |
22 | signals:
23 |
24 | };
25 |
26 | #endif // STIMSIGNALFRAME_H
27 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalfile.cpp:
--------------------------------------------------------------------------------
1 | #include "stimsignalfile.h"
2 | #include
3 | #include
4 |
5 | StimSignalFile::StimSignalFile(QString filename, QObject *parent)
6 | :
7 | QFile(filename, parent)
8 | {
9 | }
10 |
11 | bool StimSignalFile::open(QIODevice::OpenMode mode)
12 | {
13 | bool success = QIODevice::open(mode);
14 | if (success && fileName().endsWith(".wav"))
15 | {
16 | char sampleRateData[4];
17 | seek(24); //that's where the sample rate is stored
18 | read(sampleRateData, 4);
19 | sampleRate = qFromLittleEndian(sampleRateData);
20 |
21 | char bytesPerSecData[4];
22 | seek(28); //bytes per second
23 | read(bytesPerSecData, 4);
24 | bytesPerSecond = qFromLittleEndian(bytesPerSecData);
25 |
26 | char frameSizeData[4];
27 | seek(32); //that's where the size of a 'frame' is stored (mono sample size (2 bytes) * num channels (1 or 2))
28 | read(frameSizeData, 4);
29 | frameSize = qFromLittleEndian(frameSizeData);
30 |
31 | seek(WAV_HEADER_SIZE); //beginning of data section
32 | }
33 | return success;
34 | }
35 |
36 | void StimSignalFile::close()
37 | {
38 | return QIODevice::close();
39 | }
40 |
41 | void StimSignalFile::setPlayFrom(long timestamp)
42 | {
43 | //calculate the frame number we need. there are sampleRate frames per second
44 | long frameNumber = timestamp * sampleRate;
45 | //but timestamp is in miliseconds, so we've gone 1000 times too far...
46 | frameNumber /= 1000;
47 | //this is the number of the frame we need
48 | //the frame will be this many bytes into the file:
49 | long seekLocation = frameNumber * frameSize;
50 | //plus space for the header
51 | seekLocation += WAV_HEADER_SIZE;
52 |
53 | seek(seekLocation);
54 | }
55 |
56 | QAudioFormat StimSignalFile::deriveFormatFromFile(QFile * file)
57 | {
58 | if (!file->fileName().endsWith(".wav"))
59 | {
60 | qDebug() << "This isn't a wav file. We don't support that yet (consider supporting me?)";
61 | return QAudioFormat();
62 | }
63 | bool fileWasOpen = file->isOpen();
64 | if (!fileWasOpen && !file->open(QIODevice::ReadOnly))
65 | {
66 | qDebug() << "Could not open file to fild audio format.";
67 | return QAudioFormat();
68 | }
69 |
70 | QAudioFormat format;
71 | format.setByteOrder(QAudioFormat::LittleEndian); //wav is little-endian
72 | format.setSampleType(QAudioFormat::SignedInt); //or at least that's the way the generator creates them
73 | format.setCodec("audio/pcm");
74 |
75 | char sampleRateData[4];
76 | file->seek(SAMPLE_RATE_LOCATION);
77 | file->read(sampleRateData, 4);
78 | int sampleRate = qFromLittleEndian(sampleRateData);
79 | format.setSampleRate(sampleRate);
80 |
81 | char channelCountData[2];
82 | file->seek(CHANNEL_COUNT_LOCATION);
83 | file->read(channelCountData, 2);
84 | qint16 channelCount = qFromLittleEndian(channelCountData);
85 | format.setChannelCount(channelCount);
86 |
87 | char bitsPerSampleData[2];
88 | file->seek(BITS_PER_SAMPLE_LOCATION);
89 | file->read(bitsPerSampleData, 2);
90 | qint16 bitsPerSample = qFromLittleEndian(bitsPerSampleData);
91 | format.setSampleSize(bitsPerSample);
92 |
93 | if (!fileWasOpen)
94 | file->close();
95 | return format;
96 | }
97 |
98 | void StimSignalFile::seekToTimestamp(QFile * file, long timestamp, int sampleRate, int frameSize)
99 | {
100 | //calculate the frame number we need. there are sampleRate frames per second
101 | long frameNumber = timestamp * sampleRate;
102 | //but timestamp is in miliseconds, so we've gone 1000 times too far...
103 | frameNumber /= 1000;
104 | //this is the number of the frame we need
105 | //the frame will be this many bytes into the file:
106 | long seekLocation = frameNumber * frameSize;
107 | //plus space for the header
108 | seekLocation += WAV_HEADER_SIZE;
109 |
110 | file->seek(seekLocation);
111 | }
112 |
113 |
114 | //qint64 StimSignalFile::readData(char *data, qint64 maxlen)
115 | //{
116 | // return file.readData(data, maxlen);
117 | //}
118 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalfile.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALFILE_H
2 | #define STIMSIGNALFILE_H
3 |
4 | #include "stimsignalsource.h"
5 | #include
6 | #include
7 |
8 | class StimSignalFile : public QFile, public StimSignalSource
9 | {
10 | public:
11 | StimSignalFile(QString filename, QObject * parent);
12 | bool open(QIODevice::OpenMode mode) override;
13 | void close() override;
14 | void setPlayFrom(long timestamp) override;
15 | static QAudioFormat deriveFormatFromFile(QFile *);
16 | static void seekToTimestamp(QFile *file, long timestamp, int sampleRate, int frameSize);
17 | // qint64 readData(char *data, qint64 maxlen) override;
18 | // qint64 writeData(const char *data, qint64 len) override;
19 |
20 | private:
21 | qint32 sampleRate;
22 | qint32 bytesPerSecond;
23 | qint32 frameSize;
24 |
25 | static const int SAMPLE_RATE_LOCATION = 24; //4 bytes
26 | static const int CHANNEL_COUNT_LOCATION = 22; //2 bytes
27 | // static const int BYTES_PER_FRAME_LOCATION = 32; //2 bytes
28 | static const int BITS_PER_SAMPLE_LOCATION = 34; //2 bytes
29 | static const int WAV_HEADER_SIZE = 44;
30 | };
31 |
32 | #endif // STIMSIGNALFILE_H
33 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalgenerator.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALGENERATOR_H
2 | #define STIMSIGNALGENERATOR_H
3 |
4 | #include
5 | #include "stimsignalsource.h"
6 | class StimSignalModifier;
7 | class StimSignalSample;
8 | class MultithreadedSamplePipelineProcessor;
9 | class WaypointList;
10 | struct Event;
11 | extern QVector events;
12 |
13 | //DONE: Add prefs for: starting frequ, - Used
14 | // ending freq, - Used
15 | // percentage vol increase over duration, - Used
16 | // max stroke duration, - Used
17 | // (slightly?) increase volume of faster strokes - Used
18 | // stroke type (up-down-beat or down-beat-up) - Used
19 | // invert phase - Used
20 | // initial fade-in time from cold - Used
21 | // lower volume upto X% after breaks upto Yseconds - Used
22 | // lift volume reduction over period of... - Used
23 | // panning left or right - Used
24 | //DONE: Use above prefs
25 | //DONE: Allow saving of signal to a file
26 | //DONE: Allow selection of audio device (stim signal)
27 | //DONE: Start and stop signal with video
28 |
29 | class StimSignalGenerator : public QIODevice, public StimSignalSource
30 | {
31 | Q_OBJECT
32 | public:
33 | explicit StimSignalGenerator(QAudioFormat audioFormat, QObject *parent = nullptr);
34 | ~StimSignalGenerator();
35 | //TODO: destructor to delete modifiers
36 |
37 | qint64 generate(char *data, qint64 maxlen);
38 |
39 | bool open(OpenMode mode) override;
40 | void close() override;
41 | qint64 readData(char *data, qint64 maxlen) override;
42 | qint64 writeData(const char *data, qint64 len) override;
43 | bool seek(qint64 pos) override; //don't do this
44 | bool isSequential() const override;
45 | void setGenerateFrom(long from);
46 | void setPlayFrom(long timestamp) override;
47 |
48 | static StimSignalGenerator * createFromPrefs(QObject * parent);
49 |
50 | protected:
51 | virtual void setModifiers() = 0;
52 | virtual long getStopTimestamp() = 0;
53 | int sampleCounter;
54 | QAudioFormat audioFormat;
55 | long generateFromTimestamp = 0;
56 | int startingFrequency;
57 | int endingFrequency;
58 | QList modifiers;
59 | WaypointList * createWaypointList(bool waypointsComeOnOrBeforeBeat, qreal peakPositionInCycle, qreal troughLevel, QVector eventsToUse = events);
60 |
61 | private:
62 | virtual StimSignalSample * createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp) = 0;
63 | MultithreadedSamplePipelineProcessor * sampleProcessor;
64 |
65 | signals:
66 | void progressed(int progress, int outOf);
67 |
68 | };
69 |
70 | #endif // STIMSIGNALGENERATOR_H
71 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalmodifier.cpp:
--------------------------------------------------------------------------------
1 | #include "stimsignalmodifier.h"
2 |
3 | StimSignalModifier::StimSignalModifier(QObject *parent) : QObject(parent)
4 | {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalmodifier.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALMODIFIER_H
2 | #define STIMSIGNALMODIFIER_H
3 |
4 | class StimSignalSample;
5 |
6 | class StimSignalModifier : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit StimSignalModifier(QObject *parent = nullptr);
11 |
12 | virtual void modify(StimSignalSample & sample) = 0;
13 |
14 | signals:
15 |
16 | };
17 |
18 | #endif // STIMSIGNALMODIFIER_H
19 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalsample.cpp:
--------------------------------------------------------------------------------
1 | #include "stimsignalsample.h"
2 | #include
3 |
4 | StimSignalSample::StimSignalSample(int numChannels, qlonglong wholeTimestamp, qreal fractionalTimestamp, QObject *parent)
5 | :
6 | QObject(parent),
7 | wholeTimestamp(wholeTimestamp),
8 | fractionalTimestamp(fractionalTimestamp),
9 | numChannels(numChannels)
10 | {
11 | for (int i = 0; i < numChannels; ++i) {
12 | amplitudes.append(1);
13 | phases.append(0);
14 | }
15 | }
16 |
17 | //!
18 | //! \brief StimSignalSample::distanceToTimestamp
19 | //! \param timestamp the timestamp (in ms) we're working the distance to
20 | //! \return the number of milliseconds to the given timestamp. Positive if it's in the future. Negative if the given timestamp is before this one.
21 | //!
22 | qreal StimSignalSample::distanceToTimestamp(qlonglong timestamp)
23 | {
24 | qlonglong wholeDistance = timestamp - wholeTimestamp;
25 | return wholeDistance - fractionalTimestamp;
26 | }
27 |
28 | qreal StimSignalSample::getAmplitude(int channel) const
29 | {
30 | return amplitudes[channel];
31 | }
32 |
33 | void StimSignalSample::setAmplitude(int channel, const qreal &value)
34 | {
35 | amplitudes[channel] = value;
36 | }
37 |
38 | qreal StimSignalSample::getPrimaryAmplitude() const
39 | {
40 | return getAmplitude(0);
41 | }
42 |
43 | void StimSignalSample::setPrimaryAmplitude(const qreal &value)
44 | {
45 | setAmplitude(0, value);
46 | }
47 |
48 | qreal StimSignalSample::getPhase(int channel) const
49 | {
50 | return phases[channel];
51 | }
52 |
53 | void StimSignalSample::setPhase(int channel, const qreal &value)
54 | {
55 | phases[channel] = value;
56 | phases[channel] -= (int) phases[channel];
57 | }
58 |
59 | qreal StimSignalSample::getPrimaryPhase() const
60 | {
61 | return getPhase(0);
62 | }
63 |
64 | void StimSignalSample::setPrimaryPhase(const qreal &value)
65 | {
66 | setPhase(0, value);
67 | }
68 |
69 | qreal StimSignalSample::value(int channel)
70 | {
71 | return amplitudes[channel] * qSin(2 * M_PI * phases[channel]);
72 | }
73 |
74 | qreal StimSignalSample::primaryValue()
75 | {
76 | return value(0);
77 | }
78 |
79 | qint16 StimSignalSample::pcm(int channel)
80 | {
81 | return realToPcm(value(channel));
82 | }
83 |
84 | qint16 StimSignalSample::primaryPcm()
85 | {
86 | return pcm(0);
87 | }
88 |
89 | const qint16 PCMS16MaxValue = 32767;
90 | //const quint16 PCMS16MaxAmplitude = 32768; // because minimum is -32768
91 |
92 | qint16 StimSignalSample::realToPcm(qreal real)
93 | {
94 | return real * PCMS16MaxValue;
95 | }
96 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalsample.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALSAMPLE_H
2 | #define STIMSIGNALSAMPLE_H
3 |
4 | class StimSignalSample : public QObject
5 | {
6 | Q_OBJECT
7 | public:
8 | explicit StimSignalSample(int numChannels, qlonglong wholeTimestamp, qreal fractionalTimestamp, QObject *parent = nullptr);
9 |
10 | qreal totalTimestamp() const {return wholeTimestamp + fractionalTimestamp;}
11 | qreal distanceToTimestamp(qlonglong timestamp);
12 |
13 | char numberOfChannels(){return numChannels;}
14 | qreal getAmplitude(int channel) const;
15 | void setAmplitude(int channel, const qreal &value);
16 | qreal getPrimaryAmplitude() const;
17 | void setPrimaryAmplitude(const qreal &value);
18 |
19 | qreal getPhase(int channel) const;
20 | void setPhase(int channel, const qreal &value);
21 | qreal getPrimaryPhase() const;
22 | void setPrimaryPhase(const qreal &value);
23 |
24 | qreal value(int channel);
25 | qreal primaryValue();
26 |
27 | qint16 pcm(int channel);
28 | qint16 primaryPcm();
29 |
30 | protected:
31 | qlonglong wholeTimestamp; //in ms
32 | qreal fractionalTimestamp; //also in ms (may be larger than 1)
33 | char numChannels;
34 | QList amplitudes;
35 | QList phases;
36 | qint16 realToPcm(qreal real);
37 | };
38 |
39 | #endif // STIMSIGNALSAMPLE_H
40 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalsamplefactory.cpp:
--------------------------------------------------------------------------------
1 | #include "stimsignalsamplefactory.h"
2 |
3 | StimSignalSampleFactory::StimSignalSampleFactory(QObject *parent) : QObject(parent)
4 | {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalsamplefactory.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALSAMPLEFACTORY_H
2 | #define STIMSIGNALSAMPLEFACTORY_H
3 |
4 | class StimSignalSampleFactory : public QObject
5 | {
6 | Q_OBJECT
7 | public:
8 | explicit StimSignalSampleFactory(QObject *parent = nullptr);
9 |
10 | signals:
11 |
12 | };
13 |
14 | #endif // STIMSIGNALSAMPLEFACTORY_H
15 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalsource.cpp:
--------------------------------------------------------------------------------
1 | #include "stimsignalsource.h"
2 | #include "optionsdialog.h"
3 | #include "stimsignalgenerator.h"
4 | #include "stimsignalfile.h"
5 | #include "mainwindow.h"
6 | #include
7 | #include
8 |
9 | StimSignalSource::StimSignalSource()
10 | {
11 |
12 | }
13 |
14 | QIODevice *StimSignalSource::createFromPrefs(QObject *parent)
15 | {
16 | QString userSpecifiedFilename = OptionsDialog::getEstimSourceFilename();
17 |
18 | QString pregeneratedFilename = calculatePregeneratedStimFilename();
19 |
20 | switch (OptionsDialog::getEstimSourceMode())
21 | {
22 | case FROM_FILE:
23 | return new QFile(userSpecifiedFilename, parent);
24 | case PREGENERATED:
25 | return new QFile(pregeneratedFilename, parent);
26 | case ON_THE_FLY:
27 | return StimSignalGenerator::createFromPrefs(parent);
28 | }
29 | return nullptr;
30 | }
31 |
32 | QString StimSignalSource::calculatePregeneratedStimFilename()
33 | {
34 | QString basePath = OptionsDialog::getLastOpenedLocation();
35 | if (basePath.isEmpty())
36 | basePath = QDir::toNativeSeparators(QDir::homePath());
37 |
38 | QString fullPath = loadedScript;
39 | if (fullPath.isEmpty())
40 | fullPath = loadedVideo;
41 | if (fullPath.isEmpty())
42 | fullPath = QDir::cleanPath(basePath + QDir::separator() + "Untitled.wav");
43 | QFileInfo pathInfo(fullPath);
44 | QString baseName = pathInfo.completeBaseName(); //baseName or completeBaseName?
45 | QString generatedFilename = QString("%1-%2-%3.wav")
46 | .arg(baseName)
47 | .arg(OptionsDialog::getEstimSettingsFilenameSuffix())
48 | .arg(currentEventsHash(),0,16,QLatin1Char('0'));
49 | return QDir::cleanPath(pathInfo.path() + QDir::separator() + generatedFilename);
50 | }
51 |
52 | #define A 54059 /* a prime */
53 | #define B 76963 /* another prime */
54 | #define C 86969 /* yet another prime */
55 | #define FIRSTH 37 /* also prime */
56 | unsigned int StimSignalSource::currentEventsHash()
57 | {
58 | unsigned h = FIRSTH;
59 | for (auto event : events)
60 | {
61 | h = (h * A) ^ (event.toHash() * B);
62 | }
63 | return h; // or return h % C;
64 | }
65 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalsource.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALSOURCE_H
2 | #define STIMSIGNALSOURCE_H
3 |
4 | #include
5 |
6 | class StimSignalSource
7 | {
8 | public:
9 | StimSignalSource();
10 | virtual bool open(QIODevice::OpenMode mode) = 0;
11 | virtual void close() = 0;
12 | virtual void setPlayFrom(long timestamp) = 0;
13 |
14 | static QIODevice * createFromPrefs(QObject * parent);
15 | static QString calculatePregeneratedStimFilename();
16 |
17 | private:
18 | static unsigned int currentEventsHash();
19 | };
20 |
21 | #endif // STIMSIGNALSOURCE_H
22 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalworker.cpp:
--------------------------------------------------------------------------------
1 | #include "stimsignalworker.h"
2 | #include "stimsignalmodifier.h"
3 |
4 | StimSignalWorker::StimSignalWorker(QList *sampleVector, StimSignalModifier *modifier, QObject *parent)
5 | :
6 | QObject(parent),
7 | sampleVector(sampleVector),
8 | modifier(modifier)
9 | {
10 |
11 | }
12 |
13 | void StimSignalWorker::setVector(QList *newVector)
14 | {
15 | sampleVector = newVector;
16 | }
17 |
18 | void StimSignalWorker::processIndex(int index)
19 | {
20 | modifier->modify(*((*sampleVector)[index]));
21 | emit indexProcessed(index);
22 | }
23 |
--------------------------------------------------------------------------------
/Source/stimsignal/stimsignalworker.h:
--------------------------------------------------------------------------------
1 | #ifndef STIMSIGNALWORKER_H
2 | #define STIMSIGNALWORKER_H
3 |
4 | class StimSignalSample;
5 | class StimSignalModifier;
6 | template class QList;
7 |
8 | class StimSignalWorker : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit StimSignalWorker(QList * sampleVector, StimSignalModifier * modifier, QObject *parent = nullptr);
13 | void setVector(QList * newVector);
14 |
15 | signals:
16 | void indexProcessed(int index);
17 |
18 | public slots:
19 | void processIndex(int index);
20 |
21 | private:
22 | QList * sampleVector;
23 | StimSignalModifier * modifier;
24 | };
25 |
26 | #endif // STIMSIGNALWORKER_H
27 |
--------------------------------------------------------------------------------
/Source/stimsignal/triphasesignalgenerator.cpp:
--------------------------------------------------------------------------------
1 | #include "triphasesignalgenerator.h"
2 | #include "modifiers/phasesettermodifier.h"
3 | #include "modifiers/triphasemodifier.h"
4 | #include "modifiers/triphasebeatproximitymodifier.h"
5 | #include "modifiers/progressincreasemodifier.h"
6 | #include "modifiers/boostfaststrokesmodifier.h"
7 | #include "modifiers/phaseinvertermodifier.h"
8 | #include "modifiers/fadefromcoldmodifier.h"
9 | #include "modifiers/breaksoftenermodifier.h"
10 | #include "modifiers/channelbalancemodifier.h"
11 | #include "mainwindow.h"
12 | #include "optionsdialog.h"
13 | #include "stereostimsignalsample.h"
14 |
15 |
16 | TriphaseSignalGenerator::TriphaseSignalGenerator(QAudioFormat audioFormat, QObject *parent)
17 | :
18 | StimSignalGenerator(audioFormat, parent)
19 | {
20 | }
21 |
22 | void TriphaseSignalGenerator::setModifiers()
23 | {
24 | modifiers.append(new PhaseSetterModifier(OptionsDialog::getEstimTriphaseStartingFrequency(), OptionsDialog::getEstimTriphaseEndingFrequency()));
25 | modifiers.append(new TriphaseModifier());
26 | modifiers.append(new TriphaseBeatProximityModifier());
27 | modifiers.append(new ProgressIncreaseModifier());
28 | modifiers.append(new BoostFastStrokesModifier());
29 | if (OptionsDialog::getEstimInvertStrokes())
30 | modifiers.append(new PhaseInverterModifier());
31 | modifiers.append(new FadeFromColdModifier());
32 | modifiers.append(new BreakSoftenerModifier());
33 | if (OptionsDialog::getEstimSignalPan())
34 | modifiers.append(new ChannelBalanceModifier());
35 | }
36 |
37 | long TriphaseSignalGenerator::getStopTimestamp()
38 | {
39 | return mainWindow->totalPlayTime() + OptionsDialog::getEstimBeatFadeOutDelay() + OptionsDialog::getEstimBeatFadeOutTime();
40 | }
41 |
42 | StimSignalSample *TriphaseSignalGenerator::createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp)
43 | {
44 | return new StereoStimSignalSample(wholeTimestamp, fractionalTimestamp);
45 | }
46 |
--------------------------------------------------------------------------------
/Source/stimsignal/triphasesignalgenerator.h:
--------------------------------------------------------------------------------
1 | #ifndef TRIPHASESIGNALGENERATOR_H
2 | #define TRIPHASESIGNALGENERATOR_H
3 |
4 | #include "stimsignalgenerator.h"
5 |
6 | class TriphaseSignalGenerator : public StimSignalGenerator
7 | {
8 | public:
9 | explicit TriphaseSignalGenerator(QAudioFormat audioFormat, QObject *parent = nullptr);
10 | protected:
11 | void setModifiers() override;
12 | long getStopTimestamp() override;
13 | StimSignalSample * createSample(qlonglong wholeTimestamp, qreal fractionalTimestamp) override;
14 | };
15 |
16 | #endif // TRIPHASESIGNALGENERATOR_H
17 |
--------------------------------------------------------------------------------
/Source/syncfilewriter.cpp:
--------------------------------------------------------------------------------
1 | #include "syncfilewriter.h"
2 |
3 | SyncFileWriter::SyncFileWriter(QFile & file, QObject *parent)
4 | :
5 | QObject(parent),
6 | file(file)
7 | {
8 | //nothing
9 | }
10 |
--------------------------------------------------------------------------------
/Source/syncfilewriter.h:
--------------------------------------------------------------------------------
1 | #ifndef SYNCFILEWRITER_H
2 | #define SYNCFILEWRITER_H
3 |
4 | class QFile;
5 |
6 | class SyncFileWriter : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit SyncFileWriter(QFile &, QObject *parent = nullptr);
11 | virtual void writeHeader() = 0;
12 | virtual void addEvent(long timestamp, int position) = 0;
13 | virtual void writeFooter() = 0;
14 |
15 | protected:
16 | QFile & file;
17 | signals:
18 |
19 | };
20 |
21 | #endif // SYNCFILEWRITER_H
22 |
--------------------------------------------------------------------------------
/Source/uniquebeatinterval.cpp:
--------------------------------------------------------------------------------
1 | #include "uniquebeatinterval.h"
2 | #include "config.h"
3 | #include "helperfunctions.h"
4 | #include "globals.h"
5 |
6 | UniqueBeatInterval::UniqueBeatInterval()
7 | :
8 | length(0),
9 | count(0)
10 | {
11 | //nothing here
12 | }
13 |
14 | UniqueBeatInterval::UniqueBeatInterval(float len)
15 | :
16 | length(len),
17 | count(1)
18 | {
19 | //nothing here
20 | }
21 |
22 | UniqueBeatInterval::UniqueBeatInterval(float len, short cnt)
23 | :
24 | length(len),
25 | count(cnt)
26 | {
27 | //nothing here
28 | }
29 |
30 | UniqueBeatInterval::~UniqueBeatInterval()
31 | {
32 | }
33 |
34 | int UniqueBeatInterval::registerInterval(float interval)
35 | {
36 | if (matchesThisInterval(interval))
37 | {
38 | double workingValue = (count * length) + interval;
39 | ++count;
40 | length = workingValue / count;
41 | }
42 | else
43 | {
44 | length = interval;
45 | count = 1;
46 | }
47 | return length;
48 | }
49 |
--------------------------------------------------------------------------------
/Source/uniquebeatinterval.h:
--------------------------------------------------------------------------------
1 | #ifndef UNIQUEBEATINTERVAL_H
2 | #define UNIQUEBEATINTERVAL_H
3 |
4 | #include "abstractbeatinterval.h"
5 |
6 | class UniqueBeatInterval : public AbstractBeatInterval
7 | {
8 | public:
9 | UniqueBeatInterval();
10 | UniqueBeatInterval(float len);
11 | UniqueBeatInterval(float len, short cnt);
12 | ~UniqueBeatInterval();
13 |
14 | float length;
15 | short count;
16 |
17 | int registerInterval(float interval);
18 |
19 | float getLength() const {return length;}
20 | };
21 |
22 | void reorderUniqueBeatIntervals();
23 |
24 | #endif // UNIQUEBEATINTERVAL_H
25 |
--------------------------------------------------------------------------------
/Source/valuedatamodel.h:
--------------------------------------------------------------------------------
1 | #ifndef VALUEDATAMODEL_H
2 | #define VALUEDATAMODEL_H
3 |
4 | #include
5 |
6 | class BeatValue;
7 |
8 | class ValueDataModel : public QAbstractTableModel
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit ValueDataModel(QObject *parent = 0);
13 | int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
14 | int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
15 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
16 | Qt::ItemFlags flags(const QModelIndex &index) const;
17 | QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
18 | bool setData(const QModelIndex &index, const QVariant &value, int role);
19 | void addValue(const BeatValue & valueToAdd);
20 | bool removeRow (int row);
21 | void recalculateCounts();
22 |
23 | signals:
24 |
25 | public slots:
26 |
27 | private:
28 | mutable QVector counts;
29 |
30 | };
31 |
32 | #endif // VALUEDATAMODEL_H
33 |
--------------------------------------------------------------------------------
/Source/valuetablekeyboardeventhandler.cpp:
--------------------------------------------------------------------------------
1 | #include "valuetablekeyboardeventhandler.h"
2 | #include "globals.h"
3 | #include "editorwindow.h"
4 | #include "ui_editorwindow.h"
5 | #include "valuedatamodel.h"
6 |
7 | ValueTableKeyboardEventHandler::ValueTableKeyboardEventHandler(QObject *parent) :
8 | QObject(parent)
9 | {
10 | }
11 |
12 | bool ValueTableKeyboardEventHandler::eventFilter(QObject *obj, QEvent *event)
13 | {
14 | if (event->type() == QEvent::KeyPress)
15 | {
16 | QKeyEvent *keyEvent = static_cast(event);
17 | if (keyEvent->key() == Qt::Key_Delete)
18 | {
19 | keyPressEvent(keyEvent);
20 | return true;
21 | }
22 | }
23 | return QObject::eventFilter(obj, event);
24 | }
25 |
26 | void ValueTableKeyboardEventHandler::keyPressEvent(QKeyEvent *event)
27 | {
28 | if ( event->key() == Qt::Key_Delete )
29 | editor->valueModel->removeRow(editor->ui->beatValuesTable->selectionModel()->selectedRows(1).first().row());
30 | else
31 | event->ignore();
32 | }
33 |
--------------------------------------------------------------------------------
/Source/valuetablekeyboardeventhandler.h:
--------------------------------------------------------------------------------
1 | #ifndef VALUETABLEKEYBOARDEVENTHANDLER_H
2 | #define VALUETABLEKEYBOARDEVENTHANDLER_H
3 |
4 | #include
5 |
6 | class ValueTableKeyboardEventHandler : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit ValueTableKeyboardEventHandler(QObject *parent = 0);
11 | bool eventFilter(QObject *obj, QEvent *event);
12 | void keyPressEvent(QKeyEvent *event);
13 |
14 | signals:
15 |
16 | public slots:
17 |
18 | };
19 |
20 | #endif // VALUETABLEKEYBOARDEVENTHANDLER_H
21 |
--------------------------------------------------------------------------------
/Source/wavefileexporter.h:
--------------------------------------------------------------------------------
1 | #ifndef WAVEFILEEXPORTER_H
2 | #define WAVEFILEEXPORTER_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class WaveFileExporter : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit WaveFileExporter(QString inputWavFilename, QString outputWavFilename, QObject *parent = 0);
13 | bool inputFileIsValid();
14 | void writeOutputHeader();
15 | void writeSoundAt(unsigned int timestamp);
16 | void printDebugInformation();
17 | void closeFile();
18 |
19 | private:
20 | QFile inputFile;
21 | QFile outputFile;
22 | QByteArray inputHeaderData;
23 |
24 | QDataStream inputData;
25 | QDataStream outputData;
26 |
27 | quint16 inputDataChunkStartPos;
28 |
29 | void processInputHeader();
30 | bool inputHeaderProcessed;
31 |
32 | qint16 numChannels;
33 | qint32 sampleRate;
34 | qint32 bitRate;
35 | qint16 bytesPerFrame;
36 | qint16 sampleResolution;
37 | quint32 inputAudioSize;
38 |
39 | quint32 sizeOfOutputDataSectionInBytes;
40 |
41 | qint32 intFromBytes(QByteArray bytes);
42 |
43 | static const char * const riffTag;
44 | static const char * const waveTag;
45 | static const char * const dataTag;
46 |
47 | signals:
48 |
49 | public slots:
50 |
51 | };
52 |
53 | #endif // WAVEFILEEXPORTER_H
54 |
--------------------------------------------------------------------------------
/notes_on_deploying.txt:
--------------------------------------------------------------------------------
1 | REM Looks like this file used to be a batch script in a former life!
2 |
3 | REM Step 1: Build Cock Heroine (from within Qt Creator, or however. Make note of the location where the .exe is produced)
4 | REM Step 2: Run this script (make sure the path to the exe is the one you just built)
5 | REM Step 3: Clear up unwanted files from the build directory, collect 'em all up and put somewhere for people to use.
6 |
7 | REM Not sure why this doesn't work. :-/
8 | REM set PATH="C:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin;%PATH%"
9 | REM windeployqt.exe C:\Users\mm\Programming\Cpp\build-CockHeroine-Desktop_Qt_5_12_12_MinGW_32_bit-Release\release\CockHeroine.exe
10 |
11 | REM Use the full path instead
12 | REM C:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\windeployqt.exe C:\Users\mm\Programming\Cpp\build-CockHeroine-Desktop_Qt_5_12_12_MinGW_32_bit-Release\release\CockHeroine.exe
13 | REM The above doesn't work either!!
14 |
15 | REM Actual solution:
16 | REM Open the Qt command prompt (C:\Windows\System32\cmd.exe /A /Q /K C:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\qtenv2.bat)
17 | REM Then cd to the release directory: cd C:\Users\mm\Programming\Cpp\build-CockHeroine-Desktop_Qt_5_12_12_MinGW_32_bit-Release\release
18 | REM Now run: windeployqt CockHeroine.exe
19 | REM for 64-bit, change mingw73_32 to mingw73_64:
20 | REM C:\Qt\Qt5.12.12\5.12.12\mingw73_64\bin\qtenv2.bat
21 | REM cd C:\Users\mm\Programming\Cpp\build-CockHeroine-Desktop_Qt_5_12_12_MinGW_64_bit-Release\release
22 | REM windeployqt CockHeroine.exe
23 |
24 | C:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\qtenv2.bat
25 | cd C:\Users\mm\Programming\Cpp\build-CockHeroine-Desktop_Qt_5_12_12_MinGW_32_bit-Release\release
26 | windeployqt CockHeroine.exe
27 |
--------------------------------------------------------------------------------
/release64.bat:
--------------------------------------------------------------------------------
1 | echo Set up the environment for building Qt things
2 | set PATH=C:\Qt\Qt5.12.12\5.12.12\mingw73_64\bin;C:/Qt/Qt5.12.12/Tools/mingw730_64\bin;%PATH%
3 | echo Go to where we want to build
4 | mkdir C:\Users\mm\Programming\Cpp\cock-heroine-release
5 | cd /d C:\Users\mm\Programming\Cpp\cock-heroine-release
6 | echo Build the project
7 | qmake ..\cock-heroine\CockHeroine.pro
8 | make release
9 | cd release
10 | echo remove the bits we don't need
11 | rm *.o *.cpp *.h
12 | echo pull in the libraries needed
13 | windeployqt CockHeroine.exe
14 | pause
--------------------------------------------------------------------------------