bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, const fpp_t _frames, const float _freq, const LoopMode _loopmode ) { m_varLock.lockForRead(); f_cnt_t startFrame = m_startFrame; f_cnt_t endFrame = m_endFrame; f_cnt_t loopStartFrame = m_loopStartFrame; f_cnt_t loopEndFrame = m_loopEndFrame; if( endFrame == 0 || _frames == 0 ) { m_varLock.unlock(); return false; } // variable for determining if we should currently be playing backwards in a ping-pong loop bool is_backwards = _state->isBackwards(); const double freq_factor = (double) _freq / (double) m_frequency * m_sampleRate / engine::mixer()->processingSampleRate(); // calculate how many frames we have in requested pitch const f_cnt_t total_frames_for_current_pitch = static_cast<f_cnt_t>( ( endFrame - startFrame ) / freq_factor ); if( total_frames_for_current_pitch == 0 ) { m_varLock.unlock(); return false; } // this holds the number of the first frame to play f_cnt_t play_frame = _state->m_frameIndex; if( play_frame < startFrame ) { play_frame = startFrame; } if( _loopmode == LoopOff ) { if( play_frame >= endFrame ) { m_varLock.unlock(); return false; } if( ( endFrame - play_frame ) / freq_factor == 0 ) return false; } else if( _loopmode == LoopOn ) { play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); } else { play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); } f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN[ _state->interpolationMode() ]; sampleFrame * tmp = NULL; // check whether we have to change pitch... if( freq_factor != 1.0 || _state->m_varyingPitch ) { SRC_DATA src_data; // Generate output src_data.data_in = getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards, loopStartFrame, loopEndFrame, endFrame )[0]; src_data.data_out = _ab[0]; src_data.input_frames = fragment_size; src_data.output_frames = _frames; src_data.src_ratio = 1.0 / freq_factor; src_data.end_of_input = 0; int error = src_process( _state->m_resamplingData, &src_data ); if( error ) { printf( "SampleBuffer: error while resampling: %s\n", src_strerror( error ) ); } if( src_data.output_frames_gen > _frames ) { printf( "SampleBuffer: not enough frames: %ld / %d\n", src_data.output_frames_gen, _frames ); } // Advance switch( _loopmode ) { case LoopOff: play_frame += src_data.input_frames_used; break; case LoopOn: play_frame += src_data.input_frames_used; play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); break; case LoopPingPong: { f_cnt_t left = src_data.input_frames_used; if( _state->isBackwards() ) { play_frame -= src_data.input_frames_used; if( play_frame < loopStartFrame ) { left -= ( loopStartFrame - play_frame ); play_frame = loopStartFrame; } else left = 0; } play_frame += left; play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); break; } } } else { // we don't have to pitch, so we just copy the sample-data // as is into pitched-copy-buffer // Generate output memcpy( _ab, getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards, loopStartFrame, loopEndFrame, endFrame ), _frames * BYTES_PER_FRAME ); // Advance switch( _loopmode ) { case LoopOff: play_frame += _frames; break; case LoopOn: play_frame += _frames; play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); break; case LoopPingPong: { f_cnt_t left = _frames; if( _state->isBackwards() ) { play_frame -= _frames; if( play_frame < loopStartFrame ) { left -= ( loopStartFrame - play_frame ); play_frame = loopStartFrame; } else left = 0; } play_frame += left; play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); break; } } } if( tmp != NULL ) { MM_FREE( tmp ); } _state->setBackwards( is_backwards ); _state->setFrameIndex( play_frame ); for( fpp_t i = 0; i < _frames; ++i ) { _ab[i][0] *= m_amplification; _ab[i][1] *= m_amplification; } m_varLock.unlock(); return true; }
bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, const fpp_t _frames, const float _freq, const bool _looped ) { QMutexLocker ml( &m_varLock ); engine::mixer()->clearAudioBuffer( _ab, _frames ); if( m_endFrame == 0 || _frames == 0 ) { return false; } const double freq_factor = (double) _freq / (double) m_frequency * m_sampleRate / engine::mixer()->processingSampleRate(); // calculate how many frames we have in requested pitch const f_cnt_t total_frames_for_current_pitch = static_cast<f_cnt_t>( ( m_endFrame - m_startFrame ) / freq_factor ); if( total_frames_for_current_pitch == 0 ) { return false; } // this holds the number of the first frame to play f_cnt_t play_frame = _state->m_frameIndex; if( play_frame < m_startFrame ) { play_frame = m_startFrame; } // this holds the number of remaining frames in current loop f_cnt_t frames_for_loop; if( _looped ) { play_frame = getLoopedIndex( play_frame ); frames_for_loop = static_cast<f_cnt_t>( ( m_loopEndFrame - play_frame ) / freq_factor ); } else { if( play_frame >= m_endFrame ) { return false; } frames_for_loop = static_cast<f_cnt_t>( ( m_endFrame - play_frame ) / freq_factor ); if( frames_for_loop == 0 ) { return false; } } sampleFrame * tmp = NULL; // check whether we have to change pitch... if( freq_factor != 1.0 || _state->m_varyingPitch ) { SRC_DATA src_data; // Generate output const f_cnt_t margin = 64; f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + margin; src_data.data_in = getSampleFragment( play_frame, fragment_size, _looped, &tmp )[0]; src_data.data_out = _ab[0]; src_data.input_frames = fragment_size; src_data.output_frames = _frames; src_data.src_ratio = 1.0 / freq_factor; src_data.end_of_input = 0; int error = src_process( _state->m_resamplingData, &src_data ); if( error ) { printf( "SampleBuffer: error while resampling: %s\n", src_strerror( error ) ); } if( src_data.output_frames_gen > _frames ) { printf( "SampleBuffer: not enough frames: %ld / %d\n", src_data.output_frames_gen, _frames ); } // Advance play_frame += src_data.input_frames_used; if( _looped ) { play_frame = getLoopedIndex( play_frame ); } } else { // we don't have to pitch, so we just copy the sample-data // as is into pitched-copy-buffer // Generate output memcpy( _ab, getSampleFragment( play_frame, _frames, _looped, &tmp ), _frames * BYTES_PER_FRAME ); // Advance play_frame += _frames; if( _looped ) { play_frame = getLoopedIndex( play_frame ); } } delete[] tmp; _state->m_frameIndex = play_frame; return true; }