예제 #1
0
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
{
    m_predictData = 0;

    // Problem:
    //  If the SPU2 gets out of sync with the SndOut device, the writepos of the
    //  circular buffer will overtake the readpos, leading to a prolonged period
    //  of hopscotching read/write accesses (ie, lots of staticy crap sound for
    //  several seconds).
    //
    // Compromise:
    //  When an overrun occurs, we adapt by discarding a portion of the buffer.
    //  The older portion of the buffer is discarded rather than incoming data,
    //  so that the overall audio synchronization is better.

    int free = m_size - _GetApproximateDataInBuffer(); // -1, but the <= handles that
    if( free <= nSamples )
    {
        // Disabled since the lock-free queue can't handle changing the read end from the write thread
#if 0
        // Buffer overrun!
        // Dump samples from the read portion of the buffer instead of dropping
        // the newly written stuff.

        s32 comp;

        if( SynchMode == 0 ) // TimeStrech on
        {
            comp = timeStretchOverrun();
        }
        else
        {
            // Toss half the buffer plus whatever's being written anew:
            comp = GetAlignedBufferSize( (m_size + nSamples ) / 16 );
            if( comp > (m_size-SndOutPacketSize) ) comp = m_size-SndOutPacketSize;
        }

        _DropSamples_Internal(comp);

        if( MsgOverruns() )
            ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
        lastPct = 0.0;		// normalize the timestretcher
#else
        if( MsgOverruns() )
            ConLog(" * SPU2 > Overrun! 1 packet tossed)\n");
        lastPct = 0.0;		// normalize the timestretcher
        return;
#endif
    }

    _WriteSamples_Safe(bData, nSamples);
}
예제 #2
0
void SndBuffer::Init()
{
	//if( mods[OutputModule] == NULL )
	//{
	//	_InitFail();
	//	return;
	//}

	// initialize sound buffer
	// Buffer actually attempts to run ~50%, so allocate near double what
	// the requested latency is:


	m_rpos = 0;
	m_wpos = 0;
	m_data = 0;

	try
	{
		const float latencyMS = SndOutLatencyMS * (timeStretchDisabled ? 1.5f : 2.0f );
		m_size = GetAlignedBufferSize( (int)(latencyMS * SampleRate / 1000.0f ) );
		m_buffer = new StereoOut32[m_size];
		m_underrun_freeze = false;

		sndTempBuffer = new StereoOut32[SndOutPacketSize];
		sndTempBuffer16 = new StereoOut16[SndOutPacketSize];
	}
	catch( std::bad_alloc& )
	{
		// out of memory exception (most likely)

		printf( "Out of memory error occurred while initializing SPU2." );
		_InitFail();
		return;
	}

	// clear buffers!
	// Fixes loopy sounds on emu resets.
	memset( sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize );
	memset( sndTempBuffer16, 0, sizeof(StereoOut16) * SndOutPacketSize );

	sndTempProgress = 0;

	soundtouchInit();		// initializes the timestretching

	// some crap
	//spdif_set51(mods[OutputModule]->Is51Out());

	// initialize module
	//if( mods[OutputModule]->Init() == -1 ) _InitFail();
}
예제 #3
0
// Returns TRUE if there is data to be output, or false if no data
// is available to be copied.
bool SndBuffer::CheckUnderrunStatus( int& nSamples, int& quietSampleCount )
{
    quietSampleCount = 0;

    int data = _GetApproximateDataInBuffer();
    if( m_underrun_freeze )
    {
        int toFill = m_size / ( (SynchMode == 2) ? 32 : 400); // TimeStretch and Async off?
        toFill = GetAlignedBufferSize( toFill );

        // toFill is now aligned to a SndOutPacket

        if( data < toFill )
        {
            quietSampleCount = nSamples;
            return false;
        }

        m_underrun_freeze = false;
        if( MsgOverruns() )
            ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize );
        lastPct = 0.0;		// normalize timestretcher
    }
    else if( data < nSamples )
    {
        nSamples = data;
        quietSampleCount = SndOutPacketSize - data;
        m_underrun_freeze = true;

        if( SynchMode == 0 ) // TimeStrech on
            timeStretchUnderrun();

        return nSamples != 0;
    }

    return true;
}
예제 #4
0
// Returns TRUE if there is data to be output, or false if no data
// is available to be copied.
bool SndBuffer::CheckUnderrunStatus( int& nSamples, int& quietSampleCount )
{
	quietSampleCount = 0;
	if( m_underrun_freeze )
	{			
		int toFill = (int)(m_size * ( timeStretchDisabled ? 0.50f : 0.1f ) );
		toFill = GetAlignedBufferSize( toFill );

		// toFill is now aligned to a SndOutPacket

		if( m_data < toFill )
		{
			quietSampleCount = nSamples;
			return false;
		}

		m_underrun_freeze = false;
		//TODO
		//if( MsgOverruns() )
			printf(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize );
		lastPct = 0.0;		// normalize timestretcher
	}
	else if( m_data < nSamples )
	{
		nSamples = m_data;
		quietSampleCount = SndOutPacketSize - m_data;
		m_underrun_freeze = true;

		if( !timeStretchDisabled )
			timeStretchUnderrun();

		return nSamples != 0;
	}

	return true;
}
예제 #5
0
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
{
	int free = m_size-m_data;
	m_predictData = 0;

	assert( m_data <= m_size );

	// Problem:
	//  If the SPU2 gets out of sync with the SndOut device, the writepos of the
	//  circular buffer will overtake the readpos, leading to a prolonged period
	//  of hopscotching read/write accesses (ie, lots of staticy crap sound for
	//  several seconds).
	//
	// Compromise:
	//  When an overrun occurs, we adapt by discarding a portion of the buffer.
	//  The older portion of the buffer is discarded rather than incoming data,
	//  so that the overall audio synchronization is better.

	if( free < nSamples )
	{
		// Buffer overrun!
		// Dump samples from the read portion of the buffer instead of dropping
		// the newly written stuff.

		s32 comp;

		if( !timeStretchDisabled )
		{
			comp = timeStretchOverrun();
		}
		else
		{
			// Toss half the buffer plus whatever's being written anew:
			comp = GetAlignedBufferSize( (m_size + nSamples ) / 2 );
			if( comp > (m_size-SndOutPacketSize) ) comp = m_size-SndOutPacketSize;
		}

		m_data -= comp;
		m_rpos = (m_rpos+comp) % m_size;
		//TODO
		//if( MsgOverruns() )
			printf(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
		lastPct = 0.0;		// normalize the timestretcher
	}

	// copy in two phases, since there's a chance the packet
	// wraps around the buffer (it'd be nice to deal in packets only, but
	// the timestretcher and DSP options require flexibility).

	const int endPos = m_wpos + nSamples;
	const int secondCopyLen = endPos - m_size;
	StereoOut32* wposbuffer = &m_buffer[m_wpos];

	m_data += nSamples;
	if( secondCopyLen > 0 )
	{
		nSamples -= secondCopyLen;
		memcpy( m_buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) );
		m_wpos = secondCopyLen;
	}
	else
		m_wpos += nSamples;

	memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) );
}