diff src/sdl/SoundSDL.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children fa7676dbf6f2
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/sdl/SoundSDL.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,178 @@
     1.4 +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
     1.5 +// Copyright (C) 2008 VBA-M development team
     1.6 +
     1.7 +// This program is free software; you can redistribute it and/or modify
     1.8 +// it under the terms of the GNU General Public License as published by
     1.9 +// the Free Software Foundation; either version 2, or(at your option)
    1.10 +// any later version.
    1.11 +//
    1.12 +// This program is distributed in the hope that it will be useful,
    1.13 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 +// GNU General Public License for more details.
    1.16 +//
    1.17 +// You should have received a copy of the GNU General Public License
    1.18 +// along with this program; if not, write to the Free Software Foundation,
    1.19 +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    1.20 +
    1.21 +#include "SoundSDL.h"
    1.22 +
    1.23 +extern int emulating;
    1.24 +extern bool speedup;
    1.25 +
    1.26 +// Hold up to 100 ms of data in the ring buffer
    1.27 +const float SoundSDL::_delay = 0.1f;
    1.28 +
    1.29 +SoundSDL::SoundSDL():
    1.30 +	_rbuf(0),
    1.31 +	_initialized(false)
    1.32 +{
    1.33 +
    1.34 +}
    1.35 +
    1.36 +void SoundSDL::soundCallback(void *data, u8 *stream, int len)
    1.37 +{
    1.38 +	reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<u16 *>(stream), len);
    1.39 +}
    1.40 +
    1.41 +void SoundSDL::read(u16 * stream, int length)
    1.42 +{
    1.43 +	if (!_initialized || length <= 0 || !emulating)
    1.44 +		return;
    1.45 +
    1.46 +	SDL_mutexP(_mutex);
    1.47 +	_rbuf.read(stream, std::min(static_cast<std::size_t>(length) / 2, _rbuf.used()));
    1.48 +
    1.49 +	SDL_CondSignal(_cond);
    1.50 +	SDL_mutexV(_mutex);
    1.51 +}
    1.52 +
    1.53 +void SoundSDL::write(u16 * finalWave, int length)
    1.54 +{
    1.55 +	if (!_initialized)
    1.56 +		return;
    1.57 +
    1.58 +	if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)
    1.59 +		SDL_PauseAudio(0);
    1.60 +
    1.61 +	SDL_mutexP(_mutex);
    1.62 +
    1.63 +	unsigned int samples = length / 4;
    1.64 +
    1.65 +	std::size_t avail;
    1.66 +	while ((avail = _rbuf.avail() / 2) < samples)
    1.67 +	{
    1.68 +		_rbuf.write(finalWave, avail * 2);
    1.69 +
    1.70 +		finalWave += avail * 2;
    1.71 +		samples -= avail;
    1.72 +
    1.73 +		// If emulating and not in speed up mode, synchronize to audio
    1.74 +		// by waiting till there is enough room in the buffer
    1.75 +		if (emulating && !speedup)
    1.76 +		{
    1.77 +			SDL_CondWait(_cond,_mutex);
    1.78 +		}
    1.79 +		else
    1.80 +		{
    1.81 +			// Drop the remaining of the audio data
    1.82 +			SDL_mutexV(_mutex);
    1.83 +			return;
    1.84 +		}
    1.85 +	}
    1.86 +
    1.87 +	_rbuf.write(finalWave, samples * 2);
    1.88 +
    1.89 +	SDL_mutexV(_mutex);
    1.90 +}
    1.91 +
    1.92 +
    1.93 +bool SoundSDL::init()
    1.94 +{
    1.95 +	SDL_AudioSpec audio;
    1.96 +	audio.freq = SDL_SAMPLE_RATE;
    1.97 +	audio.format = AUDIO_S16SYS;
    1.98 +	audio.channels = 2;
    1.99 +	audio.samples = 1024;
   1.100 +	audio.callback = soundCallback;
   1.101 +	audio.userdata = this;
   1.102 +
   1.103 +	if(SDL_OpenAudio(&audio, NULL))
   1.104 +	{
   1.105 +		fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
   1.106 +		return false;
   1.107 +	}
   1.108 +
   1.109 +	_rbuf.reset(_delay * SDL_SAMPLE_RATE * 2);
   1.110 +
   1.111 +	_cond  = SDL_CreateCond();
   1.112 +	_mutex = SDL_CreateMutex();
   1.113 +	_initialized = true;
   1.114 +
   1.115 +	return true;
   1.116 +}
   1.117 +
   1.118 +SoundSDL::~SoundSDL()
   1.119 +{
   1.120 +	if (!_initialized)
   1.121 +		return;
   1.122 +
   1.123 +	SDL_mutexP(_mutex);
   1.124 +	int iSave = emulating;
   1.125 +	emulating = 0;
   1.126 +	SDL_CondSignal(_cond);
   1.127 +	SDL_mutexV(_mutex);
   1.128 +
   1.129 +	SDL_DestroyCond(_cond);
   1.130 +	_cond = NULL;
   1.131 +
   1.132 +	SDL_DestroyMutex(_mutex);
   1.133 +	_mutex = NULL;
   1.134 +
   1.135 +	SDL_CloseAudio();
   1.136 +
   1.137 +	emulating = iSave;
   1.138 +}
   1.139 +
   1.140 +void SoundSDL::pause()
   1.141 +{
   1.142 +	if (!_initialized)
   1.143 +		return;
   1.144 +
   1.145 +	SDL_PauseAudio(1);
   1.146 +}
   1.147 +
   1.148 +void SoundSDL::resume()
   1.149 +{
   1.150 +	if (!_initialized)
   1.151 +		return;
   1.152 +
   1.153 +	SDL_PauseAudio(0);
   1.154 +}
   1.155 +
   1.156 +void SoundSDL::reset()
   1.157 +{
   1.158 +}
   1.159 +
   1.160 +bool SoundSDL::setThrottle(unsigned short throttle){
   1.161 +	switch(throttle){
   1.162 +		case 25:
   1.163 +		case 50:
   1.164 +		case 100:
   1.165 +		case 200:
   1.166 +		case 400:
   1.167 +			break;
   1.168 +		default:
   1.169 +			return false;
   1.170 +	}
   1.171 +	SDL_CloseAudio();
   1.172 +	SDL_AudioSpec audio;
   1.173 +	audio.freq = SDL_SAMPLE_RATE*throttle/100;
   1.174 +	audio.format = AUDIO_S16SYS;
   1.175 +	audio.channels = 2;
   1.176 +	audio.samples = 1024;
   1.177 +	audio.callback = soundCallback;
   1.178 +	audio.userdata = this;
   1.179 +	_rbuf.reset((_delay * SDL_SAMPLE_RATE * throttle * 2)/100);
   1.180 +	return !SDL_OpenAudio(&audio,NULL);
   1.181 +}