diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 73533eb33..a95abb793 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -543,7 +543,7 @@ BBTCOView { /* Plugins */ -TripleOscillatorView knob { +TripleOscillatorView Knob { color: rgb(1, 32, 64); qproperty-outerColor: rgb(0, 0, 0); qproperty-innerRadius: 2; @@ -554,7 +554,7 @@ TripleOscillatorView knob { } -kickerInstrumentView knob#smallKnob { +kickerInstrumentView Knob#smallKnob { color: #595959; qproperty-outerColor: black; qproperty-innerRadius: 3; @@ -565,7 +565,7 @@ kickerInstrumentView knob#smallKnob { } -kickerInstrumentView knob#largeKnob { +kickerInstrumentView Knob#largeKnob { color: #0c3b89; qproperty-outerColor: #519fff; qproperty-innerRadius: 12.0; @@ -576,7 +576,7 @@ kickerInstrumentView knob#largeKnob { } -AudioFileProcessorView knob { +AudioFileProcessorView Knob { color: rgb(240, 147, 14); qproperty-outerColor: rgb(30, 35, 37); qproperty-innerRadius: 4; @@ -586,7 +586,7 @@ AudioFileProcessorView knob { qproperty-lineWidth: 3; } -organicInstrumentView knob { +organicInstrumentView Knob { color: rgb(124, 207, 98); qproperty-outerColor: rgb(13, 42, 4); qproperty-innerRadius: 2; @@ -596,13 +596,13 @@ organicInstrumentView knob { qproperty-lineWidth: 1.5; } -organicInstrumentView knob#harmKnob { +organicInstrumentView Knob#harmKnob { color: rgb(205, 98, 216); qproperty-outerColor: rgb(18, 4, 18); } -organicInstrumentView knob#fx1Knob, -organicInstrumentView knob#volKnob { +organicInstrumentView Knob#fx1Knob, +organicInstrumentView Knob#volKnob { color: rgb(157, 157, 157); qproperty-outerColor: rgb(37, 37, 37); qproperty-innerRadius: 4; @@ -612,7 +612,7 @@ organicInstrumentView knob#volKnob { qproperty-lineWidth: 2; } -sf2InstrumentView knob { +sf2InstrumentView Knob { color: #ff00ea; qproperty-outerColor: rgb(20, 5, 18); qproperty-innerRadius: 2; @@ -622,7 +622,7 @@ sf2InstrumentView knob { qproperty-lineWidth: 2; } -sfxrInstrumentView knob { +sfxrInstrumentView Knob { color: #000; qproperty-outerColor: rgb(194, 177, 145); qproperty-innerRadius: 2; @@ -630,42 +630,42 @@ sfxrInstrumentView knob { qproperty-lineWidth: 2; } -sfxrInstrumentView knob#envKnob { +sfxrInstrumentView Knob#envKnob { color: #263352; qproperty-outerColor: #4b66a4; } -sfxrInstrumentView knob#freqKnob { +sfxrInstrumentView Knob#freqKnob { color: #1e4a22; qproperty-outerColor: #3c9544; } -sfxrInstrumentView knob#changeKnob { +sfxrInstrumentView Knob#changeKnob { color: #591c1c; qproperty-outerColor: #b23737; } -sfxrInstrumentView knob#sqrKnob { +sfxrInstrumentView Knob#sqrKnob { color: #3b2714; qproperty-outerColor: #724c27; } -sfxrInstrumentView knob#repeatKnob { +sfxrInstrumentView Knob#repeatKnob { color: #292929; qproperty-outerColor: #515151; } -sfxrInstrumentView knob#phaserKnob { +sfxrInstrumentView Knob#phaserKnob { color: #144c4d; qproperty-outerColor: #299899; } -sfxrInstrumentView knob#filterKnob { +sfxrInstrumentView Knob#filterKnob { color: #47224c; qproperty-outerColor: #8e4397; } -opl2instrumentView knob { +opl2instrumentView Knob { color: rgb(128,128,128); qproperty-outerColor: rgb(255,255,255); qproperty-innerRadius: 2; @@ -673,7 +673,7 @@ opl2instrumentView knob { qproperty-lineWidth: 2; } -sidInstrumentView knob { +sidInstrumentView Knob { color: rgb(113,95,80); qproperty-outerColor: rgb( 255,255,255 ); qproperty-innerRadius: 2; @@ -681,7 +681,7 @@ sidInstrumentView knob { qproperty-lineWidth: 2; } -WatsynView knob { +WatsynView Knob { qproperty-innerRadius: 1; qproperty-outerRadius: 7; qproperty-centerPointX: 9.5; @@ -689,17 +689,17 @@ WatsynView knob { qproperty-lineWidth: 2; } -WatsynView knob#aKnob { +WatsynView Knob#aKnob { color: #43b2ff; qproperty-outerColor: #43b2ff; } -WatsynView knob#bKnob { +WatsynView Knob#bKnob { color: #fc5431; qproperty-outerColor: #fc5431; } -WatsynView knob#mixKnob { +WatsynView Knob#mixKnob { color: #43ff82; qproperty-outerColor: #43ff82; qproperty-outerRadius: 13; @@ -707,17 +707,17 @@ WatsynView knob#mixKnob { qproperty-centerPointY: 15.5; } -WatsynView knob#mixenvKnob { +WatsynView Knob#mixenvKnob { color: #43ff82; qproperty-outerColor: #43ff82; } -WatsynView knob#xtalkKnob { +WatsynView Knob#xtalkKnob { color: #fb50fb; qproperty-outerColor: #fb50fb; } -MonstroView knob { +MonstroView Knob { color: #ffffff; qproperty-outerColor: #aaaaaa; qproperty-outerRadius: 9; @@ -727,7 +727,7 @@ MonstroView knob { qproperty-lineWidth: 2.5; } -NesInstrumentView knob { +NesInstrumentView Knob { color: #e7231b; qproperty-outerColor: #fff; qproperty-outerRadius: 11.0; diff --git a/include/RingBuffer.h b/include/RingBuffer.h index db903109d..f601e9aa6 100644 --- a/include/RingBuffer.h +++ b/include/RingBuffer.h @@ -1,5 +1,5 @@ /* - * RingBuffer.h - an effective, thread-safe and flexible implementation of a ringbuffer for LMMS + * RingBuffer.h - an effective and flexible implementation of a ringbuffer for LMMS * * Copyright (c) 2014 Vesa Kivimäki * Copyright (c) 2005-2014 Tobias Doerffel @@ -32,7 +32,7 @@ #include "lmms_math.h" #include "MemoryManager.h" -class RingBuffer : public QObject +class EXPORT RingBuffer : public QObject { Q_OBJECT MM_OPERATORS @@ -204,14 +204,14 @@ protected slots: private: inline f_cnt_t msToFrames( float ms ) { - return static_cast( ceilf( ms * m_samplerate / 1000 ) ); + return static_cast( ceilf( ms * (float)m_samplerate * 0.001f ) ); } const fpp_t m_fpp; sample_rate_t m_samplerate; - f_cnt_t m_size; + size_t m_size; sampleFrame * m_buffer; - f_cnt_t m_position; + volatile unsigned int m_position; }; #endif diff --git a/plugins/MultitapEcho/MultitapEcho.cpp b/plugins/MultitapEcho/MultitapEcho.cpp index abbd34f25..8c060b2ea 100644 --- a/plugins/MultitapEcho/MultitapEcho.cpp +++ b/plugins/MultitapEcho/MultitapEcho.cpp @@ -49,16 +49,19 @@ Plugin::Descriptor PLUGIN_EXPORT multitapecho_plugin_descriptor = MultitapEchoEffect::MultitapEchoEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key ) : Effect( &multitapecho_plugin_descriptor, parent, key ), m_controls( this ), - m_buffer( 20000.0f ), + m_buffer( 20100.0f ), m_sampleRate( Engine::mixer()->processingSampleRate() ), m_sampleRatio( 1.0f / m_sampleRate ) { + m_work = new sampleFrame[ Engine::mixer()->framesPerPeriod() ]; + m_buffer.reset(); updateFilters( 0, 19 ); } MultitapEchoEffect::~MultitapEchoEffect() { + delete m_work; } @@ -99,9 +102,6 @@ bool MultitapEchoEffect::processAudioBuffer( sampleFrame * buf, const fpp_t fram const float dryGain = dbvToAmp( m_controls.m_dryGain.value() ); const bool swapInputs = m_controls.m_swapInputs.value(); - // temp processing stackbuffer for lp-filtering - sampleFrame work [frames]; - // add dry buffer - never swap inputs for dry m_buffer.writeAddingMultiplied( buf, 0, frames, dryGain ); @@ -111,8 +111,8 @@ bool MultitapEchoEffect::processAudioBuffer( sampleFrame * buf, const fpp_t fram float offset = stepLength; for( int i = 0; i < steps; ++i ) // add all steps swapped { - runFilter( &work[0], buf, m_filter[i], frames ); - m_buffer.writeSwappedAddingMultiplied( &work[0], offset, frames, m_amp[i] ); + runFilter( m_work, buf, m_filter[i], frames ); + m_buffer.writeSwappedAddingMultiplied( m_work, offset, frames, m_amp[i] ); offset += stepLength; } } @@ -121,19 +121,19 @@ bool MultitapEchoEffect::processAudioBuffer( sampleFrame * buf, const fpp_t fram float offset = stepLength; for( int i = 0; i < steps; ++i ) // add all steps swapped { - runFilter( &work[0], buf, m_filter[i], frames ); - m_buffer.writeAddingMultiplied( &work[0], offset, frames, m_amp[i] ); + runFilter( m_work, buf, m_filter[i], frames ); + m_buffer.writeAddingMultiplied( m_work, offset, frames, m_amp[i] ); offset += stepLength; } } // pop the buffer and mix it into output - m_buffer.pop( &work[0] ); + m_buffer.pop( m_work ); for( int f = 0; f < frames; ++f ) { - buf[f][0] = d * buf[f][0] + w * work[f][0]; - buf[f][1] = d * buf[f][1] + w * work[f][1]; + buf[f][0] = d * buf[f][0] + w * m_work[f][0]; + buf[f][1] = d * buf[f][1] + w * m_work[f][1]; outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1]; } diff --git a/plugins/MultitapEcho/MultitapEcho.h b/plugins/MultitapEcho/MultitapEcho.h index c79f0b5e0..50ac5a55f 100644 --- a/plugins/MultitapEcho/MultitapEcho.h +++ b/plugins/MultitapEcho/MultitapEcho.h @@ -86,6 +86,8 @@ private: float m_sampleRate; float m_sampleRatio; + + sampleFrame * m_work; friend class MultitapEchoControls; diff --git a/plugins/MultitapEcho/MultitapEchoControlDialog.cpp b/plugins/MultitapEcho/MultitapEchoControlDialog.cpp index dbb6e448f..feb4e8692 100644 --- a/plugins/MultitapEcho/MultitapEchoControlDialog.cpp +++ b/plugins/MultitapEcho/MultitapEchoControlDialog.cpp @@ -92,8 +92,8 @@ MultitapEchoControlDialog::MultitapEchoControlDialog( MultitapEchoControls * con // switch led - LedCheckBox * swapInputs = new LedCheckBox( "Swap inputs", this, tr( "Swap in" ), LedCheckBox::Green ); - swapInputs->move( 180, 240 ); - swapInputs->setModel( & controls-> m_swapInputs ); - ToolTip::add( swapInputs, tr( "Swap left and right channel for reflections" ) ); + LedCheckBox * swapInputs = new LedCheckBox( "Swap inputs", this, tr( "Swap inputs" ), LedCheckBox::Green ); + swapInputs->move( 20, 280 ); + swapInputs->setModel( & controls->m_swapInputs ); + ToolTip::add( swapInputs, tr( "Swap left and right input channel for reflections" ) ); } diff --git a/plugins/MultitapEcho/MultitapEchoControls.cpp b/plugins/MultitapEcho/MultitapEchoControls.cpp index 1a0b446a5..d83fd9ec4 100644 --- a/plugins/MultitapEcho/MultitapEchoControls.cpp +++ b/plugins/MultitapEcho/MultitapEchoControls.cpp @@ -38,7 +38,7 @@ MultitapEchoControls::MultitapEchoControls( MultitapEchoEffect * eff ) : m_stepLength( 100.0f, 1.0f, 1000.0f, 0.1f, 1000.0f, this, "Step length" ), m_dryGain( 0.0f, -80.0f, 20.0f, 0.1f, this, "Dry gain" ), m_swapInputs( false, this, "Swap inputs" ), - m_ampGraph( -100.0f, 0.0f, 16, this ), + m_ampGraph( -60.0f, 0.0f, 16, this ), m_lpGraph( 0.0f, 3.0f, 16, this ) { connect( &m_ampGraph, SIGNAL( samplesChanged( int, int ) ), this, SLOT( ampSamplesChanged( int, int ) ) ); @@ -140,6 +140,7 @@ void MultitapEchoControls::ampResetClicked() void MultitapEchoControls::lpSamplesChanged( int begin, int end ) { + //qDebug( "b/e %d - %d", begin, end ); const float * samples = m_lpGraph.samples(); for( int i = begin; i <= end; ++i ) { @@ -157,12 +158,18 @@ void MultitapEchoControls::lpResetClicked() void MultitapEchoControls::lengthChanged() { - m_ampGraph.setLength( m_steps.value() ); - m_lpGraph.setLength( m_steps.value() ); + const int len = m_steps.value(); + m_ampGraph.setLength( len ); + ampSamplesChanged( 0, len - 1 ); + m_lpGraph.setLength( len ); + lpSamplesChanged( 0, len - 1 ); + m_effect->updateFilters( 0, len - 1 ); } void MultitapEchoControls::sampleRateChanged() { + m_effect->m_sampleRate = Engine::mixer()->processingSampleRate(); + m_effect->m_sampleRatio = 1.0f / m_effect->m_sampleRate; m_effect->updateFilters( 0, 19 ); } diff --git a/src/core/RingBuffer.cpp b/src/core/RingBuffer.cpp index f81736bbe..21ec1f70f 100644 --- a/src/core/RingBuffer.cpp +++ b/src/core/RingBuffer.cpp @@ -1,5 +1,5 @@ /* - * RingBuffer.cpp - an effective, thread-safe and flexible implementation of a ringbuffer for LMMS + * RingBuffer.cpp - an effective and flexible implementation of a ringbuffer for LMMS * * Copyright (c) 2014 Vesa Kivimäki * Copyright (c) 2005-2014 Tobias Doerffel @@ -36,6 +36,7 @@ RingBuffer::RingBuffer( f_cnt_t size ) : m_size( size + m_fpp ) { m_buffer = new sampleFrame[ m_size ]; + memset( m_buffer, 0, m_size * sizeof( sampleFrame ) ); m_position = 0; } @@ -49,6 +50,7 @@ RingBuffer::RingBuffer( float size ) : memset( m_buffer, 0, m_size * sizeof( sampleFrame ) ); m_position = 0; setSamplerateAware( true ); + //qDebug( "m_size %d, m_position %d", m_size, m_position ); } @@ -87,11 +89,11 @@ void RingBuffer::setSamplerateAware( bool b ) { if( b ) { - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSampleRate() ), Qt::UniqueConnection ); + connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSamplerate() ), Qt::UniqueConnection ); } else { - disconnect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSampleRate() ) ); + disconnect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateSamplerate() ) ); } } @@ -118,18 +120,18 @@ void RingBuffer::pop( sampleFrame * dst ) { if( m_position + m_fpp <= m_size ) // we won't go over the edge so we can just memcpy here { - memcpy( dst, m_buffer + ( m_position * sizeof( sampleFrame ) ), m_fpp * sizeof( sampleFrame ) ); - memset( m_buffer + ( m_position * sizeof( sampleFrame ) ), 0, m_fpp * sizeof( sampleFrame ) ); + memcpy( dst, & m_buffer [ m_position ], m_fpp * sizeof( sampleFrame ) ); + memset( & m_buffer[m_position], 0, m_fpp * sizeof( sampleFrame ) ); } else { f_cnt_t first = m_size - m_position; f_cnt_t second = m_fpp - first; - memcpy( dst, m_buffer + ( m_position * sizeof( sampleFrame ) ), first * sizeof( sampleFrame ) ); - memset( m_buffer + ( m_position * sizeof( sampleFrame ) ), 0, first * sizeof( sampleFrame ) ); + memcpy( dst, & m_buffer [ m_position ], first * sizeof( sampleFrame ) ); + memset( & m_buffer [m_position], 0, first * sizeof( sampleFrame ) ); - memcpy( dst + ( first * sizeof( sampleFrame ) ), m_buffer, second * sizeof( sampleFrame ) ); + memcpy( & dst [first], m_buffer, second * sizeof( sampleFrame ) ); memset( m_buffer, 0, second * sizeof( sampleFrame ) ); } @@ -144,16 +146,16 @@ void RingBuffer::read( sampleFrame * dst, f_cnt_t offset ) if( pos + m_fpp <= m_size ) // we won't go over the edge so we can just memcpy here { - memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), m_fpp * sizeof( sampleFrame ) ); + memcpy( dst, & m_buffer [pos], m_fpp * sizeof( sampleFrame ) ); } else { f_cnt_t first = m_size - pos; f_cnt_t second = m_fpp - first; - memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), first * sizeof( sampleFrame ) ); + memcpy( dst, & m_buffer [pos], first * sizeof( sampleFrame ) ); - memcpy( dst + ( first * sizeof( sampleFrame ) ), m_buffer, second * sizeof( sampleFrame ) ); + memcpy( & dst [first], m_buffer, second * sizeof( sampleFrame ) ); } } @@ -171,16 +173,16 @@ void RingBuffer::read( sampleFrame * dst, f_cnt_t offset, f_cnt_t length ) if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here { - memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), length * sizeof( sampleFrame ) ); + memcpy( dst, & m_buffer [pos], length * sizeof( sampleFrame ) ); } else { f_cnt_t first = m_size - pos; f_cnt_t second = length - first; - memcpy( dst, m_buffer + ( pos * sizeof( sampleFrame ) ), first * sizeof( sampleFrame ) ); + memcpy( dst, & m_buffer [pos], first * sizeof( sampleFrame ) ); - memcpy( dst + ( first * sizeof( sampleFrame ) ), m_buffer, second * sizeof( sampleFrame ) ); + memcpy( & dst [first], m_buffer, second * sizeof( sampleFrame ) ); } } @@ -198,16 +200,16 @@ void RingBuffer::write( sampleFrame * src, f_cnt_t offset, f_cnt_t length ) if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here { - memcpy( m_buffer + ( pos * sizeof( sampleFrame ) ), src, length * sizeof( sampleFrame ) ); + memcpy( & m_buffer [pos], src, length * sizeof( sampleFrame ) ); } else { f_cnt_t first = m_size - pos; f_cnt_t second = length - first; - memcpy( m_buffer + ( pos * sizeof( sampleFrame ) ), src, first * sizeof( sampleFrame ) ); + memcpy( & m_buffer [pos], src, first * sizeof( sampleFrame ) ); - memcpy( m_buffer, src + ( first * sizeof( sampleFrame ) ), second * sizeof( sampleFrame ) ); + memcpy( m_buffer, & src [first], second * sizeof( sampleFrame ) ); } } @@ -225,16 +227,16 @@ void RingBuffer::writeAdding( sampleFrame * src, f_cnt_t offset, f_cnt_t length if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here { - MixHelpers::add( m_buffer + ( pos * sizeof( sampleFrame ) ), src, length ); + MixHelpers::add( & m_buffer [pos], src, length ); } else { f_cnt_t first = m_size - pos; f_cnt_t second = length - first; - MixHelpers::add( m_buffer + ( pos * sizeof( sampleFrame ) ), src, first ); + MixHelpers::add( & m_buffer[pos], src, first ); - MixHelpers::add( m_buffer, src + ( first * sizeof( sampleFrame ) ), second ); + MixHelpers::add( m_buffer, & src[first], second ); } } @@ -248,27 +250,29 @@ void RingBuffer::writeAdding( sampleFrame * src, float offset, f_cnt_t length ) void RingBuffer::writeAddingMultiplied( sampleFrame * src, f_cnt_t offset, f_cnt_t length, float level ) { const f_cnt_t pos = ( m_position + offset ) % m_size; + //qDebug( "pos %d m_pos %d ofs %d siz %d", pos, m_position, offset, m_size ); if( length == 0 ) { length = m_fpp; } if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here { - MixHelpers::addMultiplied( m_buffer + ( pos * sizeof( sampleFrame ) ), src, level, length ); + MixHelpers::addMultiplied( & m_buffer[pos], src, level, length ); } else { f_cnt_t first = m_size - pos; f_cnt_t second = length - first; - MixHelpers::addMultiplied( m_buffer + ( pos * sizeof( sampleFrame ) ), src, level, first ); + MixHelpers::addMultiplied( & m_buffer[pos], src, level, first ); - MixHelpers::addMultiplied( m_buffer, src + ( first * sizeof( sampleFrame ) ), level, second ); + MixHelpers::addMultiplied( m_buffer, & src [first], level, second ); } } void RingBuffer::writeAddingMultiplied( sampleFrame * src, float offset, f_cnt_t length, float level ) { - writeAddingMultiplied( src, msToFrames( offset ), length, level ); + f_cnt_t ofs = msToFrames( offset ); + writeAddingMultiplied( src, ofs, length, level ); } @@ -279,16 +283,16 @@ void RingBuffer::writeSwappedAddingMultiplied( sampleFrame * src, f_cnt_t offset if( pos + length <= m_size ) // we won't go over the edge so we can just memcpy here { - MixHelpers::addSwappedMultiplied( m_buffer + ( pos * sizeof( sampleFrame ) ), src, level, length ); + MixHelpers::addSwappedMultiplied( & m_buffer [pos], src, level, length ); } else { f_cnt_t first = m_size - pos; f_cnt_t second = length - first; - MixHelpers::addSwappedMultiplied( m_buffer + ( pos * sizeof( sampleFrame ) ), src, level, first ); + MixHelpers::addSwappedMultiplied( & m_buffer [pos], src, level, first ); - MixHelpers::addSwappedMultiplied( m_buffer, src + ( first * sizeof( sampleFrame ) ), level, second ); + MixHelpers::addSwappedMultiplied( m_buffer, & src [first], level, second ); } } diff --git a/src/gui/widgets/Graph.cpp b/src/gui/widgets/Graph.cpp index 2894e8283..3fea035cd 100644 --- a/src/gui/widgets/Graph.cpp +++ b/src/gui/widgets/Graph.cpp @@ -217,14 +217,17 @@ void Graph::drawLineAt( int _x, int _y, int _lastx ) int xstep = _x > _lastx ? -1 : 1; float ystep = ( lastval - val ) / linelen; + int start = INT_MAX; + int end = 0; // draw a line for ( int i = 0; i < linelen; i++ ) { - int x = (_x + (i * xstep)); // get x value - model()->drawSampleAt( (int)( x * xscale ), val + (i * ystep)); + int x = (_x + (i * xstep)) * xscale; // get x value + model()->drawSampleAt( x, val + (i * ystep)); + start = qMin( start, x ); + end = qMax( end, x ); } - int start = qMin( _x, _x + ( ( linelen - 1 ) * xstep ) ); - int end = qMax( _x, _x + ( ( linelen - 1 ) * xstep ) ); + model()->samplesChanged( start, end ); } @@ -362,7 +365,7 @@ void Graph::paintEvent( QPaintEvent * ) qMax( static_cast( ( minVal - maxVal ) * yscale ) - static_cast( ( (*samps)[i] - maxVal ) * yscale ), 1 ), gcol ); - p.setPen( QPen( m_graphColor, 1 ) ); + p.setPen( QPen( m_graphColor, 1.0 ) ); p.drawLine( 2+static_cast(i*xscale), 2+static_cast( ( (*samps)[i] - maxVal ) * yscale ),