// (c) 1995-2014 by Artsoft Entertainment
// Holger Schemel
// info@artsoft.org
-// http://www.artsoft.org/
+// https://www.artsoft.org/
// ----------------------------------------------------------------------------
// sound.c
// ============================================================================
#include "text.h"
-/* expiration time (in milliseconds) for sound loops */
+// expiration time (in milliseconds) for sound loops
#define SOUND_LOOP_EXPIRATION_TIME 200
-/* one second fading interval == 1000 ticks (milliseconds) */
+// one second fading interval == 1000 ticks (milliseconds)
#define SOUND_FADING_INTERVAL 1000
#define SND_TYPE_NONE 0
struct AudioFormatInfo
{
- boolean stereo; /* availability of stereo sound */
- int format; /* size and endianess of sample data */
- int sample_rate; /* sample frequency */
- int fragment_size; /* audio device fragment size in bytes */
+ boolean stereo; // availability of stereo sound
+ int format; // size and endianess of sample data
+ int sample_rate; // sample frequency
+ int fragment_size; // audio device fragment size in bytes
};
struct SampleInfo
int type;
int format;
- void *data_ptr; /* pointer to first sample (8 or 16 bit) */
- int data_len; /* number of samples, NOT number of bytes */
- int num_channels; /* mono: 1 channel, stereo: 2 channels */
+ void *data_ptr; // pointer to first sample (8 or 16 bit)
+ int data_len; // number of samples, NOT number of bytes
+ int num_channels; // mono: 1 channel, stereo: 2 channels
};
typedef struct SampleInfo SoundInfo;
typedef struct SampleInfo MusicInfo;
int type;
int format;
- void *data_ptr; /* pointer to first sample (8 or 16 bit) */
- int data_len; /* number of samples, NOT number of bytes */
- int num_channels; /* mono: 1 channel, stereo: 2 channels */
+ void *data_ptr; // pointer to first sample (8 or 16 bit)
+ int data_len; // number of samples, NOT number of bytes
+ int num_channels; // mono: 1 channel, stereo: 2 channels
};
typedef struct SoundControl SoundControl;
static char *currently_playing_music_filename = NULL;
-/* ========================================================================= */
-/* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
+// ============================================================================
+// THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
static struct SoundControl mixer[NUM_MIXER_CHANNELS];
static int mixer_active_channels = 0;
static void FreeSound(void *);
static void FreeMusic(void *);
static void FreeAllMusic_NoConf(void);
+static void Mixer_StopMusicChannel(void);
static SoundInfo *getSoundInfoEntryFromSoundID(int);
static MusicInfo *getMusicInfoEntryFromMusicID(int);
-/* ------------------------------------------------------------------------- */
-/* mixer functions */
-/* ------------------------------------------------------------------------- */
+// ----------------------------------------------------------------------------
+// mixer functions
+// ----------------------------------------------------------------------------
void Mixer_InitChannels(void)
{
if (expire_loop_sounds &&
IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
- DelayReached(&mixer[channel].playing_starttime,
- SOUND_LOOP_EXPIRATION_TIME))
+ DelayReachedExt2(&mixer[channel].playing_starttime,
+ SOUND_LOOP_EXPIRATION_TIME, Counter()))
return TRUE;
if (!Mix_Playing(channel))
static void Mixer_PlayChannel(int channel)
{
- /* start with inactive channel in case something goes wrong */
+ // start with inactive channel in case something goes wrong
mixer[channel].active = FALSE;
if (mixer[channel].type != MUS_TYPE_WAV)
{
int loops = (IS_LOOP(mixer[audio.music_channel]) ? -1 : 1);
+ // stopping music channel before playing next track seems to be needed to
+ // prevent audio problems that may occur when playing MP3 files on Windows
+ Mixer_StopMusicChannel();
+
// use short fade-in to prevent "plop" sound for certain music files
// (this may happen when switching on music while playing the game)
Mix_VolumeMusic(mixer[audio.music_channel].volume);
Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, loops, 100);
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
// playing MIDI music is broken since Windows Vista, as it sets the volume
// for MIDI music also for all other sounds and music, which cannot be set
// back to normal unless playing MIDI music again with that desired volume
Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
// playing MIDI music is broken since Windows Vista, as it sets the volume
// for MIDI music also for all other sounds and music, which cannot be set
// back to normal unless playing MIDI music again with that desired volume
if (snd_info == NULL)
return;
- /* copy sound sample and format information */
+ // copy sound sample and format information
snd_ctrl.type = snd_info->type;
snd_ctrl.format = snd_info->format;
snd_ctrl.data_ptr = snd_info->data_ptr;
snd_ctrl.data_len = snd_info->data_len;
snd_ctrl.num_channels = snd_info->num_channels;
- /* play music samples on a dedicated music channel */
+ // play music samples on a dedicated music channel
if (IS_MUSIC(snd_ctrl))
{
Mixer_StopMusicChannel();
return;
}
- /* check if (and how often) this sound sample is already playing */
+ // check if (and how often) this sound sample is already playing
for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++)
if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
k++;
- /* reset expiration delay for already playing loop sounds */
+ // reset expiration delay for already playing loop sounds
if (k > 0 && IS_LOOP(snd_ctrl))
{
for (i = audio.first_sound_channel; i < audio.num_channels; i++)
if (IS_FADING(mixer[i]))
Mixer_UnFadeChannel(i);
- /* restore settings like volume and stereo position */
+ // restore settings like volume and stereo position
mixer[i].volume = snd_ctrl.volume;
mixer[i].stereo_position = snd_ctrl.stereo_position;
return;
}
- /* don't play sound more than n times simultaneously (with n == 2 for now) */
+ // don't play sound more than n times simultaneously (with n == 2 for now)
if (k >= 2)
{
unsigned int playing_current = Counter();
int longest = 0, longest_nr = audio.first_sound_channel;
- /* look for oldest equal sound */
+ // look for oldest equal sound
for (i = audio.first_sound_channel; i < audio.num_channels; i++)
{
int playing_time = playing_current - mixer[i].playing_starttime;
library, we use the current playing time (in milliseconds) instead. */
#if DEBUG
- /* channel allocation sanity check -- should not be needed */
+ // channel allocation sanity check -- should not be needed
if (mixer_active_channels ==
audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
{
{
if (!mixer[i].active)
{
- Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i);
- Error(ERR_INFO, "Mixer_InsertSound: This should never happen!");
+ Debug("audio", "Mixer_InsertSound: Channel %d inactive", i);
+ Debug("audio", "Mixer_InsertSound: This should never happen!");
mixer_active_channels--;
}
Mixer_StopChannel(longest_nr);
}
- /* add the new sound to the mixer */
+ // add the new sound to the mixer
for (i = audio.first_sound_channel; i < audio.num_channels; i++)
{
if (!mixer[i].active)
{
int i;
- /* deactivate channels that have expired since the last request */
+ // deactivate channels that have expired since the last request
for (i = 0; i < audio.num_channels; i++)
if (mixer[i].active && Mixer_ChannelExpired(i))
Mixer_StopChannel(i);
- if (IS_RELOADING(snd_ctrl)) /* load new sound or music files */
+ if (IS_RELOADING(snd_ctrl)) // load new sound or music files
{
Mixer_StopMusicChannel();
for (i = audio.first_sound_channel; i < audio.num_channels; i++)
else
ReloadCustomMusic();
}
- else if (IS_FADING(snd_ctrl)) /* fade out existing sound or music */
+ else if (IS_FADING(snd_ctrl)) // fade out existing sound or music
{
if (IS_MUSIC(snd_ctrl))
{
if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
Mixer_FadeChannel(i);
}
- else if (IS_STOPPING(snd_ctrl)) /* stop existing sound or music */
+ else if (IS_STOPPING(snd_ctrl)) // stop existing sound or music
{
if (IS_MUSIC(snd_ctrl))
{
if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
Mixer_StopChannel(i);
}
- else if (SET_EXPIRE_LOOPS(snd_ctrl)) /* set loop expiration on or off */
+ else if (SET_EXPIRE_LOOPS(snd_ctrl)) // set loop expiration on or off
{
expire_loop_sounds = snd_ctrl.active;
}
- else if (snd_ctrl.active) /* add new sound to mixer */
+ else if (snd_ctrl.active) // add new sound to mixer
{
Mixer_InsertSound(snd_ctrl);
}
if (!audio.sound_available)
return;
- /* initialize stereo position conversion information */
+ // initialize stereo position conversion information
for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
stereo_volume[i] =
(int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
}
-/* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
-/* ========================================================================= */
-/* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
+// THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
+// ============================================================================
+// THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS
-#define CHUNK_ID_LEN 4 /* IFF style chunk id length */
-#define WAV_HEADER_SIZE 16 /* size of WAV file header */
+#define CHUNK_ID_LEN 4 // IFF style chunk id length
+#define WAV_HEADER_SIZE 16 // size of WAV file header
static void *Load_WAV(char *filename)
{
if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
{
- Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError());
+ Warn("cannot read sound file '%s': %s", filename, Mix_GetError());
+
free(snd_info);
+
return NULL;
}
if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
{
- Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError());
+ Warn("cannot read music file '%s': %s", filename, Mix_GetError());
+
free(mod_info);
+
return NULL;
}
static void LoadCustomMusic_NoConf(void)
{
- static boolean draw_init_text = TRUE; /* only draw at startup */
+ static boolean draw_init_text = TRUE; // only draw at startup
static char *last_music_directory = NULL;
- char *music_directory = getCustomMusicDirectory();
+ char *music_directory = getCustomMusicDirectory_NoConf();
Directory *dir;
DirectoryEntry *dir_entry;
int num_music = getMusicListSize();
if (last_music_directory != NULL &&
strEqual(last_music_directory, music_directory))
- return; /* old and new music directory are the same */
+ return; // old and new music directory are the same
if (last_music_directory != NULL)
free(last_music_directory);
if ((dir = openDirectory(music_directory)) == NULL)
{
- Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
+ Warn("cannot read music directory '%s'", music_directory);
audio.music_available = FALSE;
}
if (draw_init_text)
- DrawInitText("Loading music", 120, FC_GREEN);
+ DrawInitTextHead("Loading music");
- while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */
+ while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
{
char *basename = dir_entry->basename;
MusicInfo *mus_info = NULL;
boolean music_already_used = FALSE;
int i;
- /* skip all music files that are configured in music config file */
+ // skip all music files that are configured in music config file
for (i = 0; i < num_music; i++)
{
struct FileInfo *music = getMusicListEntry(i);
continue;
if (draw_init_text)
- DrawInitText(basename, 150, FC_YELLOW);
+ DrawInitTextItem(basename);
if (FileIsMusic(dir_entry->filename))
mus_info = Load_WAV_or_MOD(dir_entry->filename);
int num_list_entries = sound_info->num_file_list_entries;
int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
- if (pos < 0 || pos >= num_sounds) /* invalid sound */
+ if (pos < 0 || pos >= num_sounds) // invalid sound
return NULL;
return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
int num_list_entries = music_info->num_file_list_entries;
int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
- if (pos < 0 || pos >= num_music) /* invalid music */
+ if (pos < 0 || pos >= num_music) // invalid music
return NULL;
return (pos < num_list_entries ? &music_info->file_list[list_pos] :
(SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
sound_info->dynamic_artwork_list);
- if (pos < 0 || pos >= num_sounds) /* invalid sound */
+ if (pos < 0 || pos >= num_sounds) // invalid sound
return NULL;
return snd_info[list_pos];
(MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
music_info->dynamic_artwork_list);
- if (pos >= num_music) /* invalid music */
+ if (pos >= num_music) // invalid music
return NULL;
- if (pos < 0) /* undefined music */
+ if (pos < 0) // undefined music
{
- if (num_music_noconf == 0) /* no fallback music available */
+ if (num_music_noconf == 0) // no fallback music available
return NULL;
pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
return mus_info[list_pos];
}
+char *getSoundInfoEntryFilename(int pos)
+{
+ SoundInfo *snd_info = getSoundInfoEntryFromSoundID(pos);
+
+ if (snd_info == NULL)
+ return NULL;
+
+ return getBaseNamePtr(snd_info->source_filename);
+}
+
char *getMusicInfoEntryFilename(int pos)
{
MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
sound_info->type = ARTWORK_TYPE_SOUNDS;
- /* ---------- initialize file list and suffix lists ---------- */
+ // ---------- initialize file list and suffix lists ----------
sound_info->num_file_list_entries = num_file_list_entries;
sound_info->num_dynamic_file_list_entries = 0;
sound_info->suffix_list = config_suffix_list;
- /* ---------- initialize base prefix and suffixes lists ---------- */
+ // ---------- initialize base prefix and suffixes lists ----------
sound_info->num_base_prefixes = 0;
for (i = 0; base_prefixes[i] != NULL; i++)
sound_info->property_mapping = NULL;
- /* ---------- initialize artwork reference and content lists ---------- */
+ // ---------- initialize artwork reference and content lists ----------
sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
sound_info->content_list = NULL;
- /* ---------- initialize artwork loading/freeing functions ---------- */
+ // ---------- initialize artwork loading/freeing functions ----------
sound_info->load_artwork = Load_WAV;
sound_info->free_artwork = FreeSound;
music_info = checked_calloc(sizeof(struct ArtworkListInfo));
music_info->type = ARTWORK_TYPE_MUSIC;
- /* ---------- initialize file list and suffix lists ---------- */
+ // ---------- initialize file list and suffix lists ----------
music_info->num_file_list_entries = num_file_list_entries;
music_info->num_dynamic_file_list_entries = 0;
music_info->suffix_list = config_suffix_list;
- /* ---------- initialize base prefix and suffixes lists ---------- */
+ // ---------- initialize base prefix and suffixes lists ----------
music_info->num_base_prefixes = 0;
for (i = 0; base_prefixes[i] != NULL; i++)
music_info->property_mapping = NULL;
- /* ---------- initialize artwork reference and content lists ---------- */
+ // ---------- initialize artwork reference and content lists ----------
music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
music_info->content_list = NULL;
- /* ---------- initialize artwork loading/freeing functions ---------- */
+ // ---------- initialize artwork loading/freeing functions ----------
music_info->load_artwork = Load_WAV_or_MOD;
music_info->free_artwork = FreeMusic;
else if (stereo_position > SOUND_MAX_RIGHT)
stereo_position = SOUND_MAX_RIGHT;
- clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
+ clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
snd_ctrl.active = TRUE;
snd_ctrl.nr = nr;
if (!audio.sound_available)
return;
- clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
+ clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
snd_ctrl.active = FALSE;
snd_ctrl.nr = nr;
if (!audio.sound_available)
return;
- clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
+ clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
snd_ctrl.active = active;
snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
LoadArtworkConfig(music_info);
ReloadCustomArtworkList(music_info);
- /* load all music files from directory not defined in "musicinfo.conf" */
+ // load all music files from directory not defined in "musicinfo.conf"
LoadCustomMusic_NoConf();
}
-void InitReloadCustomSounds(char *set_identifier)
+void InitReloadCustomSounds(void)
{
if (!audio.sound_available)
return;
ReloadCustomSounds();
}
-void InitReloadCustomMusic(char *set_identifier)
+void InitReloadCustomMusic(void)
{
if (!audio.music_available)
return;
FreeAllMusic_NoConf();
}
-/* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
-/* ========================================================================= */
+// THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS
+// ============================================================================