source: golgotha/src/i4/music/stream.cc @ 608

Last change on this file since 608 was 80, checked in by Sam Hocevar, 15 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 7.1 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "music/stream.hh"
10#include "loaders/wav_load.hh"
11#include "file/file.hh"
12#include "sound/sound.hh"
13#include "error/error.hh"
14
15#include <memory.h>
16
17void i4_wav_callback(w32 count, void *context)
18{
19  ((i4_stream_wav_player *)context)->PRIVATE_callback(count);
20}
21
22void i4_stream_wav_player::set_volume(i4_volume vol)
23{
24  if (voice)
25    voice->set_volume(vol);
26}
27
28// loads more data from disk or clears the buffer
29void i4_stream_wav_player::load_buffer(i4_bool async)
30{
31  wait_read  = i4_F;
32  prev_total = 0;
33
34  if (async)
35  {
36    wait_read = i4_T; //we're waiting for this read to finish now
37
38    if (!fp->async_read(locked_buffer_start, locked_buffer_size, i4_wav_callback, this))
39    {
40      wait_read = i4_F;
41
42      i4_warning("i4_stream_wav_player::async read failed");
43      i4_wav_callback(fp->read(locked_buffer_start, locked_buffer_size), this);
44    }
45  }
46  else
47    i4_wav_callback(fp->read(locked_buffer_start, locked_buffer_size), this);
48}
49
50
51i4_stream_wav_player::i4_stream_wav_player(i4_file_class *_fp,
52                                           w32 _buf_size,
53                                           i4_bool _loop,
54                                           i4_bool first_load_is_async,
55                                           i4_bool _3d_capable)
56{
57 
58  fp            = _fp;
59  loop          = _loop;
60  buf_size      = _buf_size;
61  first_time    = i4_T;
62  file_finished = i4_F;
63  voice         = 0;
64 
65  // don't bother if there is no sound
66  if (i4_sound_man==&i4_null_sound)
67    return ;
68 
69  i4_sound_info info;
70  if (i4_load_wav_info(fp, info))
71  {   
72    total_size = info.size;
73
74    if (info.size <= buf_size)
75    {
76      buf_size       = info.size;
77      fits_in_memory = i4_T;
78    }
79    else
80      fits_in_memory = i4_F;
81
82    if (_3d_capable)
83      first_time = i4_F;
84
85    i4_sound_manager_class::sound_parameters p(info.sample_rate,
86                                               info.channels,
87                                               info.sample_size,
88                                               I4_SOUND_VOLUME_LEVELS-1,
89                                               0,      // pan = 0
90                                               (loop || !fits_in_memory), // loop ones that dont fit in memory
91                                               0,      // no reverb
92                                               i4_T,   // turn on streaming
93                                               _3d_capable);  // 3d capable
94
95    voice = i4_sound_man->alloc(buf_size, p);
96    if (voice)
97    {
98      start_file_offset = fp->tell();
99
100      total_read = 0;
101     
102      last_read = SECOND_HALF;
103     
104      //poll() will see that the second half has already been read, wont read in
105      //the first half until the play cursor gets halfway into the buffer
106
107      voice->lock(0, buf_size, locked_buffer_start, locked_buffer_size, unused1, unused2);
108     
109      load_buffer(first_load_is_async);
110    }
111  }
112}
113
114//be careful in this function, its recursive (although, it recurses in a different thread)
115//but watch out for how you manipulate the variable wait_read
116void i4_stream_wav_player::PRIVATE_callback(w32 count)
117{
118  total_read += count;
119
120  if (total_read > total_size)
121  {
122    count -= (total_read - total_size); //we really only read this many *valid* bytes
123    total_read = total_size;
124  }
125
126  if (count + prev_total < locked_buffer_size)
127  {
128    // we reached the end of the sample data   
129
130    if (loop)
131    {
132      //start back at the beginning
133     
134      fp->seek(start_file_offset);
135      total_read = 0;
136     
137      prev_total += count;
138
139      if (!fp->async_read(((w8 *)locked_buffer_start) + prev_total, locked_buffer_size - prev_total, i4_wav_callback, this))
140      {
141        wait_read = i4_F;
142
143        i4_warning("i4_stream_wav_player::async read failed");
144        i4_wav_callback(fp->read(((w8 *)locked_buffer_start) + prev_total, locked_buffer_size - prev_total), this);
145      }
146    }
147    else
148    {
149      //indicate that we're done
150      file_finished = i4_T;
151
152      //set the remaining part of the buffer to 0
153     
154      w8 *start_clearing_here = (w8 *)locked_buffer_start + count;
155
156      memset(start_clearing_here, 0, locked_buffer_size - count);
157     
158      voice->unlock(locked_buffer_start, locked_buffer_size, unused1, unused2);
159
160      finish_pos = count;
161     
162      wait_read  = i4_F;
163    }
164  }
165  else
166  {
167    if (fits_in_memory)
168    {
169      file_finished = i4_T;
170      finish_pos    = total_size;
171    }
172
173    voice->unlock(locked_buffer_start, locked_buffer_size, unused1, unused2);
174   
175    wait_read = i4_F;
176  }
177
178  if (first_time)     // if this was the first load, we need to start playing the sound
179  {
180    voice->play();
181    first_time = i4_F;
182  }
183}
184
185
186void i4_stream_wav_player::pause()
187{
188  if (voice && voice->is_playing())
189    voice->stop();
190}
191
192void i4_stream_wav_player::unpause()
193{
194  if (voice && !voice->is_playing())
195    voice->play();
196}
197
198
199i4_bool i4_stream_wav_player::poll()
200{
201  if (!voice)
202    return i4_F;
203
204  if (wait_read)   // if we are waiting for a read to finish or init failed
205    return i4_T;
206
207  if (fits_in_memory && loop)
208    return i4_T;
209
210  w32 pos = voice->get_sound_position();
211   
212  if (!file_finished && !fits_in_memory)
213  {
214    if (pos > buf_size/2 && last_read!=FIRST_HALF)
215    {
216      //read more into the first half of the buffer
217      voice->lock(0, buf_size/2, locked_buffer_start, locked_buffer_size, unused1, unused2);
218      last_read = FIRST_HALF;
219      load_buffer();
220    }
221    else
222    if (pos < buf_size/2 && last_read != SECOND_HALF)
223    {
224      //read more into the second half of the buffer
225      voice->lock(buf_size/2, buf_size/2, locked_buffer_start, locked_buffer_size, unused1, unused2);
226      last_read = SECOND_HALF;
227      load_buffer();
228    }
229  }
230  else
231  {
232    if (!voice->is_playing())
233      return i4_F;
234
235    if (pos < buf_size/2)
236    {
237      if (last_read==FIRST_HALF)
238      {
239        if (pos >= finish_pos)
240        {
241          voice->stop();
242          return i4_F;
243        }
244      }
245    }
246    else
247    {
248      if (last_read==SECOND_HALF)
249      {
250        if (pos >= finish_pos+buf_size/2)
251        {
252          voice->stop();
253          return i4_F;
254        }
255      }
256    }
257  }
258 
259  return i4_T;
260}
261
262i4_stream_wav_player::~i4_stream_wav_player()
263{
264  if (voice)
265  {
266    while (wait_read);    // if we need to wait for an async read to finish
267
268    i4_sound_man->free_voice(voice);
269   
270    voice = 0;
271  }
272
273  if (fp)
274  {
275    delete fp;
276    fp = 0;
277  }
278}
Note: See TracBrowser for help on using the repository browser.