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;
}
Exemple #2
0
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;
}
Exemple #4
0
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);
}
Exemple #5
0
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;
}
Exemple #7
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;
}
Exemple #8
0
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() );
}
Exemple #9
0
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) );
}
Exemple #11
0
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() );
}
Exemple #12
0
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 );
}
Exemple #14
0
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);
    }
Exemple #16
0
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();
	}
Exemple #18
0
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;
}
Exemple #19
0
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;
}
Exemple #20
0
Fichier : Module.C Projet : 0mk/non
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;
}
Exemple #21
0
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) );
	}
}
Exemple #22
0
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;
}
Exemple #23
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 );
}
Exemple #24
0
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;
}
Exemple #25
0
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;
}
Exemple #26
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();
}
Exemple #28
0
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();
}