support for fading music
[supertux.git] / src / audio / stream_sound_source.cpp
1 #include <config.h>
2
3 #include <SDL.h>
4 #include "stream_sound_source.hpp"
5 #include "sound_manager.hpp"
6 #include "sound_file.hpp"
7
8 StreamSoundSource::StreamSoundSource(SoundFile* file)
9 {
10   this->file = file;
11   alGenBuffers(STREAMFRAGMENTS, buffers);
12   SoundManager::check_al_error("Couldn't allocate audio buffers: ");
13   format = SoundManager::get_sample_format(file);
14   try {
15     for(size_t i = 0; i < STREAMFRAGMENTS; ++i) {
16       fillBufferAndQueue(buffers[i]);
17     }
18   } catch(...) {
19     alDeleteBuffers(STREAMFRAGMENTS, buffers);
20   }
21 }
22
23 StreamSoundSource::~StreamSoundSource()
24 {
25   alDeleteBuffers(STREAMFRAGMENTS, buffers);
26   SoundManager::check_al_error("Couldn't delete audio buffers: ");
27 }
28
29 void
30 StreamSoundSource::update()
31 {
32   if(!playing())
33     return;
34
35   ALint processed = 0;
36   alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
37   while(processed > 0) {
38     processed--;
39
40     ALuint buffer;
41     alSourceUnqueueBuffers(source, 1, &buffer);
42     SoundManager::check_al_error("Couldn't unqueu audio buffer: ");
43
44     fillBufferAndQueue(buffer);
45   }
46   
47   // we might have to restart the source if we had a buffer underrun
48   if(!playing()) {
49     std::cerr << "Restarting audio source because of buffer underrun.\n";
50     alSourcePlay(source);
51     SoundManager::check_al_error("Couldn't restart audio source: ");
52   }
53
54   if(fade_state == FadingOn) {
55     Uint32 ticks = SDL_GetTicks();
56     float time = (ticks - fade_start_ticks) / 1000.0;
57     if(time >= fade_time) {
58       set_gain(1.0);
59       fade_state = NoFading;
60     } else {
61       set_gain(time / fade_time);
62     }
63   } else if(fade_state == FadingOff) {
64     Uint32 ticks = SDL_GetTicks();
65     float time = (ticks - fade_start_ticks) / 1000.0;
66     if(time >= fade_time) {                              
67       stop();
68       fade_state = NoFading;
69     } else {
70       set_gain( (fade_time-time) / fade_time);
71     }
72   }
73 }
74
75 void
76 StreamSoundSource::setFading(FadeState state, float fade_time)
77 {
78   this->fade_state = state;
79   this->fade_time = fade_time;
80   this->fade_start_ticks = SDL_GetTicks();
81 }
82
83 void
84 StreamSoundSource::fillBufferAndQueue(ALuint buffer)
85 {
86   // fill buffer
87   char* bufferdata = new char[STREAMFRAGMENTSIZE];
88   size_t bytesread = 0;
89   do {
90     bytesread += file->read(bufferdata + bytesread,
91         STREAMFRAGMENTSIZE - bytesread);
92     if(bytesread < STREAMFRAGMENTSIZE) {
93       file->reset();
94     }
95   } while(bytesread < STREAMFRAGMENTSIZE);
96   
97   alBufferData(buffer, format, bufferdata, STREAMFRAGMENTSIZE, file->rate);
98   delete[] bufferdata;
99   SoundManager::check_al_error("Couldn't refill audio buffer: ");
100
101   alSourceQueueBuffers(source, 1, &buffer);
102   SoundManager::check_al_error("Couldn't queue audio buffer: ");
103 }