hydrogen 1.2.6
TargetWaveDisplay.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include "TargetWaveDisplay.h"
24
25#include <core/Basics/Sample.h>
26#include <core/Basics/Song.h>
29
30#include <memory>
31
33#include "HydrogenApp.h"
34#include "SampleEditor.h"
35
36using namespace H2Core;
37
38#define UI_WIDTH 841
39#define UI_HEIGHT 91
40
41#include <vector>
42#include <algorithm>
43#include "../Skin.h"
44
46
48 : QWidget( pParent )
49 , m_sSampleName( "" )
50{
51// setAttribute(Qt::WA_OpaquePaintEvent);
52
53 //
54 int w = UI_WIDTH;
55 int h = UI_HEIGHT;
56 resize( w, h );
57
58 bool ok = m_Background.load( Skin::getImagePath() + "/waveDisplay/targetsamplewavedisplay.png" );
59 if( ok == false ){
60 ERRORLOG( "Error loading pixmap" );
61 }
62
64 m_pPeakData_Left = new int[ w ];
65 m_pPeakData_Right = new int[ w ];
66 m_sInfo = "";
67 m_nX = -10;
68 m_nY = -10;
69 m_nLocator = -1;
70 m_UpdatePosition = false;
72 m_nSnapRadius = 6;
73 setMouseTracking(true);
74}
75
76
77
78
80{
81 //INFOLOG( "DESTROY" );
82
83 delete[] m_pPeakData_Left;
84 delete[] m_pPeakData_Right;
85}
86
87static void paintEnvelope(Sample::VelocityEnvelope &envelope, QPainter &painter,
88 int selected, const QColor & lineColor, const QColor & handleColor, const QColor & selectedColor)
89{
90 if (envelope.empty()) {
91 return;
92 }
93
94 for ( int i = 0; i < static_cast<int>(envelope.size()) -1; i++){
95 painter.setPen( QPen(lineColor, 1 , Qt::SolidLine) );
96 painter.drawLine( envelope[i].frame, envelope[i].value, envelope[i + 1].frame, envelope[i +1].value );
97 if ( i == selected ) {
98 painter.setBrush( selectedColor );
99 } else {
100 painter.setBrush( handleColor );
101 }
102 painter.drawEllipse ( envelope[i].frame - 6/2, envelope[i].value - 6/2, 6, 6 );
103 }
104
105 // draw first and last points as squares
106 if ( 0 == selected ) {
107 painter.setBrush( selectedColor );
108 } else {
109 painter.setBrush( handleColor );
110 }
111 painter.drawRect ( envelope[0].frame - 12/2, envelope[0].value - 6/2, 12, 6 );
112
113 if ( envelope.size() - 1 == selected ) {
114 painter.setBrush( selectedColor );
115 } else {
116 painter.setBrush( handleColor );
117 }
118 painter.drawRect ( envelope[envelope.size() -1].frame - 12/2, envelope[envelope.size() -1].value - 6/2, 12, 6 );
119}
120
121void TargetWaveDisplay::paintEvent(QPaintEvent *ev)
122{
123 QPainter painter( this );
124
126
127 painter.setRenderHint( QPainter::Antialiasing );
128 painter.drawPixmap( ev->rect(), m_Background, ev->rect() );
129 painter.setPen( QColor( 252, 142, 73 ));
130
131 int VCenter = height() / 2;
132 int LCenter = VCenter -4;
133 int RCenter = VCenter +4;
134
135 for ( int x = 0; x < width() - 1; x++ ) {
136 painter.drawLine( x, LCenter, x, -m_pPeakData_Left[x +1] +LCenter );
137 }
138
139 painter.setPen( QColor( 116, 186, 255 ));
140 for ( int x = 0; x < width() - 1; x++ ) {
141 painter.drawLine( x, RCenter, x, -m_pPeakData_Right[x +1] +RCenter );
142 }
143
144 QFont font;
145 font.setWeight( QFont::Bold );
146 painter.setFont( font );
147
148 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
149 painter.setPen( QPen( QColor( 255, 255, 255 ), 1, Qt::SolidLine ) );
150 painter.drawLine( m_nLocator, 4, m_nLocator, height() -4);
151
152 QColor volumeLineColor = QColor( 255, 255, 255, 200);
153 QColor volumeHandleColor = QColor( 99, 160, 233);
154 QColor panLineColor = QColor( 249, 235, 116, 200 );
155 QColor panHandleColor = QColor( 77, 189, 55 );
156 QColor selectedtHandleColor = QColor( 255, 100, 90 );
157 //volume line
158
160 volumeLineColor, volumeHandleColor, selectedtHandleColor);
161 //pan line
163 panLineColor, panHandleColor, selectedtHandleColor);
164
165 painter.setPen( QPen( QColor( 255, 255, 255 ), 1, Qt::DotLine ) );
166 painter.drawLine( 0, LCenter, UI_WIDTH, LCenter );
167 painter.setPen( QPen( QColor( 255, 255, 255 ), 1, Qt::DotLine ) );
168 painter.drawLine( 0, RCenter, UI_WIDTH, RCenter );
169
170 if (m_nY < 50){
171 if (m_nX < 790){
172 painter.drawText( m_nX +5, m_nY, 60, 20, Qt::AlignLeft, QString( m_sInfo ) );
173 }
174 else
175 {
176 painter.drawText( m_nX - 65, m_nY, 60, 20, Qt::AlignRight, QString( m_sInfo ) );
177 }
178
179 }else
180 {
181 if (m_nX < 790){
182 painter.drawText( m_nX +5, m_nY -20, 60, 20, Qt::AlignLeft, QString( m_sInfo ) );
183 }
184 else
185 {
186 painter.drawText( m_nX - 65, m_nY -20, 60, 20, Qt::AlignRight, QString( m_sInfo ) );
187 }
188 }
189
190}
191
192
194{
195 update();
196}
197
199{
200 m_UpdatePosition = updateposi;
201 if ( !updateposi ){
202 m_nLocator = -1;
203 }
204 else
205 {
206 m_nLocator = pos;
207 }
208 update();
209}
210
211void TargetWaveDisplay::updateDisplay( std::shared_ptr<H2Core::InstrumentLayer> pLayer )
212{
213 if ( pLayer && pLayer->get_sample() ) {
214
215 int nSampleLength = pLayer->get_sample()->get_frames();
216 float nScaleFactor = nSampleLength / width();
217
218 float fGain = (height() - 8) / 2.0 * pLayer->get_gain();
219
220 auto pSampleDatal = pLayer->get_sample()->get_data_l();
221 auto pSampleDatar = pLayer->get_sample()->get_data_r();
222 int nSamplePos = 0;
223 int nVall;
224 int nValr;
225 for ( int i = 0; i < width(); ++i ){
226 nVall = 0;
227 nValr = 0;
228 for ( int j = 0; j < nScaleFactor; ++j ) {
229 if ( j < nSampleLength ) {
230 if ( pSampleDatal[ nSamplePos ] < 0 ){
231 int newVal = static_cast<int>( pSampleDatal[ nSamplePos ] * -fGain );
232 nVall = newVal;
233 }else
234 {
235 int newVal = static_cast<int>( pSampleDatal[ nSamplePos ] * fGain );
236 nVall = newVal;
237 }
238 if ( pSampleDatar[ nSamplePos ] > 0 ){
239 int newVal = static_cast<int>( pSampleDatar[ nSamplePos ] * -fGain );
240 nValr = newVal;
241 }else
242 {
243 int newVal = static_cast<int>( pSampleDatar[ nSamplePos ] * fGain );
244 nValr = newVal;
245 }
246 }
247 ++nSamplePos;
248 }
249 m_pPeakData_Left[ i ] = nVall;
250 m_pPeakData_Right[ i ] = nValr;
251 }
252 }
253
254 update();
255
256}
257
259{
260 auto pEv = static_cast<MouseEvent*>( ev );
261
264
265 m_nX = std::min(UI_WIDTH, std::max(0, static_cast<int>(pEv->position().x())));
266 m_nY = std::min(UI_HEIGHT, std::max(0, static_cast<int>(pEv->position().y())));
267
268 if ( !(ev->buttons() & Qt::LeftButton) || m_nSelectedEnvelopePoint == -1) {
269 QPoint mousePoint(m_nX, m_nY);
270 int selection = -1;
271 int min_distance = 1000000;
272 for ( int i = 0; i < static_cast<int>(envelope.size()); i++){
273 if ( envelope[i].frame >= m_nX - m_nSnapRadius && envelope[i].frame <= m_nX + m_nSnapRadius ) {
274 QPoint envelopePoint(envelope[i].frame, envelope[i].value);
275 int delta = (mousePoint - envelopePoint).manhattanLength();
276 if (delta < min_distance) {
277 min_distance = delta;
278 selection = i;
279 }
280 }
281 }
282 m_nSelectedEnvelopePoint = selection;
283 }
284 if (m_nSelectedEnvelopePoint == -1) {
285 m_sInfo = "";
286 } else {
287 float info = (UI_HEIGHT - envelope[m_nSelectedEnvelopePoint].value) / (float)UI_HEIGHT;
288 m_sInfo.setNum( info, 'g', 2 );
289 }
290}
291
293{
294 if ( m_nSelectedEnvelopePoint == -1 ) {
295 return;
296 }
299 envelope.erase( envelope.begin() + m_nSelectedEnvelopePoint );
300 if ( m_nSelectedEnvelopePoint == 0 ){
301 m_nX = 0;
302 } else if ( m_nSelectedEnvelopePoint == static_cast<int>(envelope.size()) ) {
303 m_nX = UI_WIDTH;
304 }
305 envelope.push_back( EnvelopePoint( m_nX, m_nY ) );
306 sort( envelope.begin(), envelope.end(), EnvelopePoint::Comparator() );
307 for (int i = 0; i < envelope.size() - 1; ++i) {
308 if (envelope[i].frame == envelope[i+1].frame) {
309 envelope.erase( envelope.begin() + i);
310 if (i + 1 == m_nSelectedEnvelopePoint) {
312 }
313 }
314 }
315}
316
318{
320
321 if ( ! (ev->buttons() & Qt::LeftButton) ) {
322 // we are not dragging any point
323 update();
324 return;
325 }
328 update();
330}
331
332
333
335{
338
340
341 if (ev->button() == Qt::LeftButton) {
342 // add or move point
343 bool NewPoint = false;
344
345 if ( m_nSelectedEnvelopePoint == -1 ) {
346 NewPoint = true;
347 }
348
349 if (NewPoint){
350 if (envelope.empty()) {
351 envelope.push_back( EnvelopePoint( 0, m_nY ) );
352 envelope.push_back( EnvelopePoint( UI_WIDTH, m_nY ) );
353 } else {
354 envelope.push_back( EnvelopePoint( m_nX, m_nY ) );
355 }
356 sort( envelope.begin(), envelope.end(), EnvelopePoint::Comparator() );
357 } else {
358 // move old point to new position
360 }
361 } else if (ev->button() == Qt::RightButton ) {
362 //remove point
363
364 if ( m_nSelectedEnvelopePoint == -1 ||
365 envelope.size() > 2 &&
366 (m_nSelectedEnvelopePoint == 0 || m_nSelectedEnvelopePoint == envelope.size() - 1) ) {
367 // do nothing if no point is selected
368 // don't remove first or last point if more than 2 points in envelope
369 update();
370 return;
371 } else if (envelope.size() == 2) {
372 // if only 2 points, remove them both
373 envelope.clear();
374 } else {
375 envelope.erase( envelope.begin() + m_nSelectedEnvelopePoint );
376 }
377 }
378
380 update();
382}
383
384
385
386
387
394
395
397{
398 int editType = HydrogenApp::get_instance()->getSampleEditor()->EditTypeComboBox->currentIndex();
399 if (editType == 0) {
401 } else if (editType == 1) {
403 } else {
404 // combo options added
406 }
407}
#define ERRORLOG(x)
Definition Object.h:242
static void paintEnvelope(Sample::VelocityEnvelope &envelope, QPainter &painter, int selected, const QColor &lineColor, const QColor &handleColor, const QColor &selectedColor)
#define UI_WIDTH
static TargetWaveDisplay::EnvelopeEditMode getEnvelopeEditMode()
#define UI_HEIGHT
A container for a sample, being able to apply modifications on it.
Definition Sample.h:43
std::vector< EnvelopePoint > VelocityEnvelope
define the type used to store velocity envelope points
Definition Sample.h:75
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
SampleEditor * getSampleEditor()
Compatibility class to support QMouseEvent more esily in Qt5 and Qt6.
Definition MouseEvent.h:35
void returnAllTargetDisplayValues()
static QString getImagePath()
Definition Skin.h:36
virtual void mouseMoveEvent(QMouseEvent *ev) override
virtual void mousePressEvent(QMouseEvent *ev) override
EnvelopeEditMode m_EditMode
void updateDisplay(std::shared_ptr< H2Core::InstrumentLayer > pLayer)
virtual void updateMouseSelection(QMouseEvent *ev)
H2Core::Sample::VelocityEnvelope m_VelocityEnvelope
void paintLocatorEventTargetDisplay(int pos, bool last_event)
virtual void mouseReleaseEvent(QMouseEvent *ev) override
H2Core::Sample::PanEnvelope m_PanEnvelope
TargetWaveDisplay(QWidget *pParent)
virtual void updateEnvelope()
virtual void paintEvent(QPaintEvent *ev) override
to be able to sort velocity points vectors
Definition Sample.h:49