blargg_err_t Music_Emu::set_sample_rate( int rate ) { require( !sample_rate() ); // sample rate can't be changed once set RETURN_ERR( set_sample_rate_( rate ) ); RETURN_ERR( track_filter.init( this ) ); sample_rate_ = rate; tfilter.max_silence = 6 * stereo * sample_rate(); return blargg_ok; }
static rt_err_t codec_control(rt_device_t dev, rt_uint8_t cmd, void *args) { switch (cmd) { case CODEC_CMD_RESET: codec_init(dev); break; case CODEC_CMD_VOLUME: vol(*((uint16_t*) args)); break; case CODEC_CMD_SAMPLERATE: sample_rate(*((int*) args)); break; case CODEC_CMD_EQ: eq((codec_eq_args_t) args); break; case CODEC_CMD_3D: eq3d(*((uint8_t*) args)); break; default: return RT_ERROR; } return RT_EOK; }
Signal::Interval ReferenceInfo:: getInterval() const { // TaskTimer tt("Reference::getInterval"); // Similiar to getArea, but uses 1./sample_rate() instead of // "2 ^ log2_samples_size[0]" to compute the actual size of this block. // blockSize refers to the non-overlapping size. // Overlapping is needed to compute the same result for block borders // between two adjacent blocks. Thus the interval of samples that affect // this block overlap slightly into the samples that are needed for the // next block. int samplesPerBlock = block_layout_.texels_per_row (); long double blockSize = samplesPerBlock * ldexp(1.f,reference_.log2_samples_size[0]); long double elementSize = 1.0 / sample_rate(); long double blockLocalSize = samplesPerBlock * elementSize; // where the first element starts long double startTime = blockSize * reference_.block_index[0] - elementSize*.5f; // where the last element ends long double endTime = startTime + blockLocalSize; long double FS = block_layout_.targetSampleRate(); Signal::Interval i( max(0.L, floor(startTime * FS)), ceil(endTime * FS) ); //Position a, b; //getArea( a, b ); //Signal::SamplesIntervalDescriptor::Interval i = { a.time * FS, b.time * FS }; return i; }
void sound_xaudio2::update_audio_stream( bool is_throttled, int16_t const *buffer, int samples_this_frame) { if (!m_initialized || sample_rate() == 0 || !m_buffer) return; uint32_t const bytes_this_frame = samples_this_frame * m_sample_bytes; std::lock_guard<std::mutex> lock(m_buffer_lock); uint32_t bytes_left = bytes_this_frame; while (bytes_left > 0) { uint32_t chunk = std::min(uint32_t(m_buffer_size), bytes_left); // Roll the buffer if needed if (m_writepos + chunk >= m_buffer_size) { roll_buffer(); } // Copy in the data memcpy(m_buffer.get() + m_writepos, buffer, chunk); m_writepos += chunk; bytes_left -= chunk; } // Signal data available SetEvent(m_hEventDataAvailable); }
void sound_xaudio2::update_audio_stream( bool is_throttled, INT16 const *buffer, int samples_this_frame) { if ((sample_rate() == 0) || !m_buffer) return; UINT32 const bytes_this_frame = samples_this_frame * m_sample_bytes; std::lock_guard<std::mutex> lock(m_buffer_lock); UINT32 bytes_left = bytes_this_frame; while (bytes_left > 0) { UINT32 chunk = MIN(m_buffer_size, bytes_left); // Roll the buffer if needed if (m_writepos + chunk >= m_buffer_size) { roll_buffer(); } // Copy in the data memcpy(m_buffer.get() + m_writepos, buffer, chunk); m_writepos += chunk; bytes_left -= chunk; } // Signal data available SetEvent(m_hEventDataAvailable); }
blargg_err_t Effects_Buffer::set_channel_count( int count, int const* types ) { RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) ); delete_bufs(); mixer.samples_read = 0; RETURN_ERR( chans.resize( count + extra_chans ) ); RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) ); for ( int i = bufs_size; --i >= 0; ) RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) ); for ( int i = chans.size(); --i >= 0; ) { chan_t& ch = chans [i]; ch.cfg.vol = 1.0f; ch.cfg.pan = 0.0f; ch.cfg.surround = false; ch.cfg.echo = false; } // side channels with echo chans [2].cfg.echo = true; chans [3].cfg.echo = true; clock_rate( clock_rate_ ); bass_freq( bass_freq_ ); apply_config(); clear(); return 0; }
HRESULT sound_xaudio2::create_voices(const WAVEFORMATEX &format) { assert(m_xAudio2); assert(!m_masterVoice); HRESULT result; IXAudio2MasteringVoice *temp_master_voice = nullptr; HR_RET1( m_xAudio2->CreateMasteringVoice( &temp_master_voice, format.nChannels, sample_rate())); m_masterVoice = mastering_voice_ptr(temp_master_voice); // create the source voice IXAudio2SourceVoice *temp_source_voice = nullptr; HR_RET1(m_xAudio2->CreateSourceVoice( &temp_source_voice, &format, XAUDIO2_VOICE_NOSRC | XAUDIO2_VOICE_NOPITCH, 1.0, this)); m_sourceVoice = src_voice_ptr(temp_source_voice); return S_OK; }
AUX_Module::AUX_Module ( ) : JACK_Module ( false ) { is_default( false ); _number = 0; { Port p( this, Port::INPUT, Port::CONTROL, "Gain (dB)" ); p.hints.type = Port::Hints::LINEAR; p.hints.ranged = true; p.hints.minimum = -70.0f; p.hints.maximum = 6.0f; p.hints.default_value = 0.0f; p.connect_to( new float ); p.control_value( p.hints.default_value ); add_port( p ); } log_create(); color( FL_DARK1 ); copy_label( "Aux" ); smoothing.sample_rate( sample_rate() ); }
bool desc::ac3_audio(dvbpsi_descriptor_t* p_descriptor) { #if DVBPSI_SUPPORTS_DR_81_86_A0_A1 if (p_descriptor->i_tag != DT_Ac3Audio) return false; dvbpsi_ac3_audio_dr_t* dr = dvbpsi_DecodeAc3AudioDr(p_descriptor); if (desc_dr_failed(dr)) return false; dPrintf("sample rate: %s", sample_rate(dr->i_sample_rate_code)); dPrintf("bsid: %02x", dr->i_bsid); dPrintf("bit rate code: %02x", dr->i_bit_rate_code); dPrintf("surround mode: %s", surround_mode(dr->i_surround_mode)); dPrintf("bsmod: %02x", dr->i_bsmod); dPrintf("num channels: %s", num_channels(dr->i_num_channels)); dPrintf("full svc: %s", (dr->b_full_svc) ? "true" : "false"); dPrintf("description: %s", dr->text); if (dr->b_language_flag) dPrintf("language: %c%c%c", dr->language[0], dr->language[1], dr->language[2]); if (dr->b_language_flag_2) dPrintf("language_2: %c%c%c", dr->language_2[0], dr->language_2[1], dr->language_2[2]); #endif return true; }
void Music_Emu::set_fade( int start_msec, int length_msec ) { fade_set = true; this->length_msec = start_msec; this->fade_msec = length_msec; track_filter.set_fade( start_msec < 0 ? Track_Filter::indefinite_count : msec_to_samples( start_msec ), length_msec * sample_rate() / (1000 / stereo) ); }
blargg_err_t Vgm_Emu::load_mem_( byte const data [], int size ) { RETURN_ERR( core.load_mem( data, size ) ); set_voice_count( core.psg[0].osc_count ); double fm_rate = 0.0; if ( !disable_oversampling_ ) fm_rate = sample_rate() * oversample_factor; RETURN_ERR( core.init_chips( &fm_rate ) ); double psg_gain = ( ( core.header().psg_rate[3] & 0xC0 ) == 0x40 ) ? 0.5 : 1.0; if ( core.uses_fm() ) { set_voice_count( 8 ); RETURN_ERR( resampler.setup( fm_rate / sample_rate(), rolloff, gain() ) ); RETURN_ERR( resampler.reset( core.stereo_buf[0].length() * sample_rate() / 1000 ) ); core.psg[0].volume( 0.135 * fm_gain * psg_gain * gain() ); core.psg[1].volume( 0.135 * fm_gain * psg_gain * gain() ); core.ay[0].volume( 0.135 * fm_gain * gain() ); core.ay[1].volume( 0.135 * fm_gain * gain() ); core.huc6280[0].volume( 0.135 * fm_gain * gain() ); core.huc6280[1].volume( 0.135 * fm_gain * gain() ); } else { core.psg[0].volume( psg_gain * gain() ); core.psg[1].volume( psg_gain * gain() ); } static const char* const fm_names [] = { "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" }; static const char* const psg_names [] = { "Square 1", "Square 2", "Square 3", "Noise" }; set_voice_names( core.uses_fm() ? fm_names : psg_names ); static int const types [8] = { wave_type+1, wave_type+2, wave_type+3, noise_type+1, 0, 0, 0, 0 }; set_voice_types( types ); return Classic_Emu::setup_buffer( core.stereo_buf[0].center()->clock_rate() ); }
void save_sample_rate(const unsigned int rate) { if (sample_rate() == rate) return; preferences::set("sample_rate", lexical_cast<std::string>(rate)); // If audio is open, we have to re set sample rate sound::reset_sound(); }
void Music_Emu::set_tempo( double t ) { require( sample_rate() ); // sample rate must be set first double const min = 0.02; double const max = 4.00; if ( t < min ) t = min; if ( t > max ) t = max; tempo_ = t; set_tempo_( t ); }
void save_sample_rate(const unsigned int rate) { if (sample_rate() == rate) return; prefs["sample_rate"] = int(rate); // If audio is open, we have to re set sample rate sound::reset_sound(); }
// create an instance of the decoder // blocksize is fixed over the lifetime of this object for performance reasons decoder_impl(unsigned blocksize=8192): N(blocksize), halfN(blocksize/2) { #ifdef USE_FFTW3 // create FFTW buffers lt = (float*)fftwf_malloc(sizeof(float)*N); rt = (float*)fftwf_malloc(sizeof(float)*N); dst = (float*)fftwf_malloc(sizeof(float)*N); dftL = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*N); dftR = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*N); src = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*N); loadL = fftwf_plan_dft_r2c_1d(N, lt, dftL,FFTW_MEASURE); loadR = fftwf_plan_dft_r2c_1d(N, rt, dftR,FFTW_MEASURE); store = fftwf_plan_dft_c2r_1d(N, src, dst,FFTW_MEASURE); #else // create lavc fft buffers lt = (float*)av_malloc(sizeof(FFTSample)*N); rt = (float*)av_malloc(sizeof(FFTSample)*N); dftL = (FFTComplexArray*)av_malloc(sizeof(FFTComplex)*N*2); dftR = (FFTComplexArray*)av_malloc(sizeof(FFTComplex)*N*2); src = (FFTComplexArray*)av_malloc(sizeof(FFTComplex)*N*2); fftContextForward = (FFTContext*)av_malloc(sizeof(FFTContext)); memset(fftContextForward, 0, sizeof(FFTContext)); fftContextReverse = (FFTContext*)av_malloc(sizeof(FFTContext)); memset(fftContextReverse, 0, sizeof(FFTContext)); ff_fft_init(fftContextForward, 13, 0); ff_fft_init(fftContextReverse, 13, 1); #endif // resize our own buffers frontR.resize(N); frontL.resize(N); avg.resize(N); surR.resize(N); surL.resize(N); trueavg.resize(N); xfs.resize(N); yfs.resize(N); inbuf[0].resize(N); inbuf[1].resize(N); for (unsigned c=0;c<6;c++) { outbuf[c].resize(N); filter[c].resize(N); } sample_rate(48000); // generate the window function (square root of hann, b/c it is applied before and after the transform) wnd.resize(N); for (unsigned k=0;k<N;k++) wnd[k] = sqrt(0.5*(1-cos(2*PI*k/N))/N); current_buf = 0; memset(inbufs, 0, sizeof(inbufs)); memset(outbufs, 0, sizeof(outbufs)); // set the default coefficients surround_coefficients(0.8165,0.5774); phase_mode(0); separation(1,1); steering_mode(true); }
int sound_xaudio2::init(osd_options const &options) { HRESULT result; WAVEFORMATEX format = {0}; auto init_start = std::chrono::system_clock::now(); std::chrono::milliseconds init_time; CoInitializeEx(nullptr, COINIT_MULTITHREADED); // Make sure our XAudio2Create entrypoint is bound if (!XAudio2Create) { osd_printf_error("Could not find XAudio2. Please try to reinstall DirectX runtime package.\n"); return 1; } // Create the IXAudio2 object HR_GOERR(this->XAudio2Create(m_xAudio2.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR)); // make a format description for what we want format.wBitsPerSample = 16; format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 2; format.nSamplesPerSec = sample_rate(); format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; m_sample_bytes = format.nBlockAlign; // Create the buffers create_buffers(format); // Initialize our events m_hEventBufferCompleted = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_hEventDataAvailable = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_hEventExiting = CreateEvent(nullptr, FALSE, FALSE, nullptr); // create the voices and start them HR_GOERR(create_voices(format)); HR_GOERR(m_sourceVoice->Start()); // Start the thread listening m_audioThread = std::thread([](sound_xaudio2* self) { self->process_audio(); }, this); init_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - init_start); osd_printf_verbose("Sound: XAudio2 initialized. %d ms.\n", static_cast<int>(init_time.count())); m_initialized = TRUE; return 0; Error: this->exit(); return 1; }
SimpleMonophonic() : nuclear::jack_client("monosynth") { osci_voice* v = new osci_voice(); v->init(sample_rate()); _voice = v; open_audio_out_ports(1); open_midi_in_ports(1); activate(); }
const std::vector<sample_rate> & sample_rate::audio_rates( void ) { static std::vector<sample_rate> arates { sample_rate( 8000, 1 ), // telephone sample_rate( 16000, 1 ), // modern VOIP sample_rate( 44056, 1 ), // NTSC color video rate (29.97) sample_rate( 44100, 1 ), // audio CD sample_rate( 47250, 1 ), // first PCM sample_rate( 48000, 1 ), // most professional audio PCM sample_rate( 88200, 1 ), // double audio sample_rate( 96000, 1 ), // DVD / blu-ray / etc. audio (2x 48kHz) sample_rate( 192000, 1 ), // DVD / blu-ray / etc. audio (4x 48kHz) }; return arates; }
pBuffer SourceBase:: zeros( const Interval& I ) { EXCEPTION_ASSERT( I.count() ); TIME_SOURCEBASE TaskTimer tt("%s.%s %s", vartype(*this).c_str(), __FUNCTION__ , I.toString().c_str() ); pBuffer r( new Buffer(I, sample_rate(), num_channels()) ); // doesn't need to memset 0, will be set by the first initialization of a dataset //memset(r->waveform_data()->getCpuMemory(), 0, r->waveform_data()->getSizeInBytes1D()); return r; }
bool Module::show_analysis_window ( void ) { /* use a large window for more accuracy at low frequencies */ nframes_t nframes = sample_rate() / 2; float *buf = new float[nframes]; memset( buf, 0, sizeof(float) * nframes ); buf[0] = 1; if ( ! get_impulse_response( buf, nframes ) ) { // return false; } Fl_Double_Window *w = new Fl_Double_Window( 1000, 500 ); { SpectrumView * o = new SpectrumView( 25,25, 1000 - 50, 500 - 50, label() ); o->labelsize(10); o->align(FL_ALIGN_RIGHT|FL_ALIGN_TOP); o->sample_rate( sample_rate() ); o->data( buf, nframes ); } w->end(); w->show(); while ( w->shown() ) Fl::wait(); delete w; return true; }
void Gym_Emu::set_tempo_( double t ) { if ( t < min_tempo ) { set_tempo( min_tempo ); return; } if ( stereo_buf.sample_rate() ) { double denom = tempo() * 60; clocks_per_frame = (int) (clock_rate / denom); resampler.resize( (int) (sample_rate() / denom) ); } }
int sound_xaudio2::init(osd_options const &options) { HRESULT result; // Make sure our XAudio2Create entrypoint is bound int status = XAudio2Create.initialize(); if (status != 0) { osd_printf_error("Could not find XAudio2 library\n"); return 1; } // Create the IXAudio2 object IXAudio2 *temp_xaudio2 = nullptr; HR_RET1(this->XAudio2Create(&temp_xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)); m_xAudio2 = xaudio2_ptr(temp_xaudio2); // make a format description for what we want WAVEFORMATEX format = { 0 }; format.wBitsPerSample = 16; format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 2; format.nSamplesPerSec = sample_rate(); format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; m_sample_bytes = format.nBlockAlign; // Create the buffers create_buffers(format); // Initialize our events m_hEventBufferCompleted = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_hEventDataAvailable = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_hEventExiting = CreateEvent(nullptr, FALSE, FALSE, nullptr); // create the voices and start them HR_RET1(create_voices(format)); HR_RET1(m_sourceVoice->Start()); // Start the thread listening m_audioThread = std::thread([](sound_xaudio2* self) { self->process_audio(); }, this); osd_printf_verbose("Sound: XAudio2 initialized\n"); return 0; }
blargg_err_t Spc_Emu::skip_( long count ) { if ( sample_rate() != native_sample_rate ) { count = long (count * resampler.ratio()) & ~1; count -= resampler.skip_input( count ); } // TODO: shouldn't skip be adjusted for the 64 samples read afterwards? if ( count > 0 ) RETURN_ERR( apu.skip( count ) ); // eliminate pop due to resampler const int resampler_latency = 64; sample_t buf [resampler_latency]; return play_( resampler_latency, buf ); }
blargg_err_t Sfm_Emu::play_( int count, sample_t out [] ) { if ( sample_rate() == native_sample_rate ) return play_and_filter( count, out ); int remain = count; while ( remain > 0 ) { remain -= resampler.read( &out [count - remain], remain ); if ( remain > 0 ) { int n = resampler.buffer_free(); RETURN_ERR( play_and_filter( n, resampler.buffer() ) ); resampler.write( n ); } } check( remain == 0 ); return blargg_ok; }
blargg_err_t Spc_Emu::play_( long count, sample_t* out ) { if ( sample_rate() == native_sample_rate ) return apu.play( count, out ); long remain = count; while ( remain > 0 ) { remain -= resampler.read( &out [count - remain], remain ); if ( remain > 0 ) { long n = resampler.max_write(); RETURN_ERR( apu.play( n, resampler.buffer() ) ); resampler.write( n ); } } check( remain == 0 ); return 0; }
void sound_sdl::exit() { // if nothing to do, don't do it if (sample_rate() == 0) return; osd_printf_verbose("sdl_kill: closing audio\n"); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); // kill the buffers sdl_destroy_buffers(); // print out over/underflow stats if (buffer_overflows || buffer_underflows) osd_printf_verbose("Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows); if (LOG_SOUND) { fprintf(sound_log, "Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows); fclose(sound_log); } }
blargg_err_t Music_Emu::start_track( int track ) { clear_track_vars(); int remapped = track; RETURN_ERR( remap_track_( &remapped ) ); current_track_ = track; blargg_err_t err = start_track_( remapped ); if ( err ) { current_track_ = -1; return err; } // convert filter times to samples Track_Filter::setup_t s = tfilter; s.max_initial *= sample_rate() * stereo; #if GME_DISABLE_SILENCE_LOOKAHEAD s.lookahead = 1; #endif track_filter.setup( s ); return track_filter.start_track(); }
HRESULT sound_direct_sound::dsound_init() { assert(!m_dsound); HRESULT result; // create the DirectSound object result = DirectSoundCreate(nullptr, &m_dsound, nullptr); if (result != DS_OK) { osd_printf_error("Error creating DirectSound: %08x\n", (unsigned)result); goto error; } // get the capabilities DSCAPS dsound_caps; dsound_caps.dwSize = sizeof(dsound_caps); result = m_dsound->GetCaps(&dsound_caps); if (result != DS_OK) { osd_printf_error("Error getting DirectSound capabilities: %08x\n", (unsigned)result); goto error; } // set the cooperative level { #ifdef SDLMAME_WIN32 SDL_SysWMinfo wminfo; SDL_VERSION(&wminfo.version); SDL_GetWindowWMInfo(osd_common_t::s_window_list.front()->platform_window<SDL_Window*>(), &wminfo); HWND const window = wminfo.info.win.window; #else // SDLMAME_WIN32 HWND const window = osd_common_t::s_window_list.front()->platform_window<HWND>(); #endif // SDLMAME_WIN32 result = m_dsound->SetCooperativeLevel(window, DSSCL_PRIORITY); } if (result != DS_OK) { osd_printf_error("Error setting DirectSound cooperative level: %08x\n", (unsigned)result); goto error; } { // make a format description for what we want WAVEFORMATEX stream_format; stream_format.wBitsPerSample = 16; stream_format.wFormatTag = WAVE_FORMAT_PCM; stream_format.nChannels = 2; stream_format.nSamplesPerSec = sample_rate(); stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8; stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign; // compute the buffer size based on the output sample rate DWORD stream_buffer_size = stream_format.nSamplesPerSec * stream_format.nBlockAlign * m_audio_latency / 10; stream_buffer_size = std::max(DWORD(1024), (stream_buffer_size / 1024) * 1024); LOG(("stream_buffer_size = %u\n", (unsigned)stream_buffer_size)); // create the buffers m_bytes_per_sample = stream_format.nBlockAlign; m_stream_buffer_in = 0; result = create_buffers(stream_buffer_size, stream_format); if (result != DS_OK) goto error; } // start playing result = m_stream_buffer.play_looping(); if (result != DS_OK) { osd_printf_error("Error playing: %08x\n", (UINT32)result); goto error; } return DS_OK; // error handling error: destroy_buffers(); dsound_kill(); return result; }
void Effects_Buffer::apply_config() { int i; if ( !bufs_size ) return; s.treble = TO_FIXED( config_.treble ); bool echo_dirty = false; fixed_t old_feedback = s.feedback; s.feedback = TO_FIXED( config_.feedback ); if ( !old_feedback && s.feedback ) echo_dirty = true; // delays for ( i = stereo; --i >= 0; ) { long delay = config_.delay [i] * sample_rate() / 1000 * stereo; delay = max( delay, long (max_read * stereo) ); delay = min( delay, long (echo_size - max_read * stereo) ); if ( s.delay [i] != delay ) { s.delay [i] = delay; echo_dirty = true; } } // side channels for ( i = 2; --i >= 0; ) { chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f; chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan; } // convert volumes for ( i = chans.size(); --i >= 0; ) { chan_t& ch = chans [i]; ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan ); ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan ); if ( ch.cfg.surround ) ch.vol [0] = -ch.vol [0]; } assign_buffers(); // set side channels for ( i = chans.size(); --i >= 0; ) { chan_t& ch = chans [i]; ch.channel.left = chans [ch.cfg.echo*2 ].channel.center; ch.channel.right = chans [ch.cfg.echo*2+1].channel.center; } bool old_echo = !no_echo && !no_effects; // determine whether effects and echo are needed at all no_effects = true; no_echo = true; for ( i = chans.size(); --i >= extra_chans; ) { chan_t& ch = chans [i]; if ( ch.cfg.echo && s.feedback ) no_echo = false; if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) ) no_effects = false; } if ( !no_echo ) no_effects = false; if ( chans [0].vol [0] != TO_FIXED( 1 ) || chans [0].vol [1] != TO_FIXED( 0 ) || chans [1].vol [0] != TO_FIXED( 0 ) || chans [1].vol [1] != TO_FIXED( 1 ) ) no_effects = false; if ( !config_.enabled ) no_effects = true; if ( no_effects ) { for ( i = chans.size(); --i >= 0; ) { chan_t& ch = chans [i]; ch.channel.center = &bufs [2]; ch.channel.left = &bufs [0]; ch.channel.right = &bufs [1]; } } mixer.bufs [0] = &bufs [0]; mixer.bufs [1] = &bufs [1]; mixer.bufs [2] = &bufs [2]; if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) ) clear_echo(); channels_changed(); }
int Effects_Buffer::max_delay() const { require( sample_rate() ); return (echo_size / stereo - max_read) * 1000L / sample_rate(); }