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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -147,8 +147,8 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
AudioPort m_audioPort;
|
||||
FloatModel m_volumeModel;
|
||||
AudioPort m_audioPort;
|
||||
|
||||
|
||||
friend class SampleTrackView;
|
||||
|
||||
@@ -179,6 +179,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( _working_buffer, 0, ( frames + offset ) * sizeof( sampleFrame ) );
|
||||
emit isPlaying( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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" ) );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user