Massive copyright update. I'm sorry if I'm crediting Matze for something he didn...
[supertux.git] / src / audio / stream_sound_source.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <config.h>
21 #include <assert.h>
22
23 #include <SDL.h>
24
25 #include "stream_sound_source.hpp"
26 #include "sound_manager.hpp"
27 #include "sound_file.hpp"
28 #include "log.hpp"
29
30 StreamSoundSource::StreamSoundSource()
31   : file(0), fade_state(NoFading), looping(false)
32 {
33   alGenBuffers(STREAMFRAGMENTS, buffers);
34   SoundManager::check_al_error("Couldn't allocate audio buffers: ");
35 }
36
37 StreamSoundSource::~StreamSoundSource()
38 {
39   delete file;
40   stop();
41   alDeleteBuffers(STREAMFRAGMENTS, buffers);
42   SoundManager::check_al_error("Couldn't delete audio buffers: ");
43 }
44
45 void
46 StreamSoundSource::set_sound_file(SoundFile* newfile)
47 {
48   delete file;
49   file = newfile;
50
51   ALint queued;
52   alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
53   for(size_t i = 0; i < STREAMFRAGMENTS - queued; ++i) {
54     if(fillBufferAndQueue(buffers[i]) == false)
55       break;
56   }
57 }
58
59 void
60 StreamSoundSource::update()
61 {
62   ALint processed = 0;
63   alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
64   for(ALint i = 0; i < processed; ++i) {
65     ALuint buffer;
66     alSourceUnqueueBuffers(source, 1, &buffer);
67     SoundManager::check_al_error("Couldn't unqueu audio buffer: ");
68
69     if(fillBufferAndQueue(buffer) == false)
70       break;
71   }
72
73   if(!playing()) {
74     if(processed == 0 || !looping)
75       return;
76     
77     // we might have to restart the source if we had a buffer underrun  
78     log_info << "Restarting audio source because of buffer underrun" << std::endl;
79     play();
80   }
81
82   if(fade_state == FadingOn) {
83     Uint32 ticks = SDL_GetTicks();
84     float time = (ticks - fade_start_ticks) / 1000.0;
85     if(time >= fade_time) {
86       set_gain(1.0);
87       fade_state = NoFading;
88     } else {
89       set_gain(time / fade_time);
90     }
91   } else if(fade_state == FadingOff) {
92     Uint32 ticks = SDL_GetTicks();
93     float time = (ticks - fade_start_ticks) / 1000.0;
94     if(time >= fade_time) {
95       stop();
96       fade_state = NoFading;
97     } else {
98       set_gain( (fade_time-time) / fade_time);
99     }
100   }
101 }
102
103 void
104 StreamSoundSource::set_fading(FadeState state, float fade_time)
105 {
106   this->fade_state = state;
107   this->fade_time = fade_time;
108   this->fade_start_ticks = SDL_GetTicks();
109 }
110
111 bool
112 StreamSoundSource::fillBufferAndQueue(ALuint buffer)
113 {
114   // fill buffer
115   char* bufferdata = new char[STREAMFRAGMENTSIZE];
116   size_t bytesread = 0;
117   do {
118     bytesread += file->read(bufferdata + bytesread,
119         STREAMFRAGMENTSIZE - bytesread);
120     // end of sound file
121     if(bytesread < STREAMFRAGMENTSIZE) {
122       if(looping)
123         file->reset();
124       else
125         break;
126     }
127   } while(bytesread < STREAMFRAGMENTSIZE);
128
129   if(bytesread > 0) {
130     ALenum format = SoundManager::get_sample_format(file);
131     alBufferData(buffer, format, bufferdata, bytesread, file->rate);
132     delete[] bufferdata;
133     SoundManager::check_al_error("Couldn't refill audio buffer: ");
134
135     alSourceQueueBuffers(source, 1, &buffer);
136     SoundManager::check_al_error("Couldn't queue audio buffer: ");
137   }
138
139   // return false if there aren't more buffers to fill
140   return bytesread >= STREAMFRAGMENTSIZE;
141 }
142