dolphin/Branches/MusicMod/Player/Src/Input.cpp

478 lines
12 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 "Input.h"
#include "Console.h"
#include "Status.h"
#include "Playback.h"
#include "InputPlugin.h"
#include "VisPlugin.h"
#include "DspPlugin.h"
#include "VisCache.h"
#include "Output.h"
/*
#define FIXED_POINT 16
#include "kiss_fft/kiss_fftr.h"
*/
#include "fftw3/fftw3.h"
#include <math.h>
// #define SKIPPY
#ifndef SKIPPY
# define MAX_DATA_FPS ( 1000 / 12 ) // in_mp3 gives new vis data every 13 ms, so 12 leaves a little space
#else
# define MAX_DATA_FPS ( 1000 / 24 ) // will skip every second frame
#endif
#ifdef SKIPPY
bool bLastSkipped = true;
#endif
int iSpecChannels = 2;
int iWaveChannels = 2;
/*
kiss_fft_cfg kiss = { 0 };
bool bKissInitDone = false;
*/
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int dsp_isactive()
{
////////////////////////////////////////////////////////////////////////////////
DspLock.Enter();
////////////////////////////////////////////////////////////////////////////////
int res = ( active_dsp_count > 0 );
////////////////////////////////////////////////////////////////////////////////
DspLock.Leave();
////////////////////////////////////////////////////////////////////////////////
return res;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int dsp_dosamples( short int * samples, int numsamples, int bps, int nch, int srate )
{
int num = numsamples;
////////////////////////////////////////////////////////////////////////////////
DspLock.Enter();
////////////////////////////////////////////////////////////////////////////////
for( int i = 0; i < active_dsp_count; i++ )
{
// Process
num = active_dsp_mods[ i ]->mod->ModifySamples(
active_dsp_mods[ i ]->mod,
samples,
numsamples,
bps,
nch,
srate
);
}
////////////////////////////////////////////////////////////////////////////////
DspLock.Leave();
////////////////////////////////////////////////////////////////////////////////
return num;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void SAVSAInit( int maxlatency_in_ms, int srate )
{
////////////////////////////////////////////////////////////////////////////////
VisCache::Create();
VisCache::EnsureLatency( maxlatency_in_ms );
VisCache::EnsureDataFps( MAX_DATA_FPS );
VisCache::Clean();
////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void SAVSADeInit()
{
// TODO
// Console::Append( TEXT( "SAVSADeInit" ) );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void SAAddPCMData( void * PCMData, int nch, int bps, int timestamp )
{
// TODO
// Console::Append( TEXT( "SAAddPCMData" ) );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int SAGetMode()
{
// TODO
// Console::Append( TEXT( "SAGetMode" ) );
return 0;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void SAAdd( void * data, int timestamp, int csa )
{
// TODO
// Console::Append( TEXT( "SAAdd" ) );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void VSAAddPCMData( void * PCMData, int nch, int bps, int timestamp )
{
// TODO
// Console::Append( TEXT( "VSAAddPCMData" ) );
#ifdef SKIPPY
if( bLastSkipped )
bLastSkipped = false;
else
{
// Skip
bLastSkipped = true;
return;
}
#endif
////////////////////////////////////////////////////////////////////////////////
bool bVisLockLeft = false;
VisLock.Enter();
////////////////////////////////////////////////////////////////////////////////
if( active_vis_count )
{
////////////////////////////////////////////////////////////////////////////////
VisLock.Leave();
bVisLockLeft = true;
////////////////////////////////////////////////////////////////////////////////
VisCache::NextFrame();
VisCache::SetWriteTime( timestamp );
VisCache::SetReadTime( active_input_plugin->plugin->GetOutputTime() );
short * source = ( short * )PCMData;
// Waveform
static unsigned char wave_left[ 576 ];
static unsigned char wave_right[ 576 ];
if( nch < 2 )
{
// Mono
for( int i = 0; i < 576; i++ )
{
wave_left[ i ] = ( source[ i ] >> 8 );
}
VisCache::PutWaveLeft( wave_left );
}
else
{
int i;
// Stereo or more
for( i = 0; i < 576; i++ )
{
wave_left [ i ] = ( source[ i * nch ] >> 8 );
wave_right[ i ] = ( source[ i * nch + 1 ] >> 8 );
}
VisCache::PutWaveLeft( wave_left );
VisCache::PutWaveRight( wave_right );
}
// TODO: Much to optimize!
// Spectrum
static unsigned char spec_left[ 576 ];
static unsigned char spec_right[ 576 ];
static fftw_complex * in = NULL;
static fftw_complex * out = NULL;
if( !in )
{
in = ( fftw_complex * )fftw_malloc( 576 * sizeof( fftw_complex ) );
out = ( fftw_complex * )fftw_malloc( 576 * sizeof( fftw_complex ) );
}
static const double factor = 1.0 / 65536.0 / sqrt( 2.0 );
// Put left
int index = 0;
for( int i = 0; i < 576; i++ )
{
in[ i ][ 0 ] = source[ index += nch ];
in[ i ][ 1 ] = 0.0;
}
// Init FFT
fftw_plan p = fftw_plan_dft_1d( 576, in, out, FFTW_FORWARD, FFTW_ESTIMATE );
// Run left
fftw_execute( p );
// Get left
for( int i = 0; i < 576; i++ )
{
if( i & 1 )
{
spec_left [ i ] = spec_left [ i - 1 ];
continue;
}
const double re = out[ i >> 1 ][ 0 ];
const double im = out[ i >> 1 ][ 1 ];
const double root = sqrt( re*re + im*im );
const double final = 160.0 * log10( 1.0 + root * factor );
spec_left[ i ] = ( final < 255.0 ) ? ( unsigned char )final : 255;
}
VisCache::PutSpecLeft( spec_left );
if( nch > 1 )
{
// Put right
index = 1;
for( int i = 0; i < 576; i++ )
{
in[ i ][ 0 ] = source[ index += nch ];
}
// Run right
fftw_execute( p );
// Get right
for( int i = 0; i < 576; i++ )
{
if( i & 1 )
{
spec_right[ i ] = spec_right[ i - 1 ];
continue;
}
const double re = out[ i >> 1 ][ 0 ];
const double im = out[ i >> 1 ][ 1 ];
const double root = sqrt( re*re + im*im );
const double final = 160.0 * log10( 1.0 + root * factor );
spec_right[ i ] = ( final < 255.0 ) ? ( unsigned char )final : 255;
}
VisCache::PutSpecRight( spec_right );
}
// Cleanup FFT
fftw_destroy_plan( p );
// fftw_free(in);
// fftw_free(out);
}
////////////////////////////////////////////////////////////////////////////////
if( bVisLockLeft ) VisLock.Enter();
////////////////////////////////////////////////////////////////////////////////
for( int i = 0; i < active_vis_count; i++ )
{
active_vis_mods[ i ]->bAllowRender = true;
}
////////////////////////////////////////////////////////////////////////////////
VisLock.Leave();
////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int VSAGetMode( int * specNch, int * waveNch )
{
iSpecChannels = 0;
iWaveChannels = 0;
////////////////////////////////////////////////////////////////////////////////
VisLock.Enter();
////////////////////////////////////////////////////////////////////////////////
for( int i = 0; i < active_vis_count; i++ )
{
const int iSpec = active_vis_mods[ i ]->mod->spectrumNch;
const int iWave = active_vis_mods[ i ]->mod->waveformNch;
if( iSpec > iSpecChannels ) iSpecChannels = iSpec;
if( iWave > iWaveChannels ) iWaveChannels = iWave;
}
////////////////////////////////////////////////////////////////////////////////
VisLock.Leave();
////////////////////////////////////////////////////////////////////////////////
*specNch = iSpecChannels;
*waveNch = iWaveChannels;
return 1;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void VSAAdd( void * data, int timestamp )
{
#ifdef SKIPPY
if( bLastSkipped )
bLastSkipped = false;
else
{
// Skip
bLastSkipped = true;
return;
}
#endif
////////////////////////////////////////////////////////////////////////////////
bool bVisLockLeft = false;
VisLock.Enter();
////////////////////////////////////////////////////////////////////////////////
if( active_vis_count )
{
////////////////////////////////////////////////////////////////////////////////
VisLock.Leave();
bVisLockLeft = true;
////////////////////////////////////////////////////////////////////////////////
VisCache::NextFrame();
VisCache::SetWriteTime( timestamp );
VisCache::SetReadTime( active_input_plugin->plugin->GetOutputTime() );
unsigned char * source = ( unsigned char * )data;
if( iSpecChannels > 0 )
{
VisCache::PutSpecLeft( source );
source += 576;
}
if( iSpecChannels > 1 )
{
VisCache::PutSpecRight( source );
source += 576;
}
if( iWaveChannels > 0 )
{
VisCache::PutWaveLeft( source );
source += 576;
}
if( iWaveChannels > 1 )
{
VisCache::PutWaveRight( source );
}
}
////////////////////////////////////////////////////////////////////////////////
if( bVisLockLeft ) VisLock.Enter();
////////////////////////////////////////////////////////////////////////////////
for( int i = 0; i < active_vis_count; i++ )
{
active_vis_mods[ i ]->bAllowRender = true;
}
////////////////////////////////////////////////////////////////////////////////
VisLock.Leave();
////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void VSASetInfo( int nch, int srate )
{
// TODO
////////////////////////////////////////////////////////////////////////////////
VisCache::Create();
VisCache::EnsureDataFps( MAX_DATA_FPS );
VisCache::Clean();
////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void SetInfo( int bitrate, int srate, int stereo, int synched )
{
// TODO
static int last_valid_srate = 0;
if( bitrate < 0 ) return;
if( srate < 0 )
srate = last_valid_srate;
else
last_valid_srate = srate;
TCHAR szBuffer[ 5000 ] = TEXT( "" );
_stprintf( szBuffer, TEXT( " %i kbps, %i kHz" ), bitrate, srate );
StatusUpdate( szBuffer );
}