Defer updates to SampleBuffer
Removed global lock from the Mixer
This commit is contained in:
@@ -184,9 +184,9 @@ public:
|
||||
// audio-port-stuff
|
||||
inline void addAudioPort( AudioPort * _port )
|
||||
{
|
||||
lock();
|
||||
requestChangeInModel();
|
||||
m_audioPorts.push_back( _port );
|
||||
unlock();
|
||||
doneChangeInModel();
|
||||
}
|
||||
|
||||
void removeAudioPort( AudioPort * _port );
|
||||
@@ -274,16 +274,6 @@ public:
|
||||
|
||||
|
||||
// methods needed by other threads to alter knob values, waveforms, etc
|
||||
void lock()
|
||||
{
|
||||
m_globalMutex.lock();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
m_globalMutex.unlock();
|
||||
}
|
||||
|
||||
void lockInputFrames()
|
||||
{
|
||||
m_inputFramesMutex.lock();
|
||||
@@ -429,7 +419,6 @@ private:
|
||||
QString m_midiClientName;
|
||||
|
||||
// mutexes
|
||||
QMutex m_globalMutex;
|
||||
QMutex m_inputFramesMutex;
|
||||
QMutex m_playHandleMutex; // mutex used only for adding playhandles
|
||||
QMutex m_playHandleRemovalMutex;
|
||||
|
||||
@@ -151,19 +151,16 @@ public:
|
||||
|
||||
void setLoopStartFrame( f_cnt_t _start )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_loopStartFrame = _start;
|
||||
}
|
||||
|
||||
void setLoopEndFrame( f_cnt_t _end )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_loopEndFrame = _end;
|
||||
}
|
||||
|
||||
void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_startFrame = _start;
|
||||
m_endFrame = _end;
|
||||
m_loopStartFrame = _loopstart;
|
||||
@@ -202,13 +199,11 @@ public:
|
||||
|
||||
inline void setFrequency( float _freq )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_frequency = _freq;
|
||||
}
|
||||
|
||||
inline void setSampleRate( sample_rate_t _rate )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_sampleRate = _rate;
|
||||
}
|
||||
|
||||
@@ -224,31 +219,37 @@ public:
|
||||
QString & toBase64( QString & _dst ) const;
|
||||
|
||||
|
||||
static SampleBuffer * resample( sampleFrame * _data,
|
||||
const f_cnt_t _frames,
|
||||
const sample_rate_t _src_sr,
|
||||
// protect calls from the GUI to this function with dataReadLock() and
|
||||
// dataUnlock()
|
||||
SampleBuffer * resample( const sample_rate_t _src_sr,
|
||||
const sample_rate_t _dst_sr );
|
||||
|
||||
static inline SampleBuffer * resample( SampleBuffer * _buf,
|
||||
const sample_rate_t _src_sr,
|
||||
const sample_rate_t _dst_sr )
|
||||
{
|
||||
return resample( _buf->m_data, _buf->m_frames, _src_sr,
|
||||
_dst_sr );
|
||||
}
|
||||
|
||||
void normalizeSampleRate( const sample_rate_t _src_sr,
|
||||
bool _keep_settings = false );
|
||||
|
||||
// protect calls from the GUI to this function with dataReadLock() and
|
||||
// dataUnlock(), out of loops for efficiency
|
||||
inline sample_t userWaveSample( const float _sample ) const
|
||||
{
|
||||
const float frame = _sample * m_frames;
|
||||
f_cnt_t f1 = static_cast<f_cnt_t>( frame ) % m_frames;
|
||||
f_cnt_t frames = m_frames;
|
||||
sampleFrame * data = m_data;
|
||||
const float frame = _sample * frames;
|
||||
f_cnt_t f1 = static_cast<f_cnt_t>( frame ) % frames;
|
||||
if( f1 < 0 )
|
||||
{
|
||||
f1 += m_frames;
|
||||
f1 += frames;
|
||||
}
|
||||
return linearInterpolate( m_data[f1][0], m_data[ (f1 + 1) % m_frames ][0], fraction( frame ) );
|
||||
return linearInterpolate( data[f1][0], data[ (f1 + 1) % frames ][0], fraction( frame ) );
|
||||
}
|
||||
|
||||
void dataReadLock()
|
||||
{
|
||||
m_varLock.lockForRead();
|
||||
}
|
||||
|
||||
void dataUnlock()
|
||||
{
|
||||
m_varLock.unlock();
|
||||
}
|
||||
|
||||
static QString tryToMakeRelative( const QString & _file );
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
#include "MidiTime.h"
|
||||
#include "PlayHandle.h"
|
||||
#include "SampleBuffer.h"
|
||||
|
||||
class BBTrack;
|
||||
class SampleBuffer;
|
||||
class SampleTCO;
|
||||
class Track;
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "Mixer.h"
|
||||
#include "NotePlayHandle.h"
|
||||
#include "Knob.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "Song.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "endian_handling.h"
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <samplerate.h>
|
||||
|
||||
#include "Instrument.h"
|
||||
#include "PixmapButton.h"
|
||||
@@ -37,7 +38,6 @@
|
||||
#include "Knob.h"
|
||||
#include "LcdSpinBox.h"
|
||||
#include "LedCheckbox.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "gig.h"
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "Mixer.h"
|
||||
#include "NotePlayHandle.h"
|
||||
#include "Knob.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "Song.h"
|
||||
|
||||
#include "patches_dialog.h"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define SF2_PLAYER_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <samplerate.h>
|
||||
|
||||
#include "Instrument.h"
|
||||
#include "PixmapButton.h"
|
||||
@@ -36,7 +37,6 @@
|
||||
#include "LcdSpinBox.h"
|
||||
#include "LedCheckbox.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
class sf2InstrumentView;
|
||||
|
||||
@@ -644,7 +644,7 @@ void VestigeInstrumentView::openPlugin()
|
||||
{
|
||||
return;
|
||||
}
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
|
||||
if (m_vi->p_subWindow != NULL) {
|
||||
delete m_vi->p_subWindow;
|
||||
@@ -652,7 +652,7 @@ void VestigeInstrumentView::openPlugin()
|
||||
}
|
||||
|
||||
m_vi->loadFile( ofd.selectedFiles()[0] );
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
if( m_vi->m_plugin && m_vi->m_plugin->pluginWidget() )
|
||||
{
|
||||
m_vi->m_plugin->pluginWidget()->setWindowIcon(
|
||||
|
||||
@@ -122,9 +122,9 @@ void EffectChain::loadSettings( const QDomElement & _this )
|
||||
|
||||
void EffectChain::appendEffect( Effect * _effect )
|
||||
{
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
m_effects.append( _effect );
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
|
||||
emit dataChanged();
|
||||
}
|
||||
@@ -134,21 +134,18 @@ void EffectChain::appendEffect( Effect * _effect )
|
||||
|
||||
void EffectChain::removeEffect( Effect * _effect )
|
||||
{
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
|
||||
Effect ** found = qFind( m_effects.begin(), m_effects.end(), _effect );
|
||||
if( found == m_effects.end() )
|
||||
{
|
||||
goto fail;
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
return;
|
||||
}
|
||||
m_effects.erase( found );
|
||||
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
emit dataChanged();
|
||||
return;
|
||||
|
||||
fail:
|
||||
Engine::mixer()->unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +249,7 @@ void EffectChain::clear()
|
||||
{
|
||||
emit aboutToClear();
|
||||
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
|
||||
m_enabledModel.setValue( false );
|
||||
for( int i = 0; i < m_effects.count(); ++i )
|
||||
@@ -261,5 +258,5 @@ void EffectChain::clear()
|
||||
}
|
||||
m_effects.clear();
|
||||
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
@@ -285,8 +285,8 @@ void FxMixer::toggledSolo()
|
||||
|
||||
void FxMixer::deleteChannel( int index )
|
||||
{
|
||||
// lock the mixer so channel deletion is performed between mixer rounds
|
||||
Engine::mixer()->lock();
|
||||
// channel deletion is performed between mixer rounds
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
|
||||
FxChannel * ch = m_fxChannels[index];
|
||||
|
||||
@@ -347,7 +347,7 @@ void FxMixer::deleteChannel( int index )
|
||||
}
|
||||
}
|
||||
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ Mixer::Mixer( bool renderOnly ) :
|
||||
m_audioDev( NULL ),
|
||||
m_oldAudioDev( NULL ),
|
||||
m_audioDevStartFailed( false ),
|
||||
m_globalMutex( QMutex::Recursive ),
|
||||
m_profiler(),
|
||||
m_metronomeActive(false),
|
||||
m_changesSignal( false ),
|
||||
@@ -386,10 +385,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
|
||||
}
|
||||
unlockPlayHandleRemoval();
|
||||
|
||||
// now we have to make sure no other thread does anything bad
|
||||
// while we're acting...
|
||||
lock();
|
||||
|
||||
// rotate buffers
|
||||
m_writeBuffer = ( m_writeBuffer + 1 ) % m_poolDepth;
|
||||
m_readBuffer = ( m_readBuffer + 1 ) % m_poolDepth;
|
||||
@@ -453,8 +448,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
|
||||
// STAGE 3: do master mix in FX mixer
|
||||
fxMixer->masterMix( m_writeBuf );
|
||||
|
||||
unlock();
|
||||
|
||||
|
||||
emit nextAudioBuffer( m_readBuf );
|
||||
|
||||
@@ -481,7 +474,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
|
||||
void Mixer::clear()
|
||||
{
|
||||
// TODO: m_midiClient->noteOffAll();
|
||||
lock();
|
||||
lockPlayHandleRemoval();
|
||||
for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ++it )
|
||||
{
|
||||
@@ -493,7 +485,6 @@ void Mixer::clear()
|
||||
}
|
||||
}
|
||||
unlockPlayHandleRemoval();
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -620,9 +611,7 @@ void Mixer::removeAudioPort( AudioPort * _port )
|
||||
_port );
|
||||
if( it != m_audioPorts.end() )
|
||||
{
|
||||
lock();
|
||||
m_audioPorts.erase( it );
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +639,7 @@ bool Mixer::addPlayHandle( PlayHandle* handle )
|
||||
|
||||
void Mixer::removePlayHandle( PlayHandle * _ph )
|
||||
{
|
||||
lockPlayHandleRemoval();
|
||||
requestChangeInModel();
|
||||
// check thread affinity as we must not delete play-handles
|
||||
// which were created in a thread different than mixer thread
|
||||
if( _ph->affinityMatters() &&
|
||||
@@ -694,7 +683,7 @@ void Mixer::removePlayHandle( PlayHandle * _ph )
|
||||
{
|
||||
m_playHandlesToRemove.push_back( _ph );
|
||||
}
|
||||
unlockPlayHandleRemoval();
|
||||
doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -702,7 +691,7 @@ void Mixer::removePlayHandle( PlayHandle * _ph )
|
||||
|
||||
void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types )
|
||||
{
|
||||
lockPlayHandleRemoval();
|
||||
requestChangeInModel();
|
||||
PlayHandleList::Iterator it = m_playHandles.begin();
|
||||
while( it != m_playHandles.end() )
|
||||
{
|
||||
@@ -721,7 +710,7 @@ void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types )
|
||||
++it;
|
||||
}
|
||||
}
|
||||
unlockPlayHandleRemoval();
|
||||
doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -729,18 +718,13 @@ void Mixer::removePlayHandlesOfTypes( Track * _track, const quint8 types )
|
||||
|
||||
bool Mixer::hasNotePlayHandles()
|
||||
{
|
||||
lock();
|
||||
|
||||
for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ++it )
|
||||
{
|
||||
if( (*it)->type() == PlayHandle::TypeNotePlayHandle )
|
||||
{
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ void SampleBuffer::update( bool _keep_settings )
|
||||
const bool lock = ( m_data != NULL );
|
||||
if( lock )
|
||||
{
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
m_varLock.lockForWrite();
|
||||
MM_FREE( m_data );
|
||||
}
|
||||
@@ -270,6 +271,7 @@ void SampleBuffer::update( bool _keep_settings )
|
||||
if( lock )
|
||||
{
|
||||
m_varLock.unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
emit sampleUpdated();
|
||||
@@ -354,7 +356,7 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr,
|
||||
// do samplerate-conversion to our default-samplerate
|
||||
if( _src_sr != Engine::mixer()->baseSampleRate() )
|
||||
{
|
||||
SampleBuffer * resampled = resample( this, _src_sr,
|
||||
SampleBuffer * resampled = resample( _src_sr,
|
||||
Engine::mixer()->baseSampleRate() );
|
||||
MM_FREE( m_data );
|
||||
m_frames = resampled->frames();
|
||||
@@ -597,8 +599,6 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
const float _freq,
|
||||
const LoopMode _loopmode )
|
||||
{
|
||||
QReadLocker readLocker(&m_varLock);
|
||||
|
||||
f_cnt_t startFrame = m_startFrame;
|
||||
f_cnt_t endFrame = m_endFrame;
|
||||
f_cnt_t loopStartFrame = m_loopStartFrame;
|
||||
@@ -1147,12 +1147,12 @@ QString & SampleBuffer::toBase64( QString & _dst ) const
|
||||
|
||||
|
||||
|
||||
SampleBuffer * SampleBuffer::resample( sampleFrame * _data,
|
||||
const f_cnt_t _frames,
|
||||
const sample_rate_t _src_sr,
|
||||
SampleBuffer * SampleBuffer::resample( const sample_rate_t _src_sr,
|
||||
const sample_rate_t _dst_sr )
|
||||
{
|
||||
const f_cnt_t dst_frames = static_cast<f_cnt_t>( _frames /
|
||||
sampleFrame * data = m_data;
|
||||
const f_cnt_t frames = m_frames;
|
||||
const f_cnt_t dst_frames = static_cast<f_cnt_t>( frames /
|
||||
(float) _src_sr * (float) _dst_sr );
|
||||
SampleBuffer * dst_sb = new SampleBuffer( dst_frames );
|
||||
sampleFrame * dst_buf = dst_sb->m_origData;
|
||||
@@ -1165,9 +1165,9 @@ SampleBuffer * SampleBuffer::resample( sampleFrame * _data,
|
||||
{
|
||||
SRC_DATA src_data;
|
||||
src_data.end_of_input = 1;
|
||||
src_data.data_in = _data[0];
|
||||
src_data.data_in = data[0];
|
||||
src_data.data_out = dst_buf[0];
|
||||
src_data.input_frames = _frames;
|
||||
src_data.input_frames = frames;
|
||||
src_data.output_frames = dst_frames;
|
||||
src_data.src_ratio = (double) _dst_sr / _src_sr;
|
||||
if( ( error = src_process( state, &src_data ) ) )
|
||||
@@ -1355,7 +1355,6 @@ void SampleBuffer::loadFromBase64( const QString & _data )
|
||||
|
||||
void SampleBuffer::setStartFrame( const f_cnt_t _s )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_startFrame = _s;
|
||||
}
|
||||
|
||||
@@ -1364,7 +1363,6 @@ void SampleBuffer::setStartFrame( const f_cnt_t _s )
|
||||
|
||||
void SampleBuffer::setEndFrame( const f_cnt_t _e )
|
||||
{
|
||||
QWriteLocker writeLocker(&m_varLock);
|
||||
m_endFrame = _e;
|
||||
}
|
||||
|
||||
|
||||
@@ -790,7 +790,7 @@ void Song::clearProject()
|
||||
}
|
||||
|
||||
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
|
||||
if( gui && gui->getBBEditor() )
|
||||
{
|
||||
@@ -831,7 +831,7 @@ void Song::clearProject()
|
||||
AutomationPattern::globalAutomationPattern( &m_masterPitchModel )->
|
||||
clear();
|
||||
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
|
||||
if( gui && gui->getProjectNotes() )
|
||||
{
|
||||
@@ -963,7 +963,7 @@ void Song::loadProject( const QString & fileName )
|
||||
|
||||
DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeLoad );
|
||||
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
|
||||
// get the header information from the DOM
|
||||
m_tempoModel.loadSettings( dataFile.head(), "bpm" );
|
||||
@@ -1050,7 +1050,7 @@ void Song::loadProject( const QString & fileName )
|
||||
AutomationPattern::resolveAllIDs();
|
||||
|
||||
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
|
||||
ConfigManager::inst()->addRecentlyOpenedProject( fileName );
|
||||
|
||||
|
||||
@@ -534,7 +534,7 @@ void FileBrowserTreeWidget::mouseReleaseEvent(QMouseEvent * me )
|
||||
|
||||
void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it )
|
||||
{
|
||||
Engine::mixer()->lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
switch( f->handling() )
|
||||
{
|
||||
case FileItem::LoadAsProject:
|
||||
@@ -582,7 +582,7 @@ void FileBrowserTreeWidget::handleFile(FileItem * f, InstrumentTrack * it )
|
||||
break;
|
||||
|
||||
}
|
||||
Engine::mixer()->unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -604,12 +604,10 @@ void FileBrowserTreeWidget::activateListItem(QTreeWidgetItem * item,
|
||||
}
|
||||
else if( f->handling() != FileItem::NotSupported )
|
||||
{
|
||||
// engine::mixer()->lock();
|
||||
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
|
||||
Track::create( Track::InstrumentTrack,
|
||||
Engine::getBBTrackContainer() ) );
|
||||
handleFile( f, it );
|
||||
// engine::mixer()->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,11 +619,9 @@ void FileBrowserTreeWidget::openInNewInstrumentTrack( TrackContainer* tc )
|
||||
if( m_contextMenuItem->handling() == FileItem::LoadAsPreset ||
|
||||
m_contextMenuItem->handling() == FileItem::LoadByPlugin )
|
||||
{
|
||||
// engine::mixer()->lock();
|
||||
InstrumentTrack * it = dynamic_cast<InstrumentTrack *>(
|
||||
Track::create( Track::InstrumentTrack, tc ) );
|
||||
handleFile( m_contextMenuItem, it );
|
||||
// engine::mixer()->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -508,6 +508,8 @@ void EnvelopeAndLfoView::paintEvent( QPaintEvent * )
|
||||
osc_frames *= 100.0f;
|
||||
}
|
||||
|
||||
// userWaveSample() may be used, called out of loop for efficiency
|
||||
m_params->m_userWave.dataReadLock();
|
||||
float old_y = 0;
|
||||
for( int x = 0; x <= LFO_GRAPH_W; ++x )
|
||||
{
|
||||
@@ -558,6 +560,7 @@ void EnvelopeAndLfoView::paintEvent( QPaintEvent * )
|
||||
graph_y_base + cur_y ) );
|
||||
old_y = cur_y;
|
||||
}
|
||||
m_params->m_userWave.dataUnlock();
|
||||
|
||||
p.setPen( QColor( 201, 201, 225 ) );
|
||||
int ms_per_osc = static_cast<int>( SECS_PER_LFO_OSCILLATION *
|
||||
|
||||
@@ -585,11 +585,13 @@ QString graphModel::setWaveToUser()
|
||||
QString fileName = sampleBuffer->openAndSetWaveformFile();
|
||||
if( fileName.isEmpty() == false )
|
||||
{
|
||||
sampleBuffer->dataReadLock();
|
||||
for( int i = 0; i < length(); i++ )
|
||||
{
|
||||
m_samples[i] = sampleBuffer->userWaveSample(
|
||||
i / static_cast<float>( length() ) );
|
||||
}
|
||||
sampleBuffer->dataUnlock();
|
||||
}
|
||||
|
||||
sharedObject::unref( sampleBuffer );
|
||||
|
||||
Reference in New Issue
Block a user