void SndBuffer::timeStretchWrite() { // data prediction helps keep the tempo adjustments more accurate. // The timestretcher returns packets in belated "clump" form. // Meaning that most of the time we'll get nothing back, and then // suddenly we'll get several chunks back at once. Thus we use // data prediction to make the timestretcher more responsive. PredictDataWrite((int)(SndOutPacketSize / eTempo)); CvtPacketToFloat(sndTempBuffer); pSoundTouch->putSamples((float *)sndTempBuffer, SndOutPacketSize); int tempProgress; while (tempProgress = pSoundTouch->receiveSamples((float *)sndTempBuffer, SndOutPacketSize), tempProgress != 0) { // Hint: It's assumed that pSoundTouch will return chunks of 128 bytes (it always does as // long as the SSE optimizations are enabled), which means we can do our own SSE opts here. CvtPacketToInt(sndTempBuffer, tempProgress); _WriteSamples(sndTempBuffer, tempProgress); } #ifdef SPU2X_USE_OLD_STRETCHER UpdateTempoChangeSoundTouch(); #else UpdateTempoChangeSoundTouch2(); #endif }
void SndBuffer::timeStretchWrite() { bool progress = false; // data prediction helps keep the tempo adjustments more accurate. // The timestretcher returns packets in belated "clump" form. // Meaning that most of the time we'll get nothing back, and then // suddenly we'll get several chunks back at once. Thus we use // data prediction to make the timestretcher more responsive. PredictDataWrite( (int)( SndOutPacketSize / eTempo ) ); CvtPacketToFloat( sndTempBuffer ); pSoundTouch->putSamples( (float*)sndTempBuffer, SndOutPacketSize ); int tempProgress; while( tempProgress = pSoundTouch->receiveSamples( (float*)sndTempBuffer, SndOutPacketSize), tempProgress != 0 ) { // Hint: It's assumed that pSoundTouch will return chunks of 128 bytes (it always does as // long as the SSE optimizations are enabled), which means we can do our own SSE opts here. CvtPacketToInt( sndTempBuffer, tempProgress ); _WriteSamples( sndTempBuffer, tempProgress ); progress = true; } #ifdef SPU2X_USE_OLD_STRETCHER UpdateTempoChangeSoundTouch(); #else UpdateTempoChangeSoundTouch2(); #endif if( MsgOverruns() ) { if( progress ) { if( ++ts_stats_logcounter > 150 ) { ts_stats_logcounter = 0; ConLog( " * SPU2 > Timestretch Stats > %d percent stretched. Total stretchblocks = %d.\n", ( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ), ts_stats_stretchblocks); ts_stats_normalblocks = 0; ts_stats_stretchblocks = 0; } } } }
void SndBuffer::Write(const StereoOut32 &Sample) { //if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p // return; sndTempBuffer[sndTempProgress++] = Sample; // If we haven't accumulated a full packet yet, do nothing more: if (sndTempProgress < SndOutPacketSize) return; sndTempProgress = 0; if( !timeStretchDisabled ) timeStretchWrite(); else _WriteSamples(sndTempBuffer.get(), SndOutPacketSize); }
void SndBuffer::Write( const StereoOut32& Sample ) { // Log final output to wavefile. //WaveDump::WriteCore( 1, CoreSrc_External, Sample.DownSample() ); //RecordWrite( Sample.DownSample() ); //if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p // return; sndTempBuffer[sndTempProgress++] = Sample; // If we haven't accumulated a full packet yet, do nothing more: if(sndTempProgress < SndOutPacketSize) return; sndTempProgress = 0; //Don't play anything directly after loading a savestate, avoids static killing your speakers. // if ( ssFreeze > 0 ) // { // ssFreeze--; // return; // } //#ifndef __LINUX__ // else if( dspPluginEnabled ) // { // // Convert in, send to winamp DSP, and convert out. // // for( int i=0; i<SndOutPacketSize; ++i ) { sndTempBuffer16[i] = sndTempBuffer[i].DownSample(); } // m_dsp_progress += DspProcess( (s16*)sndTempBuffer16, SndOutPacketSize ); // // // Some ugly code to ensure full packet handling: // int ei = 0; // while( m_dsp_progress >= SndOutPacketSize ) // { // for( int i=0; i<SndOutPacketSize; ++i, ++ei ) { sndTempBuffer[i] = sndTempBuffer16[ei].UpSample(); } // // if( !timeStretchDisabled ) // timeStretchWrite(); // else // _WriteSamples(sndTempBuffer, sndTempProgress); // // m_dsp_progress -= SndOutPacketSize; // } // // // copy any leftovers to the front of the dsp buffer. // if( m_dsp_progress > 0 ) // { // memcpy( &sndTempBuffer16[ei], sndTempBuffer16, // sizeof(sndTempBuffer16[0]) * m_dsp_progress // ); // } // } //#endif // else { if( !timeStretchDisabled ) timeStretchWrite(); else _WriteSamples(sndTempBuffer, SndOutPacketSize); } }
void SndBuffer::Write( const StereoOut32& Sample ) { // Log final output to wavefile. WaveDump::WriteCore( 1, CoreSrc_External, Sample.DownSample() ); if( WavRecordEnabled ) RecordWrite( Sample.DownSample() ); if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p return; sndTempBuffer[sndTempProgress++] = Sample; // If we haven't accumulated a full packet yet, do nothing more: if(sndTempProgress < SndOutPacketSize) return; sndTempProgress = 0; //Don't play anything directly after loading a savestate, avoids static killing your speakers. if ( ssFreeze > 0 ) { ssFreeze--; memset( sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize ); // Play silence } #ifndef __POSIX__ if( dspPluginEnabled ) { // Convert in, send to winamp DSP, and convert out. int ei= m_dsp_progress; for( int i=0; i<SndOutPacketSize; ++i, ++ei ) { sndTempBuffer16[ei] = sndTempBuffer[i].DownSample(); } m_dsp_progress += DspProcess( (s16*)sndTempBuffer16 + m_dsp_progress, SndOutPacketSize ); // Some ugly code to ensure full packet handling: ei = 0; while( m_dsp_progress >= SndOutPacketSize ) { for( int i=0; i<SndOutPacketSize; ++i, ++ei ) { sndTempBuffer[i] = sndTempBuffer16[ei].UpSample(); } if( SynchMode == 0 ) // TimeStrech on timeStretchWrite(); else _WriteSamples(sndTempBuffer, SndOutPacketSize); m_dsp_progress -= SndOutPacketSize; } // copy any leftovers to the front of the dsp buffer. if( m_dsp_progress > 0 ) { memcpy( sndTempBuffer16, &sndTempBuffer16[ei], sizeof(sndTempBuffer16[0]) * m_dsp_progress ); } } #endif else { if( SynchMode == 0 ) // TimeStrech on timeStretchWrite(); else _WriteSamples(sndTempBuffer, SndOutPacketSize); } }