diff --git a/ChangeLog b/ChangeLog index afee01278..8556e6bbd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2006-09-18 Tobias Doerffel + + * plugins/vestige/vestige.h: + * plugins/vestige/vestige.cpp: + * plugin/vestige/lvsl_client.h: + * plugin/vestige/lvsl_client.cpp: + take advantage of LMMS' new parallelizing-support - works indeed the + way expected! all VST-servers are now balanced all over available CPUs + + * plugins/audio_file_processor/audio_file_processor.h: + * plugins/audio_file_processor/audio_file_processor.cpp: + * plugins/bit_invader/bit_invader.h: + * plugins/bit_invader/bit_invader.cpp: + * plugins/organic/organic.h: + * plugins/organic/organic.cpp: + * plugins/plucked_string_synth/plucked_string_synth.h: + * plugins/plucked_string_synth/plucked_string_synth.cpp: + * plugins/mallets/mallets.h: + * plugins/mallets/mallets.cpp: + * plugins/vestige/vestige.h: + * plugins/vestige/vestige.cpp: + * plugins/vibed/vibed.h: + * plugins/vibed/vibed.cpp: + * include/instrument.h: + * include/instrument_play_handle.h: + * include/mixer.h: + * include/note_play_handle.h: + * include/play_handle.h: + * include/plugin.h: + * include/preset_preview_play_handle.h: + * include/sample_play_handle.h: + * include/setup_dialog.h: + * include/track.h: + * src/core/instrument.cpp: + * src/core/mixer.cpp: + * src/core/plugin.cpp: + * src/core/preset_preview_play_handle.cpp: + * src/core/sample_play_handle.cpp: + * src/core/setup_dialog.cpp: + * src/tracks/instrument_track.cpp: + added first simple support for parallelizing sound-processing for + using full power of SMP-systems (e.g. my new dual-core-notebook :-) + 2006-09-17 Javier Serrano Polo * include/tempo_sync_knob.h: diff --git a/configure.in b/configure.in index 0328efebf..3d8746e73 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(lmms, 0.2.1-cvs20060917, lmms-devel/at/lists/dot/sf/dot/net) -AM_INIT_AUTOMAKE(lmms, 0.2.1-cvs20060917) +AC_INIT(lmms, 0.2.1-cvs20060918, lmms-devel/at/lists/dot/sf/dot/net) +AM_INIT_AUTOMAKE(lmms, 0.2.1-cvs20060918) AM_CONFIG_HEADER(config.h) diff --git a/include/instrument.h b/include/instrument.h index 5f4026511..15d86f7b4 100644 --- a/include/instrument.h +++ b/include/instrument.h @@ -67,10 +67,11 @@ public: // if the plugin doesn't play each note, it can create an instrument- // play-handle and re-implement this method, so that it mixes it's // output buffer only once per mixer-period - virtual void play( void ); + virtual void play( bool _try_parallelizing = FALSE ); // to be overloaded by actual plugin - virtual void FASTCALL playNote( notePlayHandle * note_to_play ); + virtual void FASTCALL playNote( notePlayHandle * note_to_play, + bool _try_parallelizing ); // needed for deleting plugin-specific-data of a note - plugin has to // cast void-ptr so that the plugin-data is deleted properly @@ -92,6 +93,10 @@ public: return( m_valid ); } + inline virtual bool notePlayHandleBased( void ) const + { + return( TRUE ); + } // instantiate instrument-plugin with given name or return NULL // on failure diff --git a/include/instrument_play_handle.h b/include/instrument_play_handle.h index b663836d1..78c082bc1 100644 --- a/include/instrument_play_handle.h +++ b/include/instrument_play_handle.h @@ -34,7 +34,7 @@ class instrumentPlayHandle : public playHandle { public: inline instrumentPlayHandle( instrument * _instrument ) : - playHandle( INSTRUMENT_PLAY_HANDLE ), + playHandle( InstrumentPlayHandle ), m_instrument( _instrument ) { } @@ -44,11 +44,11 @@ public: } - inline virtual void play( void ) + inline virtual void play( bool _try_parallelizing ) { if( m_instrument != NULL ) { - m_instrument->play(); + m_instrument->play( _try_parallelizing ); } } @@ -65,6 +65,23 @@ public: } } + inline virtual bool supportsParallelizing( void ) const + { + if( m_instrument != NULL ) + { + return( m_instrument->supportsParallelizing() ); + } + return( FALSE ); + } + + inline virtual void waitForWorkerThread( void ) + { + if( m_instrument != NULL ) + { + m_instrument->waitForWorkerThread(); + } + } + private: instrument * m_instrument; diff --git a/include/instrument_track.h b/include/instrument_track.h index 22447e0ff..41dfcab24 100755 --- a/include/instrument_track.h +++ b/include/instrument_track.h @@ -54,6 +54,7 @@ #include "tab_widget.h" #include "engine.h" #include "volume_knob.h" +#include "instrument.h" class QLineEdit; class arpAndChordsTabWidget; @@ -61,7 +62,6 @@ class audioPort; class instrumentTrackButton; class envelopeTabWidget; class fadeButton; -class instrument; class lcdSpinBox; class midiPort; class midiTabWidget; @@ -96,6 +96,7 @@ public: virtual void FASTCALL processOutEvent( const midiEvent & _me, const midiTime & _time ); + // returns the frequency of a given tone & octave. // This function also includes base_tone & base_octave in // its calculations @@ -105,7 +106,7 @@ public: // for capturing note-play-events -> need that for arpeggio, // filter and so on - void FASTCALL playNote( notePlayHandle * _n ); + void FASTCALL playNote( notePlayHandle * _n, bool _try_parallelizing ); QString instrumentName( void ) const; void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/include/mixer.h b/include/mixer.h index ec9b3f809..eba5e8d52 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -328,7 +328,7 @@ private: Uint8 m_writeBuffer; Uint8 m_analBuffer; Uint8 m_poolDepth; - + bool m_scaleClip; surroundSampleFrame m_maxClip; surroundSampleFrame m_previousSample; @@ -338,6 +338,7 @@ private: bool m_newBuffer[SURROUND_CHANNELS]; Uint8 m_cpuLoad; + int m_parallelizingLevel; playHandleVector m_playHandles; playHandleVector m_playHandlesToRemove; diff --git a/include/note_play_handle.h b/include/note_play_handle.h index 0a7c890be..d092c256f 100644 --- a/include/note_play_handle.h +++ b/include/note_play_handle.h @@ -33,9 +33,9 @@ #include "basic_filters.h" #include "bb_track.h" #include "note.h" +#include "instrument_track.h" -class instrumentTrack; class notePlayHandle; typedef vvector notePlayHandleVector; @@ -51,13 +51,14 @@ public: float m_frequency; - notePlayHandle( instrumentTrack * _chnl_trk, const f_cnt_t _frames_ahead, + notePlayHandle( instrumentTrack * _chnl_trk, + const f_cnt_t _frames_ahead, const f_cnt_t _frames, const note & _n, const bool _arp_note = FALSE ); virtual ~notePlayHandle(); - virtual void play( void ); + virtual void play( bool _try_parallelizing ); virtual inline bool done( void ) const { @@ -182,6 +183,26 @@ public: } + virtual bool supportsParallelizing( void ) const + { + return( m_instrumentTrack->m_instrument-> + supportsParallelizing() + && + // we must not parallelize note-play-handles, which + // belong to instruments that are instrument-play- + // handle-driven, because then waitForWorkerThread() + // would be additionally called for each + // note-play-handle which results in hangups + m_instrumentTrack->m_instrument-> + notePlayHandleBased() ); + } + + virtual void waitForWorkerThread( void ) + { + m_instrumentTrack->m_instrument->waitForWorkerThread(); + } + + private: instrumentTrack * m_instrumentTrack; // needed for calling // instrumentTrack::playNote diff --git a/include/play_handle.h b/include/play_handle.h index 0affb45cb..c2ce57ee4 100644 --- a/include/play_handle.h +++ b/include/play_handle.h @@ -49,8 +49,10 @@ class playHandle public: enum types { - NOTE_PLAY_HANDLE, INSTRUMENT_PLAY_HANDLE, SAMPLE_PLAY_HANDLE, - PRESET_PREVIEW_PLAY_HANDLE + NotePlayHandle, + InstrumentPlayHandle, + SamplePlayHandle, + PresetPreviewHandle } ; playHandle( const types _type ) : @@ -67,7 +69,7 @@ public: return( m_type ); } - virtual void play( void ) = 0; + virtual void play( bool _try_parallelizing = FALSE ) = 0; virtual bool done( void ) const = 0; // play-handles can invalidate themselves if an object they depend on @@ -79,6 +81,15 @@ public: { } + virtual bool supportsParallelizing( void ) const + { + return( FALSE ); + } + + virtual void waitForWorkerThread( void ) + { + } + private: types m_type; diff --git a/include/plugin.h b/include/plugin.h index 76ccb2d22..5adee1c1c 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -70,6 +70,8 @@ public: ImportFilter, // filter for importing a file ExportFilter, // filter for exporting a file AnalysisTools, // analysis-tools (level-meter etc) + Libary, // simple library holding a code-base for + // several other plugins (e.g. LADSPA-support) Other, Undefined = 255 } ; @@ -187,7 +189,21 @@ public: static plugin * FASTCALL instantiate( const QString & _plugin_name, void * _data ); - // fills given vector with descriptors for all available plugins + // some plugins run external programs for doing their actual work + // (e.g. LVSL-server) or can run in separate worker-threads, so the + // mixer can schedule processing for parallelizing work which is very + // important for at least trying to use the full power of SMP-systems, + // otherwise the mixer will create according threads on it's own which + // of course isn't that efficient + virtual bool supportsParallelizing( void ) const; + + // plugins supporting parallelizing, should re-implement that as the + // mixer will call this at the end of processing according chain + // of plugins + virtual void waitForWorkerThread( void ); + + + // fills given vector with descriptors of all available plugins static void FASTCALL getDescriptorsOfAvailPlugins( vvector & _plugin_descs ); diff --git a/include/preset_preview_play_handle.h b/include/preset_preview_play_handle.h index 3da8d8aef..e77546102 100644 --- a/include/preset_preview_play_handle.h +++ b/include/preset_preview_play_handle.h @@ -56,7 +56,7 @@ public: engine * _engine ); virtual ~presetPreviewPlayHandle(); - virtual void play( void ); + virtual void play( bool _try_parallelizing ); virtual bool done( void ) const; static void cleanUp( engine * _engine ); diff --git a/include/sample_play_handle.h b/include/sample_play_handle.h index 9f94749f0..cd9dfd3c0 100644 --- a/include/sample_play_handle.h +++ b/include/sample_play_handle.h @@ -50,8 +50,8 @@ public: samplePlayHandle( pattern * _pattern ); virtual ~samplePlayHandle(); - virtual void play( void ); - void play( const fpab_t _frame_base ); + virtual void play( bool _try_parallelizing ); + void play( const fpab_t _frame_base, bool _try_parallelizing ); virtual bool done( void ) const; f_cnt_t totalFrames( void ) const; diff --git a/include/setup_dialog.h b/include/setup_dialog.h index 362db7c4e..a6ec8955a 100644 --- a/include/setup_dialog.h +++ b/include/setup_dialog.h @@ -112,6 +112,7 @@ private slots: void toggleDisableChActInd( bool _disabled ); void toggleManualChPiano( bool _enabled ); + void setParallelizingLevel( int _level ); private: @@ -153,7 +154,7 @@ private: bool m_disableChActInd; bool m_manualChPiano; - + int m_parLevel; typedef QMap aswMap; typedef QMap mswMap; diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index b2627bdcb..98143eacb 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -392,7 +392,7 @@ void audioFileProcessor::setAudioFile( const QString & _audio_file, bool _rename -void audioFileProcessor::playNote( notePlayHandle * _n ) +void audioFileProcessor::playNote( notePlayHandle * _n, bool ) { const Uint32 frames = eng()->getMixer()->framesPerAudioBuffer(); sampleFrame * buf = bufferAllocator::alloc( frames ); diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h index 4dfdb2e2a..d57a4866f 100644 --- a/plugins/audio_file_processor/audio_file_processor.h +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -56,7 +56,8 @@ public: audioFileProcessor( instrumentTrack * _channel_track ); virtual ~audioFileProcessor(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); virtual void FASTCALL saveSettings( QDomDocument & _doc, diff --git a/plugins/bit_invader/bit_invader.cpp b/plugins/bit_invader/bit_invader.cpp index d393ba609..f34a84ed3 100644 --- a/plugins/bit_invader/bit_invader.cpp +++ b/plugins/bit_invader/bit_invader.cpp @@ -681,7 +681,7 @@ void bitInvader::smoothClicked( void ) -void bitInvader::playNote( notePlayHandle * _n ) +void bitInvader::playNote( notePlayHandle * _n, bool ) { if ( _n->totalFramesPlayed() == 0 ) { diff --git a/plugins/bit_invader/bit_invader.h b/plugins/bit_invader/bit_invader.h index af3b680cc..50c2528f5 100644 --- a/plugins/bit_invader/bit_invader.h +++ b/plugins/bit_invader/bit_invader.h @@ -68,7 +68,8 @@ public: bitInvader(instrumentTrack * _channel_track ); virtual ~bitInvader(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp index 8a4bce74c..f9639a5b4 100644 --- a/plugins/organic/organic.cpp +++ b/plugins/organic/organic.cpp @@ -297,7 +297,7 @@ QString organicInstrument::nodeName( void ) const -void organicInstrument::playNote( notePlayHandle * _n ) +void organicInstrument::playNote( notePlayHandle * _n, bool ) { if( _n->totalFramesPlayed() == 0 ) { diff --git a/plugins/organic/organic.h b/plugins/organic/organic.h index 5c58f612b..2de31e5f6 100644 --- a/plugins/organic/organic.h +++ b/plugins/organic/organic.h @@ -47,7 +47,8 @@ public: organicInstrument( instrumentTrack * _channel_track ); virtual ~organicInstrument(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/plugins/plucked_string_synth/plucked_string_synth.cpp b/plugins/plucked_string_synth/plucked_string_synth.cpp index 853b8d69d..8b8b4db16 100644 --- a/plugins/plucked_string_synth/plucked_string_synth.cpp +++ b/plugins/plucked_string_synth/plucked_string_synth.cpp @@ -133,7 +133,7 @@ QString pluckedStringSynth::nodeName( void ) const -void pluckedStringSynth::playNote( notePlayHandle * _n ) +void pluckedStringSynth::playNote( notePlayHandle * _n, bool ) { if ( _n->totalFramesPlayed() == 0 ) { diff --git a/plugins/plucked_string_synth/plucked_string_synth.h b/plugins/plucked_string_synth/plucked_string_synth.h index 329641cc3..8986b9f93 100644 --- a/plugins/plucked_string_synth/plucked_string_synth.h +++ b/plugins/plucked_string_synth/plucked_string_synth.h @@ -197,7 +197,8 @@ public: pluckedStringSynth( instrumentTrack * _channel_track ); virtual ~pluckedStringSynth(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/plugins/stk/mallets/mallets.cpp b/plugins/stk/mallets/mallets.cpp index ca971e533..1e368ab14 100644 --- a/plugins/stk/mallets/mallets.cpp +++ b/plugins/stk/mallets/mallets.cpp @@ -391,7 +391,7 @@ QString mallets::nodeName( void ) const -void mallets::playNote( notePlayHandle * _n ) +void mallets::playNote( notePlayHandle * _n, bool ) { int p = m_presets->value(); diff --git a/plugins/stk/mallets/mallets.h b/plugins/stk/mallets/mallets.h index c48730a8a..380f077d3 100644 --- a/plugins/stk/mallets/mallets.h +++ b/plugins/stk/mallets/mallets.h @@ -126,7 +126,8 @@ public: mallets( instrumentTrack * _channel_track ); virtual ~mallets(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/plugins/triple_oscillator/triple_oscillator.cpp b/plugins/triple_oscillator/triple_oscillator.cpp index ccf0ed8d3..429fb88a6 100644 --- a/plugins/triple_oscillator/triple_oscillator.cpp +++ b/plugins/triple_oscillator/triple_oscillator.cpp @@ -690,7 +690,7 @@ QString tripleOscillator::nodeName( void ) const -void tripleOscillator::playNote( notePlayHandle * _n ) +void tripleOscillator::playNote( notePlayHandle * _n, bool ) { if( _n->totalFramesPlayed() == 0 ) { diff --git a/plugins/triple_oscillator/triple_oscillator.h b/plugins/triple_oscillator/triple_oscillator.h index a56a09474..ba38e1bb9 100644 --- a/plugins/triple_oscillator/triple_oscillator.h +++ b/plugins/triple_oscillator/triple_oscillator.h @@ -48,7 +48,8 @@ public: tripleOscillator( instrumentTrack * _channel ); virtual ~tripleOscillator(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/plugins/vestige/Makefile.am b/plugins/vestige/Makefile.am index 536d1d4b2..2a32834c2 100644 --- a/plugins/vestige/Makefile.am +++ b/plugins/vestige/Makefile.am @@ -29,7 +29,6 @@ libvestige_la_SOURCES = vestige.cpp vestige.h lvsl_client.cpp lvsl_client.h $(libvestige_la_SOURCES): ./embedded_resources.h - CC = wineg++ pkglib_PROGRAMS = lvsl_server lvsl_server_SOURCES = lvsl_server.c communication.h diff --git a/plugins/vestige/communication.h b/plugins/vestige/communication.h index c4b519eaa..bf7b7b1ef 100644 --- a/plugins/vestige/communication.h +++ b/plugins/vestige/communication.h @@ -107,12 +107,12 @@ struct vstParamProperties enum hostLanguages { - LVSL_LANG_ENGLISH = 1, - LVSL_LANG_GERMAN, - LVSL_LANG_FRENCH, - LVSL_LANG_ITALIAN, - LVSL_LANG_SPANISH, - LVSL_LANG_JAPANESE + LanguageEnglish = 1, + LanguageGerman, + LanguageFrench, + LanguageItalian, + LanguageSpanish, + LanguageJapanese } ; diff --git a/plugins/vestige/lvsl_client.cpp b/plugins/vestige/lvsl_client.cpp index 780eba502..3659efbad 100644 --- a/plugins/vestige/lvsl_client.cpp +++ b/plugins/vestige/lvsl_client.cpp @@ -102,7 +102,8 @@ remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin, engine * _engine ) : m_outputCount( 0 ), m_shmID( -1 ), m_shm( NULL ), - m_shmSize( 0 ) + m_shmSize( 0 ), + m_initialized( FALSE ) { pipe( m_pipes[0] ); pipe( m_pipes[1] ); @@ -139,14 +140,14 @@ remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin, engine * _engine ) : lock(); writeValueS( VST_LANGUAGE ); - hostLanguages hlang = LVSL_LANG_ENGLISH; + hostLanguages hlang = LanguageEnglish; switch( QLocale::system().language() ) { - case QLocale::German: hlang = LVSL_LANG_GERMAN; break; - case QLocale::French: hlang = LVSL_LANG_FRENCH; break; - case QLocale::Italian: hlang = LVSL_LANG_ITALIAN; break; - case QLocale::Spanish: hlang = LVSL_LANG_SPANISH; break; - case QLocale::Japanese: hlang = LVSL_LANG_JAPANESE; break; + case QLocale::German: hlang = LanguageGerman; break; + case QLocale::French: hlang = LanguageFrench; break; + case QLocale::Italian: hlang = LanguageItalian; break; + case QLocale::Spanish: hlang = LanguageSpanish; break; + case QLocale::Japanese: hlang = LanguageJapanese; break; default: break; } writeValueS( hlang ); @@ -276,8 +277,8 @@ void remoteVSTPlugin::hideEditor( void ) -void remoteVSTPlugin::process( const sampleFrame * _in_buf, - sampleFrame * _out_buf ) +bool remoteVSTPlugin::process( const sampleFrame * _in_buf, + sampleFrame * _out_buf, bool _wait ) { const fpab_t frames = eng()->getMixer()->framesPerAudioBuffer(); @@ -291,8 +292,11 @@ void remoteVSTPlugin::process( const sampleFrame * _in_buf, { (void) processNextMessage(); } - eng()->getMixer()->clearAudioBuffer( _out_buf, frames ); - return; + if( _out_buf != NULL ) + { + eng()->getMixer()->clearAudioBuffer( _out_buf, frames ); + } + return( FALSE ); } memset( m_shm, 0, m_shmSize ); @@ -314,32 +318,50 @@ void remoteVSTPlugin::process( const sampleFrame * _in_buf, writeValueS( VST_PROCESS ); unlock(); - if( _out_buf != NULL && m_outputCount > 0 ) + if( _wait ) { - // wait until server signals that process()ing is done - while( processNextMessage() != VST_PROCESS_DONE ) - { - // hopefully scheduler gives process-time to plugin... - usleep( 10 ); - } + waitForProcessingFinished( _out_buf ); + } + m_initialized = TRUE; + return( TRUE ); +} - ch_cnt_t outputs = tMax( m_outputCount, + + + +bool remoteVSTPlugin::waitForProcessingFinished( sampleFrame * _out_buf ) +{ + if( !m_initialized || _out_buf == NULL || m_outputCount == 0 ) + { + return( FALSE ); + } + + // wait until server signals that process()ing is done + while( processNextMessage() != VST_PROCESS_DONE ) + { + // hopefully scheduler gives process-time to plugin... + usleep( 10 ); + } + + const fpab_t frames = eng()->getMixer()->framesPerAudioBuffer(); + const ch_cnt_t outputs = tMax( m_outputCount, DEFAULT_CHANNELS ); - if( outputs != DEFAULT_CHANNELS ) - { - // clear buffer, if plugin didn't fill up both channels - eng()->getMixer()->clearAudioBuffer( _out_buf, frames ); - } + if( outputs != DEFAULT_CHANNELS ) + { + // clear buffer, if plugin didn't fill up both channels + eng()->getMixer()->clearAudioBuffer( _out_buf, frames ); + } - for( ch_cnt_t ch = 0; ch < outputs; ++ch ) + for( ch_cnt_t ch = 0; ch < outputs; ++ch ) + { + for( fpab_t frame = 0; frame < frames; ++frame ) { - for( fpab_t frame = 0; frame < frames; ++frame ) - { - _out_buf[frame][ch] = m_shm[(m_inputCount+ch)* + _out_buf[frame][ch] = m_shm[(m_inputCount+ch)* frames+frame]; - } } } + + return( TRUE ); } diff --git a/plugins/vestige/lvsl_client.h b/plugins/vestige/lvsl_client.h index cc7baf6fd..8c0f1df80 100644 --- a/plugins/vestige/lvsl_client.h +++ b/plugins/vestige/lvsl_client.h @@ -77,8 +77,15 @@ public: return( m_productString ); } - void FASTCALL process( const sampleFrame * _in_buf, - sampleFrame * _out_buf ); + // if _wait == TRUE, process() calls waitForProcessingFinished() + // immediately, otherwise, _out_buf can be zero and you've to call + // waitForProcessingFinished() on your own + bool FASTCALL process( const sampleFrame * _in_buf, + sampleFrame * _out_buf, + bool _wait ); + bool FASTCALL waitForProcessingFinished( sampleFrame * _out_buf ); + + void FASTCALL enqueueMidiEvent( const midiEvent & _event, const f_cnt_t _frames_ahead ); void FASTCALL setTempo( const bpm_t _bpm ); @@ -174,6 +181,8 @@ private: float * m_shm; size_t m_shmSize; + bool m_initialized; + } ; diff --git a/plugins/vestige/lvsl_server.c b/plugins/vestige/lvsl_server.c index e901b721c..004801a80 100644 --- a/plugins/vestige/lvsl_server.c +++ b/plugins/vestige/lvsl_server.c @@ -103,7 +103,7 @@ static pthread_key_t ejmpbuf_key; #endif -static hostLanguages hlang = LVSL_LANG_ENGLISH; +static hostLanguages hlang = LanguageEnglish; class VSTPlugin; @@ -138,7 +138,7 @@ public: { if( m_window != NULL ) { - PostThreadMessageA( m_guiThreadID, WM_USER, SHOW_EDITOR, + PostThreadMessageA( m_guiThreadID, WM_USER, ShowEditor, 0 ); } } @@ -213,7 +213,7 @@ public: private: enum guiThreadMessages { - NONE, SHOW_EDITOR, CLOSE_PLUGIN + None, ShowEditor, ClosePlugin } ; // callback used by plugin for being able to communicate with it's host @@ -348,7 +348,7 @@ VSTPlugin::~VSTPlugin() { // notify GUI-thread if( !PostThreadMessageA( m_guiThreadID, WM_USER, - CLOSE_PLUGIN, 0 ) ) + ClosePlugin, 0 ) ) { //lvsMessage( "could not post message to gui thread" ); } @@ -1077,9 +1077,12 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param ) _this->m_windowHeight = er->bottom - er->top; SetWindowPos( _this->m_window, 0, 0, 0, _this->m_windowWidth + 8, - _this->m_windowHeight + 26, + _this->m_windowHeight + 26, 0 +#if 0 SWP_NOACTIVATE /*| SWP_NOREDRAW*/ | SWP_NOMOVE | - SWP_NOOWNERZORDER | SWP_NOZORDER ); + SWP_NOOWNERZORDER | SWP_NOZORDER +#endif + ); #ifdef HAVE_TLS ejmpbuf_valid = false; #else @@ -1101,13 +1104,13 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param ) { switch( msg.wParam ) { - case SHOW_EDITOR: + case ShowEditor: ShowWindow( _this->m_window, SW_SHOWNORMAL ); UpdateWindow( _this->m_window ); break; - case CLOSE_PLUGIN: + case ClosePlugin: quit = true; break; diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index d9e3d29f8..1ddd44cce 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -324,20 +324,24 @@ void vestigeInstrument::setParameter( const QString & _param, -void vestigeInstrument::play( void ) +void vestigeInstrument::waitForWorkerThread( void ) { - QMutexLocker ml( &m_pluginMutex ); + m_pluginMutex.lock(); if( m_plugin == NULL ) { + m_pluginMutex.unlock(); return; } const fpab_t frames = eng()->getMixer()->framesPerAudioBuffer(); sampleFrame * buf = bufferAllocator::alloc( frames ); - m_plugin->process( NULL, buf ); - - getInstrumentTrack()->processAudioBuffer( buf, frames, NULL ); + if( m_plugin->waitForProcessingFinished( buf ) ) + { + getInstrumentTrack()->processAudioBuffer( buf, frames, NULL ); + } + + m_pluginMutex.unlock(); bufferAllocator::free( buf ); } @@ -345,9 +349,30 @@ void vestigeInstrument::play( void ) +void vestigeInstrument::play( bool _try_parallelizing ) +{ + m_pluginMutex.lock(); + if( m_plugin == NULL ) + { + m_pluginMutex.unlock(); + return; + } + + m_plugin->process( NULL, NULL, FALSE ); + m_pluginMutex.unlock(); + + if( !_try_parallelizing ) + { + waitForWorkerThread(); + } +} -void vestigeInstrument::playNote( notePlayHandle * _n ) + + + + +void vestigeInstrument::playNote( notePlayHandle * _n, bool ) { m_pluginMutex.lock(); if( _n->totalFramesPlayed() == 0 && m_plugin != NULL ) diff --git a/plugins/vestige/vestige.h b/plugins/vestige/vestige.h index d77fc21ef..2c42e6c29 100644 --- a/plugins/vestige/vestige.h +++ b/plugins/vestige/vestige.h @@ -56,9 +56,10 @@ public: vestigeInstrument( instrumentTrack * _channel_track ); virtual ~vestigeInstrument(); - virtual void play( void ); + virtual void play( bool _try_parallelizing ); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); @@ -71,6 +72,18 @@ public: virtual void FASTCALL setParameter( const QString & _param, const QString & _value ); + virtual bool supportsParallelizing( void ) const + { + return( TRUE ); + } + + virtual void waitForWorkerThread( void ); + + virtual bool notePlayHandleBased( void ) const + { + return( FALSE ); + } + protected slots: void openPlugin( void ); diff --git a/plugins/vibed/vibed.cpp b/plugins/vibed/vibed.cpp index f742acca5..6052640fa 100644 --- a/plugins/vibed/vibed.cpp +++ b/plugins/vibed/vibed.cpp @@ -551,7 +551,7 @@ QString vibed::nodeName( void ) const -void vibed::playNote( notePlayHandle * _n ) +void vibed::playNote( notePlayHandle * _n, bool ) { if ( _n->totalFramesPlayed() == 0 ) { diff --git a/plugins/vibed/vibed.h b/plugins/vibed/vibed.h index 129ce5f5a..37238dc7b 100644 --- a/plugins/vibed/vibed.h +++ b/plugins/vibed/vibed.h @@ -48,7 +48,8 @@ public: vibed( instrumentTrack * _channel_track ); virtual ~vibed(); - virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL playNote( notePlayHandle * _n, + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); diff --git a/src/core/instrument.cpp b/src/core/instrument.cpp index 4f93b7f8a..344def9d6 100644 --- a/src/core/instrument.cpp +++ b/src/core/instrument.cpp @@ -51,14 +51,14 @@ instrument::~instrument() -void instrument::play( void ) +void instrument::play( bool ) { } -void instrument::playNote( notePlayHandle * ) +void instrument::playNote( notePlayHandle *, bool ) { } diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index d927f0311..ab13838d9 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -68,6 +68,7 @@ mixer::mixer( engine * _engine ) : m_readBuf( NULL ), m_writeBuf( NULL ), m_cpuLoad( 0 ), + m_parallelizingLevel( 1 ), m_qualityLevel( DEFAULT_QUALITY_LEVEL ), m_masterGain( 1.0f ), m_audioDev( NULL ), @@ -88,6 +89,13 @@ mixer::mixer( engine * _engine ) : QString::number( m_framesPerAudioBuffer ) ); } + if( configManager::inst()->value( "mixer", "parallelizinglevel" + ).toInt() > 0 ) + { + m_parallelizingLevel =configManager::inst()->value( "mixer", + "parallelizinglevel" ).toInt(); + } + for( Uint8 i = 0; i < 3; i++ ) { m_readBuf = bufferAllocator::alloc( @@ -258,22 +266,76 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) // if( criticalXRuns() == FALSE ) { csize idx = 0; - while( idx < m_playHandles.size() ) + if( m_parallelizingLevel > 1 ) { - register playHandle * n = m_playHandles[idx]; - // delete play-handle if it played completely - if( n->done() ) +// TODO: if not enough play-handles are found which are capable of +// parallelizing, create according worker-threads. each of this threads +// processes a certain part of our m_playHandles-vector +// the question is the queueing model which we can use: +// 1) m_playHandles is divided into m_parallelizingLevel sub-vectors +// each sub-vector is processed by a worker-thread +// 2) create a stack with all play-handles that need to be processed, +// save it via a mutex and then let all worker-threads "fetch jobs" +// from the stack - this way it's guaranteed the work is +// balanced across all worker-threads. this would avoid cases +// where the sub-vector of a thread only contains notes that are +// done and only need to be deleted. + playHandleVector par_hndls; + while( idx < m_playHandles.size() ) { - delete n; - m_playHandles.erase( m_playHandles.begin() + - idx ); - } - else - { - // play all uncompletely-played play-handles... - n->play(); + playHandle * n = m_playHandles[idx]; + if( !n->done() && n->supportsParallelizing() ) + { + n->play( TRUE ); + par_hndls.push_back( n ); + } ++idx; } + idx = 0; + while( idx < m_playHandles.size() ) + { + playHandle * n =m_playHandles[idx]; + if( n->supportsParallelizing() ) + { + ++idx; + continue; + } + else if( n->done() ) + { + delete n; + m_playHandles.erase( + m_playHandles.begin() + idx ); + } + else + { + n->play(); + ++idx; + } + } + for( playHandleVector::iterator it = par_hndls.begin(); + it != par_hndls.end(); ++it ) + { + ( *it )->waitForWorkerThread(); + } + } + else + { + while( idx < m_playHandles.size() ) + { + register playHandle * n = m_playHandles[idx]; + // delete play-handle if it played completely + if( n->done() ) + { + delete n; + m_playHandles.erase( + m_playHandles.begin() + idx ); + } + else + { + n->play(); + ++idx; + } + } } eng()->getSongEditor()->processNextBuffer(); @@ -283,7 +345,8 @@ const surroundSampleFrame * mixer::renderNextBuffer( void ) it != m_audioPorts.end(); ++it ) { more_effects = ( *it )->processEffects(); - if( ( *it )->m_bufferUsage != audioPort::NONE || more_effects ) + if( ( *it )->m_bufferUsage != audioPort::NONE || + more_effects ) { processBuffer( ( *it )->firstBuffer(), ( *it )->nextFxChannel() ); @@ -324,7 +387,7 @@ void mixer::clear( bool _everything ) // parameter _everything is true (which is the case when // clearing song for example) if( _everything == TRUE || - ( *it )->type() != playHandle::INSTRUMENT_PLAY_HANDLE ) + ( *it )->type() != playHandle::InstrumentPlayHandle ) { m_playHandlesToRemove.push_back( *it ); } diff --git a/src/core/note_play_handle.cpp b/src/core/note_play_handle.cpp index 650d2e039..c67377853 100644 --- a/src/core/note_play_handle.cpp +++ b/src/core/note_play_handle.cpp @@ -42,7 +42,7 @@ notePlayHandle::notePlayHandle( instrumentTrack * _it, const f_cnt_t _frames, const note & _n, const bool _arp_note ) : - playHandle( NOTE_PLAY_HANDLE ), + playHandle( NotePlayHandle ), note( NULL, _n.length(), _n.pos(), _n.tone(), _n.octave(), _n.getVolume(), _n.getPanning() ), m_pluginData( NULL ), @@ -121,7 +121,7 @@ notePlayHandle::~notePlayHandle() -void notePlayHandle::play( void ) +void notePlayHandle::play( bool _try_parallelizing ) { if( m_muted == TRUE || m_instrumentTrack == NULL ) { @@ -137,7 +137,7 @@ void notePlayHandle::play( void ) } // play note! - m_instrumentTrack->playNote( this ); + m_instrumentTrack->playNote( this, _try_parallelizing ); if( m_released == TRUE ) { @@ -198,7 +198,7 @@ void notePlayHandle::play( void ) for( notePlayHandleVector::iterator it = m_subNotes.begin(); it != m_subNotes.end(); ) { - ( *it )->play(); + ( *it )->play( _try_parallelizing ); if( ( *it )->done() ) { delete *it; diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index 642347a5a..8e27dba14 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -139,6 +139,21 @@ plugin * plugin::instantiate( const QString & _plugin_name, void * _data ) +bool plugin::supportsParallelizing( void ) const +{ + return( FALSE ); +} + + + + +void plugin::waitForWorkerThread( void ) +{ +} + + + + void plugin::getDescriptorsOfAvailPlugins( vvector & _plugin_descs ) { QDir directory( configManager::inst()->pluginDir() ); diff --git a/src/core/preset_preview_play_handle.cpp b/src/core/preset_preview_play_handle.cpp index 51afdbceb..e2af78ab9 100644 --- a/src/core/preset_preview_play_handle.cpp +++ b/src/core/preset_preview_play_handle.cpp @@ -127,7 +127,7 @@ QMap presetPreviewPlayHandle::presetPreviewPlayHandle( const QString & _preset_file, engine * _engine ) : - playHandle( PRESET_PREVIEW_PLAY_HANDLE ), + playHandle( PresetPreviewHandle ), engineObject( _engine ), m_previewNote( NULL ) { @@ -192,9 +192,9 @@ presetPreviewPlayHandle::~presetPreviewPlayHandle() -void presetPreviewPlayHandle::play( void ) +void presetPreviewPlayHandle::play( bool _try_parallelizing ) { - m_previewNote->play(); + m_previewNote->play( _try_parallelizing ); } diff --git a/src/core/sample_play_handle.cpp b/src/core/sample_play_handle.cpp index f8166f64b..df88446be 100644 --- a/src/core/sample_play_handle.cpp +++ b/src/core/sample_play_handle.cpp @@ -38,7 +38,7 @@ samplePlayHandle::samplePlayHandle( const QString & _sample_file, engine * _engine ) : - playHandle( SAMPLE_PLAY_HANDLE ), + playHandle( SamplePlayHandle ), engineObject( _engine ), m_sampleBuffer( new sampleBuffer( eng(), _sample_file ) ), m_doneMayReturnTrue( TRUE ), @@ -55,7 +55,7 @@ samplePlayHandle::samplePlayHandle( const QString & _sample_file, samplePlayHandle::samplePlayHandle( sampleBuffer * _sample_buffer ) : - playHandle( SAMPLE_PLAY_HANDLE ), + playHandle( SamplePlayHandle ), engineObject( _sample_buffer->eng() ), m_sampleBuffer( sharedObject::ref( _sample_buffer ) ), m_doneMayReturnTrue( TRUE ), @@ -72,7 +72,7 @@ samplePlayHandle::samplePlayHandle( sampleBuffer * _sample_buffer ) : samplePlayHandle::samplePlayHandle( sampleTCO * _tco ) : - playHandle( SAMPLE_PLAY_HANDLE ), + playHandle( SamplePlayHandle ), engineObject( _tco->eng() ), m_sampleBuffer( sharedObject::ref( _tco->getSampleBuffer() ) ), m_doneMayReturnTrue( TRUE ), @@ -89,7 +89,7 @@ samplePlayHandle::samplePlayHandle( sampleTCO * _tco ) : samplePlayHandle::samplePlayHandle( pattern * _pattern ) : - playHandle( SAMPLE_PLAY_HANDLE ), + playHandle( SamplePlayHandle ), engineObject( _pattern->eng() ), m_sampleBuffer( sharedObject::ref( _pattern->getFrozenPattern() ) ), m_doneMayReturnTrue( TRUE ), @@ -117,15 +117,15 @@ samplePlayHandle::~samplePlayHandle() -void samplePlayHandle::play( void ) +void samplePlayHandle::play( bool _try_parallelizing ) { - play( 0 ); + play( 0, _try_parallelizing ); } -void samplePlayHandle::play( const fpab_t _frame_base ) +void samplePlayHandle::play( const fpab_t _frame_base, bool ) { if( framesDone() >= totalFrames() ) { diff --git a/src/core/setup_dialog.cpp b/src/core/setup_dialog.cpp index eea02ad3e..6658ba8d1 100644 --- a/src/core/setup_dialog.cpp +++ b/src/core/setup_dialog.cpp @@ -63,6 +63,7 @@ #include "debug.h" #include "tooltip.h" #include "led_checkbox.h" +#include "lcd_spinbox.h" #include "ladspa_manager.h" @@ -126,7 +127,9 @@ setupDialog::setupDialog( engine * _engine, configTabs _tab_to_open ) : m_disableChActInd( configManager::inst()->value( "ui", "disablechannelactivityindicators" ).toInt() ), m_manualChPiano( configManager::inst()->value( "ui", - "manualchannelpiano" ).toInt() ) + "manualchannelpiano" ).toInt() ), + m_parLevel( configManager::inst()->value( "mixer", + "parallelizinglevel" ).toInt() ) { setWindowIcon( embed::getIconPixmap( "setup_general" ) ); @@ -453,8 +456,45 @@ setupDialog::setupDialog( engine * _engine, configTabs _tab_to_open ) : + tabWidget * smp_supp_tw = new tabWidget( tr( "SMP support" ).toUpper(), + performance ); + smp_supp_tw->setFixedHeight( 180 ); + + QLabel * par_level_lbl = new QLabel( tr( "Parallelizing level" ), + smp_supp_tw ); + par_level_lbl->move( 10, 15 ); + lcdSpinBox * par_level = new lcdSpinBox( 1, 16, 2, smp_supp_tw, + tr( "SMP-level" ), + eng(), NULL ); + par_level->setValue( m_parLevel ); + connect( par_level, SIGNAL( valueChanged( int ) ), + this, SLOT( setParallelizingLevel( int ) ) ); + + par_level->move( 120, 20 ); + + QLabel * smp_help = new QLabel( + tr( "If you have a machine with more then one processor " + "(e.g. dual-core systems) you should use a " + "parallelizing-level above 1 which means that LMMS " + "will try to split up sound-processing into several " + "threads which should should be run on several cores " + "by the underlaying operating-system.\n" + "Please note that in some cases parallelizing won't " + "work with small buffer-sizes. If you experience " + "problems (i.e. lot of xruns), try to increase buffer-" + "size." ), smp_supp_tw ); + smp_help->setFixedSize( performance->width() - 20, 110 ); +#ifndef QT3 + smp_help->setWordWrap( TRUE ); +#else + smp_help->setAlignment( Qt::WordBreak ); +#endif + smp_help->move( 10, 55 ); + perf_layout->addWidget( ui_fx_tw ); + perf_layout->addSpacing( 15 ); + perf_layout->addWidget( smp_supp_tw ); perf_layout->addStretch(); @@ -721,6 +761,8 @@ void setupDialog::accept( void ) QString::number( m_disableChActInd ) ); configManager::inst()->setValue( "ui", "manualchannelpiano", QString::number( m_manualChPiano ) ); + configManager::inst()->setValue( "mixer", "parallelizinglevel", + QString::number( m_parLevel ) ); configManager::inst()->setWorkingDir( m_workingDir ); configManager::inst()->setVSTDir( m_vstDir ); @@ -878,6 +920,13 @@ void setupDialog::toggleManualChPiano( bool _enabled ) +void setupDialog::setParallelizingLevel( int _level ) +{ + m_parLevel = _level; +} + + + void setupDialog::openWorkingDir( void ) { diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index eb5c70ccc..dd061589d 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -734,7 +734,7 @@ void instrumentTrack::processOutEvent( const midiEvent & _me, -void instrumentTrack::playNote( notePlayHandle * _n ) +void instrumentTrack::playNote( notePlayHandle * _n, bool _try_parallelizing ) { // arpeggio- and chord-widget has to do its work -> adding sub-notes // for chords/arpeggios @@ -743,7 +743,7 @@ void instrumentTrack::playNote( notePlayHandle * _n ) if( _n->arpBaseNote() == FALSE && m_instrument != NULL ) { // all is done, so now lets play the note! - m_instrument->playNote( _n ); + m_instrument->playNote( _n, _try_parallelizing ); } } @@ -1031,7 +1031,7 @@ bool FASTCALL instrumentTrack::play( const midiTime & _start, note_frames, *cur_note ); note_play_handle->setBBTrack( bb_track ); - note_play_handle->play(); + note_play_handle->play( FALSE ); // could we play all within current number of // frames per audio-buffer? if( note_play_handle->done() == FALSE )