annotate src/sdl/SoundSDL.cpp @ 546:36e5fa62eb3c

i believe this latest change will correct all A/V synching problems.
author Robert McIntyre <rlm@mit.edu>
date Wed, 27 Jun 2012 14:08:59 -0500
parents fa7676dbf6f2
children
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@525 19 #include <stdio.h>
rlm@525 20
rlm@1 21
rlm@1 22 extern int emulating;
rlm@1 23 extern bool speedup;
rlm@1 24
rlm@1 25 // Hold up to 100 ms of data in the ring buffer
rlm@1 26 const float SoundSDL::_delay = 0.1f;
rlm@1 27
rlm@1 28 SoundSDL::SoundSDL():
rlm@1 29 _rbuf(0),
rlm@1 30 _initialized(false)
rlm@1 31 {
rlm@1 32
rlm@1 33 }
rlm@1 34
rlm@1 35 void SoundSDL::soundCallback(void *data, u8 *stream, int len)
rlm@1 36 {
rlm@1 37 reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<u16 *>(stream), len);
rlm@1 38 }
rlm@1 39
rlm@1 40 void SoundSDL::read(u16 * stream, int length)
rlm@1 41 {
rlm@525 42 if (!_initialized || length <= 0 || !emulating)
rlm@525 43 return;
rlm@1 44
rlm@525 45 SDL_mutexP(_mutex);
rlm@525 46 _rbuf.read(stream, std::min(static_cast<std::size_t>(length) / 2, _rbuf.used()));
rlm@1 47
rlm@525 48 SDL_CondSignal(_cond);
rlm@525 49 SDL_mutexV(_mutex);
rlm@1 50 }
rlm@1 51
rlm@1 52 void SoundSDL::write(u16 * finalWave, int length)
rlm@1 53 {
rlm@525 54 if (!_initialized)
rlm@525 55 return;
rlm@1 56
rlm@525 57 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING){
rlm@525 58 SDL_PauseAudio(0);
rlm@525 59 printf("SDLPauseAudio\n");
rlm@525 60 }
rlm@1 61
rlm@525 62 SDL_mutexP(_mutex);
rlm@1 63
rlm@525 64 //printf("RLM: length = %d\n", length);
rlm@1 65
rlm@525 66 unsigned int samples = length / 4;
rlm@525 67
rlm@525 68 // printf("RLM: length / 4 = %d\n", samples);
rlm@525 69
rlm@525 70 std::size_t avail;
rlm@525 71 while ((avail = _rbuf.avail() / 2) < samples)
rlm@525 72 {
rlm@525 73 _rbuf.write(finalWave, avail * 2);
rlm@525 74
rlm@525 75 finalWave += avail * 2;
rlm@525 76 samples -= avail;
rlm@525 77
rlm@525 78 // If emulating and not in speed up mode, synchronize to audio
rlm@525 79 // by waiting till there is enough room in the buffer
rlm@525 80 if (emulating && !speedup)
rlm@1 81 {
rlm@525 82 //printf("SDL_CondWait\n");
rlm@525 83 SDL_CondWait(_cond,_mutex);
rlm@525 84 }
rlm@525 85 else
rlm@525 86 {
rlm@525 87 // Drop the remainder of the audio data
rlm@525 88 printf("RLM: Drop samples!\n");
rlm@525 89 SDL_mutexV(_mutex);
rlm@525 90 return;
rlm@525 91 }
rlm@525 92 }
rlm@1 93
rlm@525 94 _rbuf.write(finalWave, samples * 2);
rlm@525 95 //printf("RLM: writing %d samples\n", samples);
rlm@525 96 SDL_mutexV(_mutex);
rlm@1 97 }
rlm@1 98
rlm@1 99
rlm@1 100 bool SoundSDL::init()
rlm@1 101 {
rlm@1 102 SDL_AudioSpec audio;
rlm@1 103 audio.freq = SDL_SAMPLE_RATE;
rlm@1 104 audio.format = AUDIO_S16SYS;
rlm@1 105 audio.channels = 2;
rlm@1 106 audio.samples = 1024;
rlm@1 107 audio.callback = soundCallback;
rlm@1 108 audio.userdata = this;
rlm@1 109
rlm@1 110 if(SDL_OpenAudio(&audio, NULL))
rlm@1 111 {
rlm@1 112 fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
rlm@1 113 return false;
rlm@1 114 }
rlm@1 115
rlm@1 116 _rbuf.reset(_delay * SDL_SAMPLE_RATE * 2);
rlm@1 117
rlm@1 118 _cond = SDL_CreateCond();
rlm@1 119 _mutex = SDL_CreateMutex();
rlm@1 120 _initialized = true;
rlm@1 121
rlm@1 122 return true;
rlm@1 123 }
rlm@1 124
rlm@1 125 SoundSDL::~SoundSDL()
rlm@1 126 {
rlm@1 127 if (!_initialized)
rlm@1 128 return;
rlm@1 129
rlm@1 130 SDL_mutexP(_mutex);
rlm@1 131 int iSave = emulating;
rlm@1 132 emulating = 0;
rlm@1 133 SDL_CondSignal(_cond);
rlm@1 134 SDL_mutexV(_mutex);
rlm@1 135
rlm@1 136 SDL_DestroyCond(_cond);
rlm@1 137 _cond = NULL;
rlm@1 138
rlm@1 139 SDL_DestroyMutex(_mutex);
rlm@1 140 _mutex = NULL;
rlm@1 141
rlm@1 142 SDL_CloseAudio();
rlm@1 143
rlm@1 144 emulating = iSave;
rlm@1 145 }
rlm@1 146
rlm@1 147 void SoundSDL::pause()
rlm@1 148 {
rlm@1 149 if (!_initialized)
rlm@1 150 return;
rlm@1 151
rlm@1 152 SDL_PauseAudio(1);
rlm@1 153 }
rlm@1 154
rlm@1 155 void SoundSDL::resume()
rlm@1 156 {
rlm@1 157 if (!_initialized)
rlm@1 158 return;
rlm@1 159
rlm@1 160 SDL_PauseAudio(0);
rlm@1 161 }
rlm@1 162
rlm@1 163 void SoundSDL::reset()
rlm@1 164 {
rlm@1 165 }
rlm@1 166
rlm@1 167 bool SoundSDL::setThrottle(unsigned short throttle){
rlm@1 168 switch(throttle){
rlm@1 169 case 25:
rlm@1 170 case 50:
rlm@1 171 case 100:
rlm@1 172 case 200:
rlm@1 173 case 400:
rlm@1 174 break;
rlm@1 175 default:
rlm@1 176 return false;
rlm@1 177 }
rlm@1 178 SDL_CloseAudio();
rlm@1 179 SDL_AudioSpec audio;
rlm@1 180 audio.freq = SDL_SAMPLE_RATE*throttle/100;
rlm@1 181 audio.format = AUDIO_S16SYS;
rlm@1 182 audio.channels = 2;
rlm@1 183 audio.samples = 1024;
rlm@1 184 audio.callback = soundCallback;
rlm@1 185 audio.userdata = this;
rlm@1 186 _rbuf.reset((_delay * SDL_SAMPLE_RATE * throttle * 2)/100);
rlm@1 187 return !SDL_OpenAudio(&audio,NULL);
rlm@1 188 }