hydrogen 1.2.3
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-2024 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 <core/Basics/Sample.h>
24#include <core/Basics/Song.h>
27
28#include <memory>
29
30#include "HydrogenApp.h"
31#include "SampleEditor.h"
32
33using namespace H2Core;
34
35#define UI_WIDTH 841
36#define UI_HEIGHT 91
37
38#include <vector>
39#include <algorithm>
40#include "TargetWaveDisplay.h"
41#include "../Skin.h"
42
44
46 : QWidget( pParent )
47 , m_sSampleName( "" )
48{
49// setAttribute(Qt::WA_OpaquePaintEvent);
50
51 //
52 int w = UI_WIDTH;
53 int h = UI_HEIGHT;
54 resize( w, h );
55
56 bool ok = m_Background.load( Skin::getImagePath() + "/waveDisplay/targetsamplewavedisplay.png" );
57 if( ok == false ){
58 ERRORLOG( "Error loading pixmap" );
59 }
60
62 m_pPeakData_Left = new int[ w ];
63 m_pPeakData_Right = new int[ w ];
64 m_sInfo = "";
65 m_nX = -10;
66 m_nY = -10;
67 m_nLocator = -1;
68 m_UpdatePosition = false;
70 m_nSnapRadius = 6;
71 setMouseTracking(true);
72}
73
74
75
76
78{
79 //INFOLOG( "DESTROY" );
80
81 delete[] m_pPeakData_Left;
82 delete[] m_pPeakData_Right;
83}
84
85static void paintEnvelope(Sample::VelocityEnvelope &envelope, QPainter &painter,
86 int selected, const QColor & lineColor, const QColor & handleColor, const QColor & selectedColor)
87{
88 if (envelope.empty()) {
89 return;
90 }
91
92 for ( int i = 0; i < static_cast<int>(envelope.size()) -1; i++){
93 painter.setPen( QPen(lineColor, 1 , Qt::SolidLine) );
94 painter.drawLine( envelope[i].frame, envelope[i].value, envelope[i + 1].frame, envelope[i +1].value );
95 if ( i == selected ) {
96 painter.setBrush( selectedColor );
97 } else {
98 painter.setBrush( handleColor );
99 }
100 painter.drawEllipse ( envelope[i].frame - 6/2, envelope[i].value - 6/2, 6, 6 );
101 }
102
103 // draw first and last points as squares
104 if ( 0 == selected ) {
105 painter.setBrush( selectedColor );
106 } else {
107 painter.setBrush( handleColor );
108 }
109 painter.drawRect ( envelope[0].frame - 12/2, envelope[0].value - 6/2, 12, 6 );
110
111 if ( envelope.size() - 1 == selected ) {
112 painter.setBrush( selectedColor );
113 } else {
114 painter.setBrush( handleColor );
115 }
116 painter.drawRect ( envelope[envelope.size() -1].frame - 12/2, envelope[envelope.size() -1].value - 6/2, 12, 6 );
117}
118
119void TargetWaveDisplay::paintEvent(QPaintEvent *ev)
120{
121 QPainter painter( this );
122
124
125 painter.setRenderHint( QPainter::Antialiasing );
126 painter.drawPixmap( ev->rect(), m_Background, ev->rect() );
127 painter.setPen( QColor( 252, 142, 73 ));
128
129 int VCenter = height() / 2;
130 int LCenter = VCenter -4;
131 int RCenter = VCenter +4;
132
133 for ( int x = 0; x < width() - 1; x++ ) {
134 painter.drawLine( x, LCenter, x, -m_pPeakData_Left[x +1] +LCenter );
135 }
136
137 painter.setPen( QColor( 116, 186, 255 ));
138 for ( int x = 0; x < width() - 1; x++ ) {
139 painter.drawLine( x, RCenter, x, -m_pPeakData_Right[x +1] +RCenter );
140 }
141
142 QFont Font;
143 Font.setWeight( 63 );
144 painter.setFont( Font );
145
146 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
147 painter.setPen( QPen( QColor( 255, 255, 255 ), 1, Qt::SolidLine ) );
148 painter.drawLine( m_nLocator, 4, m_nLocator, height() -4);
149
150 QColor volumeLineColor = QColor( 255, 255, 255, 200);
151 QColor volumeHandleColor = QColor( 99, 160, 233);
152 QColor panLineColor = QColor( 249, 235, 116, 200 );
153 QColor panHandleColor = QColor( 77, 189, 55 );
154 QColor selectedtHandleColor = QColor( 255, 100, 90 );
155 //volume line
156
158 volumeLineColor, volumeHandleColor, selectedtHandleColor);
159 //pan line
161 panLineColor, panHandleColor, selectedtHandleColor);
162
163 painter.setPen( QPen( QColor( 255, 255, 255 ), 1, Qt::DotLine ) );
164 painter.drawLine( 0, LCenter, UI_WIDTH, LCenter );
165 painter.setPen( QPen( QColor( 255, 255, 255 ), 1, Qt::DotLine ) );
166 painter.drawLine( 0, RCenter, UI_WIDTH, RCenter );
167
168 if (m_nY < 50){
169 if (m_nX < 790){
170 painter.drawText( m_nX +5, m_nY, 60, 20, Qt::AlignLeft, QString( m_sInfo ) );
171 }
172 else
173 {
174 painter.drawText( m_nX - 65, m_nY, 60, 20, Qt::AlignRight, QString( m_sInfo ) );
175 }
176
177 }else
178 {
179 if (m_nX < 790){
180 painter.drawText( m_nX +5, m_nY -20, 60, 20, Qt::AlignLeft, QString( m_sInfo ) );
181 }
182 else
183 {
184 painter.drawText( m_nX - 65, m_nY -20, 60, 20, Qt::AlignRight, QString( m_sInfo ) );
185 }
186 }
187
188}
189
190
192{
193 update();
194}
195
197{
198 m_UpdatePosition = updateposi;
199 if ( !updateposi ){
200 m_nLocator = -1;
201 }
202 else
203 {
204 m_nLocator = pos;
205 }
206 update();
207}
208
209void TargetWaveDisplay::updateDisplay( std::shared_ptr<H2Core::InstrumentLayer> pLayer )
210{
211 if ( pLayer && pLayer->get_sample() ) {
212
213 int nSampleLength = pLayer->get_sample()->get_frames();
214 float nScaleFactor = nSampleLength / width();
215
216 float fGain = (height() - 8) / 2.0 * pLayer->get_gain();
217
218 auto pSampleDatal = pLayer->get_sample()->get_data_l();
219 auto pSampleDatar = pLayer->get_sample()->get_data_r();
220 int nSamplePos = 0;
221 int nVall;
222 int nValr;
223 for ( int i = 0; i < width(); ++i ){
224 nVall = 0;
225 nValr = 0;
226 for ( int j = 0; j < nScaleFactor; ++j ) {
227 if ( j < nSampleLength ) {
228 if ( pSampleDatal[ nSamplePos ] < 0 ){
229 int newVal = static_cast<int>( pSampleDatal[ nSamplePos ] * -fGain );
230 nVall = newVal;
231 }else
232 {
233 int newVal = static_cast<int>( pSampleDatal[ nSamplePos ] * fGain );
234 nVall = newVal;
235 }
236 if ( pSampleDatar[ nSamplePos ] > 0 ){
237 int newVal = static_cast<int>( pSampleDatar[ nSamplePos ] * -fGain );
238 nValr = newVal;
239 }else
240 {
241 int newVal = static_cast<int>( pSampleDatar[ nSamplePos ] * fGain );
242 nValr = newVal;
243 }
244 }
245 ++nSamplePos;
246 }
247 m_pPeakData_Left[ i ] = nVall;
248 m_pPeakData_Right[ i ] = nValr;
249 }
250 }
251
252 update();
253
254}
255
257{
260
261 m_nX = std::min(UI_WIDTH, std::max(0, ev->x()));
262 m_nY = std::min(UI_HEIGHT, std::max(0, ev->y()));
263
264 if ( !(ev->buttons() & Qt::LeftButton) || m_nSelectedEnvelopePoint == -1) {
265 QPoint mousePoint(m_nX, m_nY);
266 int selection = -1;
267 int min_distance = 1000000;
268 for ( int i = 0; i < static_cast<int>(envelope.size()); i++){
269 if ( envelope[i].frame >= m_nX - m_nSnapRadius && envelope[i].frame <= m_nX + m_nSnapRadius ) {
270 QPoint envelopePoint(envelope[i].frame, envelope[i].value);
271 int delta = (mousePoint - envelopePoint).manhattanLength();
272 if (delta < min_distance) {
273 min_distance = delta;
274 selection = i;
275 }
276 }
277 }
278 m_nSelectedEnvelopePoint = selection;
279 }
280 if (m_nSelectedEnvelopePoint == -1) {
281 m_sInfo = "";
282 } else {
283 float info = (UI_HEIGHT - envelope[m_nSelectedEnvelopePoint].value) / (float)UI_HEIGHT;
284 m_sInfo.setNum( info, 'g', 2 );
285 }
286}
287
289{
290 if ( m_nSelectedEnvelopePoint == -1 ) {
291 return;
292 }
295 envelope.erase( envelope.begin() + m_nSelectedEnvelopePoint );
296 if ( m_nSelectedEnvelopePoint == 0 ){
297 m_nX = 0;
298 } else if ( m_nSelectedEnvelopePoint == static_cast<int>(envelope.size()) ) {
299 m_nX = UI_WIDTH;
300 }
301 envelope.push_back( EnvelopePoint( m_nX, m_nY ) );
302 sort( envelope.begin(), envelope.end(), EnvelopePoint::Comparator() );
303 for (int i = 0; i < envelope.size() - 1; ++i) {
304 if (envelope[i].frame == envelope[i+1].frame) {
305 envelope.erase( envelope.begin() + i);
306 if (i + 1 == m_nSelectedEnvelopePoint) {
308 }
309 }
310 }
311}
312
314{
316
317 if ( ! (ev->buttons() & Qt::LeftButton) ) {
318 // we are not dragging any point
319 update();
320 return;
321 }
324 update();
326}
327
328
329
331{
334
336
337 if (ev->button() == Qt::LeftButton) {
338 // add or move point
339 bool NewPoint = false;
340
341 if ( m_nSelectedEnvelopePoint == -1 ) {
342 NewPoint = true;
343 }
344
345 if (NewPoint){
346 if (envelope.empty()) {
347 envelope.push_back( EnvelopePoint( 0, m_nY ) );
348 envelope.push_back( EnvelopePoint( UI_WIDTH, m_nY ) );
349 } else {
350 envelope.push_back( EnvelopePoint( m_nX, m_nY ) );
351 }
352 sort( envelope.begin(), envelope.end(), EnvelopePoint::Comparator() );
353 } else {
354 // move old point to new position
356 }
357 } else if (ev->button() == Qt::RightButton ) {
358 //remove point
359
360 if ( m_nSelectedEnvelopePoint == -1 ||
361 envelope.size() > 2 &&
362 (m_nSelectedEnvelopePoint == 0 || m_nSelectedEnvelopePoint == envelope.size() - 1) ) {
363 // do nothing if no point is selected
364 // don't remove first or last point if more than 2 points in envelope
365 update();
366 return;
367 } else if (envelope.size() == 2) {
368 // if only 2 points, remove them both
369 envelope.clear();
370 } else {
371 envelope.erase( envelope.begin() + m_nSelectedEnvelopePoint );
372 }
373 }
374
376 update();
378}
379
380
381
382
383
390
391
393{
394 int editType = HydrogenApp::get_instance()->getSampleEditor()->EditTypeComboBox->currentIndex();
395 if (editType == 0) {
397 } else if (editType == 1) {
399 } else {
400 // combo options added
402 }
403}
#define ERRORLOG(x)
Definition Object.h:239
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()
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