diff options
author | mio <[email protected]> | 2024-10-27 11:26:22 +1000 |
---|---|---|
committer | Michele Calgaro <[email protected]> | 2024-10-28 09:16:23 +0900 |
commit | 55b425fe49ce8f28e0e7aac719e01bd42494b2fe (patch) | |
tree | a4edaf04f69a2edbadafe8eb91abf512ebf1f50a /src/app/xineEngine.cpp | |
parent | 4fe9282a9b13ac41e256f2b0fb4405dbcc46f2dd (diff) | |
download | codeine-55b425fe49ce8f28e0e7aac719e01bd42494b2fe.tar.gz codeine-55b425fe49ce8f28e0e7aac719e01bd42494b2fe.zip |
Update the xineScope to remove global variables.
This patch updates xineScope.c to better align with Amarok's code. As a
result, the analyzer is more accurate. For instance, when playing an
audio file and there is a silent spot, the blocks will correctly "drop"
to the bottom, leaving an empty analyzer. The previous behaviour would
leave some blocks "stuck" in their position
See: TDE/codeine#23
Signed-off-by: mio <[email protected]>
(cherry picked from commit ff2a5768dd4d199cb8bbbe2af4ea3fbb68a489f3)
Diffstat (limited to 'src/app/xineEngine.cpp')
-rw-r--r-- | src/app/xineEngine.cpp | 85 |
1 files changed, 56 insertions, 29 deletions
diff --git a/src/app/xineEngine.cpp b/src/app/xineEngine.cpp index 2cb9cd3..7f73e0d 100644 --- a/src/app/xineEngine.cpp +++ b/src/app/xineEngine.cpp @@ -36,8 +36,9 @@ VideoWindow::VideoWindow( TQWidget *parent ) , m_eventQueue( nullptr ) , m_videoPort( nullptr ) , m_audioPort( nullptr ) - , m_scope( nullptr ) + , m_post( nullptr ) , m_xine( nullptr ) + , m_scope( Analyzer::SCOPE_SIZE * 2 ) // Multiply by two to account for interleaved PCM. , m_current_vpts( 0 ) { DEBUG_BLOCK @@ -51,10 +52,6 @@ VideoWindow::VideoWindow( TQWidget *parent ) setPaletteBackgroundColor( TQt::black ); setFocusPolicy( ClickFocus ); - //TODO sucks - //TODO namespace this? - myList->next = myList; //init the buffer list - // Detect xine version, this is used for volume adjustment. // Xine versions prior to 1.2.13 use linear volume, so the engine uses logarithmic volume. // Xine versions starting from 1.2.13 use logarithmic volume, so the engine uses linear volume. @@ -101,7 +98,7 @@ VideoWindow::~VideoWindow() if( m_stream ) xine_dispose( m_stream ); if( m_audioPort ) xine_close_audio_driver( m_xine, m_audioPort ); if( m_videoPort ) xine_close_video_driver( m_xine, m_videoPort ); - if( m_scope ) xine_post_dispose( m_xine, m_scope ); + if( m_post ) xine_post_dispose( m_xine, m_post ); if( m_xine ) xine_exit( m_xine ); cleanUpVideo(); @@ -119,7 +116,7 @@ VideoWindow::init() if( !m_xine ) return false; - xine_engine_set_param( m_xine, XINE_ENGINE_PARAM_VERBOSITY, 99 ); + xine_engine_set_param(m_xine, XINE_ENGINE_PARAM_VERBOSITY, XINE_VERBOSITY_DEBUG); debug() << "xine_config_load()\n"; xine_config_load( m_xine, TQFile::encodeName( TQDir::homeDirPath() + "/.xine/config" ) ); @@ -161,9 +158,9 @@ VideoWindow::init() debug() << "scope_plugin_new()\n"; #if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) - m_scope = xine_post_init( m_xine, "codeine-scope", 1, &m_audioPort, nullptr ); + m_post = xine_post_init( m_xine, "codeine-scope", 1, &m_audioPort, nullptr ); #else - m_scope = scope_plugin_new( m_xine, m_audioPort ); + m_post = scope_plugin_new( m_xine, m_audioPort ); //FIXME this one seems to make seeking unstable for Codeine, perhaps xine_set_param( m_stream, XINE_PARAM_METRONOM_PREBUFFER, 6000 ); //less buffering, faster seeking.. @@ -281,9 +278,9 @@ VideoWindow::load( const KURL &url ) // FIXME leaves one erroneous buffer timerEvent( nullptr ); - if( m_scope ) { + if( m_post ) { xine_post_out_t *source = xine_get_audio_source( m_stream ); - xine_post_in_t *target = (xine_post_in_t*)xine_post_input( m_scope, const_cast<char*>("audio in") ); + xine_post_in_t *target = (xine_post_in_t*)xine_post_input( m_post, const_cast<char*>("audio in") ); xine_post_wire( source, target ); } @@ -373,6 +370,8 @@ VideoWindow::stop() { xine_stop( m_stream ); + std::fill(m_scope.begin(), m_scope.end(), 0); + announceStateChange(); } @@ -590,7 +589,7 @@ VideoWindow::setStreamParameter( int value ) else if( sender == "volume" ) { parameter = XINE_PARAM_AUDIO_AMP_LEVEL; - value = 100 - value; // TQt sliders are wrong way round when vertical + value = 100 - value; // TQt sliders are the wrong way round when vertical if (s_logarithmicVolume) { value = makeVolumeLogarithmic(value); @@ -607,16 +606,25 @@ VideoWindow::scope() { using Analyzer::SCOPE_SIZE; - static Engine::Scope scope( SCOPE_SIZE ); + if (!m_post || !m_stream || xine_get_status(m_stream) != XINE_STATUS_PLAY) + { + return m_scope; + } - if( xine_get_status( m_stream ) != XINE_STATUS_PLAY ) - return scope; + MyNode *const myList = scope_plugin_list(m_post); + const int64_t pts_per_smpls = scope_plugin_pts_per_smpls(m_post); + const int channels = scope_plugin_channels(m_post); + int scopeIdx = 0; + + if (channels > 2) + { + return m_scope; + } //prune the buffer list and update the m_current_vpts timestamp timerEvent( nullptr ); - const int64_t pts_per_smpls = scope_plugin_pts_per_smpls(m_scope); - for( int channels = xine_get_stream_info( m_stream, XINE_STREAM_INFO_AUDIO_CHANNELS ), frame = 0; frame < SCOPE_SIZE; ) + for (int n, frame = 0; frame < SCOPE_SIZE; /* no-op */) { MyNode *best_node = nullptr; @@ -637,10 +645,10 @@ VideoWindow::scope() data16 = best_node->mem; data16 += diff; - diff += diff % channels; //important correction to ensure we don't overflow the buffer - diff /= channels; + diff += diff % channels; // important correction to ensure we don't overflow the buffer. + diff /= channels; // use units of frames, not samples. - int + // calculate the number of available samples in this buffer. n = best_node->num_frames; n -= diff; n += frame; //clipping for # of frames we need @@ -650,33 +658,52 @@ VideoWindow::scope() for( int a, c; frame < n; ++frame, data16 += channels ) { for( a = c = 0; c < channels; ++c ) - a += data16[c]; - - a /= channels; - scope[frame] = a; + { + // now we give interleaved PCM to the scope. + m_scope[scopeIdx++] = data16[c]; + if (channels == 1) + { + // Duplicate mono samples. + m_scope[scopeIdx++] = data16[c]; + } + } } m_current_vpts = best_node->vpts_end; m_current_vpts++; //FIXME needs to be done for some reason, or you get situations where it uses same buffer again and again } - return scope; + return m_scope; } void VideoWindow::timerEvent( TQTimerEvent* ) { + if (!m_stream) + { + return; + } + /// here we prune the buffer list regularly - MyNode * const first_node = myList->next; - MyNode const * const list_end = myList; + MyNode *myList = scope_plugin_list(m_post); + + if (!myList) + { + return; + } + + // We operate on a subset of the list for thread-safety. + MyNode *const firstNode = myList->next; + const MyNode *const listEnd = myList; + // If we're not playing or paused, empty the list. m_current_vpts = (xine_get_status( m_stream ) == XINE_STATUS_PLAY) ? xine_get_current_vpts( m_stream ) : std::numeric_limits<int64_t>::max(); - for( MyNode *prev = first_node, *node = first_node->next; node != list_end; node = node->next ) + for( MyNode *prev = firstNode, *node = firstNode->next; node != listEnd; node = node->next ) { - // we never delete first_node + // we never delete firstNode // this maintains thread-safety if( node->vpts_end < m_current_vpts ) { prev->next = node->next; |