annotate src/sdl/SoundSDL.cpp @ 386:d8cbbf2a3133

changed scratch ragisters from BC to DE.
author Robert McIntyre <rlm@mit.edu>
date Thu, 12 Apr 2012 06:27:03 -0500
parents f9f4f1b99eed
children fa7676dbf6f2
rev   line source
rlm@1 1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
rlm@1 2 // Copyright (C) 2008 VBA-M development team
rlm@1 3
rlm@1 4 // This program is free software; you can redistribute it and/or modify
rlm@1 5 // it under the terms of the GNU General Public License as published by
rlm@1 6 // the Free Software Foundation; either version 2, or(at your option)
rlm@1 7 // any later version.
rlm@1 8 //
rlm@1 9 // This program is distributed in the hope that it will be useful,
rlm@1 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
rlm@1 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
rlm@1 12 // GNU General Public License for more details.
rlm@1 13 //
rlm@1 14 // You should have received a copy of the GNU General Public License
rlm@1 15 // along with this program; if not, write to the Free Software Foundation,
rlm@1 16 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
rlm@1 17
rlm@1 18 #include "SoundSDL.h"
rlm@1 19
rlm@1 20 extern int emulating;
rlm@1 21 extern bool speedup;
rlm@1 22
rlm@1 23 // Hold up to 100 ms of data in the ring buffer
rlm@1 24 const float SoundSDL::_delay = 0.1f;
rlm@1 25
rlm@1 26 SoundSDL::SoundSDL():
rlm@1 27 _rbuf(0),
rlm@1 28 _initialized(false)
rlm@1 29 {
rlm@1 30
rlm@1 31 }
rlm@1 32
rlm@1 33 void SoundSDL::soundCallback(void *data, u8 *stream, int len)
rlm@1 34 {
rlm@1 35 reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<u16 *>(stream), len);
rlm@1 36 }
rlm@1 37
rlm@1 38 void SoundSDL::read(u16 * stream, int length)
rlm@1 39 {
rlm@1 40 if (!_initialized || length <= 0 || !emulating)
rlm@1 41 return;
rlm@1 42
rlm@1 43 SDL_mutexP(_mutex);
rlm@1 44 _rbuf.read(stream, std::min(static_cast<std::size_t>(length) / 2, _rbuf.used()));
rlm@1 45
rlm@1 46 SDL_CondSignal(_cond);
rlm@1 47 SDL_mutexV(_mutex);
rlm@1 48 }
rlm@1 49
rlm@1 50 void SoundSDL::write(u16 * finalWave, int length)
rlm@1 51 {
rlm@1 52 if (!_initialized)
rlm@1 53 return;
rlm@1 54
rlm@1 55 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)
rlm@1 56 SDL_PauseAudio(0);
rlm@1 57
rlm@1 58 SDL_mutexP(_mutex);
rlm@1 59
rlm@1 60 unsigned int samples = length / 4;
rlm@1 61
rlm@1 62 std::size_t avail;
rlm@1 63 while ((avail = _rbuf.avail() / 2) < samples)
rlm@1 64 {
rlm@1 65 _rbuf.write(finalWave, avail * 2);
rlm@1 66
rlm@1 67 finalWave += avail * 2;
rlm@1 68 samples -= avail;
rlm@1 69
rlm@1 70 // If emulating and not in speed up mode, synchronize to audio
rlm@1 71 // by waiting till there is enough room in the buffer
rlm@1 72 if (emulating && !speedup)
rlm@1 73 {
rlm@1 74 SDL_CondWait(_cond,_mutex);
rlm@1 75 }
rlm@1 76 else
rlm@1 77 {
rlm@1 78 // Drop the remaining of the audio data
rlm@1 79 SDL_mutexV(_mutex);
rlm@1 80 return;
rlm@1 81 }
rlm@1 82 }
rlm@1 83
rlm@1 84 _rbuf.write(finalWave, samples * 2);
rlm@1 85
rlm@1 86 SDL_mutexV(_mutex);
rlm@1 87 }
rlm@1 88
rlm@1 89
rlm@1 90 bool SoundSDL::init()
rlm@1 91 {
rlm@1 92 SDL_AudioSpec audio;
rlm@1 93 audio.freq = SDL_SAMPLE_RATE;
rlm@1 94 audio.format = AUDIO_S16SYS;
rlm@1 95 audio.channels = 2;
rlm@1 96 audio.samples = 1024;
rlm@1 97 audio.callback = soundCallback;
rlm@1 98 audio.userdata = this;
rlm@1 99
rlm@1 100 if(SDL_OpenAudio(&audio, NULL))
rlm@1 101 {
rlm@1 102 fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
rlm@1 103 return false;
rlm@1 104 }
rlm@1 105
rlm@1 106 _rbuf.reset(_delay * SDL_SAMPLE_RATE * 2);
rlm@1 107
rlm@1 108 _cond = SDL_CreateCond();
rlm@1 109 _mutex = SDL_CreateMutex();
rlm@1 110 _initialized = true;
rlm@1 111
rlm@1 112 return true;
rlm@1 113 }
rlm@1 114
rlm@1 115 SoundSDL::~SoundSDL()
rlm@1 116 {
rlm@1 117 if (!_initialized)
rlm@1 118 return;
rlm@1 119
rlm@1 120 SDL_mutexP(_mutex);
rlm@1 121 int iSave = emulating;
rlm@1 122 emulating = 0;
rlm@1 123 SDL_CondSignal(_cond);
rlm@1 124 SDL_mutexV(_mutex);
rlm@1 125
rlm@1 126 SDL_DestroyCond(_cond);
rlm@1 127 _cond = NULL;
rlm@1 128
rlm@1 129 SDL_DestroyMutex(_mutex);
rlm@1 130 _mutex = NULL;
rlm@1 131
rlm@1 132 SDL_CloseAudio();
rlm@1 133
rlm@1 134 emulating = iSave;
rlm@1 135 }
rlm@1 136
rlm@1 137 void SoundSDL::pause()
rlm@1 138 {
rlm@1 139 if (!_initialized)
rlm@1 140 return;
rlm@1 141
rlm@1 142 SDL_PauseAudio(1);
rlm@1 143 }
rlm@1 144
rlm@1 145 void SoundSDL::resume()
rlm@1 146 {
rlm@1 147 if (!_initialized)
rlm@1 148 return;
rlm@1 149
rlm@1 150 SDL_PauseAudio(0);
rlm@1 151 }
rlm@1 152
rlm@1 153 void SoundSDL::reset()
rlm@1 154 {
rlm@1 155 }
rlm@1 156
rlm@1 157 bool SoundSDL::setThrottle(unsigned short throttle){
rlm@1 158 switch(throttle){
rlm@1 159 case 25:
rlm@1 160 case 50:
rlm@1 161 case 100:
rlm@1 162 case 200:
rlm@1 163 case 400:
rlm@1 164 break;
rlm@1 165 default:
rlm@1 166 return false;
rlm@1 167 }
rlm@1 168 SDL_CloseAudio();
rlm@1 169 SDL_AudioSpec audio;
rlm@1 170 audio.freq = SDL_SAMPLE_RATE*throttle/100;
rlm@1 171 audio.format = AUDIO_S16SYS;
rlm@1 172 audio.channels = 2;
rlm@1 173 audio.samples = 1024;
rlm@1 174 audio.callback = soundCallback;
rlm@1 175 audio.userdata = this;
rlm@1 176 _rbuf.reset((_delay * SDL_SAMPLE_RATE * throttle * 2)/100);
rlm@1 177 return !SDL_OpenAudio(&audio,NULL);
rlm@1 178 }