00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00032
00033
00034
00035
00036
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040
00041 #include "stratagus.h"
00042
00043 #include "SDL.h"
00044
00045 #include "sound_server.h"
00046 #include "iolib.h"
00047 #include "iocompat.h"
00048
00049
00050
00051
00052
00053
00054 static bool SoundInitialized;
00055 static bool MusicPlaying;
00056
00057 static int EffectsVolume = 128;
00058 static int MusicVolume = 128;
00059
00060 static bool MusicEnabled = true;
00061 static bool EffectsEnabled = true;
00062
00064 struct SoundChannel {
00065 CSample *Sample;
00066 unsigned char Volume;
00067 signed char Stereo;
00068
00069 bool Playing;
00070 int Point;
00071
00072 void (*FinishedCallback)(int channel);
00073 };
00074
00075 #define MaxChannels 32
00076
00077 static SoundChannel Channels[MaxChannels];
00078 static int NextFreeChannel;
00079
00080 static struct {
00081 CSample *Sample;
00082 void (*FinishedCallback)();
00083 } MusicChannel;
00084
00085 static void ChannelFinished(int channel);
00086
00087 static int *MixerBuffer;
00088 static int MixerBufferSize;
00089
00090
00091
00092
00093
00094
00107 static int ConvertToStereo32(const char *src, char *dest, int frequency,
00108 int chansize, int channels, int bytes)
00109 {
00110 SDL_AudioCVT acvt;
00111 Uint16 format;
00112
00113 if (chansize == 1) {
00114 format = AUDIO_U8;
00115 } else {
00116 format = AUDIO_S16SYS;
00117 }
00118 SDL_BuildAudioCVT(&acvt, format, channels, frequency, AUDIO_S16SYS, 2, 44100);
00119
00120 acvt.buf = (Uint8 *)dest;
00121 memcpy(dest, src, bytes);
00122 acvt.len = bytes;
00123
00124 SDL_ConvertAudio(&acvt);
00125
00126 return acvt.len_mult * bytes;
00127 }
00128
00138 static void MixMusicToStereo32(int *buffer, int size)
00139 {
00140 int i;
00141 int n;
00142 int len;
00143 short *buf;
00144 char *tmp;
00145 int div;
00146
00147 if (MusicPlaying) {
00148 Assert(MusicChannel.Sample);
00149
00150 len = size * sizeof(*buf);
00151 tmp = new char[len];
00152 buf = new short[len];
00153
00154 div = 176400 / (MusicChannel.Sample->Frequency * (MusicChannel.Sample->SampleSize / 8)
00155 * MusicChannel.Sample->Channels);
00156
00157 size = MusicChannel.Sample->Read(tmp, len / div);
00158
00159 n = ConvertToStereo32((char *)(tmp), (char *)buf, MusicChannel.Sample->Frequency,
00160 MusicChannel.Sample->SampleSize / 8, MusicChannel.Sample->Channels, size);
00161
00162 for (i = 0; i < n / (int)sizeof(*buf); ++i) {
00163
00164
00165 buffer[i] += buf[i] * MusicVolume / MaxVolume / 2;
00166 }
00167
00168 delete[] tmp;
00169 delete[] buf;
00170
00171 if (n < len) {
00172 MusicPlaying = false;
00173 delete MusicChannel.Sample;
00174 MusicChannel.Sample = NULL;
00175
00176 if (MusicChannel.FinishedCallback) {
00177 MusicChannel.FinishedCallback();
00178 }
00179 }
00180 }
00181 }
00182
00200 static int MixSampleToStereo32(CSample *sample, int index, unsigned char volume,
00201 char stereo, int *buffer, int size)
00202 {
00203 int local_volume;
00204 unsigned char left;
00205 unsigned char right;
00206 int i;
00207 static int buf[SOUND_BUFFER_SIZE / 2];
00208 int div;
00209
00210 div = 176400 / (sample->Frequency * (sample->SampleSize / 8)
00211 * sample->Channels);
00212
00213 local_volume = (int)volume * EffectsVolume / MaxVolume;
00214
00215 if (stereo < 0) {
00216 left = 128;
00217 right = 128 + stereo;
00218 } else {
00219 left = 128 - stereo;
00220 right = 128;
00221 }
00222
00223 Assert(!(index & 1));
00224
00225 if (size >= (sample->Len - index) * div / 2) {
00226 size = (sample->Len - index) * div / 2;
00227 }
00228
00229 size = ConvertToStereo32((char *)(sample->Buffer + index), (char *)buf, sample->Frequency,
00230 sample->SampleSize / 8, sample->Channels,
00231 size * 2 / div);
00232
00233 size /= 2;
00234 for (i = 0; i < size; i += 2) {
00235
00236 buffer[i] += ((short *)buf)[i] * local_volume * left / 128 / MaxVolume / 2;
00237 buffer[i + 1] += ((short *)buf)[i + 1] * local_volume * right / 128 / MaxVolume / 2;
00238 }
00239
00240 return 2 * size / div;
00241 }
00242
00251 static int MixChannelsToStereo32(int *buffer, int size)
00252 {
00253 int channel;
00254 int i;
00255 int new_free_channels;
00256
00257 new_free_channels = 0;
00258 for (channel = 0; channel < MaxChannels; ++channel) {
00259 if (Channels[channel].Playing && Channels[channel].Sample) {
00260 i = MixSampleToStereo32(Channels[channel].Sample,
00261 Channels[channel].Point, Channels[channel].Volume,
00262 Channels[channel].Stereo, buffer, size);
00263 Channels[channel].Point += i;
00264 Assert(Channels[channel].Point <= Channels[channel].Sample->Len);
00265
00266 if (Channels[channel].Point == Channels[channel].Sample->Len) {
00267 ChannelFinished(channel);
00268 ++new_free_channels;
00269 }
00270 }
00271 }
00272
00273 return new_free_channels;
00274 }
00275
00283 static void ClipMixToStereo16(const int *mix, int size, short *output)
00284 {
00285 int s;
00286 const int *end;
00287
00288 end = mix + size;
00289 while (mix < end) {
00290 s = (*mix++);
00291 if (s > SHRT_MAX) {
00292 *output++ = SHRT_MAX;
00293 } else if (s < SHRT_MIN) {
00294 *output++ = SHRT_MIN;
00295 } else {
00296 *output++ = s;
00297 }
00298 }
00299 }
00300
00307 static void MixIntoBuffer(void *buffer, int samples)
00308 {
00309 if (samples > MixerBufferSize) {
00310 delete[] MixerBuffer;
00311 MixerBuffer = new int[samples];
00312 MixerBufferSize = samples;
00313 }
00314
00315
00316 memset(MixerBuffer, 0, samples * sizeof(*MixerBuffer));
00317
00318 if (EffectsEnabled) {
00319
00320 MixChannelsToStereo32(MixerBuffer, samples);
00321 }
00322 if (MusicEnabled) {
00323
00324 MixMusicToStereo32(MixerBuffer, samples);
00325 }
00326
00327 ClipMixToStereo16(MixerBuffer, samples, (short *)buffer);
00328 }
00329
00339 static void FillAudio(void *udata, Uint8 *stream, int len)
00340 {
00341 len >>= 1;
00342 MixIntoBuffer(stream, len);
00343 }
00344
00345
00346
00347
00348
00352 static void ChannelFinished(int channel)
00353 {
00354 if (Channels[channel].FinishedCallback) {
00355 Channels[channel].FinishedCallback(channel);
00356 }
00357
00358 Channels[channel].Playing = false;
00359 Channels[channel].Point = NextFreeChannel;
00360 NextFreeChannel = channel;
00361 }
00362
00366 static int FillChannel(CSample *sample, unsigned char volume, char stereo)
00367 {
00368 Assert(NextFreeChannel < MaxChannels);
00369
00370 int old_free = NextFreeChannel;
00371 int next_free = Channels[NextFreeChannel].Point;
00372
00373 Channels[NextFreeChannel].Volume = volume;
00374 Channels[NextFreeChannel].Point = 0;
00375 Channels[NextFreeChannel].Playing = true;
00376 Channels[NextFreeChannel].Sample = sample;
00377 Channels[NextFreeChannel].Stereo = stereo;
00378 Channels[NextFreeChannel].FinishedCallback = NULL;
00379
00380 NextFreeChannel = next_free;
00381
00382 return old_free;
00383 }
00384
00393 int SetChannelVolume(int channel, int volume)
00394 {
00395 if (channel < 0 || channel >= MaxChannels) {
00396 return -1;
00397 }
00398
00399 if (volume < 0) {
00400 volume = Channels[channel].Volume;
00401 } else {
00402 SDL_LockAudio();
00403
00404 if (volume > MaxVolume) {
00405 volume = MaxVolume;
00406 }
00407 Channels[channel].Volume = volume;
00408
00409 SDL_UnlockAudio();
00410 }
00411
00412 return volume;
00413 }
00414
00423 int SetChannelStereo(int channel, int stereo)
00424 {
00425 if (channel < 0 || channel >= MaxChannels) {
00426 return -1;
00427 }
00428
00429 if (stereo < -128 || stereo > 127) {
00430 stereo = Channels[channel].Stereo;
00431 } else {
00432 SDL_LockAudio();
00433
00434 if (stereo > 127) {
00435 stereo = 127;
00436 } else if (stereo < -128) {
00437 stereo = -128;
00438 }
00439 Channels[channel].Stereo = stereo;
00440
00441 SDL_UnlockAudio();
00442 }
00443
00444 return stereo;
00445 }
00446
00453 void SetChannelFinishedCallback(int channel, void (*callback)(int channel))
00454 {
00455 if (channel < 0 || channel >= MaxChannels) {
00456 return;
00457 }
00458
00459 Channels[channel].FinishedCallback = callback;
00460 }
00461
00465 CSample *GetChannelSample(int channel)
00466 {
00467 if (channel < 0 || channel >= MaxChannels) {
00468 return NULL;
00469 }
00470
00471 return Channels[channel].Sample;
00472 }
00473
00479 void StopChannel(int channel)
00480 {
00481 SDL_LockAudio();
00482
00483 if (channel >= 0 && channel < MaxChannels) {
00484 if (Channels[channel].Playing) {
00485 ChannelFinished(channel);
00486 }
00487 }
00488
00489 SDL_UnlockAudio();
00490 }
00491
00495 void StopAllChannels()
00496 {
00497 SDL_LockAudio();
00498
00499 for (int i = 0; i < MaxChannels; ++i) {
00500 if (Channels[i].Playing) {
00501 ChannelFinished(i);
00502 }
00503 }
00504
00505 SDL_UnlockAudio();
00506 }
00507
00517 CSample *LoadSample(const std::string &name)
00518 {
00519 CSample *sample;
00520 char buf[PATH_MAX];
00521
00522 LibraryFileName(name.c_str(), buf, sizeof(buf));
00523
00524 if ((sample = LoadWav(buf, PlayAudioLoadInMemory))) {
00525 return sample;
00526 }
00527 #ifdef USE_VORBIS
00528 if ((sample = LoadVorbis(buf, PlayAudioLoadInMemory))) {
00529 return sample;
00530 }
00531 #endif
00532
00533 fprintf(stderr, "Can't load the sound `%s'\n", name.c_str());
00534
00535 return sample;
00536 }
00537
00545 int PlaySample(CSample *sample)
00546 {
00547 int channel = -1;
00548
00549 SDL_LockAudio();
00550
00551 if (SoundEnabled() && EffectsEnabled && sample &&
00552 NextFreeChannel != MaxChannels) {
00553 channel = FillChannel(sample, EffectsVolume, 0);
00554 }
00555
00556 SDL_UnlockAudio();
00557
00558 return channel;
00559 }
00560
00568 int PlaySoundFile(const std::string &name)
00569 {
00570 CSample *sample = LoadSample(name);
00571 if (sample) {
00572 return PlaySample(sample);
00573 }
00574 return -1;
00575 }
00576
00582 void SetEffectsVolume(int volume)
00583 {
00584 if (volume < 0) {
00585 EffectsVolume = 0;
00586 } else if (volume > MaxVolume) {
00587 EffectsVolume = MaxVolume;
00588 } else {
00589 EffectsVolume = volume;
00590 }
00591 }
00592
00596 int GetEffectsVolume(void)
00597 {
00598 return EffectsVolume;
00599 }
00600
00604 void SetEffectsEnabled(bool enabled)
00605 {
00606 EffectsEnabled = enabled;
00607 }
00608
00612 bool IsEffectsEnabled(void)
00613 {
00614 return EffectsEnabled;
00615 }
00616
00617
00618
00619
00620
00624 void SetMusicFinishedCallback(void (*callback)(void))
00625 {
00626 MusicChannel.FinishedCallback = callback;
00627 }
00628
00636 int PlayMusic(CSample *sample)
00637 {
00638 if (sample) {
00639 StopMusic();
00640 MusicChannel.Sample = sample;
00641 MusicPlaying = true;
00642 return 0;
00643 } else {
00644 DebugPrint("Could not play sample\n");
00645 return -1;
00646 }
00647 }
00648
00656 int PlayMusic(const std::string &file)
00657 {
00658 char name[PATH_MAX];
00659 CSample *sample;
00660
00661 if (!SoundEnabled() || !IsMusicEnabled()) {
00662 return -1;
00663 }
00664
00665 LibraryFileName(file.c_str(), name, sizeof(name));
00666
00667 DebugPrint("play music %s\n" _C_ name);
00668
00669 sample = LoadWav(name, PlayAudioStream);
00670
00671 #ifdef USE_VORBIS
00672 if (!sample) {
00673 sample = LoadVorbis(name, PlayAudioStream);
00674 }
00675 #endif
00676
00677 if (sample) {
00678 StopMusic();
00679 MusicChannel.Sample = sample;
00680 MusicPlaying = true;
00681 return 0;
00682 } else {
00683 DebugPrint("Could not play %s\n" _C_ file.c_str());
00684 return -1;
00685 }
00686 }
00687
00691 void StopMusic(void)
00692 {
00693 if (MusicPlaying) {
00694 MusicPlaying = false;
00695 if (MusicChannel.Sample) {
00696 SDL_LockAudio();
00697 delete MusicChannel.Sample;
00698 MusicChannel.Sample = NULL;
00699 SDL_UnlockAudio();
00700 }
00701 }
00702 }
00703
00709 void SetMusicVolume(int volume)
00710 {
00711 if (volume < 0) {
00712 MusicVolume = 0;
00713 } else if (volume > MaxVolume) {
00714 MusicVolume = MaxVolume;
00715 } else {
00716 MusicVolume = volume;
00717 }
00718 }
00719
00723 int GetMusicVolume(void)
00724 {
00725 return MusicVolume;
00726 }
00727
00731 void SetMusicEnabled(bool enabled)
00732 {
00733 if (enabled) {
00734 MusicEnabled = true;
00735 } else {
00736 MusicEnabled = false;
00737 StopMusic();
00738 }
00739 }
00740
00744 bool IsMusicEnabled(void)
00745 {
00746 return MusicEnabled;
00747 }
00748
00752 bool IsMusicPlaying(void)
00753 {
00754 return MusicPlaying;
00755 }
00756
00757
00758
00759
00760
00764 bool SoundEnabled(void)
00765 {
00766 return SoundInitialized;
00767 }
00768
00777 static int InitSdlSound(int freq, int size)
00778 {
00779 SDL_AudioSpec wanted;
00780
00781 wanted.freq = freq;
00782 if (size == 8) {
00783 wanted.format = AUDIO_U8;
00784 } else if (size == 16) {
00785 wanted.format = AUDIO_S16SYS;
00786 } else {
00787 DebugPrint("Unexpected sample size %d\n" _C_ size);
00788 wanted.format = AUDIO_S16SYS;
00789 }
00790 wanted.channels = 2;
00791 wanted.samples = 4096;
00792 wanted.callback = FillAudio;
00793 wanted.userdata = NULL;
00794
00795
00796 if (SDL_OpenAudio(&wanted, NULL) < 0) {
00797 fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
00798 return -1;
00799 }
00800 SDL_PauseAudio(0);
00801
00802 return 0;
00803 }
00804
00810 int InitSound(void)
00811 {
00812
00813
00814
00815 if (InitSdlSound(44100, 16)) {
00816 SoundInitialized = false;
00817 return 1;
00818 }
00819 SoundInitialized = true;
00820
00821
00822
00823
00824 for (int i = 0; i < MaxChannels; ++i) {
00825 Channels[i].Point = i + 1;
00826 }
00827
00828 return 0;
00829 }
00830
00834 void QuitSound(void)
00835 {
00836 SDL_CloseAudio();
00837 SoundInitialized = false;
00838 delete[] MixerBuffer;
00839 MixerBuffer = NULL;
00840 }
00841