Ergonomic enhancements for AudioFileProcessor plugin (interactive wave view).
This patch includes: * sampleBuffer::visualise(): add possibility to specified a range to visualize instead of the whole sample * add sampleBuffer::sampleRate() and sampleBuffer::sampleLength() getters * definition of AudioFileProcessorWaveView and AudioFileProcessorWaveView::knob classes for AudioFileProcessor plugin * knob::getValue() specified “virtual” to allow redefinition in child class AudioFileProcessorWaveView::knob * delete audioFileKnob class (made obsolete by AudioFileProcessorWaveView::knob) * add audioFileProcessor::isPlaying() signal, which is emitted in audioFileProcessor::playNote * change type of AudioFileProcessorView::m_startKnob and AudioFileProcessorView::m_endKnob (AudioFileProcessorWaveView::knob instead of audioFileKnob) * replace AudioFileProcessorView::m_graph (QPixmap) by AudioFileProcessorView::m_waveView (AudioFileProcessorWaveView) Signed-off-by: Tobias Doerffel <tobias.doerffel@gmail.com>
This commit is contained in:
committed by
Tobias Doerffel
parent
ad3af97798
commit
d448e6743d
@@ -112,6 +112,8 @@ protected:
|
||||
virtual void paintEvent( QPaintEvent * _me );
|
||||
virtual void wheelEvent( QWheelEvent * _me );
|
||||
|
||||
virtual float getValue( const QPoint & _p );
|
||||
|
||||
private slots:
|
||||
virtual void enterValue();
|
||||
void displayHelp();
|
||||
@@ -128,7 +130,6 @@ private:
|
||||
|
||||
void drawKnob( QPainter * _p );
|
||||
void setPosition( const QPoint & _p );
|
||||
float getValue( const QPoint & _p );
|
||||
bool updateAngle();
|
||||
|
||||
inline float pageSize() const
|
||||
|
||||
@@ -77,10 +77,10 @@ public:
|
||||
const float _freq,
|
||||
const bool _looped = false );
|
||||
|
||||
void visualize( QPainter & _p, const QRect & _dr, const QRect & _clip );
|
||||
inline void visualize( QPainter & _p, const QRect & _dr )
|
||||
void visualize( QPainter & _p, const QRect & _dr, const QRect & _clip, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 );
|
||||
inline void visualize( QPainter & _p, const QRect & _dr, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 )
|
||||
{
|
||||
visualize( _p, _dr, _dr );
|
||||
visualize( _p, _dr, _dr, _from_frame, _to_frame );
|
||||
}
|
||||
|
||||
inline const QString & audioFile() const
|
||||
@@ -132,6 +132,16 @@ public:
|
||||
return m_frequency;
|
||||
}
|
||||
|
||||
sample_rate_t sampleRate() const
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
int sampleLength() const
|
||||
{
|
||||
return double( m_endFrame - m_startFrame ) / m_sampleRate * 1000;
|
||||
}
|
||||
|
||||
inline void setFrequency( float _freq )
|
||||
{
|
||||
m_varLock.lock();
|
||||
|
||||
@@ -115,6 +115,11 @@ void audioFileProcessor::playNote( notePlayHandle * _n,
|
||||
applyRelease( _working_buffer, _n );
|
||||
instrumentTrack()->processAudioBuffer( _working_buffer,
|
||||
frames,_n );
|
||||
emit isPlaying( _n->totalFramesPlayed() * _n->frequency() / m_sampleBuffer.frequency() );
|
||||
}
|
||||
else
|
||||
{
|
||||
emit isPlaying( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,22 +265,6 @@ void audioFileProcessor::loopPointChanged( void )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class audioFileKnob : public knob
|
||||
{
|
||||
public:
|
||||
audioFileKnob( QWidget * _parent ) :
|
||||
knob( knobStyled, _parent )
|
||||
{
|
||||
setFixedSize( 37, 47 );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
QPixmap * AudioFileProcessorView::s_artwork = NULL;
|
||||
|
||||
|
||||
@@ -347,7 +336,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
|
||||
"Otherwise it will be amplified up or down (your "
|
||||
"actual sample-file isn't touched!)" ) );
|
||||
|
||||
m_startKnob = new audioFileKnob( this );
|
||||
m_startKnob = new AudioFileProcessorWaveView::knob( this );
|
||||
m_startKnob->move( 68, 108 );
|
||||
m_startKnob->setHintText( tr( "Startpoint:" )+" ", "" );
|
||||
m_startKnob->setWhatsThis(
|
||||
@@ -357,7 +346,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
|
||||
"which AudioFileProcessor returns if a note is longer "
|
||||
"than the sample between the start and end-points." ) );
|
||||
|
||||
m_endKnob = new audioFileKnob( this );
|
||||
m_endKnob = new AudioFileProcessorWaveView::knob( this );
|
||||
m_endKnob->move( 119, 108 );
|
||||
m_endKnob->setHintText( tr( "Endpoint:" )+" ", "" );
|
||||
m_endKnob->setWhatsThis(
|
||||
@@ -367,6 +356,18 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument,
|
||||
"AudioFileProcessor returns if a note is longer than "
|
||||
"the sample between the start and end-points." ) );
|
||||
|
||||
m_waveView = new AudioFileProcessorWaveView( this, 245, 75, castModel<audioFileProcessor>()->m_sampleBuffer );
|
||||
m_waveView->move( 2, 172 );
|
||||
m_waveView->setKnobs(
|
||||
dynamic_cast<AudioFileProcessorWaveView::knob *>( m_startKnob ),
|
||||
dynamic_cast<AudioFileProcessorWaveView::knob *>( m_endKnob )
|
||||
);
|
||||
|
||||
connect( castModel<audioFileProcessor>(), SIGNAL( isPlaying( f_cnt_t ) ),
|
||||
m_waveView, SLOT( isPlaying( f_cnt_t ) ) );
|
||||
|
||||
qRegisterMetaType<f_cnt_t>( "f_cnt_t" );
|
||||
|
||||
setAcceptDrops( TRUE );
|
||||
}
|
||||
|
||||
@@ -464,26 +465,6 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * )
|
||||
|
||||
p.setPen( QColor( 255, 255, 255 ) );
|
||||
p.drawText( 8, 99, file_name );
|
||||
|
||||
p.drawPixmap( 2, 172, m_graph );
|
||||
|
||||
|
||||
p.setPen( QColor( 0xFF, 0xAA, 0x00 ) );
|
||||
const QRect graph_rect( 4, 174, 241, 70 );
|
||||
const f_cnt_t frames = qMax( a->m_sampleBuffer.frames(),
|
||||
static_cast<f_cnt_t>( 1 ) );
|
||||
const int start_frame_x = a->m_sampleBuffer.startFrame() *
|
||||
graph_rect.width() / frames;
|
||||
const int end_frame_x = a->m_sampleBuffer.endFrame() *
|
||||
graph_rect.width() / frames;
|
||||
|
||||
p.drawLine( start_frame_x + graph_rect.x(), graph_rect.y(),
|
||||
start_frame_x + graph_rect.x(),
|
||||
graph_rect.height() + graph_rect.y() );
|
||||
p.drawLine( end_frame_x + graph_rect.x(), graph_rect.y(),
|
||||
end_frame_x + graph_rect.x(),
|
||||
graph_rect.height() + graph_rect.y() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -491,13 +472,7 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * )
|
||||
|
||||
void AudioFileProcessorView::sampleUpdated( void )
|
||||
{
|
||||
m_graph = QPixmap( 245, 75 );
|
||||
m_graph.fill( Qt::transparent );
|
||||
QPainter p( &m_graph );
|
||||
p.setPen( QColor( 64, 255, 160 ) );
|
||||
castModel<audioFileProcessor>()->m_sampleBuffer.
|
||||
visualize( p, QRect( 2, 2, m_graph.width() - 4,
|
||||
m_graph.height() - 4 ) );
|
||||
m_waveView->update();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -535,6 +510,498 @@ void AudioFileProcessorView::modelChanged( void )
|
||||
|
||||
|
||||
|
||||
AudioFileProcessorWaveView::AudioFileProcessorWaveView( QWidget * _parent, int _w, int _h, sampleBuffer & _buf ) :
|
||||
QWidget( _parent ),
|
||||
m_sampleBuffer( _buf ),
|
||||
m_graph( QPixmap( _w - 2 * s_padding, _h - 2 * s_padding ) ),
|
||||
m_from( 0 ),
|
||||
m_to( m_sampleBuffer.frames() ),
|
||||
m_last_from( 0 ),
|
||||
m_last_to( 0 ),
|
||||
m_startKnob( 0 ),
|
||||
m_endKnob( 0 ),
|
||||
m_isDragging( false ),
|
||||
m_reversed( false ),
|
||||
m_framesPlayed( 0 )
|
||||
{
|
||||
setFixedSize( _w, _h );
|
||||
setMouseTracking( true );
|
||||
|
||||
if( m_sampleBuffer.frames() > 1 )
|
||||
{
|
||||
const f_cnt_t marging = ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() ) * 0.1;
|
||||
m_from = qMax( 0, m_sampleBuffer.startFrame() - marging );
|
||||
m_to = qMin( m_sampleBuffer.endFrame() + marging, m_sampleBuffer.frames() );
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::isPlaying( f_cnt_t _frames_played )
|
||||
{
|
||||
m_framesPlayed = _frames_played % ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::enterEvent( QEvent * _e )
|
||||
{
|
||||
QApplication::setOverrideCursor( Qt::OpenHandCursor );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::leaveEvent( QEvent * _e )
|
||||
{
|
||||
while( QApplication::overrideCursor() )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::mousePressEvent( QMouseEvent * _me )
|
||||
{
|
||||
m_isDragging = true;
|
||||
m_draggingLastPoint = _me->pos();
|
||||
|
||||
if( isCloseTo( _me->x(), m_startFrameX ) )
|
||||
{
|
||||
m_draggingType = sample_start;
|
||||
}
|
||||
else if( isCloseTo( _me->x(), m_endFrameX ) )
|
||||
{
|
||||
m_draggingType = sample_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_draggingType = wave;
|
||||
QApplication::setOverrideCursor( Qt::ClosedHandCursor );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::mouseReleaseEvent( QMouseEvent * _me )
|
||||
{
|
||||
m_isDragging = false;
|
||||
if( m_draggingType == wave )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::mouseMoveEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( ! m_isDragging )
|
||||
{
|
||||
const bool is_size_cursor =
|
||||
QApplication::overrideCursor()->shape() == Qt::SizeHorCursor;
|
||||
|
||||
if( isCloseTo( _me->x(), m_startFrameX ) ||
|
||||
isCloseTo( _me->x(), m_endFrameX ) )
|
||||
{
|
||||
if( ! is_size_cursor )
|
||||
{
|
||||
QApplication::setOverrideCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
}
|
||||
else if( is_size_cursor )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int step = _me->x() - m_draggingLastPoint.x();
|
||||
switch( m_draggingType )
|
||||
{
|
||||
case sample_start:
|
||||
slideSamplePointByPx( start, step );
|
||||
break;
|
||||
case sample_end:
|
||||
slideSamplePointByPx( end, step );
|
||||
break;
|
||||
default:
|
||||
if( qAbs( _me->y() - m_draggingLastPoint.y() )
|
||||
< 2 * qAbs( _me->x() - m_draggingLastPoint.x() ) )
|
||||
{
|
||||
slide( step );
|
||||
}
|
||||
else
|
||||
{
|
||||
zoom( _me->y() < m_draggingLastPoint.y() );
|
||||
}
|
||||
}
|
||||
|
||||
m_draggingLastPoint = _me->pos();
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::wheelEvent( QWheelEvent * _we )
|
||||
{
|
||||
zoom( _we->delta() > 0 );
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe )
|
||||
{
|
||||
QPainter p( this );
|
||||
|
||||
p.drawPixmap( s_padding, s_padding, m_graph );
|
||||
|
||||
p.setPen( QColor( 0xFF, 0xFF, 0x00 ) );
|
||||
const QRect graph_rect( s_padding, s_padding, width() - 2 * s_padding, height() - 2 * s_padding );
|
||||
const f_cnt_t frames = m_to - m_from;
|
||||
m_startFrameX = graph_rect.x() + ( m_sampleBuffer.startFrame() - m_from ) *
|
||||
double( graph_rect.width() ) / frames;
|
||||
m_endFrameX = graph_rect.x() + ( m_sampleBuffer.endFrame() - m_from ) *
|
||||
double( graph_rect.width() ) / frames;
|
||||
|
||||
p.drawLine( m_startFrameX, graph_rect.y(),
|
||||
m_startFrameX,
|
||||
graph_rect.height() + graph_rect.y() );
|
||||
p.drawLine( m_endFrameX, graph_rect.y(),
|
||||
m_endFrameX,
|
||||
graph_rect.height() + graph_rect.y() );
|
||||
|
||||
if( m_endFrameX - m_startFrameX > 2 )
|
||||
{
|
||||
p.fillRect(
|
||||
m_startFrameX + 1,
|
||||
graph_rect.y(),
|
||||
m_endFrameX - m_startFrameX - 1,
|
||||
graph_rect.height() + graph_rect.y(),
|
||||
QColor( 255, 255, 0, 70 )
|
||||
);
|
||||
|
||||
if( m_framesPlayed )
|
||||
{
|
||||
const int played_width_px = m_framesPlayed
|
||||
/ double( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() )
|
||||
* ( m_endFrameX - m_startFrameX );
|
||||
QLinearGradient g( m_startFrameX + 1, 0, m_startFrameX + 1 + played_width_px, 0 );
|
||||
const QColor c( 0, 120, 255, 180 );
|
||||
g.setColorAt( 0, Qt::transparent );
|
||||
g.setColorAt( 0.8, c );
|
||||
g.setColorAt( 1, c );
|
||||
p.fillRect(
|
||||
m_startFrameX + 1,
|
||||
graph_rect.y(),
|
||||
played_width_px,
|
||||
graph_rect.height() + graph_rect.y(),
|
||||
g
|
||||
);
|
||||
p.setPen( QColor( 0, 255, 255 ) );
|
||||
p.drawLine(
|
||||
m_startFrameX + 1 + played_width_px,
|
||||
graph_rect.y(),
|
||||
m_startFrameX + 1 + played_width_px,
|
||||
graph_rect.height() + graph_rect.y()
|
||||
);
|
||||
m_framesPlayed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QLinearGradient g( 0, 0, width() * 0.7, 0 );
|
||||
const QColor c( 0, 0, 150, 180 );
|
||||
g.setColorAt( 0, c );
|
||||
g.setColorAt( 0.4, c );
|
||||
g.setColorAt( 1, Qt::transparent );
|
||||
p.fillRect( s_padding, s_padding, m_graph.width(), 14, g );
|
||||
|
||||
p.setPen( QColor( 255, 255, 20 ) );
|
||||
p.setFont( pointSize<8>( font() ) );
|
||||
|
||||
QString length_text;
|
||||
const int length = m_sampleBuffer.sampleLength();
|
||||
|
||||
if( length > 20000 )
|
||||
{
|
||||
length_text = QString::number( length / 1000 ) + "s";
|
||||
}
|
||||
else if( length > 2000 )
|
||||
{
|
||||
length_text = QString::number( ( length / 100 ) / 10.0 ) + "s";
|
||||
}
|
||||
else
|
||||
{
|
||||
length_text = QString::number( length ) + "ms";
|
||||
}
|
||||
|
||||
p.drawText(
|
||||
s_padding + 2,
|
||||
s_padding + 10,
|
||||
tr( "Sample length:" ) + " " + length_text
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::updateGraph()
|
||||
{
|
||||
if( m_to == 1 )
|
||||
{
|
||||
m_to = m_sampleBuffer.frames() * 0.7;
|
||||
slideSamplePointToFrames( end, m_to * 0.7 );
|
||||
}
|
||||
|
||||
if( m_from > m_sampleBuffer.startFrame() )
|
||||
{
|
||||
m_from = m_sampleBuffer.startFrame();
|
||||
}
|
||||
|
||||
if( m_to < m_sampleBuffer.endFrame() )
|
||||
{
|
||||
m_to = m_sampleBuffer.endFrame();
|
||||
}
|
||||
|
||||
if( m_sampleBuffer.reversed() != m_reversed )
|
||||
{
|
||||
reverse();
|
||||
}
|
||||
else if( m_last_from == m_from && m_last_to == m_to )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_last_from = m_from;
|
||||
m_last_to = m_to;
|
||||
|
||||
m_graph.fill( Qt::transparent );
|
||||
QPainter p( &m_graph );
|
||||
p.setPen( QColor( 64, 255, 160 ) );
|
||||
m_sampleBuffer.visualize(
|
||||
p,
|
||||
QRect( 0, 0, m_graph.width(), m_graph.height() ),
|
||||
m_from, m_to
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::zoom( const bool _out )
|
||||
{
|
||||
const f_cnt_t start = m_sampleBuffer.startFrame();
|
||||
const f_cnt_t end = m_sampleBuffer.endFrame();
|
||||
const f_cnt_t frames = m_sampleBuffer.frames();
|
||||
const f_cnt_t d_from = start - m_from;
|
||||
const f_cnt_t d_to = m_to - end;
|
||||
|
||||
const f_cnt_t step = qMax( 1, qMax( d_from, d_to ) / 10 );
|
||||
const f_cnt_t step_from = ( _out ? - step : step );
|
||||
const f_cnt_t step_to = ( _out ? step : - step );
|
||||
|
||||
const double comp_ratio = double( qMin( d_from, d_to ) )
|
||||
/ qMax( 1, qMax( d_from, d_to ) );
|
||||
|
||||
f_cnt_t new_from;
|
||||
f_cnt_t new_to;
|
||||
|
||||
if( ( _out && d_from < d_to ) || ( ! _out && d_to < d_from ) )
|
||||
{
|
||||
new_from = qBound( 0, m_from + step_from, start );
|
||||
new_to = qBound(
|
||||
end,
|
||||
m_to + f_cnt_t( step_to * ( new_from == m_from ? 1 : comp_ratio ) ),
|
||||
frames
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_to = qBound( end, m_to + step_to, frames );
|
||||
new_from = qBound(
|
||||
0,
|
||||
m_from + f_cnt_t( step_from * ( new_to == m_to ? 1 : comp_ratio ) ),
|
||||
start
|
||||
);
|
||||
}
|
||||
|
||||
if( double( new_to - new_from ) / m_sampleBuffer.sampleRate() > 0.05 )
|
||||
{
|
||||
m_from = new_from;
|
||||
m_to = new_to;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::slide( int _px )
|
||||
{
|
||||
const double fact = qAbs( double( _px ) / width() );
|
||||
f_cnt_t step = ( m_to - m_from ) * fact;
|
||||
if( _px > 0 )
|
||||
{
|
||||
step = -step;
|
||||
}
|
||||
|
||||
f_cnt_t step_from = qBound( 0, m_from + step, m_sampleBuffer.frames() ) - m_from;
|
||||
f_cnt_t step_to = qBound( m_from + 1, m_to + step, m_sampleBuffer.frames() ) - m_to;
|
||||
|
||||
step = qAbs( step_from ) < qAbs( step_to ) ? step_from : step_to;
|
||||
|
||||
m_from += step;
|
||||
m_to += step;
|
||||
slideSampleByFrames( step );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::setKnobs( knob * _start, knob * _end )
|
||||
{
|
||||
m_startKnob = _start;
|
||||
m_endKnob = _end;
|
||||
|
||||
m_startKnob->setWaveView( this );
|
||||
m_startKnob->setRelatedKnob( m_endKnob );
|
||||
|
||||
m_endKnob->setWaveView( this );
|
||||
m_endKnob->setRelatedKnob( m_startKnob );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::slideSamplePointByPx( knobType _point, int _px )
|
||||
{
|
||||
slideSamplePointByFrames(
|
||||
_point,
|
||||
f_cnt_t( ( double( _px ) / width() ) * ( m_to - m_from ) )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::slideSamplePointByFrames( knobType _point, f_cnt_t _frames, bool _slide_to )
|
||||
{
|
||||
knob * knob = _point == start ? m_startKnob : m_endKnob;
|
||||
if( ! knob )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const double v = double( _frames ) / m_sampleBuffer.frames();
|
||||
if( _slide_to )
|
||||
{
|
||||
knob->slideTo( v );
|
||||
}
|
||||
else
|
||||
{
|
||||
knob->slideBy( v );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::slideSampleByFrames( f_cnt_t _frames )
|
||||
{
|
||||
const double v = double( _frames ) / m_sampleBuffer.frames();
|
||||
m_startKnob->slideBy( v, false );
|
||||
m_endKnob->slideBy( v, false );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::reverse()
|
||||
{
|
||||
slideSampleByFrames(
|
||||
m_sampleBuffer.frames()
|
||||
- m_sampleBuffer.endFrame()
|
||||
- m_sampleBuffer.startFrame()
|
||||
);
|
||||
|
||||
const f_cnt_t from = m_from;
|
||||
m_from = m_sampleBuffer.frames() - m_to;
|
||||
m_to = m_sampleBuffer.frames() - from;
|
||||
|
||||
m_reversed = ! m_reversed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AudioFileProcessorWaveView::knob::slideTo( double _v, bool _check_bound )
|
||||
{
|
||||
if( _check_bound && ! checkBound( _v ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
model()->setValue( _v );
|
||||
emit sliderMoved( model()->value() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
float AudioFileProcessorWaveView::knob::getValue( const QPoint & _p )
|
||||
{
|
||||
const double dec_fact = ! m_waveView ? 1 :
|
||||
double( m_waveView->m_to - m_waveView->m_from )
|
||||
/ m_waveView->m_sampleBuffer.frames();
|
||||
const float inc = ::knob::getValue( _p ) * dec_fact;
|
||||
const float next = model()->value() - inc;
|
||||
|
||||
if( ! checkBound( next ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return inc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool AudioFileProcessorWaveView::knob::checkBound( double _v ) const
|
||||
{
|
||||
if( ! m_relatedKnob || ! m_waveView )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ( m_relatedKnob->model()->value() - _v > 0 ) !=
|
||||
( m_relatedKnob->model()->value() - model()->value() > 0 ) )
|
||||
return false;
|
||||
|
||||
const double d1 = qAbs( m_relatedKnob->model()->value() - model()->value() )
|
||||
* ( m_waveView->m_sampleBuffer.frames() )
|
||||
/ m_waveView->m_sampleBuffer.sampleRate();
|
||||
|
||||
const double d2 = qAbs( m_relatedKnob->model()->value() - _v )
|
||||
* ( m_waveView->m_sampleBuffer.frames() )
|
||||
/ m_waveView->m_sampleBuffer.sampleRate();
|
||||
|
||||
return d1 < d2 || d2 > 0.02;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -76,6 +76,10 @@ private slots:
|
||||
void loopPointChanged();
|
||||
|
||||
|
||||
signals:
|
||||
void isPlaying( f_cnt_t _frames_played );
|
||||
|
||||
|
||||
private:
|
||||
typedef sampleBuffer::handleState handleState;
|
||||
|
||||
@@ -94,6 +98,9 @@ private:
|
||||
|
||||
|
||||
|
||||
class AudioFileProcessorWaveView;
|
||||
|
||||
|
||||
class AudioFileProcessorView : public InstrumentView
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -118,7 +125,7 @@ private:
|
||||
|
||||
static QPixmap * s_artwork;
|
||||
|
||||
QPixmap m_graph;
|
||||
AudioFileProcessorWaveView * m_waveView;
|
||||
knob * m_ampKnob;
|
||||
knob * m_startKnob;
|
||||
knob * m_endKnob;
|
||||
@@ -130,5 +137,134 @@ private:
|
||||
|
||||
|
||||
|
||||
class AudioFileProcessorWaveView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
virtual void enterEvent( QEvent * _e );
|
||||
virtual void leaveEvent( QEvent * _e );
|
||||
virtual void mousePressEvent( QMouseEvent * _me );
|
||||
virtual void mouseReleaseEvent( QMouseEvent * _me );
|
||||
virtual void mouseMoveEvent( QMouseEvent * _me );
|
||||
virtual void wheelEvent( QWheelEvent * _we );
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
|
||||
|
||||
public:
|
||||
enum knobType
|
||||
{
|
||||
start,
|
||||
end,
|
||||
} ;
|
||||
|
||||
class knob : public ::knob
|
||||
{
|
||||
const AudioFileProcessorWaveView * m_waveView;
|
||||
const knob * m_relatedKnob;
|
||||
|
||||
|
||||
public:
|
||||
knob( QWidget * _parent ) :
|
||||
::knob( knobStyled, _parent ),
|
||||
m_waveView( 0 ),
|
||||
m_relatedKnob( 0 )
|
||||
{
|
||||
setFixedSize( 37, 47 );
|
||||
}
|
||||
|
||||
void setWaveView( const AudioFileProcessorWaveView * _wv )
|
||||
{
|
||||
m_waveView = _wv;
|
||||
}
|
||||
|
||||
void setRelatedKnob( const knob * _knob )
|
||||
{
|
||||
m_relatedKnob = _knob;
|
||||
}
|
||||
|
||||
void slideBy( double _v, bool _check_bound = true )
|
||||
{
|
||||
slideTo( model()->value() + _v, _check_bound );
|
||||
}
|
||||
|
||||
void slideTo( double _v, bool _check_bound = true );
|
||||
|
||||
|
||||
protected:
|
||||
float getValue( const QPoint & _p );
|
||||
|
||||
|
||||
private:
|
||||
bool checkBound( double _v ) const;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
public slots:
|
||||
void update()
|
||||
{
|
||||
updateGraph();
|
||||
QWidget::update();
|
||||
}
|
||||
|
||||
void isPlaying( f_cnt_t _frames_played );
|
||||
|
||||
|
||||
private:
|
||||
static const int s_padding = 2;
|
||||
|
||||
enum draggingType
|
||||
{
|
||||
wave,
|
||||
sample_start,
|
||||
sample_end,
|
||||
} ;
|
||||
|
||||
sampleBuffer & m_sampleBuffer;
|
||||
QPixmap m_graph;
|
||||
f_cnt_t m_from;
|
||||
f_cnt_t m_to;
|
||||
f_cnt_t m_last_from;
|
||||
f_cnt_t m_last_to;
|
||||
knob * m_startKnob;
|
||||
knob * m_endKnob;
|
||||
f_cnt_t m_startFrameX;
|
||||
f_cnt_t m_endFrameX;
|
||||
bool m_isDragging;
|
||||
QPoint m_draggingLastPoint;
|
||||
draggingType m_draggingType;
|
||||
bool m_reversed;
|
||||
f_cnt_t m_framesPlayed;
|
||||
|
||||
|
||||
public:
|
||||
AudioFileProcessorWaveView( QWidget * _parent, int _w, int _h, sampleBuffer & _buf );
|
||||
void setKnobs( knob * _start, knob * _end );
|
||||
|
||||
|
||||
private:
|
||||
void zoom( const bool _out = false );
|
||||
void slide( int _px );
|
||||
void slideSamplePointByPx( knobType _point, int _px );
|
||||
void slideSamplePointByFrames( knobType _point, f_cnt_t _frames, bool _slide_to = false );
|
||||
void slideSampleByFrames( f_cnt_t _frames );
|
||||
|
||||
void slideSamplePointToFrames( knobType _point, f_cnt_t _frames )
|
||||
{
|
||||
slideSamplePointByFrames( _point, _frames, true );
|
||||
}
|
||||
|
||||
void updateGraph();
|
||||
void reverse();
|
||||
|
||||
static bool isCloseTo( int _a, int _b )
|
||||
{
|
||||
return qAbs( _a - _b ) < 3;
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -699,8 +699,10 @@ f_cnt_t sampleBuffer::getLoopedIndex( f_cnt_t _index ) const
|
||||
|
||||
|
||||
void sampleBuffer::visualize( QPainter & _p, const QRect & _dr,
|
||||
const QRect & _clip )
|
||||
const QRect & _clip, f_cnt_t _from_frame, f_cnt_t _to_frame )
|
||||
{
|
||||
const bool focus_on_range = _to_frame <= m_frames
|
||||
&& 0 <= _from_frame && _from_frame < _to_frame;
|
||||
// _p.setClipRect( _clip );
|
||||
// _p.setPen( QColor( 0x22, 0xFF, 0x44 ) );
|
||||
//_p.setPen( QColor( 64, 224, 160 ) );
|
||||
@@ -709,25 +711,28 @@ void sampleBuffer::visualize( QPainter & _p, const QRect & _dr,
|
||||
|
||||
const int yb = h / 2 + _dr.y();
|
||||
const float y_space = h*0.25f;
|
||||
const int nb_frames = focus_on_range ? _to_frame - _from_frame : m_frames;
|
||||
|
||||
if( m_frames < 60000 )
|
||||
if( nb_frames < 60000 )
|
||||
{
|
||||
_p.setRenderHint( QPainter::Antialiasing );
|
||||
QColor c = _p.pen().color();
|
||||
_p.setPen( QPen( c, 0.7 ) );
|
||||
}
|
||||
const int fpp = tLimit<int>( m_frames / w, 1, 20 );
|
||||
QPoint * l = new QPoint[m_frames / fpp + 1];
|
||||
const int fpp = tLimit<int>( nb_frames / w, 1, 20 );
|
||||
QPoint * l = new QPoint[nb_frames / fpp + 1];
|
||||
int n = 0;
|
||||
const int xb = _dr.x();
|
||||
for( int frame = 0; frame < m_frames; frame += fpp )
|
||||
const int first = focus_on_range ? _from_frame : 0;
|
||||
const int last = focus_on_range ? _to_frame : m_frames;
|
||||
for( int frame = first; frame < last; frame += fpp )
|
||||
{
|
||||
l[n] = QPoint( xb + ( frame * w / m_frames ),
|
||||
l[n] = QPoint( xb + ( (frame - first) * double( w ) / nb_frames ),
|
||||
(int)( yb - ( ( m_data[frame][0]+m_data[frame][1] ) *
|
||||
y_space ) ) );
|
||||
++n;
|
||||
}
|
||||
_p.drawPolyline( l, m_frames / fpp );
|
||||
_p.drawPolyline( l, nb_frames / fpp );
|
||||
delete[] l;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user