Adonthell  0.4
audio.cc
1 /*
2  $Id: audio.cc,v 1.32 2003/01/16 11:22:45 ksterker Exp $
3 
4  Copyright (C) 2000 Andrew Henderson <hendersa@db.erau.edu>
5  Copyright (C) 2002 Kai Sterker <kaisterker@linuxgames.com>
6  Part of the Adonthell Project http://adonthell.linuxgames.com
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include <string.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include "SDL.h"
20 #include "audio.h"
21 
22 // #include "audio_loop.h"
23 
24 bool audio::audio_initialized = false;
25 
26 int audio::background_volume;
27 int audio::effects_volume;
28 #ifdef OGG_MUSIC
29 // loop_info *audio::loop[NUM_MUSIC];
30 #endif
31 Mix_Music *audio::music[NUM_MUSIC];
32 string audio::music_file[NUM_MUSIC];
33 Mix_Chunk *audio::sounds[NUM_WAVES];
34 int audio::current_background;
35 int audio::last_background;
36 bool audio::background_paused;
37 int audio::audio_rate;
38 Uint16 audio::buffer_size;
39 Uint16 audio::audio_format;
40 int audio::audio_channels;
41 
42 // python schedule stuff
43 py_object audio::schedule;
44 bool audio::schedule_active = 0;
45 PyObject *audio::schedule_args = NULL;
46 
47 
48 void audio::init (config *myconfig) {
49  int i; // Generic counter variable
50 
51  // Sample rate: 11025, 22050 or 44100 Hz
52  switch( myconfig->audio_sample_rate ) {
53  case 0: {
54  audio_rate = 11025;
55  break; }
56  case 1: {
57  audio_rate = 22050;
58  break; }
59  default: {
60  audio_rate = 44100;
61  break; }
62  }
63 
64  // Output in signed 8/16-bit form
65  audio_format = myconfig->audio_resolution == 0 ? AUDIO_S8 : AUDIO_S16;
66 
67  // 1 is mono, 2 is stereo
68  audio_channels = myconfig->audio_channels == 0 ? 1 : 2;
69 
70  // 100... scales to percentages ;>
71  background_volume = myconfig->audio_volume;
72 
73  buffer_size = 4096; // Audio buffer size
74  effects_volume = 128; // Still figuring this one out...
75  current_background = -1; // No song currently playing
76  last_background = -1; // No song played so far
77  background_paused = false; // Music isn't paused
78  audio_initialized = false; // No audio connection yet
79  schedule_active = false; // No schedule file yet
80 
81  // Mark all slots in sound and music arrays as empty
82  for (i = 0; i < NUM_WAVES; i++) sounds[i] = NULL;
83  for (i = 0; i < NUM_MUSIC; i++) {
84  music[i] = NULL;
85  music_file[i] = "";
86  }
87 
88  // Try opening the audio device at our defaults
89  i = Mix_OpenAudio(audio_rate, audio_format, audio_channels, buffer_size);
90 
91  // Now see what we got when opening the audio device
92  // If we COULDN'T open the audio...
93  if ( i < 0 ) {
94  fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
95  fprintf(stderr, "Audio will not be used.\n");
96 
97  // If we COULD open the audio...
98  } else {
99  audio_initialized = true;
100  Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
101  set_background_volume (background_volume);
102  }
103 }
104 
105 void audio::cleanup(void)
106 {
107  int i;
108  // No music is queued to play
109  current_background = -1;
110 
111  // Null out those tunes and sound effects
112  for (i = 0; i < NUM_WAVES; i++)
113  {
114  unload_wave(i);
115  sounds[i] = NULL;
116  }
117 
118  for (i = 0; i < NUM_MUSIC; i++)
119  {
120  unload_background(i);
121  music[i] = NULL;
122  music_file[i] = "";
123  }
124 
125  // Clean audio schedule
126  schedule.clear ();
127 
128  // Close out audio connection
129  if (audio_initialized == true)
130  {
131  Mix_CloseAudio();
132  audio_initialized = false;
133  }
134 }
135 
136 int audio::load_background(int slot, char *filename) {
137 
138  if (!audio_initialized) return (0);
139 
140  // Check for bad input
141  if ((slot >= NUM_MUSIC) || (slot < 0)) {
142  fprintf(stderr, "Error: Tried to put music in invalid slot.\n");
143  return(0);
144  }
145 
146  // Check if the file exists at all...
147  FILE *f = fopen (filename, "r");
148  if (!f) {
149  fprintf(stderr, "Error: No such file: %s.\n", filename);
150  return 0;
151  }
152  fclose (f);
153 
154  // Music already occupies that slot
155  if (music[slot] != NULL)
156  unload_background (slot);
157 
158  // No music in slot, load new tune in, ...
159  music[slot] = Mix_LoadMUS(filename);
160  music_file[slot] = filename;
161 
162 #ifdef OGG_MUSIC
163  // read loop points and ...
164  // loop[slot] = new loop_info (&music[slot]->ogg_data.ogg->vf);
165 
166  // ... enable looping
167  // music[slot]->ogg_data.ogg->vf.callbacks.read_func = &ogg_read_callback;
168 #endif
169  return(1);
170 }
171 
172 void audio::unload_background (int slot)
173 {
174  if (music[slot] == NULL) return;
175 
176  // If we are unloading background music from the slot
177  // the current background music is in...
178  if (current_background == slot)
179  {
180  last_background = current_background;
181  current_background = -1;
182 
183  // Just a precaution
184  Mix_HaltMusic();
185  Mix_ResumeMusic ();
186  }
187 
188  Mix_FreeMusic (music[slot]);
189  music[slot] = NULL;
190  music_file[slot] = "";
191 
192 #ifdef OGG_MUSIC
193  // delete loop[slot];
194 #endif
195 }
196 
197 void audio::pause_music(void) {
198  Mix_PauseMusic();
199 }
200 
201 void audio::unpause_music(void) {
202  Mix_ResumeMusic();
203 }
204 
205 // Accepts a percentage of the maximum volume level
206 // and clips out of bounds values to 0-100.
207 void audio::set_background_volume(int volume) {
208 
209  // Check for bad input
210  if (volume < 0) {
211  background_volume = 0;
212  } else if (volume > 100) {
213  background_volume = 100;
214  } else
215  background_volume = volume;
216 
217  // Scales 0-100% to 0-128
218  Mix_VolumeMusic(int(background_volume * 1.28));
219 }
220 
221 // This should be done better, but I'll wait until
222 // I have enough sound effects to play with ;>
223 int audio::load_wave(int slot, char *filename) {
224 
225  if (!audio_initialized) return(1);
226 
227  // Check for bad input
228  if ((slot >= NUM_WAVES) || (slot < 0)) {
229  fprintf(stderr, "Error: Tried to put wave in invalid slot.\n");
230  return(1);
231  } else {
232  // Check if the file exists at all...
233  FILE *f = fopen (filename, "r");
234  if (!f)
235  {
236  sounds[slot] = NULL;
237  return 1;
238  }
239 
240  fclose (f);
241 
242  sounds[slot] = Mix_LoadWAV(filename);
243  }
244  return(0);
245 }
246 
247 void audio::unload_wave(int wave) {
248  if (sounds[wave] != NULL) {
249  Mix_FreeChunk(sounds[wave]);
250  sounds[wave] = NULL;
251  }
252 }
253 
254 void audio::play_wave(int channel, int slot) {
255  if ((slot > -1) && (slot < NUM_CHANNELS))
256  if (sounds[slot] != NULL) Mix_PlayChannel(channel, sounds[slot], 0);
257 }
258 
259 void audio::play_background(int slot) {
260  if (music[slot] != NULL) {
261  current_background = slot;
262  Mix_PlayMusic(music[current_background], 0);
263  }
264 }
265 
266 void audio::fade_out_background(int time) {
267  if (Mix_PlayingMusic ())
268  {
269  Mix_FadeOutMusic(time);
270  last_background = current_background;
271  current_background = -1;
272  }
273 #ifdef OGG_MUSIC
274  // music[current_background]->ogg_data.ogg->vf.callbacks.read_func = &fread_wrap;
275 #endif
276 }
277 
278 void audio::fade_in_background(int slot, int time) {
279  if (music[slot] != NULL) {
280  current_background = slot;
281  Mix_FadeInMusic(music[slot], 0, time);
282  }
283 }
284 
285 // Temporary convience function for testing
286 void audio::change_background(int slot, int time) {
287  fade_out_background(time);
288  fade_in_background(slot, time);
289 }
290 
291 #ifdef OGG_MUSIC
292 // OggVorbis_File* audio::get_vorbisfile ()
293 // {
294 // return &music[current_background]->ogg_data.ogg->vf;
295 // }
296 #endif
297 
298 // set audio schedule
299 void audio::set_schedule (string file, PyObject * args)
300 {
301  // Clears the schedule
302  schedule.clear ();
303  Py_XDECREF (schedule_args);
304  schedule_args = NULL;
305 
306  // Set new schedule
307  if (file != "")
308  {
309  schedule_args = args;
310  Py_XINCREF (schedule_args);
311  schedule.create_instance ("schedules.audio." + file, file, args);
312  }
313 }
314 
315 // run the audio control schedule
316 void audio::run_schedule ()
317 {
318  PyObject *song = Py_BuildValue ("(i)", last_background);
319  if (schedule_active) schedule.call_method ("music_finished", song);
320  Py_DECREF (song);
321 }
322 
323 // save state
324 s_int8 audio::put_state (ogzstream& file)
325 {
326  // currently playing
327  current_background >> file;
328 
329  // music file
330  if (current_background != -1) music_file[current_background] >> file;
331 
332  // Save the schedule script state
333  schedule.class_name () >> file;
334  if (schedule_args)
335  {
336  true >> file;
337  python::put_tuple (schedule_args, file);
338  }
339  else false >> file;
340  is_schedule_activated () >> file;
341 
342  return 1;
343 }
344 
345 // get state
346 s_int8 audio::get_state (igzstream& file)
347 {
348  string song, script;
349  bool have_args;
350 
351  // current background
352  last_background << file;
353 
354  // if song was playing, see which it is
355  if (last_background != -1)
356  {
357  song << file;
358 
359  // ... and resume playing
360  if (load_background (last_background, (char *) song.c_str ()))
361  play_background (last_background);
362  }
363 
364  // Restore the schedule script state
365  PyObject * args = NULL;
366  script << file;
367 
368  have_args << file;
369  if (have_args) args = python::get_tuple (file);
370  set_schedule (script, args);
371  Py_XDECREF (args);
372 
373  schedule_active << file;
374 
375  return 1;
376 }
Class to write data from a Gzip compressed file.
Definition: fileops.h:223
void call_method(const string &name, PyObject *args=NULL) const
Call a method of this object.
Definition: py_object.h:109
Class to read data from a Gzip compressed file.
Definition: fileops.h:131
void clear()
Resets the script to it&#39;s post-constructor state.
Definition: py_object.cc:42
Python object class.
Definition: py_object.h:41
u_int8 audio_sample_rate
The sample rate: 11025 Hz (0), 22050 Hz (1) or 44100 Hz (2)
Definition: prefs.h:156
static void put_tuple(PyObject *tuple, ogzstream &file)
Save a Python tuple into a file.
std::string class_name() const
Returns the class name of this object.
Definition: py_object.h:219
bool create_instance(string file, string classname, PyObject *args=NULL)
Creates an instance of a Python class.
Definition: py_object.cc:53
static PyObject * get_tuple(igzstream &file)
Loads a Python tuple previously saved with put_tuple ().
u_int8 audio_volume
The volume: a value betwen 0 and 100.
Definition: prefs.h:161
u_int8 audio_resolution
The resolution: 8 bit (0) or 16 bit (1)
Definition: prefs.h:152
u_int8 audio_channels
The number of channels: mono (0) or stereo (1).
Definition: prefs.h:148
This class contains the engine&#39;s configuration read either from the config file or from the command l...
Definition: prefs.h:70
#define s_int8
8 bits long signed integer
Definition: types.h:38