dolphin/Externals/MusicMod/Player/Src/Output.cpp

383 lines
10 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// Plainamp, Open source Winamp core
//
// Copyright © 2005 Sebastian Pipping <webmaster@hartwork.org>
//
// --> http://www.hartwork.org
//
// This source code is released under the GNU General Public License (GPL).
// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
////////////////////////////////////////////////////////////////////////////////
#include "Output.h"
#include "OutputPlugin.h"
#include "Console.h"
#include <time.h>
int iNullSampleRate;
int iNullSumBytesPerSample;
int iNullWrittenMillis;
bool bNullPlaying;
int bNullPaused;
DWORD dwNullOpenTimestamp;
DWORD dwNullPauseTimestamp;
const int NULL_DEFAULT_LATENCY = 1000;
int Output_Open( int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms );
void Output_Close();
int Output_Write( char * buf, int len );
int Output_CanWrite();
int Output_IsPlaying();
int Output_Pause( int pause );
void Output_SetVolume( int volume );
void Output_SetPan( int pan );
void Output_Flush( int t );
int Output_GetOutputTime();
int Output_GetWrittenTime();
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
Out_Module output_server = {
OUT_VER, // int version
"Plainamp Output Server", // char * description;
0x7fffffff, // int id
NULL, // HWND hMainWindow
NULL, // HINSTANCE hDllInstance
NULL, // void (*Config)(HWND hwndParent);
NULL, // void (*About)(HWND hwndParent);
NULL, // void (*Init)();
NULL, // void (*Quit)();
Output_Open, // int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
Output_Close, // void (*Close)();
Output_Write, // int (*Write)(char *buf, int len);
Output_CanWrite, // int (*CanWrite)();
Output_IsPlaying, // int (*IsPlaying)();
Output_Pause, // int (*Pause)(int pause);
Output_SetVolume, // void (*SetVolume)(int volume);
Output_SetPan, // void (*SetPan)(int pan);
Output_Flush, // void (*Flush)(int t);
Output_GetOutputTime, // int (*GetOutputTime)();
Output_GetWrittenTime, // int (*GetWrittenTime)();
};
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Output_Open( int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms )
{
if( active_output_count > 0 )
{
// Maximum
int res = 0;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->Open( samplerate, numchannels, bitspersamp, bufferlenms, prebufferms );
if( res_temp > res ) res = res_temp;
}
return res;
}
else
{
iNullSampleRate = samplerate;
iNullSumBytesPerSample = numchannels * ( bitspersamp / 8 );
iNullWrittenMillis = 0;
bNullPlaying = false;
bNullPaused = 0;
dwNullOpenTimestamp = GetTickCount();
return NULL_DEFAULT_LATENCY;
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void Output_Close()
{
if( active_output_count > 0 )
{
for( int i = 0; i < active_output_count; i++ )
{
active_output_plugins[ i ]->plugin->Close();
}
}
else
{
bNullPlaying = false;
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Output_Write( char * buf, int len )
{
if( active_output_count > 0 )
{
// Maximum
int res = 0;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->Write( buf, len );
if( res_temp > res ) res = res_temp;
}
return res;
}
else
{
if( iNullWrittenMillis == 0 )
{
dwNullOpenTimestamp = GetTickCount();
bNullPlaying = true;
}
iNullWrittenMillis += ( len / iNullSumBytesPerSample ) * 1000 / iNullSampleRate;
return 0; // 0 == Success
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Output_CanWrite()
{
if( active_output_count > 0 )
{
// Minimum
int res = 0x7fffffff;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->CanWrite();
if( res_temp < res ) res = res_temp;
}
return res;
}
else
{
const int diff = Output_GetWrittenTime() - Output_GetOutputTime();
if( diff >= NULL_DEFAULT_LATENCY )
{
return 0;
}
else
{
return ( NULL_DEFAULT_LATENCY - diff ) * iNullSumBytesPerSample * iNullSampleRate / 1000;
}
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Output_IsPlaying()
{
if( active_output_count > 0 )
{
// Maximum
int res = 0;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->IsPlaying();
if( res_temp > res ) res = res_temp;
}
return res;
}
else
{
return ( Output_GetOutputTime() < Output_GetWrittenTime() ) ? 1 : 0;
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Output_Pause( int pause )
{
if( active_output_count > 0 )
{
// Maximum
int res = 0;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->Pause( pause );
if( res_temp > res ) res = res_temp;
}
return res;
}
else
{
int res = bNullPaused;
if( pause && !bNullPaused )
{
// Playback should be paused
dwNullPauseTimestamp = GetTickCount();
bNullPaused = 1;
}
else if( !pause && bNullPaused )
{
// Playback should be continued
// Add the gap length to the open timestamp like no gap exists
dwNullOpenTimestamp += ( GetTickCount() - dwNullPauseTimestamp );
bNullPaused = 0;
}
return res; // Previous state
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void Output_SetVolume( int volume )
{
/* There was a call here with the volume value -666 that I could not see the source of,
so I added this check to see that we got a positive volume. */
if(volume >= 0)
{
// =======================================================================================
// The volume goes from 0 to 255
//TCHAR szBuffer[ 5000 ];
//_stprintf( szBuffer, TEXT( "DLL > Output_SetVolume <%i>" ), volume );
//Console::Append( szBuffer );
//Console::Append( TEXT( " " ) );
//NOTICE_LOG(AUDIO, "DLL > Output_SetVolume <%i>\n", volume );
// =======================================================================================
for( int i = 0; i < active_output_count; i++ )
{
active_output_plugins[ i ]->plugin->SetVolume( volume );
}
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void Output_SetPan( int pan )
{
for( int i = 0; i < active_output_count; i++ )
{
active_output_plugins[ i ]->plugin->SetPan( pan );
}
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void Output_Flush( int t )
{
if( active_output_count > 0 )
{
for( int i = 0; i < active_output_count; i++ )
{
active_output_plugins[ i ]->plugin->Flush( t );
}
}
else
{
dwNullOpenTimestamp = GetTickCount() - t;
iNullWrittenMillis = t;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Returns the number of milliseconds the song would be at
/// if we had zero latency. This value is never bigger than
/// the one returned by Output_GetWrittenTime().
////////////////////////////////////////////////////////////////////////////////
int Output_GetOutputTime() // <= GetWrittenTime()
{
if( active_output_count > 0 )
{
// Minimum
int res = 0x7fffffff;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->GetOutputTime();
if( res_temp < res ) res = res_temp;
}
return res;
}
else
{
if( bNullPlaying )
{
int res;
if( bNullPaused )
{
res = dwNullPauseTimestamp - dwNullOpenTimestamp;
}
else
{
res = GetTickCount() - dwNullOpenTimestamp;
}
return MIN( res, iNullWrittenMillis );
}
else
{
return 0;
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// Returns the number of milliseconds already written.
/// Due to latency this value is always bigger than
/// the value returned by Output_GetOutputTime().
////////////////////////////////////////////////////////////////////////////////
int Output_GetWrittenTime()
{
if( active_output_count > 0 )
{
// Maximum
int res = 0;
int res_temp;
for( int i = 0; i < active_output_count; i++ )
{
res_temp = active_output_plugins[ i ]->plugin->GetWrittenTime();
if( res_temp > res ) res = res_temp;
}
return res;
}
else
{
return iNullWrittenMillis;
}
}