1/*
2 * Copyright (c) 2015-2021 Meltytech, LLC
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18import QtQuick 2.12
19import QtQuick.Layouts 1.12
20import QtQuick.Controls 2.12
21import Shotcut.Controls 1.0 as Shotcut
22
23Item {
24    width: 350
25    height: 300
26    Component.onCompleted: {
27        if (filter.isNew) {
28            // Set default parameter values
29            filter.set('0', 0)
30            filter.set('1', 100)
31            filter.set('2', 400)
32            filter.set('3', 0)
33            filter.set('4', 1)
34            filter.set('5', 3.25)
35            filter.set('6', 0)
36            filter.savePreset(preset.parameters)
37        }
38        setControls()
39        timer.start()
40    }
41
42    function setControls() {
43        sliderPeak.value = filter.getDouble('0') * sliderPeak.maximumValue
44        sliderAttack.value = filter.getDouble('1')
45        sliderRelease.value = filter.getDouble('2')
46        sliderThreshold.value = filter.getDouble('3')
47        sliderRatio.value = filter.getDouble('4')
48        sliderRadius.value = filter.getDouble('5')
49        sliderGain.value = filter.getDouble('6')
50    }
51
52    Timer {
53        id: timer
54        interval: 100
55        running: false
56        repeat: true
57        onTriggered: {
58            grGauge.value = filter.getDouble('8[0]')
59        }
60    }
61
62    GridLayout {
63        anchors.fill: parent
64        anchors.margins: 8
65        columns: 3
66
67        Label {
68            text: qsTr('Preset')
69            Layout.alignment: Qt.AlignRight
70        }
71        Shotcut.Preset {
72            id: preset
73            parameters: ['0', '1', '2', '3', '4', '5', '6']
74            Layout.columnSpan: 2
75            onPresetSelected: setControls()
76        }
77
78        Label {
79            text: qsTr('RMS')
80            Layout.alignment: Qt.AlignRight
81            Shotcut.HoverTip {text: qsTr('The balance between the RMS and peak envelope followers. RMS is generally better for subtle, musical compression and peak is better for heavier, fast compression and percussion.')}
82        }
83        Shotcut.SliderSpinner {
84            id: sliderPeak
85            minimumValue: 0
86            maximumValue: 100
87            decimals: 1
88            label: qsTr('Peak')
89            suffix: ' %'
90            value: filter.getDouble('0') * maximumValue
91            onValueChanged: {
92                filter.set('0', value / maximumValue)
93            }
94        }
95        Shotcut.UndoButton {
96            onClicked: sliderPeak.value = sliderPeak.minimumValue
97        }
98
99        Label {
100            text: qsTr('Attack')
101            Layout.alignment: Qt.AlignRight
102        }
103        Shotcut.SliderSpinner {
104            id: sliderAttack
105            minimumValue: 2
106            maximumValue: 400
107            suffix: ' ms'
108            value: filter.getDouble('1')
109            onValueChanged: {
110                filter.set('1', value)
111            }
112        }
113        Shotcut.UndoButton {
114            onClicked: sliderAttack.value = 100
115        }
116
117        Label {
118            text: qsTr('Release')
119            Layout.alignment: Qt.AlignRight
120        }
121        Shotcut.SliderSpinner {
122            id: sliderRelease
123            minimumValue: 2
124            maximumValue: 800
125            suffix: ' ms'
126            value: filter.getDouble('2')
127            onValueChanged: {
128                filter.set('2', value)
129            }
130        }
131        Shotcut.UndoButton {
132            onClicked: sliderRelease.value = 400
133        }
134
135        Label {
136            text: qsTr('Threshold')
137            Layout.alignment: Qt.AlignRight
138            Shotcut.HoverTip {text: qsTr('The point at which the compressor will start to kick in.')}
139        }
140        Shotcut.SliderSpinner {
141            id: sliderThreshold
142            minimumValue: -30
143            maximumValue: 0
144            decimals: 1
145            suffix: ' dB'
146            value: filter.getDouble('3')
147            onValueChanged: {
148                filter.set('3', value)
149            }
150        }
151        Shotcut.UndoButton {
152            onClicked: sliderThreshold.value = 0
153        }
154
155        Label {
156            text: qsTr('Ratio')
157            Layout.alignment: Qt.AlignRight
158            Shotcut.HoverTip {text: qsTr('The gain reduction ratio used when the signal level exceeds the threshold.')}
159        }
160        Shotcut.SliderSpinner {
161            id: sliderRatio
162            minimumValue: 1
163            maximumValue: 20
164            prefix: ' 1:'
165            value: filter.getDouble('4')
166            onValueChanged: {
167                filter.set('4', value)
168            }
169        }
170        Shotcut.UndoButton {
171            onClicked: sliderRatio.value = 1
172        }
173
174        Label {
175            text: qsTr('Knee radius')
176            Layout.alignment: Qt.AlignRight
177            Shotcut.HoverTip {text: qsTr('The distance from the threshold where the knee curve starts.')}
178        }
179        Shotcut.SliderSpinner {
180            id: sliderRadius
181            minimumValue: 1
182            maximumValue: 10
183            decimals: 1
184            suffix: ' dB'
185            value: filter.getDouble('5')
186            onValueChanged: {
187                filter.set('5', value)
188            }
189        }
190        Shotcut.UndoButton {
191            onClicked: sliderRadius.value = 3.25
192        }
193
194        Label {
195            text: qsTr('Makeup gain')
196            Layout.alignment: Qt.AlignRight
197            Shotcut.HoverTip {text: qsTr('The gain of the makeup input signal.')}
198        }
199        Shotcut.SliderSpinner {
200            id: sliderGain
201            minimumValue: 0
202            maximumValue: 24
203            decimals: 1
204            suffix: ' dB'
205            value: filter.getDouble('6')
206            onValueChanged: {
207                filter.set('6', value)
208            }
209        }
210        Shotcut.UndoButton {
211            onClicked: sliderGain.value = 0
212        }
213
214        Rectangle {
215            Layout.columnSpan: 3
216            Layout.fillWidth: true
217            Layout.minimumHeight: 12
218            color: 'transparent'
219            Rectangle {
220                anchors.verticalCenter: parent.verticalCenter
221                width: parent.width
222                height: 2
223                radius: 2
224                color: activePalette.text
225            }
226        }
227
228        Label {
229            id: grLabel
230            text: qsTr('Gain Reduction')
231            Layout.alignment: Qt.AlignRight | Qt.AlignTop
232            Shotcut.HoverTip {text: qsTr('Status indicator showing the gain reduction applied by the compressor.')}
233        }
234        Shotcut.Gauge {
235            Layout.columnSpan: 2
236            Layout.fillWidth: true
237            id: grGauge
238            from: -24
239            value: 0
240            to: 0
241            orientation: Qt.Horizontal
242            decimals: 0
243        }
244
245        Label {
246            id: link_Text
247            Layout.columnSpan: 3
248            text: qsTr('About dynamic range compression')
249            font.underline: true
250            MouseArea {
251                anchors.fill: parent
252                onClicked: Qt.openUrlExternally('https://en.wikipedia.org/wiki/Dynamic_range_compression')
253            }
254        }
255
256        Item {
257            Layout.fillHeight: true;
258        }
259    }
260}
261