Logo Search packages:      
Sourcecode: adonthell version File versions  Download package

audio.cc

/*
   $Id: audio.cc,v 1.32 2003/01/16 11:22:45 ksterker Exp $

   Copyright (C) 2000 Andrew Henderson <hendersa@db.erau.edu>
   Copyright (C) 2002 Kai Sterker <kaisterker@linuxgames.com>
   Part of the Adonthell Project http://adonthell.linuxgames.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "SDL.h"
#include "audio.h"

// #include "audio_loop.h"

bool audio::audio_initialized = false;

int audio::background_volume;
int audio::effects_volume;
#ifdef OGG_MUSIC
// loop_info *audio::loop[NUM_MUSIC];
#endif
Mix_Music *audio::music[NUM_MUSIC];
string audio::music_file[NUM_MUSIC];
Mix_Chunk *audio::sounds[NUM_WAVES];
int audio::current_background;
int audio::last_background;
bool audio::background_paused;
int audio::audio_rate;
Uint16 audio::buffer_size;
Uint16 audio::audio_format;
int audio::audio_channels;

// python schedule stuff
py_object audio::schedule;
bool audio::schedule_active = 0;
PyObject *audio::schedule_args = NULL;


void audio::init (config *myconfig) {
  int i;  // Generic counter variable

  // Sample rate: 11025, 22050 or 44100 Hz
  switch( myconfig->audio_sample_rate ) {
    case 0: {
      audio_rate = 11025;
      break; }
    case 1: {
      audio_rate = 22050;
      break; }
    default: {
      audio_rate = 44100;
      break; }
  }
  
  // Output in signed 8/16-bit form
  audio_format = myconfig->audio_resolution == 0 ? AUDIO_S8 : AUDIO_S16; 

  // 1 is mono, 2 is stereo
  audio_channels = myconfig->audio_channels == 0 ? 1 : 2;  

  // 100... scales to percentages ;>
  background_volume = myconfig->audio_volume;   

  buffer_size = 4096;        // Audio buffer size
  effects_volume = 128;      // Still figuring this one out...
  current_background = -1;   // No song currently playing
  last_background = -1;      // No song played so far
  background_paused = false; // Music isn't paused
  audio_initialized = false; // No audio connection yet
  schedule_active = false;   // No schedule file yet
  
  // Mark all slots in sound and music arrays as empty
  for (i = 0; i < NUM_WAVES; i++) sounds[i] = NULL;
  for (i = 0; i < NUM_MUSIC; i++) {
      music[i] = NULL; 
      music_file[i] = "";
  }
  
  // Try opening the audio device at our defaults
  i = Mix_OpenAudio(audio_rate, audio_format, audio_channels, buffer_size);

  // Now see what we got when opening the audio device
  // If we COULDN'T open the audio...
  if ( i < 0 ) {
    fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
    fprintf(stderr, "Audio will not be used.\n");

  // If we COULD open the audio...
  } else {
    audio_initialized = true;
    Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
    set_background_volume (background_volume);
  }
}

void audio::cleanup(void) 
{
    int i;
    // No music is queued to play
    current_background = -1;

    // Null out those tunes and sound effects
    for (i = 0; i < NUM_WAVES; i++) 
    {
        unload_wave(i);
        sounds[i] = NULL;
    }
    
    for (i = 0; i < NUM_MUSIC; i++) 
    {
        unload_background(i);
        music[i] = NULL;
        music_file[i] = "";
    }

    // Clean audio schedule
    schedule.clear ();
  
    // Close out audio connection
    if (audio_initialized == true)
    {
        Mix_CloseAudio();
        audio_initialized = false;
    }
}

int audio::load_background(int slot, char *filename) {

  if (!audio_initialized) return (0);

  // Check for bad input
  if ((slot >= NUM_MUSIC) || (slot < 0)) {
    fprintf(stderr, "Error: Tried to put music in invalid slot.\n");
    return(0);
  }

  //  Check if the file exists at all...
  FILE *f = fopen (filename, "r");
  if (!f) {
    fprintf(stderr, "Error: No such file: %s.\n", filename);
    return 0;
  }
  fclose (f);   

  // Music already occupies that slot
  if (music[slot] != NULL)
      unload_background (slot);

  // No music in slot, load new tune in, ...
  music[slot] = Mix_LoadMUS(filename);
  music_file[slot] = filename;

#ifdef OGG_MUSIC
  // read loop points and ...
  // loop[slot] = new loop_info (&music[slot]->ogg_data.ogg->vf);
  
  // ... enable looping
  // music[slot]->ogg_data.ogg->vf.callbacks.read_func = &ogg_read_callback;
#endif
  return(1);
}

void audio::unload_background (int slot)
{
    if (music[slot] == NULL) return;

    // If we are unloading background music from the slot
    // the current background music is in...
    if (current_background == slot)
    {
        last_background = current_background;
        current_background = -1;

        // Just a precaution
        Mix_HaltMusic();
        Mix_ResumeMusic ();
    }

    Mix_FreeMusic (music[slot]);
    music[slot] = NULL;
    music_file[slot] = "";

#ifdef OGG_MUSIC
    // delete loop[slot];
#endif
}

void audio::pause_music(void) {
  Mix_PauseMusic();
}

void audio::unpause_music(void) {
  Mix_ResumeMusic();
}

// Accepts a percentage of the maximum volume level
// and clips out of bounds values to 0-100.
void audio::set_background_volume(int volume) {

  // Check for bad input
  if (volume < 0) {
    background_volume = 0;
  } else if (volume > 100) {
    background_volume = 100;
  } else
    background_volume = volume;

  // Scales 0-100% to 0-128
  Mix_VolumeMusic(int(background_volume * 1.28));
}

// This should be done better, but I'll wait until
// I have enough sound effects to play with ;>
int audio::load_wave(int slot, char *filename) {

  if (!audio_initialized) return(1);
 
  // Check for bad input
  if ((slot >= NUM_WAVES) || (slot < 0)) {
    fprintf(stderr, "Error: Tried to put wave in invalid slot.\n");
    return(1);
  } else {
      //  Check if the file exists at all...
      FILE *f = fopen (filename, "r");
      if (!f)  
      {
          sounds[slot] = NULL; 
          return 1;
      }
      
      fclose (f);   
      
      sounds[slot] = Mix_LoadWAV(filename);
  }
  return(0);
}

void audio::unload_wave(int wave) {
  if (sounds[wave] != NULL) {
    Mix_FreeChunk(sounds[wave]);
    sounds[wave] = NULL;
  }
}

void audio::play_wave(int channel, int slot) {
  if ((slot > -1) && (slot < NUM_CHANNELS))
    if (sounds[slot] != NULL) Mix_PlayChannel(channel, sounds[slot], 0);
}

void audio::play_background(int slot) {
  if (music[slot] != NULL) {
    current_background = slot;
    Mix_PlayMusic(music[current_background], 0);
  }
}

void audio::fade_out_background(int time) {
    if (Mix_PlayingMusic ())
    {
        Mix_FadeOutMusic(time);
        last_background = current_background;
        current_background = -1;
    }
#ifdef OGG_MUSIC
    // music[current_background]->ogg_data.ogg->vf.callbacks.read_func = &fread_wrap;
#endif
}

void audio::fade_in_background(int slot, int time) {
  if (music[slot] != NULL) {
    current_background = slot;
    Mix_FadeInMusic(music[slot], 0, time);
  }
}

// Temporary convience function for testing
void audio::change_background(int slot, int time) {
  fade_out_background(time);
  fade_in_background(slot, time);
}

#ifdef OGG_MUSIC
// OggVorbis_File* audio::get_vorbisfile ()
// {
//     return &music[current_background]->ogg_data.ogg->vf;
// }
#endif

// set audio schedule
void audio::set_schedule (string file, PyObject * args)
{     
    // Clears the schedule
    schedule.clear ();
    Py_XDECREF (schedule_args);
    schedule_args = NULL;

    // Set new schedule
    if (file != "")
    {
        schedule_args = args; 
        Py_XINCREF (schedule_args); 
        schedule.create_instance ("schedules.audio." + file, file, args);
    }
}

// run the audio control schedule
void audio::run_schedule ()
{
    PyObject *song = Py_BuildValue ("(i)", last_background);
    if (schedule_active) schedule.call_method ("music_finished", song);
    Py_DECREF (song);
}

// save state
s_int8 audio::put_state (ogzstream& file)
{
    // currently playing
    current_background >> file;

    // music file
    if (current_background != -1) music_file[current_background] >> file;

    // Save the schedule script state
    schedule.class_name () >> file;
    if (schedule_args) 
    {
        true >> file; 
        python::put_tuple (schedule_args, file);
    }
    else false >> file; 
    is_schedule_activated () >> file;
    
    return 1;
}

// get state
s_int8 audio::get_state (igzstream& file)
{
    string song, script;
    bool have_args;
    
    // current background
    last_background << file;

    // if song was playing, see which it is
    if (last_background != -1)
    {
        song << file;

        // ... and resume playing
        if (load_background (last_background, (char *) song.c_str ()))
            play_background (last_background);
    }

    // Restore the schedule script state
    PyObject * args = NULL; 
    script << file;
    
    have_args << file;
    if (have_args) args = python::get_tuple (file); 
    set_schedule (script, args);      
    Py_XDECREF (args); 
    
    schedule_active << file;

    return 1;
}

Generated by  Doxygen 1.6.0   Back to index