From 6abd605ce8fa80df21b387127e34d69cc78ca90d Mon Sep 17 00:00:00 2001 From: Steve Checkoway Date: Sat, 14 Jun 2003 04:18:58 +0000 Subject: [PATCH] Added preliminary sound support for OSX. As far as I know, it should work on any system with SDL. However, I have no way of checking anything other than OSX. --- .../src/arch/Sound/RageSoundDriver_SDL.cpp | 146 ++++++++++++++++++ .../src/arch/Sound/RageSoundDriver_SDL.h | 45 ++++++ stepmania/src/arch/arch.cpp | 11 +- stepmania/src/arch/arch.h | 2 +- stepmania/src/arch/arch_darwin.h | 16 ++ 5 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 stepmania/src/arch/Sound/RageSoundDriver_SDL.cpp create mode 100644 stepmania/src/arch/Sound/RageSoundDriver_SDL.h create mode 100644 stepmania/src/arch/arch_darwin.h diff --git a/stepmania/src/arch/Sound/RageSoundDriver_SDL.cpp b/stepmania/src/arch/Sound/RageSoundDriver_SDL.cpp new file mode 100644 index 0000000000..1e508809dc --- /dev/null +++ b/stepmania/src/arch/Sound/RageSoundDriver_SDL.cpp @@ -0,0 +1,146 @@ +/* + * RageSoundDriver_SDL.cpp + * stepmania + * + * Created by Steve Checkoway on Fri Jun 13 2003. + * Copyright (c) 2003 Steve Checkoway. All rights reserved. + * + */ + +#include "global.h" +#include "RageSoundDriver_SDL.h" +#include "RageTimer.h" +#include "RageLog.h" +#include "RageSound.h" +#include "RageUtil.h" + +const unsigned channels = 2; +const unsigned samplerate = 441000; +const unsigned samplesize = channels*2; +const unsigned buffersize_frames = 1024; /* in samples */ +const unsigned buffersize = buffersize_frames * samplesize; + +RageSound_SDL::RageSound_SDL() { + last_cursor_pos = 0; + /* Do we need to init SDL_Audio? */ + initedSDL_Audio = SDL_WasInit(SDL_INIT_AUDIO) != SDL_INIT_AUDIO; + + if (initedSDL_Audio) + if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { + LOG->Trace("Initializing SDL_Audio subsytem."); + RageException::ThrowNonfatal(SDL_GetError()); + } + + SDL_AudioSpec *specs = static_cast(calloc(1, sizeof(SDL_AudioSpec))); + specs->freq = samplerate; + specs->format = AUDIO_S16MSB; /* Signed 16-bit big-endian samples */ + specs->channels = channels; + specs->samples = buffersize_frames; + specs->callback = GetData; + specs->userdata = this; + if (SDL_OpenAudio(specs, NULL)) + RageException::ThrowNonfatal(SDL_GetError()); + ASSERT(specs->size == buffersize); + SDL_PauseAudio(0); +} + +RageSound_SDL::~RageSound_SDL() { + SDL_CloseAudio(); + LOG->Trace("Mixing thread shut down."); + /* Did we init SDL_Audio? */ + if (initedSDL_Audio) { + SDL_QuitSubSystem(SDL_INIT_AUDIO); + LOG->Trace("SDL_Audio subsystem quit."); + } +} + +/* This function is called by the SDL_Audio subsytem to get the data + * to output. + * Params: userdata: A pointer to the creating RageSound_SDL. + * stream: The audio buffer to fill. + * len: The length of the buffer. + */ +void RageSound_SDL::GetData(void *userdata, Uint8 *stream, int len) { + LockMutex L(SOUNDMAN->lock); + static Sint16 *buf = NULL; + static int bufsize = buffersize_frames * channels; + static SoundMixBuffer mix; + if (!buf) + buf = new Sint16[bufsize]; + RageSound_SDL *P = static_cast(userdata); + + memset(buf, 0, bufsize*sizeof(Uint16)); + + /* I don't like this but I can't think of another place to put it. */ + while (!SOUNDMAN) + sleep(10); + + for (unsigned i = 0; i < P->sounds.size(); ++i) { + if (P->sounds[i]->stopping) + continue; + + int got = P->sounds[i]->snd->GetPCM(reinterpret_cast(buf), len, P->last_cursor_pos); + + mix.write(buf, got/2); + if (got < len) { + P->sounds[i]->stopping = true; + P->sounds[i]->flush_pos = P->last_cursor_pos + (got / samplesize); + } + } + + memcpy(stream, buf, len); + P->last_cursor_pos += buffersize_frames; +} + +void RageSound_SDL::StartMixing(RageSound *snd) { + sound *s = new sound; + s->snd = snd; + + LockMutex L(SOUNDMAN->lock); + sounds.push_back(s); +} + +void RageSound_SDL::StopMixing(RageSound *snd) { + LockMutex L(SOUNDMAN->lock); + + /* Find the sound. */ + unsigned i; + for(i = 0; i < sounds.size(); ++i) + if(sounds[i]->snd == snd) break; + if(i == sounds.size()) + { + LOG->Trace("not stopping a sound because it's not playing"); + return; + } + + delete sounds[i]; + sounds.erase(sounds.begin()+i, sounds.begin()+i+1); +} + +void RageSound_SDL::Update(float delta) { + LockMutex L(SOUNDMAN->lock); + + vectorsnds = sounds; + for (unsigned i = 0; i < snds.size(); ++i) { + if (!sounds[i]->stopping) + continue; + if (GetPosition(snds[i]->snd) < sounds[i]->flush_pos) + continue; + snds[i]->snd->StopPlaying(); + } +} + +/* What is this parameter for? + * This returns the same as is passed to RageSound::GetPCM + * as required by RageSoundDriver. I suppose I don't really + * understand the purpose of this method. + * --Steve + */ +int RageSound_SDL::GetPosition(const RageSound *snd) const { + return last_cursor_pos; +} + +float RageSound_SDL::GetPlayLatency() const { + return (1.0f / samplerate) * (7/8); +} + diff --git a/stepmania/src/arch/Sound/RageSoundDriver_SDL.h b/stepmania/src/arch/Sound/RageSoundDriver_SDL.h new file mode 100644 index 0000000000..ee06bbe1cd --- /dev/null +++ b/stepmania/src/arch/Sound/RageSoundDriver_SDL.h @@ -0,0 +1,45 @@ +#ifndef RAGE_SOUND_SDL +#define RAGE_SOUND_SDL +/* + * RageSoundDriver_SDL.h + * stepmania + * + * Created by Steve Checkoway on Fri Jun 13 2003. + * Judicially copying from RageSoundDriver_Null.* + * Copyright (c) 2003 Steve Checkoway. All rights reserved. + * + */ + +#include "RageSound.h" +#include +#include "RageSoundDriver.h" +#include + +class RageSound_SDL: public RageSoundDriver { +private: + struct sound { + RageSound *snd; + bool stopping; + int flush_pos; + sound() { snd=NULL; stopping=false; flush_pos=0; } + }; + + vector sounds; + SDL_AudioSpec *specs; + bool initedSDL_Audio; + int last_cursor_pos; + +protected: + virtual void StartMixing(RageSound *snd); + virtual void StopMixing(RageSound *snd); + virtual int GetPosition(const RageSound *snd) const; + virtual void Update(float delta); + virtual float GetPlayLatency() const; + +public: + RageSound_SDL(); + virtual ~RageSound_SDL(); + static void GetData(void *userdata, Uint8 *stream, int len); +}; + +#endif /*RAGE_SOUND_SDL*/ \ No newline at end of file diff --git a/stepmania/src/arch/arch.cpp b/stepmania/src/arch/arch.cpp index 7683059569..e123f5e723 100644 --- a/stepmania/src/arch/arch.cpp +++ b/stepmania/src/arch/arch.cpp @@ -16,12 +16,11 @@ #if defined(LINUX) #include "arch_linux.h" #elif defined(DARWIN) -// #include "arch_darwin.h" +#include "arch_darwin.h" #elif defined(WIN32) #include "arch_Win32.h" #endif - LoadingWindow *MakeLoadingWindow() { return new ARCH_LOADING_WINDOW; } ErrorDialog *MakeErrorDialog() { return new ARCH_ERROR_DIALOG; } ArchHooks *MakeArchHooks() { return new ARCH_HOOKS; } @@ -69,7 +68,13 @@ RageSoundDriver *MakeRageSoundDriver(CString drivers) #endif #ifdef HAVE_OSS if(!DriversToTry[i].CompareNoCase("OSS")) ret = new RageSound_OSS; -#endif +#endif + if(!DriversToTry[i].CompareNoCase("SDL")) + try { + ret = new RageSound_SDL; + } catch (RageException e) { + ret = NULL; + } if(!DriversToTry[i].CompareNoCase("Null")) ret = new RageSound_Null; if( !ret ) LOG->Warn("Unknown sound driver name: %s", DriversToTry[i].c_str()); diff --git a/stepmania/src/arch/arch.h b/stepmania/src/arch/arch.h index bcd34bb33e..78359fabf5 100644 --- a/stepmania/src/arch/arch.h +++ b/stepmania/src/arch/arch.h @@ -22,7 +22,7 @@ RageSoundDriver *MakeRageSoundDriver(CString drivers); #if defined(LINUX) #define DEFAULT_SOUND_DRIVER_LIST "ALSA9,OSS,Null" #elif defined(DARWIN) -#define DEFAULT_SOUND_DRIVER_LIST "Null" /* XXX */ +#define DEFAULT_SOUND_DRIVER_LIST "SDL,Null" #elif defined(WIN32) #define DEFAULT_SOUND_DRIVER_LIST "DirectSound,DirectSound-sw,WaveOut" #else diff --git a/stepmania/src/arch/arch_darwin.h b/stepmania/src/arch/arch_darwin.h new file mode 100644 index 0000000000..4dd303f7c7 --- /dev/null +++ b/stepmania/src/arch/arch_darwin.h @@ -0,0 +1,16 @@ +#ifndef ARCH_DARWIN_H +#define ARCH_DARWIN_H + +/* + * arch_darwin.h + * stepmania + * + * Created by Steve Checkoway on Fri Jun 13 2003. + * Copyright (c) 2003 Steve Checkoway. All rights reserved. + * + */ + +#include +#include "RageSoundDriver_SDL.h" +#endif +