hydrogen 1.2.3
PlaybackTrackWaveDisplay.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>
25#include <core/Hydrogen.h>
30#include <core/Basics/Pattern.h>
31using namespace H2Core;
32
33
34#include "../HydrogenApp.h"
36#include "../Skin.h"
37
39#include "SongEditor.h"
40#include "SongEditorPanel.h"
41
43 : WaveDisplay( pParent )
44 , m_fTick( 0 )
45{
46 qreal pixelRatio = devicePixelRatio();
47 m_pBackgroundPixmap = new QPixmap( width() * pixelRatio,
48 height() * pixelRatio );
49 m_pBackgroundPixmap->setDevicePixelRatio( pixelRatio );
50
51 setAcceptDrops(true);
52}
53
58
59
61{
62 const QMimeData* mimeData = event->mimeData();
63 QString sText = event->mimeData()->text();
64
65 if ( mimeData->hasUrls() ) {
66 QList<QUrl> urlList = mimeData->urls();
67
68 //someone dragged a file from an external tool.
69 //check if is a supported sample, and then try to load it
70 if( sText.startsWith("file://")) {
71 Hydrogen::get_instance()->loadPlaybackTrack( urlList.at(0).toLocalFile() );
73
75 }
76 }
77}
78
79void PlaybackTrackWaveDisplay::dragEnterEvent(QDragEnterEvent * event)
80{
81 if(event->mimeData()->hasFormat("text/plain")) {
82 event->acceptProposedAction();
83 }
84}
85
86void PlaybackTrackWaveDisplay::dragMoveEvent(QDragMoveEvent *event)
87{
88 event->accept();
89}
90
91void PlaybackTrackWaveDisplay::updateDisplay( std::shared_ptr<H2Core::InstrumentLayer> pLayer )
92{
95
96 QColor defaultColor = pPref->getColorTheme()->m_songEditor_backgroundColor;
97
98 // Resize pixmap if pixel ratio has changed
99 qreal pixelRatio = devicePixelRatio();
100 if ( m_pBackgroundPixmap->devicePixelRatio() != pixelRatio ||
101 width() != m_pBackgroundPixmap->width() ||
102 height() != m_pBackgroundPixmap->height() ) {
103 delete m_pBackgroundPixmap;
104 m_pBackgroundPixmap = new QPixmap( width() * pixelRatio , height() * pixelRatio );
105 m_pBackgroundPixmap->setDevicePixelRatio( pixelRatio );
106 }
107
108 int currentWidth = width();
109
110 if( pLayer == nullptr || currentWidth <= 0 ){
111 m_pLayer = nullptr;
112 m_sSampleName = tr( "No playback track selected" );
113
114 QPainter painter( m_pBackgroundPixmap );
115 createBackground( &painter );
116 update();
117 return;
118 }
119
120 if(currentWidth != m_nCurrentWidth){
121 delete[] m_pPeakData;
122 m_pPeakData = new int[ currentWidth ];
123
124 m_nCurrentWidth = currentWidth;
125 }
126
127 //initialise everything with 0..
128 memset( m_pPeakData, 0, currentWidth * sizeof(m_pPeakData[0]) );
129
130 if ( pLayer && pLayer->get_sample() ) {
131 std::shared_ptr<Song> pSong = Hydrogen::get_instance()->getSong();
132
133 m_pLayer = pLayer;
134 m_sSampleName = m_pLayer->get_sample()->get_filename();
135
136 auto pSampleData = pLayer->get_sample()->get_data_l();
137 int nSampleLength = m_pLayer->get_sample()->get_frames();
138 float fLengthOfPlaybackTrackInSecs = ( float )( nSampleLength / (float) m_pLayer->get_sample()->get_sample_rate() );
139 float fRemainingLengthOfPlaybackTrack = fLengthOfPlaybackTrackInSecs;
140 float fGain = height() / 2.0 * pLayer->get_gain();
141 int nSamplePos = 0;
142 int nMaxBars = pPref->getMaxBars();
143
144 std::vector<PatternList*> *pPatternColumns = pSong->getPatternGroupVector();
145 int nColumns = pPatternColumns->size();
146
147 int nSongEditorGridWith;
148 if( pH2App->getSongEditorPanel() ) {
149 nSongEditorGridWith = pH2App->getSongEditorPanel()->getSongEditor()->getGridWidth();
150 } else {
151 //this might happen during init of SongEditorPanel
152 nSongEditorGridWith = 16;
153 }
154
155 int nRenderStartPosition = 0.8 * nSongEditorGridWith;
156
157 for ( int patternPosition = 0; patternPosition < nMaxBars; ++patternPosition ) {
158 int maxPatternSize = 0;
159
160 if( patternPosition < nColumns ) {
161 PatternList *pColumn = ( *pPatternColumns )[ patternPosition ];
162
163 for ( unsigned j = 0; j < pColumn->size(); j++ ) {
164 const Pattern *pPattern = pColumn->get( j );
165 int nPatternSize = pPattern->get_length();
166
167 if(maxPatternSize < nPatternSize) {
168 maxPatternSize = nPatternSize;
169 }
170 }
171 }
172
173 //No pattern found in this column, use default size (Size: 8)
174 if( maxPatternSize == 0 ) {
175 maxPatternSize = 192;
176 }
177
178 //length (in seconds) of one pattern is: (nPatternSize/24) / ((ppSong->getBpm() * 2) / 60)
179 float fLengthOfCurrentPatternInSecs = (maxPatternSize/24) / ((pSong->getBpm() * 2) / 60);
180
181 if( fRemainingLengthOfPlaybackTrack >= fLengthOfCurrentPatternInSecs ) {
182 //only a part of the PlaybackTrack will fit into this Pattern
183 float nScaleFactor = fLengthOfCurrentPatternInSecs / fLengthOfPlaybackTrackInSecs;
184 int nSamplesToRender = nScaleFactor * nSampleLength;
185
186 int nVal = 0;
187
188 for ( int i = nRenderStartPosition; i < nRenderStartPosition + nSongEditorGridWith ; ++i ) {
189 if( i < m_nCurrentWidth ) {
190 nVal = 0;
191
192 int nSamplesToRenderInThisStep = (nSamplesToRender / nSongEditorGridWith);
193 for ( int j = 0; j < nSamplesToRenderInThisStep; ++j ) {
194 if ( nSamplePos < nSampleLength ) {
195 int newVal = (int)( pSampleData[ nSamplePos ] * fGain );
196 if ( newVal > nVal ) {
197 nVal = newVal;
198 }
199 }
200
201 ++nSamplePos;
202 }
203
204 m_pPeakData[ i ] = nVal;
205 }
206 }
207
208 nRenderStartPosition += nSongEditorGridWith;
209 fRemainingLengthOfPlaybackTrack -= fLengthOfCurrentPatternInSecs;
210 }
211 }
212 } else {
213 m_sSampleName = "-";
214 for ( int i =0; i < m_nCurrentWidth; ++i ){
215 m_pPeakData[ i ] = 0;
216 }
217
218 }
219
220 QPainter painter( m_pBackgroundPixmap );
221 createBackground( &painter );
222 update();
223}
224
226 m_fTick = fTick;
227 update();
228}
229
231
232 if (!isVisible()) {
233 return;
234 }
235
236 QPainter painter( this );
237
238 qreal pixelRatio = devicePixelRatio();
239 if ( pixelRatio != m_pBackgroundPixmap->devicePixelRatio() ||
240 width() != m_pBackgroundPixmap->width() ||
241 height() != m_pBackgroundPixmap->height() ) {
243 }
244
245 // Render the wave display.
246 painter.drawPixmap( ev->rect(), *m_pBackgroundPixmap,
247 QRectF( pixelRatio * ev->rect().x(),
248 pixelRatio * ev->rect().y(),
249 pixelRatio * ev->rect().width(),
250 pixelRatio * ev->rect().height() ) );
251
252 // Draw playhead
253 auto pSongEditorPanel = HydrogenApp::get_instance()->getSongEditorPanel();
254 if ( m_fTick != -1 && pSongEditorPanel != nullptr ) {
255 if ( pSongEditorPanel->getSongEditor() != nullptr ) {
256 int nX = static_cast<int>( static_cast<float>(SongEditor::nMargin) + 1 +
257 m_fTick *
258 static_cast<float>(pSongEditorPanel->getSongEditor()->
259 getGridWidth()) -
260 static_cast<float>(Skin::nPlayheadWidth) / 2 );
261 int nOffset = Skin::getPlayheadShaftOffset();
262 Skin::setPlayheadPen( &painter, false );
263 painter.drawLine( nX + nOffset, 0, nX + nOffset, height() );
264 }
265 }
266
267}
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:122
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
void loadPlaybackTrack(QString sFilename)
Wrapper function for loading the playback track.
Definition Hydrogen.cpp:262
std::shared_ptr< Sample > get_sample() const
get the sample of the layer
PatternList is a collection of patterns.
Definition PatternList.h:43
int size() const
returns the numbers of patterns
Pattern * get(int idx)
get a pattern from the list
Pattern class is a Note container.
Definition Pattern.h:46
int get_length() const
set the denominator of the pattern
Definition Pattern.h:340
Manager for User Preferences File (singleton)
Definition Preferences.h:78
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
const std::shared_ptr< ColorTheme > getColorTheme() const
int getMaxBars() const
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
SongEditorPanel * getSongEditorPanel()
float m_fTick
Cached position of the playhead.
void updateDisplay(std::shared_ptr< H2Core::InstrumentLayer > pLayer) override
virtual void dragMoveEvent(QDragMoveEvent *event) override
virtual void dragEnterEvent(QDragEnterEvent *event) override
virtual void paintEvent(QPaintEvent *event) override
virtual void dropEvent(QDropEvent *event) override
static constexpr int nPlayheadWidth
Definition Skin.h:77
static void setPlayheadPen(QPainter *p, bool bHovered=false)
Definition Skin.cpp:190
static int getPlayheadShaftOffset()
Definition Skin.h:79
SongEditor * getSongEditor() const
void updatePlaybackTrackIfNecessary()
static constexpr int nMargin
Definition SongEditor.h:106
int getGridWidth()
int m_nCurrentWidth
Definition WaveDisplay.h:76
void createBackground(QPainter *painter)
QString m_sSampleName
Definition WaveDisplay.h:69
int * m_pPeakData
Definition WaveDisplay.h:70
std::shared_ptr< H2Core::InstrumentLayer > m_pLayer
Definition WaveDisplay.h:78