Finish audioport rehaul, get vol/pan knobs working again, also some bugfixes

We're now doing the vol/pan stuff in audioport, since this way we avoid the pointless repetition of doing it in the playhandles
This commit is contained in:
Vesa
2014-08-27 23:08:22 +03:00
parent 857de8d2c8
commit 1deb80acc3
9 changed files with 142 additions and 60 deletions

View File

@@ -34,12 +34,14 @@
#include "PlayHandle.h"
class EffectChain;
class FloatModel;
class AudioPort : public ThreadableJob
{
MM_OPERATORS
public:
AudioPort( const QString & _name, bool _has_effect_chain = true );
AudioPort( const QString & _name, bool _has_effect_chain = true,
FloatModel * volumeModel = NULL, FloatModel * panningModel = NULL );
virtual ~AudioPort();
inline sampleFrame * buffer()
@@ -120,6 +122,9 @@ private:
PlayHandleList m_playHandles;
QMutex m_playHandleLock;
FloatModel * m_volumeModel;
FloatModel * m_panningModel;
friend class Mixer;
friend class MixerWorkerThread;

View File

@@ -225,7 +225,6 @@ protected slots:
private:
AudioPort m_audioPort;
MidiPort m_midiPort;
NotePlayHandle* m_notes[NumKeys];
@@ -244,6 +243,9 @@ private:
FloatModel m_volumeModel;
FloatModel m_panningModel;
AudioPort m_audioPort;
FloatModel m_pitchModel;
IntModel m_pitchRangeModel;
IntModel m_effectChannelModel;

View File

@@ -26,7 +26,7 @@
#ifndef SAMPLE_BUFFER_H
#define SAMPLE_BUFFER_H
#include <QtCore/QMutex>
#include <QtCore/QReadWriteLock>
#include <QtCore/QObject>
#include <QtCore/QRect>
@@ -151,21 +151,21 @@ public:
void setLoopStartFrame( f_cnt_t _start )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_loopStartFrame = _start;
m_varLock.unlock();
}
void setLoopEndFrame( f_cnt_t _end )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_loopEndFrame = _end;
m_varLock.unlock();
}
void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_startFrame = _start;
m_endFrame = _end;
m_loopStartFrame = _loopstart;
@@ -205,14 +205,14 @@ public:
inline void setFrequency( float _freq )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_frequency = _freq;
m_varLock.unlock();
}
inline void setSampleRate( sample_rate_t _rate )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_sampleRate = _rate;
m_varLock.unlock();
}
@@ -291,7 +291,7 @@ private:
sampleFrame * m_origData;
f_cnt_t m_origFrames;
sampleFrame * m_data;
QMutex m_varLock;
QReadWriteLock m_varLock;
f_cnt_t m_frames;
f_cnt_t m_startFrame;
f_cnt_t m_endFrame;

View File

@@ -147,8 +147,8 @@ public:
private:
AudioPort m_audioPort;
FloatModel m_volumeModel;
AudioPort m_audioPort;
friend class SampleTrackView;

View File

@@ -179,6 +179,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
}
else
{
memset( _working_buffer, 0, ( frames + offset ) * sizeof( sampleFrame ) );
emit isPlaying( 0 );
}
}

View File

@@ -160,7 +160,7 @@ void SampleBuffer::update( bool _keep_settings )
const bool lock = ( m_data != NULL );
if( lock )
{
engine::mixer()->lock();
m_varLock.lockForWrite();
MM_FREE( m_data );
}
@@ -262,7 +262,7 @@ void SampleBuffer::update( bool _keep_settings )
if( lock )
{
engine::mixer()->unlock();
m_varLock.unlock();
}
emit sampleUpdated();
@@ -598,7 +598,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
const float _freq,
const LoopMode _loopmode )
{
QMutexLocker ml( &m_varLock );
m_varLock.lockForRead();
f_cnt_t startFrame = m_startFrame;
f_cnt_t endFrame = m_endFrame;
@@ -607,6 +607,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
if( endFrame == 0 || _frames == 0 )
{
m_varLock.unlock();
return false;
}
@@ -623,6 +624,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
if( total_frames_for_current_pitch == 0 )
{
m_varLock.unlock();
return false;
}
@@ -639,6 +641,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
{
if( play_frame >= endFrame )
{
m_varLock.unlock();
return false;
}
@@ -655,6 +658,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame );
}
f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN[ _state->interpolationMode() ];
sampleFrame * tmp = NULL;
@@ -663,7 +667,6 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
{
SRC_DATA src_data;
// Generate output
f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN[ _state->interpolationMode() ];
src_data.data_in =
getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards,
loopStartFrame, loopEndFrame, endFrame )[0];
@@ -767,8 +770,8 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
_ab[i][1] *= m_amplification;
}
m_varLock.unlock();
return true;
}
@@ -1364,7 +1367,7 @@ void SampleBuffer::loadFromBase64( const QString & _data )
void SampleBuffer::setStartFrame( const f_cnt_t _s )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_startFrame = _s;
m_varLock.unlock();
}
@@ -1374,7 +1377,7 @@ void SampleBuffer::setStartFrame( const f_cnt_t _s )
void SampleBuffer::setEndFrame( const f_cnt_t _e )
{
m_varLock.lock();
m_varLock.lockForWrite();
m_endFrame = _e;
m_varLock.unlock();
}

View File

@@ -29,15 +29,20 @@
#include "engine.h"
#include "MixHelpers.h"
#include "BufferManager.h"
#include "ValueBuffer.h"
#include "panning.h"
AudioPort::AudioPort( const QString & _name, bool _has_effect_chain ) :
AudioPort::AudioPort( const QString & _name, bool _has_effect_chain,
FloatModel * volumeModel, FloatModel * panningModel ) :
m_bufferUsage( false ),
m_portBuffer( NULL ),
m_extOutputEnabled( false ),
m_nextFxChannel( 0 ),
m_name( "unnamed port" ),
m_effects( _has_effect_chain ? new EffectChain( NULL ) : NULL )
m_effects( _has_effect_chain ? new EffectChain( NULL ) : NULL ),
m_volumeModel( volumeModel ),
m_panningModel( panningModel )
{
engine::mixer()->addAudioPort( this );
setExtOutputEnabled( true );
@@ -120,10 +125,100 @@ void AudioPort::doProcessing()
}
}
if( m_bufferUsage )
{
// handle volume and panning
// has both vol and pan models
if( m_volumeModel && m_panningModel )
{
ValueBuffer * volBuf = m_volumeModel->valueBuffer();
ValueBuffer * panBuf = m_panningModel->valueBuffer();
// both vol and pan have s.ex.data:
if( volBuf && panBuf )
{
for( f_cnt_t f = 0; f < fpp; ++f )
{
float v = volBuf->values()[ f ] * 0.01f;
float p = panBuf->values()[ f ] * 0.01f;
m_portBuffer[f][0] *= ( p <= 0 ? 1.0f : 1.0f - p ) * v;
m_portBuffer[f][1] *= ( p >= 0 ? 1.0f : 1.0f + p ) * v;
}
}
// only vol has s.ex.data:
else if( volBuf )
{
float p = m_panningModel->value() * 0.01f;
float l = ( p <= 0 ? 1.0f : 1.0f - p );
float r = ( p >= 0 ? 1.0f : 1.0f + p );
for( f_cnt_t f = 0; f < fpp; ++f )
{
float v = volBuf->values()[ f ] * 0.01f;
m_portBuffer[f][0] *= v * l;
m_portBuffer[f][1] *= v * r;
}
}
// only pan has s.ex.data:
else if( panBuf )
{
float v = m_volumeModel->value() * 0.01f;
for( f_cnt_t f = 0; f < fpp; ++f )
{
float p = panBuf->values()[ f ] * 0.01f;
m_portBuffer[f][0] *= ( p <= 0 ? 1.0f : 1.0f - p ) * v;
m_portBuffer[f][1] *= ( p >= 0 ? 1.0f : 1.0f + p ) * v;
}
}
// neither has s.ex.data:
else
{
float p = m_panningModel->value() * 0.01f;
float v = m_volumeModel->value() * 0.01f;
for( f_cnt_t f = 0; f < fpp; ++f )
{
m_portBuffer[f][0] *= ( p <= 0 ? 1.0f : 1.0f - p ) * v;
m_portBuffer[f][1] *= ( p >= 0 ? 1.0f : 1.0f + p ) * v;
}
}
}
// has vol model only
else if( m_volumeModel )
{
ValueBuffer * volBuf = m_volumeModel->valueBuffer();
if( volBuf )
{
for( f_cnt_t f = 0; f < fpp; ++f )
{
float v = volBuf->values()[ f ] * 0.01f;
m_portBuffer[f][0] *= v;
m_portBuffer[f][1] *= v;
}
}
else
{
float v = m_volumeModel->value() * 0.01f;
for( f_cnt_t f = 0; f < fpp; ++f )
{
m_portBuffer[f][0] *= v;
m_portBuffer[f][1] *= v;
}
}
}
}
// as of now there's no situation where we only have panning model but no volume model
// if we have neither, we don't have to do anything here - just pass the audio as is
// handle effects
const bool me = processEffects();
if( me || m_bufferUsage )
{
engine::fxMixer()->mixToChannel( m_portBuffer, m_nextFxChannel );
engine::fxMixer()->mixToChannel( m_portBuffer, m_nextFxChannel ); // send output to fx mixer
// TODO: improve the flow here - convert to pull model
m_bufferUsage = false;
}

View File

@@ -77,6 +77,7 @@
#include "tooltip.h"
#include "track_label_button.h"
#include "ValueBuffer.h"
#include "volume.h"
const char * volume_help = QT_TRANSLATE_NOOP( "InstrumentTrack",
@@ -94,7 +95,6 @@ const int INSTRUMENT_WINDOW_CACHE_SIZE = 8;
InstrumentTrack::InstrumentTrack( TrackContainer* tc ) :
track( track::InstrumentTrack, tc ),
MidiEventProcessor(),
m_audioPort( tr( "unnamed_track" ) ),
m_midiPort( tr( "unnamed_track" ), engine::mixer()->midiClient(),
this, this ),
m_notes(),
@@ -104,6 +104,7 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) :
tr( "Base note" ) ),
m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 0.1f, this, tr( "Volume" ) ),
m_panningModel( DefaultPanning, PanningLeft, PanningRight, 0.1f, this, tr( "Panning" ) ),
m_audioPort( tr( "unnamed_track" ), true, &m_volumeModel, &m_panningModel ),
m_pitchModel( 0, MinPitchDefault, MaxPitchDefault, 1, this, tr( "Pitch" ) ),
m_pitchRangeModel( 1, 1, 24, this, tr( "Pitch range" ) ),
m_effectChannelModel( 0, 0, 0, this, tr( "FX channel" ) ),
@@ -188,10 +189,10 @@ void InstrumentTrack::processAudioBuffer( sampleFrame* buf, const fpp_t frames,
// get volume knob data
static const float DefaultVolumeRatio = 1.0f / DefaultVolume;
ValueBuffer * volBuf = m_volumeModel.valueBuffer();
/*ValueBuffer * volBuf = m_volumeModel.valueBuffer();
float v_scale = volBuf
? 1.0f
: getVolume() * DefaultVolumeRatio;
: getVolume() * DefaultVolumeRatio;*/
// instruments using instrument-play-handles will call this method
// without any knowledge about notes, so they pass NULL for n, which
@@ -200,44 +201,19 @@ void InstrumentTrack::processAudioBuffer( sampleFrame* buf, const fpp_t frames,
{
const f_cnt_t offset = n->noteOffset();
m_soundShaping.processAudioBuffer( buf + offset, frames - offset, n );
v_scale *= ( (float) n->getVolume() * DefaultVolumeRatio );
const float vol = ( (float) n->getVolume() * DefaultVolumeRatio );
const panning_t pan = qBound( PanningLeft, n->getPanning(), PanningRight );
stereoVolumeVector vv = panningToVolumeVector( pan, vol );
for( f_cnt_t f = offset; f < frames; ++f )
{
for( int c = 0; c < 2; ++c )
{
buf[f][c] *= vv.vol[c];
}
}
}
m_audioPort.setNextFxChannel( m_effectChannelModel.value() );
// get panning knob data
ValueBuffer * panBuf = m_panningModel.valueBuffer();
int panning = panBuf
? 0
: m_panningModel.value();
if( n )
{
panning += n->getPanning();
panning = tLimit<int>( panning, PanningLeft, PanningRight );
}
// apply sample-exact volume/panning data
if( volBuf )
{
for( f_cnt_t f = 0; f < frames; ++f )
{
float v = volBuf->values()[ f ] * 0.01f;
buf[f][0] *= v;
buf[f][1] *= v;
}
}
if( panBuf )
{
for( f_cnt_t f = 0; f < frames; ++f )
{
float p = panBuf->values()[ f ] * 0.01f;
buf[f][0] *= ( p <= 0 ? 1.0f : 1.0f - p );
buf[f][1] *= ( p >= 0 ? 1.0f : 1.0f + p );
}
}
//engine::mixer()->bufferToPort( buf, frames, panningToVolumeVector( panning, v_scale ), &m_audioPort );
}

View File

@@ -403,9 +403,9 @@ void SampleTCOView::paintEvent( QPaintEvent * _pe )
SampleTrack::SampleTrack( TrackContainer* tc ) :
track( track::SampleTrack, tc ),
m_audioPort( tr( "Sample track" ) ),
m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 1.0, this,
tr( "Volume" ) )
tr( "Volume" ) ),
m_audioPort( tr( "Sample track" ), true, &m_volumeModel, NULL )
{
setName( tr( "Sample track" ) );
}