rnd-20020427-2-src
[rocksndiamonds.git] / src / libgame / sound.c
index 744c4bd8900c0aaa0947b0a1ac64d42126f494ca..144dd1ad5dccc26ee07e419f34b81fb7cd168ece 100644 (file)
@@ -43,11 +43,12 @@ static struct SoundControl emptySoundControl =
 static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
 static char premix_first_buffer[SND_BLOCKSIZE];
 #if defined(AUDIO_STREAMING_DSP)
-static char premix_left_buffer[SND_BLOCKSIZE];
-static char premix_right_buffer[SND_BLOCKSIZE];
-static int premix_last_buffer[SND_BLOCKSIZE];
+static short premix_second_buffer[SND_BLOCKSIZE];
+static short premix_left_buffer[SND_BLOCKSIZE];
+static short premix_right_buffer[SND_BLOCKSIZE];
+static long premix_last_buffer[SND_BLOCKSIZE];
 #endif
-static unsigned char playing_buffer[SND_BLOCKSIZE];
+static short playing_buffer[SND_BLOCKSIZE];
 #endif
 
 /* forward declaration of internal functions */
@@ -66,7 +67,7 @@ static boolean InitAudioDevice_NetBSD();
 static boolean InitAudioDevice_HPUX();
 #elif defined(PLATFORM_MSDOS)
 static void SoundServer_InsertNewSound(struct SoundControl);
-static void SoundServer_StopSound(int);
+static void SoundServer_StopSound(struct SoundControl);
 static void SoundServer_StopAllSounds();
 #endif
 
@@ -227,16 +228,65 @@ void SoundServer(void)
 
     if (snd_ctrl.reload_sounds || snd_ctrl.reload_music)
     {
-      for(i=0; i<MAX_SOUNDS_PLAYING; i++)
-       playlist[i] = emptySoundControl;
-      playing_sounds = 0;
+      char *set_name = checked_malloc(snd_ctrl.data_len);
+      TreeInfo **ti_ptr =
+       (snd_ctrl.reload_sounds ? &artwork.snd_current : &artwork.mus_current);
+      TreeInfo *ti = *ti_ptr;
+      unsigned long str_size1, str_size2, str_size3;
+
+      if (leveldir_current == NULL)
+       leveldir_current = checked_calloc(sizeof(TreeInfo));
+      if (ti == NULL)
+       ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
+      if (leveldir_current->fullpath != NULL)
+       free(leveldir_current->fullpath);
+      if (ti->basepath != NULL)
+       free(ti->basepath);
+      if (ti->fullpath != NULL)
+       free(ti->fullpath);
+
+      if (read(audio.soundserver_pipe[0], set_name,
+              snd_ctrl.data_len) != snd_ctrl.data_len ||
+         read(audio.soundserver_pipe[0], leveldir_current,
+              sizeof(TreeInfo)) != sizeof(TreeInfo) ||
+         read(audio.soundserver_pipe[0], ti,
+              sizeof(TreeInfo)) != sizeof(TreeInfo) ||
+         read(audio.soundserver_pipe[0], &str_size1,
+              sizeof(unsigned long)) != sizeof(unsigned long) ||
+         read(audio.soundserver_pipe[0], &str_size2,
+              sizeof(unsigned long)) != sizeof(unsigned long) ||
+         read(audio.soundserver_pipe[0], &str_size3,
+              sizeof(unsigned long)) != sizeof(unsigned long))
+       Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+
+      leveldir_current->fullpath = checked_calloc(str_size1);
+      ti->basepath = checked_calloc(str_size2);
+      ti->fullpath = checked_calloc(str_size3);
+
+      if (read(audio.soundserver_pipe[0], leveldir_current->fullpath,
+              str_size1) != str_size1 ||
+         read(audio.soundserver_pipe[0], ti->basepath,
+              str_size2) != str_size2 ||
+         read(audio.soundserver_pipe[0], ti->fullpath,
+              str_size3) != str_size3)
+       Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+
+      InitPlaylist();
 
       close(audio.device_fd);
 
       if (snd_ctrl.reload_sounds)
-       ReloadSounds();
+      {
+       artwork.sounds_set_current = set_name;
+       audio.func_reload_sounds();
+      }
       else
-       ReloadMusic();
+      {
+       artwork.music_set_current = set_name;
+       audio.func_reload_music();
+      }
+
+      free(set_name);
 
       continue;
     }
@@ -296,8 +346,8 @@ void SoundServer(void)
       struct timeval delay = { 0, 0 };
       byte *sample_ptr;
       long sample_size;
-      static long max_sample_size = 0;
-      static long fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+      static int max_sample_size = 0;
+      static int fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
       int sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
       static boolean stereo = TRUE;
 
@@ -311,22 +361,22 @@ void SoundServer(void)
 #elif defined(PLATFORM_NETBSD)
          stereo = InitAudioDevice_NetBSD(fragment_size, sample_rate);
 #endif
-         max_sample_size = fragment_size / (stereo ? 2 : 1);
+         max_sample_size = fragment_size / ((stereo ? 2 : 1) * sizeof(short));
        }
 
        if (snd_ctrl.active)    /* new sound has arrived */
          SoundServer_InsertNewSound(snd_ctrl);
 
-       while(playing_sounds &&
-             select(audio.soundserver_pipe[0] + 1,
-                    &sound_fdset, NULL, NULL, &delay) < 1)
+       while (playing_sounds &&
+              select(audio.soundserver_pipe[0] + 1,
+                     &sound_fdset, NULL, NULL, &delay) < 1)
        {       
          FD_SET(audio.soundserver_pipe[0], &sound_fdset);
 
          /* first clear the last premixing buffer */
-         memset(premix_last_buffer, 0, fragment_size * sizeof(int));
+         memset(premix_last_buffer, 0, fragment_size * sizeof(short));
 
-         for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+         for(i=0; i<MAX_SOUNDS_PLAYING; i++)
          {
            int j;
 
@@ -351,6 +401,10 @@ void SoundServer(void)
              sample_size = max_sample_size;
            }
 
+           /* expand sample from 8 to 16 bit */
+           for(j=0; j<sample_size; j++)
+             premix_second_buffer[j] = premix_first_buffer[j] << 8;
+
            /* decrease volume if sound is fading out */
            if (playlist[i].fade_sound &&
                playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
@@ -359,33 +413,34 @@ void SoundServer(void)
            /* adjust volume of actual sound sample */
            if (playlist[i].volume != PSND_MAX_VOLUME)
              for(j=0; j<sample_size; j++)
-               premix_first_buffer[j] =
-                 (playlist[i].volume * (int)premix_first_buffer[j])
+               premix_second_buffer[j] =
+                 (playlist[i].volume * (int)premix_second_buffer[j])
                    >> PSND_MAX_VOLUME_BITS;
 
            /* fill the last mixing buffer with stereo or mono sound */
            if (stereo)
            {
-             int middle_pos = PSND_MAX_LEFT2RIGHT/2;
-             int left_volume  = stereo_volume[middle_pos +playlist[i].stereo];
-             int right_volume = stereo_volume[middle_pos -playlist[i].stereo];
+             int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
+             int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
+             int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
 
              for(j=0; j<sample_size; j++)
              {
                premix_left_buffer[j] =
-                 (left_volume * (int)premix_first_buffer[j])
+                 (left_volume * premix_second_buffer[j])
                    >> PSND_MAX_LEFT2RIGHT_BITS;
                premix_right_buffer[j] =
-                 (right_volume * (int)premix_first_buffer[j])
+                 (right_volume * premix_second_buffer[j])
                    >> PSND_MAX_LEFT2RIGHT_BITS;
-               premix_last_buffer[2*j+0] += premix_left_buffer[j];
-               premix_last_buffer[2*j+1] += premix_right_buffer[j];
+
+               premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
+               premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
              }
            }
            else
            {
-             for(j=0;j<sample_size;j++)
-               premix_last_buffer[j] += (int)premix_first_buffer[j];
+             for(j=0; j<sample_size; j++)
+               premix_last_buffer[j] += premix_second_buffer[j];
            }
 
            /* delete completed sound entries from the playlist */
@@ -409,12 +464,12 @@ void SoundServer(void)
          /* put last mixing buffer to final playing buffer */
          for(i=0; i<fragment_size; i++)
          {
-           if (premix_last_buffer[i]<-255)
-             playing_buffer[i] = 0;
-           else if (premix_last_buffer[i]>255)
-             playing_buffer[i] = 255;
+           if (premix_last_buffer[i] < -65535)
+             playing_buffer[i] = -32767;
+           else if (premix_last_buffer[i] > 65535)
+             playing_buffer[i] = 32767;
            else
-             playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
+             playing_buffer[i] = (short)(premix_last_buffer[i] >> 1);
          }
 
          /* finally play the sound fragment */
@@ -442,9 +497,9 @@ void SoundServer(void)
       {
        playing_sounds = 1;
 
-       while(playing_sounds &&
-             select(audio.soundserver_pipe[0] + 1,
-                    &sound_fdset, NULL, NULL, &delay) < 1)
+       while (playing_sounds &&
+              select(audio.soundserver_pipe[0] + 1,
+                     &sound_fdset, NULL, NULL, &delay) < 1)
        {       
          FD_SET(audio.soundserver_pipe[0], &sound_fdset);
 
@@ -652,7 +707,7 @@ static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
       playing_sounds++;
 
 #if defined(PLATFORM_MSDOS)
-      playlist[i].voice = allocate_voice(playlist[i].data_ptr);
+      playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
 
       if (snd_ctrl.loop)
         voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
@@ -738,16 +793,17 @@ static void SoundServer_StopAllSounds()
 /* ------------------------------------------------------------------------- */
 
 #if defined(AUDIO_LINUX_IOCTL)
-static boolean InitAudioDevice_Linux(long fragment_size, int sample_rate)
+static boolean InitAudioDevice_Linux(int fragment_size, int sample_rate)
 {
   /* "ioctl()" expects pointer to 'int' value for stereo flag
      (boolean is defined as 'char', which will not work here) */
+  unsigned int fragment_spec = 0;
+  unsigned int audio_format = 0;
+  int fragment_size_query;
   int stereo = TRUE;
-  unsigned long fragment_spec = 0;
 
   /* determine logarithm (log2) of the fragment size */
-  for (fragment_spec=0; (1 << fragment_spec) < fragment_size;
-       fragment_spec++);
+  for (fragment_spec=0; (1 << fragment_spec) < fragment_size; fragment_spec++);
 
   /* use two fragments (play one fragment, prepare the other);
      one fragment would result in interrupted audio output, more
@@ -763,6 +819,11 @@ static boolean InitAudioDevice_Linux(long fragment_size, int sample_rate)
     Error(ERR_EXIT_SOUND_SERVER,
          "cannot set fragment size of /dev/dsp -- no sounds");
 
+  audio_format = AFMT_S16_LE;
+  if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) < 0)
+    Error(ERR_EXIT_SOUND_SERVER,
+         "cannot set audio format of /dev/dsp -- no sounds");
+
   /* try if we can use stereo sound */
   if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
   {
@@ -783,16 +844,19 @@ static boolean InitAudioDevice_Linux(long fragment_size, int sample_rate)
          "cannot set sample rate of /dev/dsp -- no sounds");
 
   /* get the real fragmentation size; this should return 512 */
-  if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size) < 0)
+  if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0)
     Error(ERR_EXIT_SOUND_SERVER,
          "cannot get fragment size of /dev/dsp -- no sounds");
+  if (fragment_size_query != fragment_size)
+    Error(ERR_EXIT_SOUND_SERVER,
+         "cannot set fragment size of /dev/dsp -- no sounds");
 
   return (boolean)stereo;
 }
 #endif /* AUDIO_LINUX_IOCTL */
 
 #if defined(PLATFORM_NETBSD)
-static boolean InitAudioDevice_NetBSD(long fragment_size, int sample_rate)
+static boolean InitAudioDevice_NetBSD(int fragment_size, int sample_rate)
 {
   audio_info_t a_info;
   boolean stereo = TRUE;
@@ -956,16 +1020,6 @@ static int ulaw_to_linear(unsigned char ulawbyte)
 /* ========================================================================= */
 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS                          */
 
-void ReloadSounds()
-{
-  printf("reloading sounds ...\n");
-}
-
-void ReloadMusic()
-{
-  printf("reloading music ...\n");
-}
-
 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
 #define WAV_HEADER_SIZE                16      /* size of WAV file header */
 
@@ -1077,7 +1131,7 @@ static SoundInfo *Load_WAV(char *filename)
   }
 
   for (i=0; i<snd_info->data_len; i++)
-    ((byte *)snd_info->data_ptr)[i] = ((byte *)snd_info->data_ptr)[i] ^ 0x80;
+    ((byte *)snd_info->data_ptr)[i] ^= 0x80;
 
 #endif /* PLATFORM_UNIX */
 
@@ -1165,9 +1219,9 @@ void LoadCustomMusic(void)
     char *filename = getPath2(music_directory, basename);
     MusicInfo *mus_info = NULL;
 
-    if (FileIsSound(filename))
+    if (FileIsSound(basename))
       mus_info = Load_WAV(filename);
-    else if (FileIsMusic(filename))
+    else if (FileIsMusic(basename))
       mus_info = Load_MOD(filename);
 
     free(filename);
@@ -1194,6 +1248,8 @@ void PlayMusic(int nr)
 
 #if defined(TARGET_SDL)
 
+  nr = nr % num_music;
+
   if (Music[nr]->type == MUS_TYPE_MOD)
   {
     Mix_PlayMusic(Music[nr]->data_ptr, -1);
@@ -1372,8 +1428,8 @@ void StopSoundExt(int nr, int method)
       Mix_HaltMusic();
   }
 
-#else
-#if !defined(PLATFORM_MSDOS)
+#elif !defined(PLATFORM_MSDOS)
+
   if (audio.soundserver_pid == 0)      /* we are child process */
     return;
 
@@ -1386,59 +1442,74 @@ void StopSoundExt(int nr, int method)
 #else
   sound_handler(snd_ctrl);
 #endif
-#endif
 }
 
-void InitReloadSounds(char *set_name)
+static void InitReloadSoundsOrMusic(char *set_name, int type)
 {
+#if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
   struct SoundControl snd_ctrl = emptySoundControl;
+  TreeInfo *ti =
+    (type == SND_RELOAD_SOUNDS ? artwork.snd_current : artwork.mus_current);
+  unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
+  unsigned long str_size2 = strlen(ti->basepath) + 1;
+  unsigned long str_size3 = strlen(ti->fullpath) + 1;
+#endif
 
   if (!audio.sound_available)
     return;
 
-  snd_ctrl.reload_sounds = TRUE;
-
-#if defined(TARGET_SDL)
-  ReloadSounds();
+#if defined(TARGET_SDL) || defined(TARGET_ALLEGRO)
+  if (type == SND_RELOAD_SOUNDS)
+    audio.func_reload_sounds();
+  else
+    audio.func_reload_music();
 #elif defined(PLATFORM_UNIX)
   if (audio.soundserver_pid == 0)      /* we are child process */
     return;
 
-  if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
+  if (leveldir_current == NULL)                /* should never happen */
+    Error(ERR_EXIT, "leveldir_current == NULL");
+
+  snd_ctrl.reload_sounds = (type == SND_RELOAD_SOUNDS);
+  snd_ctrl.reload_music  = (type == SND_RELOAD_MUSIC);
+  snd_ctrl.data_len = strlen(set_name) + 1;
+
+  if (write(audio.soundserver_pipe[1], &snd_ctrl,
+           sizeof(snd_ctrl)) < 0 ||
+      write(audio.soundserver_pipe[1], set_name,
+           snd_ctrl.data_len) < 0 ||
+      write(audio.soundserver_pipe[1], leveldir_current,
+           sizeof(TreeInfo)) < 0 ||
+      write(audio.soundserver_pipe[1], ti,
+           sizeof(TreeInfo)) < 0 ||
+      write(audio.soundserver_pipe[1], &str_size1,
+           sizeof(unsigned long)) < 0 ||
+      write(audio.soundserver_pipe[1], &str_size2,
+           sizeof(unsigned long)) < 0 ||
+      write(audio.soundserver_pipe[1], &str_size3,
+           sizeof(unsigned long)) < 0 ||
+      write(audio.soundserver_pipe[1], leveldir_current->fullpath,
+           str_size1) < 0 ||
+      write(audio.soundserver_pipe[1], ti->basepath,
+           str_size2) < 0 ||
+      write(audio.soundserver_pipe[1], ti->fullpath,
+           str_size3) < 0)
   {
     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
     audio.sound_available = audio.sound_enabled = FALSE;
     return;
   }
-#elif defined(PLATFORM_MSDOS)
-  sound_handler(snd_ctrl);
 #endif
 }
 
-void InitReloadMusic(char *set_name)
+void InitReloadSounds(char *set_name)
 {
-  struct SoundControl snd_ctrl = emptySoundControl;
-
-  if (!audio.sound_available)
-    return;
-
-  snd_ctrl.reload_music = TRUE;
-
-#if defined(TARGET_SDL)
-  ReloadMusic();
-#elif defined(PLATFORM_UNIX)
-  if (audio.soundserver_pid == 0)      /* we are child process */
-    return;
+  InitReloadSoundsOrMusic(set_name, SND_RELOAD_SOUNDS);
+}
 
-  if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
-  {
-    Error(ERR_WARN, "cannot pipe to child process -- no sounds");
-    audio.sound_available = audio.sound_enabled = FALSE;
-    return;
-  }
-#elif defined(PLATFORM_MSDOS)
-  sound_handler(snd_ctrl);
-#endif
+void InitReloadMusic(char *set_name)
+{
+  InitReloadSoundsOrMusic(set_name, SND_RELOAD_MUSIC);
 }
 
 void FreeSound(SoundInfo *sound)
@@ -1493,6 +1564,9 @@ void FreeAllSounds()
     FreeSound(Sound[i]);
 
   free(Sound);
+
+  Sound = NULL;
+  num_sounds = 0;
 }
 
 void FreeAllMusic()
@@ -1506,6 +1580,9 @@ void FreeAllMusic()
     FreeMusic(Music[i]);
 
   free(Music);
+
+  Music = NULL;
+  num_music = 0;
 }
 
 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS                          */