summaryrefslogtreecommitdiffstats
path: root/src/app/xineEngine.cpp
diff options
context:
space:
mode:
authormio <[email protected]>2024-10-27 11:26:22 +1000
committerMichele Calgaro <[email protected]>2024-10-28 09:16:23 +0900
commit55b425fe49ce8f28e0e7aac719e01bd42494b2fe (patch)
treea4edaf04f69a2edbadafe8eb91abf512ebf1f50a /src/app/xineEngine.cpp
parent4fe9282a9b13ac41e256f2b0fb4405dbcc46f2dd (diff)
downloadcodeine-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.cpp85
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;