1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "audio/sound_file.hpp"
18#include "audio/sound_manager.hpp"
19#include "audio/stream_sound_source.hpp"
20#include "supertux/globals.hpp"
21#include "util/log.hpp"
22
23StreamSoundSource::StreamSoundSource() :
24 m_file(),
25 m_fade_state(NoFading),
26 m_fade_start_time(),
27 m_fade_time(),
28 m_looping(false)
29{
30 alGenBuffers(STREAMFRAGMENTS, m_buffers);
31 try
32 {
33 SoundManager::check_al_error("Couldn't allocate audio buffers: ");
34 }
35 catch(std::exception& e)
36 {
37 log_warning << e.what() << std::endl;
38 }
39 //add me to update list
40 SoundManager::current()->register_for_update( this );
41}
42
43StreamSoundSource::~StreamSoundSource()
44{
45 //don't update me any longer
46 SoundManager::current()->remove_from_update( this );
47 m_file.reset();
48 stop();
49 alDeleteBuffers(STREAMFRAGMENTS, m_buffers);
50 try
51 {
52 SoundManager::check_al_error("Couldn't delete audio buffers: ");
53 }
54 catch(std::exception& e)
55 {
56 // Am I bovvered?
57 log_warning << e.what() << std::endl;
58 }
59}
60
61void
62StreamSoundSource::set_sound_file(std::unique_ptr<SoundFile> newfile)
63{
64 m_file = std::move(newfile);
65
66 ALint queued;
67 alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queued);
68 for (size_t i = 0; i < STREAMFRAGMENTS - queued; ++i) {
69 if (fillBufferAndQueue(m_buffers[i]) == false)
70 break;
71 }
72}
73
74void
75StreamSoundSource::update()
76{
77 ALint processed = 0;
78 alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processed);
79 for (ALint i = 0; i < processed; ++i) {
80 ALuint buffer;
81 alSourceUnqueueBuffers(m_source, 1, &buffer);
82 try
83 {
84 SoundManager::check_al_error("Couldn't unqueue audio buffer: ");
85 }
86 catch(std::exception& e)
87 {
88 log_warning << e.what() << std::endl;
89 }
90
91 if (fillBufferAndQueue(buffer) == false)
92 break;
93 }
94
95 if (!playing()) {
96 if (processed == 0 || !m_looping)
97 return;
98
99 // we might have to restart the source if we had a buffer underrun
100 log_info << "Restarting audio source because of buffer underrun" << std::endl;
101 play();
102 }
103
104 if (m_fade_state == FadingOn || m_fade_state == FadingResume) {
105 float time = g_real_time - m_fade_start_time;
106 if (time >= m_fade_time) {
107 set_gain(1.0);
108 m_fade_state = NoFading;
109 } else {
110 set_gain(time / m_fade_time);
111 }
112 } else if (m_fade_state == FadingOff || m_fade_state == FadingPause) {
113 float time = g_real_time - m_fade_start_time;
114 if (time >= m_fade_time) {
115 if (m_fade_state == FadingOff)
116 stop();
117 else
118 pause();
119 m_fade_state = NoFading;
120 } else {
121 set_gain( (m_fade_time - time) / m_fade_time);
122 }
123 }
124}
125
126void
127StreamSoundSource::set_fading(FadeState state, float fade_time_)
128{
129 m_fade_state = state;
130 m_fade_time = fade_time_;
131 m_fade_start_time = g_real_time;
132}
133
134bool
135StreamSoundSource::fillBufferAndQueue(ALuint buffer)
136{
137 // fill buffer
138 std::unique_ptr<char[]> bufferdata(new char[STREAMFRAGMENTSIZE]);
139 size_t bytesread = 0;
140 do {
141 bytesread += m_file->read(bufferdata.get() + bytesread,
142 STREAMFRAGMENTSIZE - bytesread);
143 // end of sound file
144 if (bytesread < STREAMFRAGMENTSIZE) {
145 if (m_looping)
146 m_file->reset();
147 else
148 break;
149 }
150 } while(bytesread < STREAMFRAGMENTSIZE);
151
152 if (bytesread > 0) {
153 ALenum format = SoundManager::get_sample_format(*m_file);
154 try
155 {
156 alBufferData(buffer, format, bufferdata.get(), static_cast<ALsizei>(bytesread), m_file->m_rate);
157 SoundManager::check_al_error("Couldn't refill audio buffer: ");
158
159 alSourceQueueBuffers(m_source, 1, &buffer);
160 SoundManager::check_al_error("Couldn't queue audio buffer: ");
161 }
162 catch(std::exception& e)
163 {
164 log_warning << e.what() << std::endl;
165 }
166 }
167
168 // return false if there aren't more buffers to fill
169 return bytesread >= STREAMFRAGMENTSIZE;
170}
171
172/* EOF */
173