Browse Source

Audio system refactor

1. Now the volume of music and sound can be specified separately
2. The function name in the audio system are mostly changed from 'SOUND_' to 'AUDIO_'
3. The sound play function is rewritten, now each sound played is automatically mixed with the previously sounds, so that now there is only one ring buffer for sound play
4. In the callback function for filling audio buffer, use customized fix function rather than 'SDL_MixAudio'
5. Now the byte-order swap happens only when the buffer is mixed and ready to commit, so that in earlier stages, all data are operated completely in native byte-order and there are no needs to swap byte orders in the audio system
louyihua 8 years ago
parent
commit
1d74726652

+ 6 - 6
battle.c

@@ -326,7 +326,7 @@ PAL_BattleMain(
    //
    //
    // Fade out the music and delay for a while
    // Fade out the music and delay for a while
    //
    //
-   SOUND_PlayMUS(0, FALSE, 1);
+   AUDIO_PlayMusic(0, FALSE, 1);
    UTIL_Delay(200);
    UTIL_Delay(200);
 
 
    //
    //
@@ -337,7 +337,7 @@ PAL_BattleMain(
    //
    //
    // Play the battle music
    // Play the battle music
    //
    //
-   SOUND_PlayMUS(gpGlobals->wNumBattleMusic, TRUE, 0);
+   AUDIO_PlayMusic(gpGlobals->wNumBattleMusic, TRUE, 0);
 
 
    //
    //
    // Fade in the screen when needed
    // Fade in the screen when needed
@@ -646,7 +646,7 @@ PAL_BattleWon(
       //
       //
       // Play the "battle win" music
       // Play the "battle win" music
       //
       //
-      SOUND_PlayMUS(g_Battle.fIsBoss ? 2 : 3, FALSE, 0);
+      AUDIO_PlayMusic(g_Battle.fIsBoss ? 2 : 3, FALSE, 0);
 
 
       //
       //
       // Show the message about the total number of exp. and cash gained
       // Show the message about the total number of exp. and cash gained
@@ -973,7 +973,7 @@ PAL_BattleEnemyEscape(
    int j, x, y, w;
    int j, x, y, w;
    BOOL f = TRUE;
    BOOL f = TRUE;
 
 
-   SOUND_Play(45);
+   AUDIO_PlaySound(45);
 
 
    //
    //
    // Show the animation
    // Show the animation
@@ -1035,7 +1035,7 @@ PAL_BattlePlayerEscape(
    int         i, j;
    int         i, j;
    WORD        wPlayerRole;
    WORD        wPlayerRole;
 
 
-   SOUND_Play(45);
+   AUDIO_PlaySound(45);
 
 
    PAL_BattleUpdateFighters();
    PAL_BattleUpdateFighters();
 
 
@@ -1441,7 +1441,7 @@ PAL_StartBattle(
 
 
    gpGlobals->fInBattle = FALSE;
    gpGlobals->fInBattle = FALSE;
 
 
-   SOUND_PlayMUS(gpGlobals->wNumMusic, TRUE, 1);
+   AUDIO_PlayMusic(gpGlobals->wNumMusic, TRUE, 1);
 
 
    //
    //
    // Restore the screen waving effects
    // Restore the screen waving effects

+ 9 - 9
ending.c

@@ -434,13 +434,13 @@ PAL_EndingScreen(
    VOID
    VOID
 )
 )
 {
 {
-	SOUND_PlayMUS(0x1a, TRUE, 0);
+	AUDIO_PlayMusic(0x1a, TRUE, 0);
 	PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 110, 150, 7);
 	PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 110, 150, 7);
 	PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 151, 999, 9);
 	PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 151, 999, 9);
 
 
 	PAL_FadeOut(2);
 	PAL_FadeOut(2);
 
 
-	SOUND_PlayMUS(0x19, TRUE, 0);
+	AUDIO_PlayMusic(0x19, TRUE, 0);
 
 
 	PAL_ShowFBP(75, 0);
 	PAL_ShowFBP(75, 0);
 	PAL_FadeIn(5, FALSE, 1);
 	PAL_FadeIn(5, FALSE, 1);
@@ -453,12 +453,12 @@ PAL_EndingScreen(
 	gpGlobals->fNeedToFadeIn = TRUE;
 	gpGlobals->fNeedToFadeIn = TRUE;
 	PAL_EndingAnimation();
 	PAL_EndingAnimation();
 
 
-	SOUND_PlayMUS(0, FALSE, 2);
+	AUDIO_PlayMusic(0, FALSE, 2);
 	PAL_ColorFade(7, 15, FALSE);
 	PAL_ColorFade(7, 15, FALSE);
 
 
-	if (!SOUND_PlayCDA(2))
+	if (!AUDIO_PlayCDTrack(2))
 	{
 	{
-		SOUND_PlayMUS(0x11, TRUE, 0);
+		AUDIO_PlayMusic(0x11, TRUE, 0);
 	}
 	}
 
 
 	SDL_FillRect(gpScreen, NULL, 0);
 	SDL_FillRect(gpScreen, NULL, 0);
@@ -491,12 +491,12 @@ PAL_EndingScreen(
 	PAL_ShowFBP(68, 6);
 	PAL_ShowFBP(68, 6);
 
 
 	PAL_WaitForKey(0);
 	PAL_WaitForKey(0);
-	SOUND_PlayMUS(0, FALSE, 1);
+	AUDIO_PlayMusic(0, FALSE, 1);
 	UTIL_Delay(500);
 	UTIL_Delay(500);
 
 
-	if (!SOUND_PlayCDA(13))
+	if (!AUDIO_PlayCDTrack(13))
 	{
 	{
-		SOUND_PlayMUS(9, TRUE, 0);
+		AUDIO_PlayMusic(9, TRUE, 0);
 	}
 	}
 
 
 	PAL_ScrollFBP(67, 0xf, TRUE);
 	PAL_ScrollFBP(67, 0xf, TRUE);
@@ -509,7 +509,7 @@ PAL_EndingScreen(
 	PAL_ScrollFBP(60, 0xf, TRUE);
 	PAL_ScrollFBP(60, 0xf, TRUE);
 	PAL_ScrollFBP(59, 0xf, TRUE);
 	PAL_ScrollFBP(59, 0xf, TRUE);
 
 
-	SOUND_PlayMUS(0, FALSE, 6);
+	AUDIO_PlayMusic(0, FALSE, 6);
 	PAL_FadeOut(3);
 	PAL_FadeOut(3);
 }
 }
 
 

+ 24 - 24
fight.c

@@ -717,7 +717,7 @@ PAL_BattlePostActionCheck(
          g_Battle.iExpGained += g_Battle.rgEnemy[i].e.wExp;
          g_Battle.iExpGained += g_Battle.rgEnemy[i].e.wExp;
          g_Battle.iCashGained += g_Battle.rgEnemy[i].e.wCash;
          g_Battle.iCashGained += g_Battle.rgEnemy[i].e.wCash;
 
 
-         SOUND_Play(g_Battle.rgEnemy[i].e.wDeathSound);
+         AUDIO_PlaySound(g_Battle.rgEnemy[i].e.wDeathSound);
          g_Battle.rgEnemy[i].wObjectID = 0;
          g_Battle.rgEnemy[i].wObjectID = 0;
          fFade = TRUE;
          fFade = TRUE;
 
 
@@ -808,7 +808,7 @@ PAL_BattlePostActionCheck(
 
 
                wName = gpGlobals->g.PlayerRoles.rgwName[w];
                wName = gpGlobals->g.PlayerRoles.rgwName[w];
 
 
-               SOUND_Play(gpGlobals->g.PlayerRoles.rgwDyingSound[w]);
+               AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwDyingSound[w]);
 
 
                for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)
                for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)
                {
                {
@@ -1079,7 +1079,7 @@ PAL_BattleStartFrame(
       // All enemies are cleared. Won the battle.
       // All enemies are cleared. Won the battle.
       //
       //
       g_Battle.BattleResult = kBattleResultWon;
       g_Battle.BattleResult = kBattleResultWon;
-      SOUND_Play(0);
+      AUDIO_PlaySound(0);
       return;
       return;
    }
    }
    else
    else
@@ -1952,11 +1952,11 @@ PAL_BattleShowPlayerAttackAnim(
    {
    {
       if (!fCritical)
       if (!fCritical)
       {
       {
-         SOUND_Play(gpGlobals->g.PlayerRoles.rgwAttackSound[wPlayerRole]);
+         AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwAttackSound[wPlayerRole]);
       }
       }
       else
       else
       {
       {
-         SOUND_Play(gpGlobals->g.PlayerRoles.rgwCriticalSound[wPlayerRole]);
+         AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwCriticalSound[wPlayerRole]);
       }
       }
    }
    }
 
 
@@ -1981,7 +1981,7 @@ PAL_BattleShowPlayerAttackAnim(
    x -= 16;
    x -= 16;
    y -= 4;
    y -= 4;
 
 
-   SOUND_Play(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]);
+   AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]);
 
 
    x = enemy_x;
    x = enemy_x;
    y = enemy_y - enemy_h / 3 + 10;
    y = enemy_y - enemy_h / 3 + 10;
@@ -2141,7 +2141,7 @@ PAL_BattleShowPlayerUseItemAnim(
 
 
    g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;
    g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;
 
 
-   SOUND_Play(28);
+   AUDIO_PlaySound(28);
 
 
    for (i = 0; i <= 6; i++)
    for (i = 0; i <= 6; i++)
    {
    {
@@ -2218,7 +2218,7 @@ PAL_BattleShowPlayerPreMagicAnim(
    g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;
    g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;
    if (!gConfig.fIsWIN95)
    if (!gConfig.fIsWIN95)
    {
    {
-      SOUND_Play(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);
+      AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);
    }
    }
 
 
    if (!fSummon)
    if (!fSummon)
@@ -2233,7 +2233,7 @@ PAL_BattleShowPlayerPreMagicAnim(
       index += 15;
       index += 15;
 	  if (gConfig.fIsWIN95)
 	  if (gConfig.fIsWIN95)
 	  {
 	  {
-		  SOUND_Play(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);
+		  AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);
 	  }
 	  }
 	  for (i = 0; i < 10; i++)
 	  for (i = 0; i < 10; i++)
       {
       {
@@ -2341,7 +2341,7 @@ PAL_BattleShowPlayerDefMagicAnim(
 
 
       if (i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay)
       if (i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay)
       {
       {
-         SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);
+         AUDIO_PlaySound(gpGlobals->g.lprgMagic[iMagicNum].wSound);
       }
       }
 
 
       //
       //
@@ -2515,7 +2515,7 @@ PAL_BattleShowPlayerOffMagicAnim(
 
 
    if (gConfig.fIsWIN95 && !fSummon && gpGlobals->g.lprgMagic[iMagicNum].wSound != 0)
    if (gConfig.fIsWIN95 && !fSummon && gpGlobals->g.lprgMagic[iMagicNum].wSound != 0)
    {
    {
-      SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);
+      AUDIO_PlaySound(gpGlobals->g.lprgMagic[iMagicNum].wSound);
    }
    }
 
 
    for (i = 0; i < l; i++)
    for (i = 0; i < l; i++)
@@ -2557,7 +2557,7 @@ PAL_BattleShowPlayerOffMagicAnim(
 
 
 		 if (!gConfig.fIsWIN95 && (i - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay) % n == 0)
 		 if (!gConfig.fIsWIN95 && (i - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay) % n == 0)
          {
          {
-            SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);
+            AUDIO_PlaySound(gpGlobals->g.lprgMagic[iMagicNum].wSound);
          }
          }
       }
       }
       else
       else
@@ -2752,7 +2752,7 @@ PAL_BattleShowEnemyMagicAnim(
 
 
          if (i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay)
          if (i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay)
          {
          {
-            SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);
+            AUDIO_PlaySound(gpGlobals->g.lprgMagic[iMagicNum].wSound);
          }
          }
       }
       }
       else
       else
@@ -2910,7 +2910,7 @@ PAL_BattleShowPlayerSummonMagicAnim(
    //
    //
    if (gConfig.fIsWIN95)
    if (gConfig.fIsWIN95)
    {
    {
-	   SOUND_Play(gpGlobals->g.lprgMagic[wMagicNum].wSound);
+	   AUDIO_PlaySound(gpGlobals->g.lprgMagic[wMagicNum].wSound);
    }
    }
 
 
    //
    //
@@ -3502,7 +3502,7 @@ PAL_BattlePlayerPerformAction(
          PAL_BattleDelay(5, 0, TRUE);
          PAL_BattleDelay(5, 0, TRUE);
 
 
          g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 9;
          g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 9;
-         SOUND_Play(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]);
+         AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]);
 
 
          str = PAL_GetPlayerAttackStrength(wPlayerRole);
          str = PAL_GetPlayerAttackStrength(wPlayerRole);
          def = PAL_GetPlayerDefense(gpGlobals->rgParty[sTarget].wPlayerRole);
          def = PAL_GetPlayerDefense(gpGlobals->rgParty[sTarget].wPlayerRole);
@@ -3562,7 +3562,7 @@ PAL_BattlePlayerPerformAction(
          //
          //
          // Sound should be played before action begins
          // Sound should be played before action begins
          //
          //
-         SOUND_Play(29);
+         AUDIO_PlaySound(29);
 
 
          for (i = 1; i <= 6; i++)
          for (i = 1; i <= 6; i++)
          {
          {
@@ -3994,7 +3994,7 @@ PAL_BattlePlayerPerformAction(
       PAL_BattleDelay(2, wObject, TRUE);
       PAL_BattleDelay(2, wObject, TRUE);
 
 
       g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;
       g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;
-      SOUND_Play(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);
+      AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);
 
 
       PAL_BattleDelay(8, wObject, TRUE);
       PAL_BattleDelay(8, wObject, TRUE);
 
 
@@ -4254,7 +4254,7 @@ PAL_BattleEnemyPerformAction(
       g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(ex, ey);
       g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(ex, ey);
       PAL_BattleDelay(1, 0, FALSE);
       PAL_BattleDelay(1, 0, FALSE);
 
 
-      SOUND_Play(g_Battle.rgEnemy[wEnemyIndex].e.wMagicSound);
+      AUDIO_PlaySound(g_Battle.rgEnemy[wEnemyIndex].e.wMagicSound);
 
 
       for (i = 0; i < g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames; i++)
       for (i = 0; i < g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames; i++)
       {
       {
@@ -4375,7 +4375,7 @@ PAL_BattleEnemyPerformAction(
 
 
                if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0)
                if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0)
                {
                {
-                  SOUND_Play(gpGlobals->g.PlayerRoles.rgwDeathSound[w]);
+                  AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwDeathSound[w]);
                }
                }
             }
             }
          }
          }
@@ -4410,7 +4410,7 @@ PAL_BattleEnemyPerformAction(
 
 
             if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)
             if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)
             {
             {
-               SOUND_Play(gpGlobals->g.PlayerRoles.rgwDeathSound[wPlayerRole]);
+               AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwDeathSound[wPlayerRole]);
             }
             }
          }
          }
       }
       }
@@ -4490,7 +4490,7 @@ PAL_BattleEnemyPerformAction(
          def *= 2;
          def *= 2;
       }
       }
 
 
-      SOUND_Play(g_Battle.rgEnemy[wEnemyIndex].e.wAttackSound);
+      AUDIO_PlaySound(g_Battle.rgEnemy[wEnemyIndex].e.wAttackSound);
 
 
       iCoverIndex = -1;
       iCoverIndex = -1;
 
 
@@ -4559,7 +4559,7 @@ PAL_BattleEnemyPerformAction(
       }
       }
 	  if (!gConfig.fIsWIN95 || g_Battle.rgEnemy[wEnemyIndex].e.wActionSound != 0)
 	  if (!gConfig.fIsWIN95 || g_Battle.rgEnemy[wEnemyIndex].e.wActionSound != 0)
       {
       {
-         SOUND_Play(g_Battle.rgEnemy[wEnemyIndex].e.wActionSound);
+         AUDIO_PlaySound(g_Battle.rgEnemy[wEnemyIndex].e.wActionSound);
       }
       }
       PAL_BattleDelay(1, 0, FALSE);
       PAL_BattleDelay(1, 0, FALSE);
 
 
@@ -4640,7 +4640,7 @@ PAL_BattleEnemyPerformAction(
       }
       }
 	  if (!gConfig.fIsWIN95 || iSound != 0)
 	  if (!gConfig.fIsWIN95 || iSound != 0)
       {
       {
-         SOUND_Play(iSound);
+         AUDIO_PlaySound(iSound);
       }
       }
       PAL_BattleDelay(1, 0, FALSE);
       PAL_BattleDelay(1, 0, FALSE);
 
 
@@ -4666,7 +4666,7 @@ PAL_BattleEnemyPerformAction(
 
 
       if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)
       if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)
       {
       {
-         SOUND_Play(gpGlobals->g.PlayerRoles.rgwDeathSound[wPlayerRole]);
+         AUDIO_PlaySound(gpGlobals->g.PlayerRoles.rgwDeathSound[wPlayerRole]);
          wFrameBak = 2;
          wFrameBak = 2;
       }
       }
       else if (PAL_IsPlayerDying(wPlayerRole))
       else if (PAL_IsPlayerDying(wPlayerRole))

+ 1 - 1
game.c

@@ -47,7 +47,7 @@ PAL_GameStart(
       //
       //
       // Fade in music if the player has loaded an old game.
       // Fade in music if the player has loaded an old game.
       //
       //
-      SOUND_PlayMUS(gpGlobals->wNumMusic, TRUE, 1);
+      AUDIO_PlayMusic(gpGlobals->wNumMusic, TRUE, 1);
    }
    }
 
 
    gpGlobals->fNeedToFadeIn = TRUE;
    gpGlobals->fNeedToFadeIn = TRUE;

+ 4 - 4
input.c

@@ -92,10 +92,10 @@ PAL_KeyboardEventFilter(
          VIDEO_ToggleScaleScreen();
          VIDEO_ToggleScaleScreen();
          break;
          break;
       case SDLK_1:
       case SDLK_1:
-         SOUND_AdjustVolume(0);
+         AUDIO_AdjustVolume(0);
          break;
          break;
       case SDLK_3:
       case SDLK_3:
-         SOUND_AdjustVolume(1);
+         AUDIO_AdjustVolume(1);
          break;
          break;
 #endif
 #endif
       case SDLK_UP:
       case SDLK_UP:
@@ -415,14 +415,14 @@ PAL_MouseEventFilter(
       case 2:
       case 2:
         if( isLeftMouseDBClick )
         if( isLeftMouseDBClick )
        {
        {
-          SOUND_AdjustVolume(1);
+          AUDIO_AdjustVolume(1);
           break;
           break;
        }
        }
       case 6:
       case 6:
       case 0:
       case 0:
         if( isLeftMouseDBClick )
         if( isLeftMouseDBClick )
        {
        {
-          SOUND_AdjustVolume(0);
+          AUDIO_AdjustVolume(0);
           break;
           break;
        }
        }
       case 7:
       case 7:

+ 45 - 31
libmad/music_mad.c

@@ -53,7 +53,6 @@ mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int resampler_quality) {
   mad_synth_init(&mp3_mad->synth);
   mad_synth_init(&mp3_mad->synth);
   mp3_mad->frames_read = 0;
   mp3_mad->frames_read = 0;
   mad_timer_reset(&mp3_mad->next_frame_start);
   mad_timer_reset(&mp3_mad->next_frame_start);
-  mp3_mad->volume = 128;
   mp3_mad->status = 0;
   mp3_mad->status = 0;
   mp3_mad->output_begin = 0;
   mp3_mad->output_begin = 0;
   mp3_mad->output_end = 0;
   mp3_mad->output_end = 0;
@@ -93,6 +92,29 @@ mad_isPlaying(mad_data *mp3_mad) {
   return ((mp3_mad->status & MS_playing) != 0);
   return ((mp3_mad->status & MS_playing) != 0);
 }
 }
 
 
+static void
+convert_mono(signed short *srcdst, int samples)
+{
+	signed short *left = srcdst, *right = srcdst + 1;
+	while (samples > 0)
+	{
+		*srcdst++ = (signed short)(((signed int)(*left) + (signed int)(*right)) >> 1);
+		samples--; left += 2; right += 2;
+	}
+}
+
+static void
+convert_stereo(signed short *srcdst, int samples)
+{
+	signed short *left = srcdst + (samples - 1) * 2, *right = srcdst + samples * 2 - 1;
+	srcdst += samples - 1;
+	while (samples > 0)
+	{
+		*left = *right = *srcdst--;
+		samples--; left -= 2; right -= 2;
+	}
+}
+
 /* Reads the next frame from the file.  Returns true on success or
 /* Reads the next frame from the file.  Returns true on success or
    false on failure. */
    false on failure. */
 static int
 static int
@@ -224,8 +246,13 @@ decode_frame(mad_data *mp3_mad) {
         mp3_mad->mixer.freq = mp3_mad->frame.header.samplerate;
         mp3_mad->mixer.freq = mp3_mad->frame.header.samplerate;
       }
       }
     }
     }
-    /* ------------------------------- SDLPAL end ------------------------------- */
-	SDL_BuildAudioCVT(&mp3_mad->cvt, AUDIO_S16, (Uint8)pcm->channels, mp3_mad->frame.header.samplerate, mp3_mad->mixer.format, mp3_mad->mixer.channels, mp3_mad->mixer.freq);
+	if (pcm->channels == 1 && mp3_mad->mixer.channels == 2)
+		mp3_mad->converter = convert_stereo;
+	else if (pcm->channels == 2 && mp3_mad->mixer.channels == 1)
+		mp3_mad->converter = convert_mono;
+	else
+		mp3_mad->converter = NULL;
+	/* ------------------------------- SDLPAL end ------------------------------- */
   }
   }
 
 
   /* pcm->samplerate contains the sampling frequency */
   /* pcm->samplerate contains the sampling frequency */
@@ -236,18 +263,12 @@ decode_frame(mad_data *mp3_mad) {
   right_ch  = pcm->samples[1];
   right_ch  = pcm->samples[1];
 
 
   while (nsamples--) {
   while (nsamples--) {
-    signed int sample;
-
-    /* output sample(s) in 16-bit signed little-endian PCM */
+    /* output sample(s) in 16-bit signed native-endian PCM */
 
 
-    sample = scale(*left_ch++);
-    *out++ = ((sample >> 0) & 0xff);
-    *out++ = ((sample >> 8) & 0xff);
+	*((signed short*)out) = (signed short)scale(*left_ch++); out += 2;
 
 
     if (nchannels == 2) {
     if (nchannels == 2) {
-      sample = scale(*right_ch++);
-      *out++ = ((sample >> 0) & 0xff);
-      *out++ = ((sample >> 8) & 0xff);
+      *((signed short*)out) = scale(*right_ch++); out += 2;
     }
     }
   }
   }
 
 
@@ -287,14 +308,17 @@ mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
 
 
 		/* Now convert the frame data to the appropriate format for
 		/* Now convert the frame data to the appropriate format for
 		   output. */
 		   output. */
-		mp3_mad->cvt.buf = mp3_mad->output_buffer;
-		mp3_mad->cvt.len = mp3_mad->output_end;
-		
-		mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
-		/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
-		SDL_ConvertAudio(&mp3_mad->cvt);
-
         /* ------------------------------- SDLPAL start ------------------------------- */
         /* ------------------------------- SDLPAL start ------------------------------- */
+		if (mp3_mad->converter)
+		{
+			int nchannels = (mp3_mad->converter == convert_stereo) ? 1 : 2;
+			mp3_mad->converter((signed short *)mp3_mad->output_buffer, mp3_mad->output_end / (nchannels * 2));
+			if (nchannels == 1)
+				mp3_mad->output_end <<= 1;
+			else
+				mp3_mad->output_end >>= 1;
+		}
+
         if (mp3_mad->resampler[0]) {
         if (mp3_mad->resampler[0]) {
 		  int dst_samples = 0, pos = 0, i;
 		  int dst_samples = 0, pos = 0, i;
 		  if (mp3_mad->upsample) {
 		  if (mp3_mad->upsample) {
@@ -313,7 +337,7 @@ mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
             while(src_samples > 0) {
             while(src_samples > 0) {
               int to_write = resampler_get_free_count(mp3_mad->resampler[i]), j;
               int to_write = resampler_get_free_count(mp3_mad->resampler[i]), j;
               for (j = 0; j < to_write; j++) {
               for (j = 0; j < to_write; j++) {
-                resampler_write_sample(mp3_mad->resampler[i], SDL_SwapLE16(*src));
+                resampler_write_sample(mp3_mad->resampler[i], *src);
                 src += mp3_mad->mixer.channels;
                 src += mp3_mad->mixer.channels;
               }
               }
 			  src_samples -= to_write;
 			  src_samples -= to_write;
@@ -334,12 +358,7 @@ mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
 	  num_bytes = bytes_remaining;
 	  num_bytes = bytes_remaining;
 	}
 	}
 
 
-	if (mp3_mad->volume == 128) {
-	  memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
-	} else {
-	  SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
-				   num_bytes, mp3_mad->volume);
-	}
+	memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
 	out += num_bytes;
 	out += num_bytes;
 	mp3_mad->output_begin += num_bytes;
 	mp3_mad->output_begin += num_bytes;
 	bytes_remaining -= num_bytes;
 	bytes_remaining -= num_bytes;
@@ -389,8 +408,3 @@ mad_seek(mad_data *mp3_mad, double position) {
 	 we could get more precise by decoding the frame now and counting
 	 we could get more precise by decoding the frame now and counting
 	 the appropriate number of samples out of it. */
 	 the appropriate number of samples out of it. */
 }
 }
-
-void
-mad_setVolume(mad_data *mp3_mad, int volume) {
-  mp3_mad->volume = volume;
-}

+ 1 - 3
libmad/music_mad.h

@@ -46,13 +46,12 @@ typedef struct {
   struct mad_synth synth;
   struct mad_synth synth;
   int frames_read;
   int frames_read;
   mad_timer_t next_frame_start;
   mad_timer_t next_frame_start;
-  int volume;
   int status;
   int status;
   int output_begin, output_end;
   int output_begin, output_end;
   int upsample; /* SDLPAL: Is upsample or downsample */
   int upsample; /* SDLPAL: Is upsample or downsample */
   int resampler_quality; /* SDLPAL:resampler quality */
   int resampler_quality; /* SDLPAL:resampler quality */
   SDL_AudioSpec mixer;
   SDL_AudioSpec mixer;
-  SDL_AudioCVT cvt;
+  void (*converter)(signed short *, int);
 
 
   unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
   unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
   unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
   unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
@@ -68,4 +67,3 @@ int mad_isPlaying(mad_data *mp3_mad);
 
 
 void mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
 void mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
 void mad_seek(mad_data *mp3_mad, double position);
 void mad_seek(mad_data *mp3_mad, double position);
-void mad_setVolume(mad_data *mp3_mad, int volume);

+ 5 - 5
main.c

@@ -130,7 +130,7 @@ PAL_Init(
 
 
    PAL_InitInput();
    PAL_InitInput();
    PAL_InitResources();
    PAL_InitResources();
-   SOUND_OpenAudio();
+   AUDIO_OpenDevice();
 
 
    if (gConfig.fIsWIN95)
    if (gConfig.fIsWIN95)
    {
    {
@@ -169,7 +169,7 @@ PAL_Shutdown(
 
 
 --*/
 --*/
 {
 {
-   SOUND_CloseAudio();
+   AUDIO_CloseDevice();
    PAL_FreeFont();
    PAL_FreeFont();
    PAL_FreeResources();
    PAL_FreeResources();
    PAL_FreeGlobals();
    PAL_FreeGlobals();
@@ -315,10 +315,10 @@ PAL_SplashScreen(
    //
    //
    // Play the title music
    // Play the title music
    //
    //
-   if (!SOUND_PlayCDA(7))
+   if (!AUDIO_PlayCDTrack(7))
    {
    {
       fUseCD = FALSE;
       fUseCD = FALSE;
-      SOUND_PlayMUS(NUM_RIX_TITLE, TRUE, 2);
+      AUDIO_PlayMusic(NUM_RIX_TITLE, TRUE, 2);
    }
    }
 
 
    //
    //
@@ -487,7 +487,7 @@ PAL_SplashScreen(
 
 
    if (!fUseCD)
    if (!fUseCD)
    {
    {
-      SOUND_PlayMUS(0, FALSE, 1);
+      AUDIO_PlayMusic(0, FALSE, 1);
    }
    }
 
 
    PAL_FadeOut(1);
    PAL_FadeOut(1);

+ 2 - 2
midi.c

@@ -55,12 +55,12 @@ MIDI_Play(
       return;
       return;
    }
    }
 
 
-   SOUND_PlayCDA(-1);
+   AUDIO_PlayCDTrack(-1);
    native_midi_freesong(g_pMid);
    native_midi_freesong(g_pMid);
    g_pMid = NULL;
    g_pMid = NULL;
    iMidCurrent = -1;
    iMidCurrent = -1;
 
 
-   if (g_fNoMusic || iNumRIX <= 0)
+   if (!AUDIO_MusicEnabled() || iNumRIX <= 0)
    {
    {
       return;
       return;
    }
    }

+ 5 - 8
mp3play.c

@@ -33,7 +33,7 @@
 
 
 typedef struct tagMP3PLAYER
 typedef struct tagMP3PLAYER
 {
 {
-	MUSICPLAYER_FUNCTIONS;
+	MUSICPLAYER_COMMONS;
 
 
 	mad_data           *pMP3;
 	mad_data           *pMP3;
 	INT                 iMusic;
 	INT                 iMusic;
@@ -62,17 +62,14 @@ MP3_FillBuffer(
 {
 {
 	LPMP3PLAYER player = (LPMP3PLAYER)object;
 	LPMP3PLAYER player = (LPMP3PLAYER)object;
 	if (player->pMP3) {
 	if (player->pMP3) {
-		player->pMP3->volume = gConfig.iVolume * 3 / 4;
-
-		mad_getSamples(player->pMP3, stream, len);
-
 		if (!mad_isPlaying(player->pMP3) && player->fLoop)
 		if (!mad_isPlaying(player->pMP3) && player->fLoop)
 		{
 		{
 			mad_seek(player->pMP3, 0);
 			mad_seek(player->pMP3, 0);
 			mad_start(player->pMP3);
 			mad_start(player->pMP3);
+		}
 
 
+		if (mad_isPlaying(player->pMP3))
 			mad_getSamples(player->pMP3, stream, len);
 			mad_getSamples(player->pMP3, stream, len);
-		}
 	}
 	}
 }
 }
 
 
@@ -117,9 +114,9 @@ MP3_Play(
 
 
 	if (iNum > 0)
 	if (iNum > 0)
 	{
 	{
-		if ((player->pMP3 = mad_openFile(va("%smp3/%.2d.mp3", gConfig.pszGamePath, iNum), SOUND_GetAudioSpec(), gConfig.iResampleQuality)) == NULL)
+		if ((player->pMP3 = mad_openFile(va("%smp3/%.2d.mp3", gConfig.pszGamePath, iNum), AUDIO_GetDeviceSpec(), gConfig.iResampleQuality)) == NULL)
 		{
 		{
-			player->pMP3 = mad_openFile(va("%sMP3/%.2d.MP3", gConfig.pszGamePath, iNum), SOUND_GetAudioSpec(), gConfig.iResampleQuality);
+			player->pMP3 = mad_openFile(va("%sMP3/%.2d.MP3", gConfig.pszGamePath, iNum), AUDIO_GetDeviceSpec(), gConfig.iResampleQuality);
 		}
 		}
 
 
 		if (player->pMP3)
 		if (player->pMP3)

+ 13 - 14
oggplay.c

@@ -49,7 +49,7 @@
 
 
 typedef struct tagOGGPLAYER
 typedef struct tagOGGPLAYER
 {
 {
-	MUSICPLAYER_FUNCTIONS;
+	MUSICPLAYER_COMMONS;
 
 
 	ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
 	ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
 	ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
 	ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
@@ -70,9 +70,9 @@ typedef struct tagOGGPLAYER
 	BOOL             fUseResampler;
 	BOOL             fUseResampler;
 } OGGPLAYER, *LPOGGPLAYER;
 } OGGPLAYER, *LPOGGPLAYER;
 
 
-PAL_FORCE_INLINE ogg_int16_t OGG_GetSample(float pcm, double volume)
+PAL_FORCE_INLINE ogg_int16_t OGG_GetSample(float pcm)
 {
 {
-	int val = (int)(floor(pcm * 32767.f + .5f) * volume);
+	int val = (int)(floor(pcm * 32767.f + .5f));
 	/* might as well guard against clipping */
 	/* might as well guard against clipping */
 	if (val > 32767) {
 	if (val > 32767) {
 		val = 32767;
 		val = 32767;
@@ -86,15 +86,15 @@ PAL_FORCE_INLINE ogg_int16_t OGG_GetSample(float pcm, double volume)
 PAL_FORCE_INLINE void OGG_FillResample(LPOGGPLAYER player, ogg_int16_t* stream)
 PAL_FORCE_INLINE void OGG_FillResample(LPOGGPLAYER player, ogg_int16_t* stream)
 {
 {
 	if (gConfig.iAudioChannels == 2) {
 	if (gConfig.iAudioChannels == 2) {
-		stream[0] = SDL_SwapLE16(resampler_get_and_remove_sample(player->resampler[0]));
-		stream[1] = (player->vi.channels > 1) ? SDL_SwapLE16(resampler_get_and_remove_sample(player->resampler[1])) : stream[0];
+		stream[0] = resampler_get_and_remove_sample(player->resampler[0]);
+		stream[1] = (player->vi.channels > 1) ? resampler_get_and_remove_sample(player->resampler[1]) : stream[0];
 	}
 	}
 	else {
 	else {
 		if (player->vi.channels > 1) {
 		if (player->vi.channels > 1) {
-			*stream = SDL_SwapLE16((short)((int)(resampler_get_and_remove_sample(player->resampler[0]) + resampler_get_and_remove_sample(player->resampler[1])) >> 1));
+			*stream = (short)((int)(resampler_get_and_remove_sample(player->resampler[0]) + resampler_get_and_remove_sample(player->resampler[1])) >> 1);
 		}
 		}
 		else {
 		else {
-			*stream = SDL_SwapLE16(resampler_get_and_remove_sample(player->resampler[0]));
+			*stream = resampler_get_and_remove_sample(player->resampler[0]);
 		}
 		}
 	}
 	}
 }
 }
@@ -240,7 +240,7 @@ static BOOL OGG_Rewind(LPOGGPLAYER player)
 			double factor = (double)player->vi.rate / (double)gConfig.iSampleRate;
 			double factor = (double)player->vi.rate / (double)gConfig.iSampleRate;
 			for (i = 0; i < min(player->vi.channels, 2); i++)
 			for (i = 0; i < min(player->vi.channels, 2); i++)
 			{
 			{
-				resampler_set_quality(player->resampler[i], SOUND_IsIntegerConversion(player->vi.rate) ? RESAMPLER_QUALITY_MIN : gConfig.iResampleQuality);
+				resampler_set_quality(player->resampler[i], AUDIO_IsIntegerConversion(player->vi.rate) ? RESAMPLER_QUALITY_MIN : gConfig.iResampleQuality);
 				resampler_set_rate(player->resampler[i], factor);
 				resampler_set_rate(player->resampler[i], factor);
 				resampler_clear(player->resampler[i]);
 				resampler_clear(player->resampler[i]);
 			}
 			}
@@ -264,7 +264,6 @@ OGG_FillBuffer(
 
 
 	if (player->fReady) {
 	if (player->fReady) {
 		ogg_packet       op; /* one raw packet of data for decode */
 		ogg_packet       op; /* one raw packet of data for decode */
-		double volume = (double)gConfig.iVolume / (SDL_MIX_MAXVOLUME * 3 / 4);
 		int total_bytes = 0, stage = player->iStage;
 		int total_bytes = 0, stage = player->iStage;
 
 
 		while (total_bytes < len) {
 		while (total_bytes < len) {
@@ -331,7 +330,7 @@ OGG_FillBuffer(
 								for (i = 0; i < min(player->vi.channels, 2); i++) {
 								for (i = 0; i < min(player->vi.channels, 2); i++) {
 									float *mono = pcm[i] + bout;
 									float *mono = pcm[i] + bout;
 									for (j = 0; j < to_write; j++) {
 									for (j = 0; j < to_write; j++) {
-										resampler_write_sample(player->resampler[i], OGG_GetSample(mono[j], volume));
+										resampler_write_sample(player->resampler[i], OGG_GetSample(mono[j]));
 									}
 									}
 								}
 								}
 							}
 							}
@@ -353,15 +352,15 @@ OGG_FillBuffer(
 						if (bout > samples) bout = samples;
 						if (bout > samples) bout = samples;
 						for (i = 0; i < bout; i++) {
 						for (i = 0; i < bout; i++) {
 							if (gConfig.iAudioChannels == 2) {
 							if (gConfig.iAudioChannels == 2) {
-								ptr[0] = SDL_SwapLE16(OGG_GetSample(pcm[0][i], volume));
-								ptr[1] = (player->vi.channels > 1) ? SDL_SwapLE16(OGG_GetSample(pcm[1][i], volume)) : ptr[0];
+								ptr[0] = OGG_GetSample(pcm[0][i]);
+								ptr[1] = (player->vi.channels > 1) ? OGG_GetSample(pcm[1][i]) : ptr[0];
 							}
 							}
 							else {
 							else {
 								if (player->vi.channels > 1) {
 								if (player->vi.channels > 1) {
-									ptr[0] = SDL_SwapLE16((short)((int)(OGG_GetSample(pcm[0][i], volume) + OGG_GetSample(pcm[1][i], volume)) >> 1));
+									ptr[0] = (short)((int)(OGG_GetSample(pcm[0][i]) + OGG_GetSample(pcm[1][i])) >> 1);
 								}
 								}
 								else {
 								else {
-									ptr[0] = SDL_SwapLE16(OGG_GetSample(pcm[0][i], volume));
+									ptr[0] = OGG_GetSample(pcm[0][i]);
 								}
 								}
 							}
 							}
 							ptr += gConfig.iAudioChannels;
 							ptr += gConfig.iAudioChannels;

+ 6 - 3
palcfg.c

@@ -25,7 +25,8 @@ static const ConfigItem gConfigItems[PALCFG_ALL_MAX] = {
 	{ PALCFG_OPLSAMPLERATE,     PALCFG_UNSIGNED, "OPLSAMPLERATE",     13, 49716,   0, UINT32_MAX },
 	{ PALCFG_OPLSAMPLERATE,     PALCFG_UNSIGNED, "OPLSAMPLERATE",     13, 49716,   0, UINT32_MAX },
 	{ PALCFG_RESAMPLEQUALITY,   PALCFG_UNSIGNED, "RESAMPLEQUALITY",   15, RESAMPLER_QUALITY_MAX, RESAMPLER_QUALITY_MIN, RESAMPLER_QUALITY_MAX },	// Default for best quality
 	{ PALCFG_RESAMPLEQUALITY,   PALCFG_UNSIGNED, "RESAMPLEQUALITY",   15, RESAMPLER_QUALITY_MAX, RESAMPLER_QUALITY_MIN, RESAMPLER_QUALITY_MAX },	// Default for best quality
 	{ PALCFG_SAMPLERATE,        PALCFG_UNSIGNED, "SAMPLERATE",        10, 44100,   0, PAL_MAX_SAMPLERATE },
 	{ PALCFG_SAMPLERATE,        PALCFG_UNSIGNED, "SAMPLERATE",        10, 44100,   0, PAL_MAX_SAMPLERATE },
-	{ PALCFG_VOLUME,            PALCFG_UNSIGNED, "VOLUME",             6, 100,     0, 100 },														// Default for maximum volume
+	{ PALCFG_MUSICVOLUME,       PALCFG_UNSIGNED, "MUSICVOLUME",       11, PAL_MAX_VOLUME, 0, PAL_MAX_VOLUME },										// Default for maximum volume
+	{ PALCFG_SOUNDVOLUME,       PALCFG_UNSIGNED, "SOUNDVOLUME",       11, PAL_MAX_VOLUME, 0, PAL_MAX_VOLUME },										// Default for maximum volume
 	{ PALCFG_WINDOWHEIGHT,      PALCFG_UNSIGNED, "WINDOWHEIGHT",      12, PAL_DEFAULT_WINDOW_HEIGHT, 0, UINT32_MAX },
 	{ PALCFG_WINDOWHEIGHT,      PALCFG_UNSIGNED, "WINDOWHEIGHT",      12, PAL_DEFAULT_WINDOW_HEIGHT, 0, UINT32_MAX },
 	{ PALCFG_WINDOWWIDTH,       PALCFG_UNSIGNED, "WINDOWWIDTH",       11, PAL_DEFAULT_WINDOW_WIDTH,  0, UINT32_MAX },
 	{ PALCFG_WINDOWWIDTH,       PALCFG_UNSIGNED, "WINDOWWIDTH",       11, PAL_DEFAULT_WINDOW_WIDTH,  0, UINT32_MAX },
 
 
@@ -377,7 +378,8 @@ PAL_LoadConfig(
 	gConfig.iResampleQuality = values[PALCFG_RESAMPLEQUALITY].uValue;
 	gConfig.iResampleQuality = values[PALCFG_RESAMPLEQUALITY].uValue;
 	gConfig.uCodePage = values[PALCFG_CODEPAGE].uValue;
 	gConfig.uCodePage = values[PALCFG_CODEPAGE].uValue;
 	gConfig.wAudioBufferSize = (WORD)values[PALCFG_AUDIOBUFFERSIZE].uValue;
 	gConfig.wAudioBufferSize = (WORD)values[PALCFG_AUDIOBUFFERSIZE].uValue;
-	gConfig.iVolume = SDL_MIX_MAXVOLUME * values[PALCFG_VOLUME].uValue / 100;
+	gConfig.iMusicVolume = values[PALCFG_MUSICVOLUME].uValue;
+	gConfig.iSoundVolume = values[PALCFG_SOUNDVOLUME].uValue;
 
 
 	if (UTIL_GetScreenSize(&values[PALCFG_WINDOWWIDTH].uValue, &values[PALCFG_WINDOWHEIGHT].uValue))
 	if (UTIL_GetScreenSize(&values[PALCFG_WINDOWWIDTH].uValue, &values[PALCFG_WINDOWHEIGHT].uValue))
 	{
 	{
@@ -421,7 +423,8 @@ PAL_SaveConfig(
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_OPLSAMPLERATE), gConfig.iOPLSampleRate); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_OPLSAMPLERATE), gConfig.iOPLSampleRate); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_RESAMPLEQUALITY), gConfig.iResampleQuality); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_RESAMPLEQUALITY), gConfig.iResampleQuality); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_SAMPLERATE), gConfig.iSampleRate); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_SAMPLERATE), gConfig.iSampleRate); fputs(buf, fp);
-		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_VOLUME), gConfig.iVolume * 100 / SDL_MIX_MAXVOLUME); fputs(buf, fp);
+		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_MUSICVOLUME), gConfig.iMusicVolume); fputs(buf, fp);
+		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_SOUNDVOLUME), gConfig.iSoundVolume); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_WINDOWHEIGHT), gConfig.dwScreenHeight); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_WINDOWHEIGHT), gConfig.dwScreenHeight); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_WINDOWWIDTH), gConfig.dwScreenWidth); fputs(buf, fp);
 		sprintf(buf, "%s=%u\n", PAL_ConfigName(PALCFG_WINDOWWIDTH), gConfig.dwScreenWidth); fputs(buf, fp);
 
 

+ 5 - 2
palcfg.h

@@ -30,6 +30,7 @@ extern "C"
 #include "palcommon.h"
 #include "palcommon.h"
 
 
 #define     PAL_MAX_SAMPLERATE           48000
 #define     PAL_MAX_SAMPLERATE           48000
+#define     PAL_MAX_VOLUME               100
 
 
 typedef enum tagPALCFG_ITEM
 typedef enum tagPALCFG_ITEM
 {
 {
@@ -60,7 +61,8 @@ typedef enum tagPALCFG_ITEM
 	PALCFG_OPLSAMPLERATE,
 	PALCFG_OPLSAMPLERATE,
 	PALCFG_RESAMPLEQUALITY,
 	PALCFG_RESAMPLEQUALITY,
 	PALCFG_SAMPLERATE,
 	PALCFG_SAMPLERATE,
-	PALCFG_VOLUME,
+	PALCFG_MUSICVOLUME,
+	PALCFG_SOUNDVOLUME,
 	PALCFG_WINDOWHEIGHT,
 	PALCFG_WINDOWHEIGHT,
 	PALCFG_WINDOWWIDTH,
 	PALCFG_WINDOWWIDTH,
 	/* Unsigneds */
 	/* Unsigneds */
@@ -167,7 +169,8 @@ typedef struct tagCONFIGURATION
 	INT              iSampleRate;
 	INT              iSampleRate;
 	INT              iOPLSampleRate;
 	INT              iOPLSampleRate;
 	INT              iResampleQuality;
 	INT              iResampleQuality;
-	INT              iVolume;
+	INT              iMusicVolume;
+	INT              iSoundVolume;
 	MUSICTYPE        eMusicType;
 	MUSICTYPE        eMusicType;
 	MUSICTYPE        eCDType;
 	MUSICTYPE        eCDType;
 	OPLTYPE          eOPLType;
 	OPLTYPE          eOPLType;

+ 4 - 4
players.h

@@ -20,8 +20,8 @@
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //
 //
 
 
-#ifndef RIX_PLAY_H
-#define RIX_PLAY_H
+#ifndef PLAYERS_H
+#define PLAYERS_H
 
 
 #include "common.h"
 #include "common.h"
 
 
@@ -33,12 +33,12 @@ extern "C"
 
 
 typedef struct tagMUSICPLAYER
 typedef struct tagMUSICPLAYER
 {
 {
-#define MUSICPLAYER_FUNCTIONS \
+#define MUSICPLAYER_COMMONS \
 	VOID (*Shutdown)(VOID*); \
 	VOID (*Shutdown)(VOID*); \
 	BOOL (*Play)(VOID*, INT, BOOL, FLOAT); \
 	BOOL (*Play)(VOID*, INT, BOOL, FLOAT); \
 	VOID (*FillBuffer)(VOID*, LPBYTE, INT)
 	VOID (*FillBuffer)(VOID*, LPBYTE, INT)
 
 
-	MUSICPLAYER_FUNCTIONS;
+	MUSICPLAYER_COMMONS;
 } MUSICPLAYER, *LPMUSICPLAYER;
 } MUSICPLAYER, *LPMUSICPLAYER;
 
 
 /* RIX */
 /* RIX */

+ 14 - 17
rixplay.cpp

@@ -34,8 +34,6 @@
 #include "adplug/surroundopl.h"
 #include "adplug/surroundopl.h"
 #include "adplug/rix.h"
 #include "adplug/rix.h"
 
 
-extern "C" BOOL g_fNoMusic;
-
 typedef struct tagRIXPLAYER :
 typedef struct tagRIXPLAYER :
 	public MUSICPLAYER
 	public MUSICPLAYER
 {
 {
@@ -81,7 +79,7 @@ RIX_FillBuffer(
 --*/
 --*/
 {
 {
 	LPRIXPLAYER pRixPlayer = (LPRIXPLAYER)object;
 	LPRIXPLAYER pRixPlayer = (LPRIXPLAYER)object;
-	const INT max_volume = gConfig.iVolume * 3 / 4;
+	static const int max_volume = PAL_MAX_VOLUME;
 
 
 	if (pRixPlayer == NULL || !pRixPlayer->fReady)
 	if (pRixPlayer == NULL || !pRixPlayer->fReady)
 	{
 	{
@@ -116,7 +114,7 @@ RIX_FillBuffer(
 			if (pRixPlayer->iTotalFadeOutSamples == pRixPlayer->iRemainingFadeSamples && pRixPlayer->iTotalFadeOutSamples > 0)
 			if (pRixPlayer->iTotalFadeOutSamples == pRixPlayer->iRemainingFadeSamples && pRixPlayer->iTotalFadeOutSamples > 0)
 			{
 			{
 				UINT  now = SDL_GetTicks();
 				UINT  now = SDL_GetTicks();
-				INT   passed_samples = ((INT)(now - pRixPlayer->dwStartFadeTime) > 0) ? (INT)((now - pRixPlayer->dwStartFadeTime) * SOUND_GetAudioSpec()->freq / 1000) : 0;
+				INT   passed_samples = ((INT)(now - pRixPlayer->dwStartFadeTime) > 0) ? (INT)((now - pRixPlayer->dwStartFadeTime) * AUDIO_GetDeviceSpec()->freq / 1000) : 0;
 				pRixPlayer->iRemainingFadeSamples -= passed_samples;
 				pRixPlayer->iRemainingFadeSamples -= passed_samples;
 			}
 			}
 			if (pRixPlayer->iCurrentMusic == -1 || pRixPlayer->iRemainingFadeSamples <= 0)
 			if (pRixPlayer->iCurrentMusic == -1 || pRixPlayer->iRemainingFadeSamples <= 0)
@@ -216,17 +214,16 @@ RIX_FillBuffer(
 						if (to_write)
 						if (to_write)
 						{
 						{
 							short *tempBuf = (short*)alloca(to_write * gConfig.iAudioChannels * sizeof(short));
 							short *tempBuf = (short*)alloca(to_write * gConfig.iAudioChannels * sizeof(short));
+							int temp_buf_read = 0;
 							pRixPlayer->opl->update(tempBuf, to_write);
 							pRixPlayer->opl->update(tempBuf, to_write);
-							for (int i = 0; i < to_write; i++)
-								for (int j = 0; j < gConfig.iAudioChannels; j++)
-									resampler_write_sample(pRixPlayer->resampler[j], tempBuf[i * gConfig.iAudioChannels + j]);
+							for (int i = 0; i < to_write * gConfig.iAudioChannels; i++)
+								resampler_write_sample(pRixPlayer->resampler[i % gConfig.iAudioChannels], tempBuf[temp_buf_read++]);
 						}
 						}
 
 
 						int to_get = resampler_get_sample_count(pRixPlayer->resampler[0]);
 						int to_get = resampler_get_sample_count(pRixPlayer->resampler[0]);
 						if (to_get > sample_count) to_get = sample_count;
 						if (to_get > sample_count) to_get = sample_count;
-						for (int i = 0; i < to_get; i++)
-							for (int j = 0; j < gConfig.iAudioChannels; j++)
-								finalBuf[samples_written++] = resampler_get_and_remove_sample(pRixPlayer->resampler[j]);
+						for (int i = 0; i < to_get * gConfig.iAudioChannels; i++)
+							finalBuf[samples_written++] = resampler_get_and_remove_sample(pRixPlayer->resampler[i % gConfig.iAudioChannels]);
 						sample_count -= to_get;
 						sample_count -= to_get;
 					}
 					}
 				}
 				}
@@ -241,14 +238,13 @@ RIX_FillBuffer(
 
 
 			//
 			//
 			// Put audio data into buffer and adjust volume
 			// Put audio data into buffer and adjust volume
-			// WARNING: for signed 16-bit little-endian only
 			//
 			//
 			SHORT* ptr = (SHORT*)stream;
 			SHORT* ptr = (SHORT*)stream;
 			if (pRixPlayer->FadeType == RIXPLAYER::NONE)
 			if (pRixPlayer->FadeType == RIXPLAYER::NONE)
 			{
 			{
 				for (int i = 0; i < l; i++)
 				for (int i = 0; i < l; i++)
 				{
 				{
-					*ptr++ = SDL_SwapLE16((short)((int)(*(SHORT *)(pRixPlayer->pos)) * volume / SDL_MIX_MAXVOLUME));
+					*ptr++ = *(SHORT *)pRixPlayer->pos * volume / max_volume;
 					pRixPlayer->pos += sizeof(SHORT);
 					pRixPlayer->pos += sizeof(SHORT);
 				}
 				}
 			}
 			}
@@ -256,12 +252,13 @@ RIX_FillBuffer(
 			{
 			{
 				for (int i = 0; i < l && pRixPlayer->iRemainingFadeSamples > 0; volume += vol_delta)
 				for (int i = 0; i < l && pRixPlayer->iRemainingFadeSamples > 0; volume += vol_delta)
 				{
 				{
-					for (int j = 0; i < l && j < delta_samples; i++, j++)
+					int j = 0;
+					for (j = 0; i < l && j < delta_samples; i++, j++)
 					{
 					{
-						*ptr++ = SDL_SwapLE16((short)((int)(*(SHORT *)(pRixPlayer->pos)) * volume / SDL_MIX_MAXVOLUME));
+						*ptr++ = *(SHORT *)pRixPlayer->pos * volume / max_volume;
 						pRixPlayer->pos += sizeof(SHORT);
 						pRixPlayer->pos += sizeof(SHORT);
 					}
 					}
-					pRixPlayer->iRemainingFadeSamples -= delta_samples;
+					pRixPlayer->iRemainingFadeSamples -= j;
 				}
 				}
 				fContinue = (pRixPlayer->iRemainingFadeSamples > 0);
 				fContinue = (pRixPlayer->iRemainingFadeSamples > 0);
 			}
 			}
@@ -342,7 +339,7 @@ RIX_Play(
 	//
 	//
 	// Stop the current CD music.
 	// Stop the current CD music.
 	//
 	//
-	SOUND_PlayCDA(-1);
+	AUDIO_PlayCDTrack(-1);
 
 
 	if (iNumRIX == pRixPlayer->iCurrentMusic && pRixPlayer->iNextMusic == -1)
 	if (iNumRIX == pRixPlayer->iCurrentMusic && pRixPlayer->iNextMusic == -1)
 	{
 	{
@@ -482,7 +479,7 @@ RIX_Init(
 		for (int i = 0; i < gConfig.iAudioChannels; i++)
 		for (int i = 0; i < gConfig.iAudioChannels; i++)
 		{
 		{
 			pRixPlayer->resampler[i] = resampler_create();
 			pRixPlayer->resampler[i] = resampler_create();
-			resampler_set_quality(pRixPlayer->resampler[i], SOUND_IsIntegerConversion(gConfig.iOPLSampleRate) ? RESAMPLER_QUALITY_MIN : gConfig.iResampleQuality);
+			resampler_set_quality(pRixPlayer->resampler[i], AUDIO_IsIntegerConversion(gConfig.iOPLSampleRate) ? RESAMPLER_QUALITY_MIN : gConfig.iResampleQuality);
 			resampler_set_rate(pRixPlayer->resampler[i], (double)gConfig.iOPLSampleRate / (double)gConfig.iSampleRate);
 			resampler_set_rate(pRixPlayer->resampler[i], (double)gConfig.iOPLSampleRate / (double)gConfig.iSampleRate);
 		}
 		}
 	}
 	}

+ 7 - 7
script.c

@@ -1587,7 +1587,7 @@ PAL_InterpretInstruction(
       // Set background music
       // Set background music
       //
       //
       gpGlobals->wNumMusic = pScript->rgwOperand[0];
       gpGlobals->wNumMusic = pScript->rgwOperand[0];
-      SOUND_PlayMUS(pScript->rgwOperand[0], (pScript->rgwOperand[0] != 0x3D), pScript->rgwOperand[1]);
+      AUDIO_PlayMusic(pScript->rgwOperand[0], (pScript->rgwOperand[0] != 0x3D), pScript->rgwOperand[1]);
       break;
       break;
 
 
    case 0x0044:
    case 0x0044:
@@ -1648,7 +1648,7 @@ PAL_InterpretInstruction(
       //
       //
       // Play sound effect
       // Play sound effect
       //
       //
-      SOUND_Play(pScript->rgwOperand[0]);
+      AUDIO_PlaySound(pScript->rgwOperand[0]);
       break;
       break;
 
 
    case 0x0049:
    case 0x0049:
@@ -2162,7 +2162,7 @@ PAL_InterpretInstruction(
       //
       //
       // Stop current playing music
       // Stop current playing music
       //
       //
-      SOUND_PlayMUS(0, FALSE,
+      AUDIO_PlayMusic(0, FALSE,
          (pScript->rgwOperand[0] == 0) ? 2.0f : (FLOAT)(pScript->rgwOperand[0]) * 2);
          (pScript->rgwOperand[0] == 0) ? 2.0f : (FLOAT)(pScript->rgwOperand[0]) * 2);
       gpGlobals->wNumMusic = 0;
       gpGlobals->wNumMusic = 0;
       break;
       break;
@@ -2854,7 +2854,7 @@ PAL_InterpretInstruction(
          PAL_BattleBackupScene();
          PAL_BattleBackupScene();
          PAL_LoadBattleSprites();
          PAL_LoadBattleSprites();
          PAL_BattleMakeScene();
          PAL_BattleMakeScene();
-         SOUND_Play(212);
+         AUDIO_PlaySound(212);
          PAL_BattleFadeScene();
          PAL_BattleFadeScene();
 
 
          for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
          for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
@@ -2894,7 +2894,7 @@ PAL_InterpretInstruction(
 
 
          g_Battle.rgEnemy[wEventObjectID].iColorShift = 0;
          g_Battle.rgEnemy[wEventObjectID].iColorShift = 0;
 
 
-		 SOUND_Play(47);
+		 AUDIO_PlaySound(47);
          PAL_BattleBackupScene();
          PAL_BattleBackupScene();
          PAL_LoadBattleSprites();
          PAL_LoadBattleSprites();
          PAL_BattleMakeScene();
          PAL_BattleMakeScene();
@@ -2941,9 +2941,9 @@ PAL_InterpretInstruction(
       //
       //
       // Play CD music. Use the RIX music for fallback.
       // Play CD music. Use the RIX music for fallback.
       //
       //
-      if (!SOUND_PlayCDA(pScript->rgwOperand[0]))
+      if (!AUDIO_PlayCDTrack(pScript->rgwOperand[0]))
       {
       {
-         SOUND_PlayMUS(pScript->rgwOperand[1], TRUE, 0);
+         AUDIO_PlayMusic(pScript->rgwOperand[1], TRUE, 0);
       }
       }
       break;
       break;
 
 

+ 287 - 140
sound.c

@@ -33,37 +33,144 @@
 #include <vorbis/codec.h>
 #include <vorbis/codec.h>
 #endif
 #endif
 
 
-static BOOL  gSndOpened = FALSE;
-
-BOOL         g_fNoSound = FALSE;
-BOOL         g_fNoMusic = FALSE;
-
-#ifdef PAL_CLASSIC
-int          g_iCurrChannel = 0;
-#endif
-
 #define PAL_CDTRACK_BASE    10000
 #define PAL_CDTRACK_BASE    10000
 
 
 typedef LPCBYTE(*FNLoadSoundData)(LPCBYTE, DWORD, SDL_AudioSpec *);
 typedef LPCBYTE(*FNLoadSoundData)(LPCBYTE, DWORD, SDL_AudioSpec *);
 
 
+typedef struct tagWAVEPLAYER
+{
+	FNLoadSoundData           LoadSoundData;
+	void                     *resampler;
+	short                    *buf;
+	int                       buf_len, pos, len;
+} WAVEPLAYER;
+
 typedef struct tagSNDPLAYER
 typedef struct tagSNDPLAYER
 {
 {
    FILE                     *mkf;
    FILE                     *mkf;
    SDL_AudioSpec             spec;
    SDL_AudioSpec             spec;
+   SDL_AudioCVT              cvt;
    SDL_mutex                *mtx;
    SDL_mutex                *mtx;
-   LPBYTE                    buf[2], pos[2];
-   INT                       audio_len[2];
-   void                     *resampler;
    MUSICPLAYER              *pMusPlayer;
    MUSICPLAYER              *pMusPlayer;
    MUSICPLAYER              *pCDPlayer;
    MUSICPLAYER              *pCDPlayer;
 #if PAL_HAS_SDLCD
 #if PAL_HAS_SDLCD
    SDL_CD                   *pCD;
    SDL_CD                   *pCD;
 #endif
 #endif
-   FNLoadSoundData           LoadSoundData;
+   WAVEPLAYER                wavePlayer;
+   BOOL                      fOpened;
+   BOOL                      fMusicEnabled;
+   BOOL                      fSoundEnabled;
 } SNDPLAYER;
 } SNDPLAYER;
 
 
 static SNDPLAYER gSndPlayer;
 static SNDPLAYER gSndPlayer;
 
 
+PAL_FORCE_INLINE
+void
+AUDIO_MixNative(
+	short     *dst,
+	short     *src,
+	int        samples
+)
+{
+	while (samples > 0)
+	{
+		int val = *src++ + *dst;
+		if (val > SHRT_MAX)
+			*dst++ = SHRT_MAX;
+		else if (val < SHRT_MIN)
+			*dst++ = SHRT_MIN;
+		else
+			*dst++ = (short)val;
+		samples--;
+	}
+}
+
+PAL_FORCE_INLINE
+void
+AUDIO_MixNativeVolume(
+	short     *dst,
+	int        iDstVolume,
+	short     *src,
+	int        iSrcVolume,
+	int        samples
+)
+{
+	while (samples > 0)
+	{
+		int val = ((*src++) * iSrcVolume + *dst * iDstVolume) / PAL_MAX_VOLUME;
+		if (val > SHRT_MAX)
+			*dst++ = SHRT_MAX;
+		else if (val < SHRT_MIN)
+			*dst++ = SHRT_MIN;
+		else
+			*dst++ = (short)val;
+		samples--;
+	}
+}
+
+PAL_FORCE_INLINE
+void
+AUDIO_AdjustNativeVolume(
+	short     *srcdst,
+	int        iVolume,
+	int        samples
+)
+{
+	while (samples > 0)
+	{
+		*srcdst = *srcdst * iVolume / PAL_MAX_VOLUME;
+		samples--; srcdst++;
+	}
+}
+
+#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
+
+PAL_FORCE_INLINE
+void
+AUDIO_MixNative_SSE2(
+	short     *dst,
+	short     *src,
+	int        samples
+)
+{
+	while (samples > 0)
+	{
+		int val = *src++ + *dst;
+		if (val > SHRT_MAX)
+			*dst++ = SHRT_MAX;
+		else if (val < SHRT_MIN)
+			*dst++ = SHRT_MIN;
+		else
+			*dst++ = (short)val;
+		samples--;
+	}
+}
+
+PAL_FORCE_INLINE
+void
+AUDIO_MixNativeVolume_SSE2(
+	short     *dst,
+	int        iDstVolume,
+	short     *src,
+	int        iSrcVolume,
+	int        samples
+)
+{
+	while (samples > 0)
+	{
+		int val = ((*src++) * iSrcVolume + *dst * iDstVolume) / PAL_MAX_VOLUME;
+		if (val > SHRT_MAX)
+			*dst++ = SHRT_MAX;
+		else if (val < SHRT_MIN)
+			*dst++ = SHRT_MIN;
+		else
+			*dst++ = (short)val;
+		samples--;
+	}
+}
+
+#endif
+
 typedef struct tagRIFFHEADER
 typedef struct tagRIFFHEADER
 {
 {
 	DWORD   riff_sig;	/* 'RIFF' */
 	DWORD   riff_sig;	/* 'RIFF' */
@@ -318,7 +425,7 @@ SOUND_ResampleU8(
 			src_samples -= to_write;
 			src_samples -= to_write;
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			{
 			{
-				*dst = SDL_SwapLE16(resampler_get_and_remove_sample(resampler));
+				*dst = resampler_get_and_remove_sample(resampler);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 			}
 			}
 		}
 		}
@@ -330,7 +437,7 @@ SOUND_ResampleU8(
 				resampler_write_sample(resampler, (src[-lpSpec->channels] ^ 0x80) << 8);
 				resampler_write_sample(resampler, (src[-lpSpec->channels] ^ 0x80) << 8);
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			{
 			{
-				*dst = SDL_SwapLE16(resampler_get_and_remove_sample(resampler));
+				*dst = resampler_get_and_remove_sample(resampler);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 			}
 			}
 		}
 		}
@@ -391,7 +498,7 @@ SOUND_ResampleS16(
 			src_samples -= to_write;
 			src_samples -= to_write;
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			{
 			{
-				*dst = SDL_SwapLE16(resampler_get_and_remove_sample(resampler));
+				*dst = resampler_get_and_remove_sample(resampler);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 			}
 			}
 		}
 		}
@@ -404,7 +511,7 @@ SOUND_ResampleS16(
 				resampler_write_sample(resampler, val);
 				resampler_write_sample(resampler, val);
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			while (total_bytes < channel_len && resampler_get_sample_count(resampler) > 0)
 			{
 			{
-				*dst = SDL_SwapLE16(resampler_get_and_remove_sample(resampler));
+				*dst = resampler_get_and_remove_sample(resampler);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 				dst += lpSpec->channels; total_bytes += (SDL_AUDIO_BITSIZE(AUDIO_S16) >> 3);
 			}
 			}
 		}
 		}
@@ -412,7 +519,7 @@ SOUND_ResampleS16(
 }
 }
 
 
 static VOID SDLCALL
 static VOID SDLCALL
-SOUND_FillAudio(
+AUDIO_FillBuffer(
    LPVOID          udata,
    LPVOID          udata,
    LPBYTE          stream,
    LPBYTE          stream,
    INT             len
    INT             len
@@ -436,18 +543,20 @@ SOUND_FillAudio(
 
 
 --*/
 --*/
 {
 {
-   int        i;
-
 #if SDL_VERSION_ATLEAST(2,0,0)
 #if SDL_VERSION_ATLEAST(2,0,0)
    memset(stream, 0, len);
    memset(stream, 0, len);
 #endif
 #endif
 
 
+   SDL_mutexP(gSndPlayer.mtx);
+
+   gSndPlayer.cvt.buf = stream;
+   gSndPlayer.cvt.len = len;
+
    //
    //
    // Play music
    // Play music
    //
    //
-   if (!g_fNoMusic)
+   if (gSndPlayer.fMusicEnabled)
    {
    {
-	   SDL_mutexP(gSndPlayer.mtx);
 	   if (gSndPlayer.pMusPlayer)
 	   if (gSndPlayer.pMusPlayer)
 	   {
 	   {
 		   gSndPlayer.pMusPlayer->FillBuffer(gSndPlayer.pMusPlayer, stream, len);
 		   gSndPlayer.pMusPlayer->FillBuffer(gSndPlayer.pMusPlayer, stream, len);
@@ -457,47 +566,43 @@ SOUND_FillAudio(
 	   {
 	   {
 		   gSndPlayer.pCDPlayer->FillBuffer(gSndPlayer.pCDPlayer, stream, len);
 		   gSndPlayer.pCDPlayer->FillBuffer(gSndPlayer.pCDPlayer, stream, len);
 	   }
 	   }
-	   SDL_mutexV(gSndPlayer.mtx);
    }
    }
 
 
    //
    //
-   // No current playing sound
+   // Play sound
    //
    //
-   if (g_fNoSound)
-   {
-      return;
-   }
-
-   SDL_mutexP(gSndPlayer.mtx);
-
-   for (i = 0; i < 2; i++)
+   if (gSndPlayer.fSoundEnabled && gSndPlayer.wavePlayer.len > 0)
    {
    {
       //
       //
-      // Only play if we have data left
+      // Mix as much sound data as possible
       //
       //
-      if (gSndPlayer.buf[i] == NULL)
+      WAVEPLAYER *player = &gSndPlayer.wavePlayer;
+      int mixlen = min(player->len, len >> 1);
+      if (player->pos + mixlen > player->buf_len)
       {
       {
-         continue;
+         AUDIO_MixNativeVolume((short *)stream, gConfig.iMusicVolume, player->buf + player->pos, gConfig.iSoundVolume, player->buf_len - player->pos);
+         stream += (player->buf_len - player->pos) << 1; memset(player->buf + player->pos, 0, (player->buf_len - player->pos) << 1);
+		 AUDIO_MixNativeVolume((short *)stream, gConfig.iMusicVolume, player->buf, gConfig.iSoundVolume, player->pos + mixlen - player->buf_len);
+         stream += (player->pos + mixlen - player->buf_len) << 1; memset(player->buf, 0, (player->pos + mixlen - player->buf_len) << 1);
       }
       }
-
-      if (gSndPlayer.audio_len[i] == 0)
+      else
       {
       {
-         //
-         // Delete the audio buffer from memory
-         //
-         free(gSndPlayer.buf[i]);
-         gSndPlayer.buf[i] = NULL;
-         continue;
+         AUDIO_MixNativeVolume((short *)stream, gConfig.iMusicVolume, player->buf + player->pos, gConfig.iSoundVolume, mixlen);
+         stream += mixlen << 1; memset(player->buf + player->pos, 0, mixlen << 1);
       }
       }
-
-      //
-      // Mix as much data as possible
-      //
-      len = (len > gSndPlayer.audio_len[i]) ? gSndPlayer.audio_len[i] : len;
-      SDL_MixAudio(stream, gSndPlayer.pos[i], len, gConfig.iVolume);
-      gSndPlayer.pos[i] += len;
-      gSndPlayer.audio_len[i] -= len;
+      player->pos = (player->pos + mixlen) % player->buf_len; player->len -= mixlen; len -= (mixlen << 1);
    }
    }
+
+   //
+   // Adjust volume in the remaing buffer
+   //
+   AUDIO_AdjustNativeVolume((short *)stream, gConfig.iMusicVolume, len >> 1);
+
+   //
+   // Convert audio from native byte-order to actual byte-order
+   //
+   SDL_ConvertAudio(&gSndPlayer.cvt);
+
    SDL_mutexV(gSndPlayer.mtx);
    SDL_mutexV(gSndPlayer.mtx);
 }
 }
 
 
@@ -540,14 +645,14 @@ SOUND_LoadMKF(
 		gSndPlayer.mkf = UTIL_OpenFile(mkfs[i]);
 		gSndPlayer.mkf = UTIL_OpenFile(mkfs[i]);
 		if (gSndPlayer.mkf)
 		if (gSndPlayer.mkf)
 		{
 		{
-			gSndPlayer.LoadSoundData = func[i];
+			gSndPlayer.wavePlayer.LoadSoundData = func[i];
 			break;
 			break;
 		}
 		}
 	}
 	}
 }
 }
 
 
 INT
 INT
-SOUND_OpenAudio(
+AUDIO_OpenDevice(
    VOID
    VOID
 )
 )
 /*++
 /*++
@@ -567,7 +672,7 @@ SOUND_OpenAudio(
 {
 {
    SDL_AudioSpec spec;
    SDL_AudioSpec spec;
 
 
-   if (gSndOpened)
+   if (gSndPlayer.fOpened)
    {
    {
       //
       //
       // Already opened
       // Already opened
@@ -575,7 +680,9 @@ SOUND_OpenAudio(
       return -1;
       return -1;
    }
    }
 
 
-   gSndOpened = FALSE;
+   gSndPlayer.fOpened = FALSE;
+   gSndPlayer.fMusicEnabled = TRUE;
+   gSndPlayer.fSoundEnabled = TRUE;
 
 
    //
    //
    // Load the MKF file.
    // Load the MKF file.
@@ -590,7 +697,7 @@ SOUND_OpenAudio(
    // Initialize the resampler
    // Initialize the resampler
    //
    //
    resampler_init();
    resampler_init();
-   gSndPlayer.resampler = resampler_create();
+   gSndPlayer.wavePlayer.resampler = resampler_create();
 
 
    //
    //
    // Open the sound subsystem.
    // Open the sound subsystem.
@@ -599,7 +706,7 @@ SOUND_OpenAudio(
    gSndPlayer.spec.format = AUDIO_S16;
    gSndPlayer.spec.format = AUDIO_S16;
    gSndPlayer.spec.channels = gConfig.iAudioChannels;
    gSndPlayer.spec.channels = gConfig.iAudioChannels;
    gSndPlayer.spec.samples = gConfig.wAudioBufferSize;
    gSndPlayer.spec.samples = gConfig.wAudioBufferSize;
-   gSndPlayer.spec.callback = SOUND_FillAudio;
+   gSndPlayer.spec.callback = AUDIO_FillBuffer;
 
 
    if (SDL_OpenAudio(&gSndPlayer.spec, &spec) < 0)
    if (SDL_OpenAudio(&gSndPlayer.spec, &spec) < 0)
    {
    {
@@ -608,19 +715,18 @@ SOUND_OpenAudio(
       //
       //
       return -3;
       return -3;
    }
    }
+   else
+      gSndPlayer.spec = spec;
 
 
-   memcpy(&gSndPlayer.spec, &spec, sizeof(SDL_AudioSpec));
-
-   gSndPlayer.buf[0] = NULL;
-   gSndPlayer.pos[0] = NULL;
-   gSndPlayer.audio_len[0] = 0;
+   SDL_BuildAudioCVT(&gSndPlayer.cvt, AUDIO_S16SYS, spec.channels, spec.freq, spec.format, spec.channels, spec.freq);
 
 
-   gSndPlayer.buf[1] = NULL;
-   gSndPlayer.pos[1] = NULL;
-   gSndPlayer.audio_len[1] = 0;
+   gSndPlayer.wavePlayer.buf = NULL;
+   gSndPlayer.wavePlayer.buf_len = 0;
+   gSndPlayer.wavePlayer.pos = 0;
+   gSndPlayer.wavePlayer.len = 0;
 
 
    gSndPlayer.mtx = SDL_CreateMutex();
    gSndPlayer.mtx = SDL_CreateMutex();
-   gSndOpened = TRUE;
+   gSndPlayer.fOpened = TRUE;
 
 
    //
    //
    // Initialize the music subsystem.
    // Initialize the music subsystem.
@@ -708,7 +814,7 @@ SOUND_OpenAudio(
 }
 }
 
 
 VOID
 VOID
-SOUND_CloseAudio(
+AUDIO_CloseDevice(
    VOID
    VOID
 )
 )
 /*++
 /*++
@@ -730,16 +836,13 @@ SOUND_CloseAudio(
 
 
    SDL_mutexP(gSndPlayer.mtx);
    SDL_mutexP(gSndPlayer.mtx);
 
 
-   if (gSndPlayer.buf[0] != NULL)
-   {
-      free(gSndPlayer.buf[0]);
-      gSndPlayer.buf[0] = NULL;
-   }
-
-   if (gSndPlayer.buf[1] != NULL)
+   if (gSndPlayer.wavePlayer.buf != NULL)
    {
    {
-      free(gSndPlayer.buf[1]);
-      gSndPlayer.buf[1] = NULL;
+      free(gSndPlayer.wavePlayer.buf);
+      gSndPlayer.wavePlayer.buf = NULL;
+	  gSndPlayer.wavePlayer.buf_len = 0;
+	  gSndPlayer.wavePlayer.pos = 0;
+	  gSndPlayer.wavePlayer.len = 0;
    }
    }
 
 
    if (gSndPlayer.mkf != NULL)
    if (gSndPlayer.mkf != NULL)
@@ -763,17 +866,17 @@ SOUND_CloseAudio(
 #if PAL_HAS_SDLCD
 #if PAL_HAS_SDLCD
    if (gSndPlayer.pCD != NULL)
    if (gSndPlayer.pCD != NULL)
    {
    {
-      SOUND_PlayCDA(-1);
+      AUDIO_PlayCDTrack(-1);
       SDL_CDClose(gSndPlayer.pCD);
       SDL_CDClose(gSndPlayer.pCD);
    }
    }
 #endif
 #endif
 
 
    if (gConfig.eMusicType == MUSIC_MIDI) MIDI_Play(0, FALSE);
    if (gConfig.eMusicType == MUSIC_MIDI) MIDI_Play(0, FALSE);
 
 
-   if (gSndPlayer.resampler)
+   if (gSndPlayer.wavePlayer.resampler)
    {
    {
-      resampler_delete(gSndPlayer.resampler);
-	  gSndPlayer.resampler = NULL;
+      resampler_delete(gSndPlayer.wavePlayer.resampler);
+	  gSndPlayer.wavePlayer.resampler = NULL;
    }
    }
 
 
    SDL_mutexV(gSndPlayer.mtx);
    SDL_mutexV(gSndPlayer.mtx);
@@ -781,15 +884,29 @@ SOUND_CloseAudio(
 }
 }
 
 
 SDL_AudioSpec*
 SDL_AudioSpec*
-SOUND_GetAudioSpec(
+AUDIO_GetDeviceSpec(
 	VOID
 	VOID
 )
 )
 {
 {
 	return &gSndPlayer.spec;
 	return &gSndPlayer.spec;
 }
 }
 
 
+static INT
+AUDIO_AdjustVolumeByValue(
+   INT   *iVolume,
+   INT    iValue
+)
+{
+   *iVolume += iValue;
+   if (*iVolume > PAL_MAX_VOLUME)
+      *iVolume = PAL_MAX_VOLUME;
+   else if (*iVolume < 0)
+      *iVolume = 0;
+   return *iVolume;
+}
+
 VOID
 VOID
-SOUND_AdjustVolume(
+AUDIO_AdjustVolume(
    INT    iDirection
    INT    iDirection
 )
 )
 /*++
 /*++
@@ -807,28 +924,13 @@ SOUND_AdjustVolume(
 
 
 --*/
 --*/
 {
 {
-   if (iDirection > 0)
-   {
-      gConfig.iVolume += SDL_MIX_MAXVOLUME * 0.03;
-      if (gConfig.iVolume > SDL_MIX_MAXVOLUME)
-      {
-		  gConfig.iVolume = SDL_MIX_MAXVOLUME;
-      }
-   }
-   else
-   {
-      gConfig.iVolume -= SDL_MIX_MAXVOLUME * 0.03;
-      if (gConfig.iVolume < 0)
-      {
-		  gConfig.iVolume = 0;
-      }
-   }
+   AUDIO_AdjustVolumeByValue(&gConfig.iMusicVolume, (iDirection > 0) ? 3 : -3);
+   AUDIO_AdjustVolumeByValue(&gConfig.iSoundVolume, (iDirection > 0) ? 3 : -3);
 }
 }
 
 
 VOID
 VOID
-SOUND_PlayChannel(
-   INT    iSoundNum,
-   INT    iChannel
+AUDIO_PlaySound(
+   INT    iSoundNum
 )
 )
 /*++
 /*++
   Purpose:
   Purpose:
@@ -839,8 +941,6 @@ SOUND_PlayChannel(
 
 
     [IN]  iSoundNum - number of the sound; the absolute value is used.
     [IN]  iSoundNum - number of the sound; the absolute value is used.
 
 
-    [IN]  iChannel - the number of channel (0 or 1).
-
   Return value:
   Return value:
 
 
     None.
     None.
@@ -853,22 +953,11 @@ SOUND_PlayChannel(
    LPCBYTE         bufsrc;
    LPCBYTE         bufsrc;
    int             len;
    int             len;
 
 
-   if (!gSndOpened || g_fNoSound)
+   if (!gSndPlayer.fOpened || !gSndPlayer.fSoundEnabled)
    {
    {
       return;
       return;
    }
    }
 
 
-   //
-   // Stop playing current sound.
-   //
-   SDL_mutexP(gSndPlayer.mtx);
-   if (gSndPlayer.buf[iChannel] != NULL)
-   {
-      free(gSndPlayer.buf[iChannel]);
-      gSndPlayer.buf[iChannel] = NULL;
-   }
-   SDL_mutexV(gSndPlayer.mtx);
-
    if (iSoundNum < 0)
    if (iSoundNum < 0)
    {
    {
       iSoundNum = -iSoundNum;
       iSoundNum = -iSoundNum;
@@ -894,7 +983,7 @@ SOUND_PlayChannel(
    //
    //
    PAL_MKFReadChunk(buf, len, iSoundNum, gSndPlayer.mkf);
    PAL_MKFReadChunk(buf, len, iSoundNum, gSndPlayer.mkf);
 
 
-   bufsrc = gSndPlayer.LoadSoundData(buf, len, &wavespec);
+   bufsrc = gSndPlayer.wavePlayer.LoadSoundData(buf, len, &wavespec);
    if (bufsrc == NULL)
    if (bufsrc == NULL)
    {
    {
 	   free(buf);
 	   free(buf);
@@ -904,18 +993,18 @@ SOUND_PlayChannel(
    if (wavespec.freq != gSndPlayer.spec.freq)
    if (wavespec.freq != gSndPlayer.spec.freq)
    {
    {
 	   /* Resampler is needed */
 	   /* Resampler is needed */
-	   resampler_set_quality(gSndPlayer.resampler, SOUND_IsIntegerConversion(wavespec.freq) ? RESAMPLER_QUALITY_MIN : gConfig.iResampleQuality);
-	   resampler_set_rate(gSndPlayer.resampler, (double)wavespec.freq / (double)gSndPlayer.spec.freq);
-	   len = (int)ceil(wavespec.size * (double)gSndPlayer.spec.freq / (double)wavespec.freq) * (SDL_AUDIO_BITSIZE(AUDIO_S16) / SDL_AUDIO_BITSIZE(wavespec.format));
+	   resampler_set_quality(gSndPlayer.wavePlayer.resampler, AUDIO_IsIntegerConversion(wavespec.freq) ? RESAMPLER_QUALITY_MIN : gConfig.iResampleQuality);
+	   resampler_set_rate(gSndPlayer.wavePlayer.resampler, (double)wavespec.freq / (double)gSndPlayer.spec.freq);
+	   len = (int)ceil(wavespec.size * (double)gSndPlayer.spec.freq / (double)wavespec.freq) * (SDL_AUDIO_BITSIZE(AUDIO_S16SYS) / SDL_AUDIO_BITSIZE(wavespec.format));
 	   if (len >= wavespec.channels * 2 && (bufdec = malloc(len)))
 	   if (len >= wavespec.channels * 2 && (bufdec = malloc(len)))
 	   {
 	   {
 		   if (wavespec.format == AUDIO_S16)
 		   if (wavespec.format == AUDIO_S16)
-			   SOUND_ResampleS16(bufsrc, &wavespec, bufdec, len, gSndPlayer.resampler);
+			   SOUND_ResampleS16(bufsrc, &wavespec, bufdec, len, gSndPlayer.wavePlayer.resampler);
 		   else
 		   else
-			   SOUND_ResampleU8(bufsrc, &wavespec, bufdec, len, gSndPlayer.resampler);
+			   SOUND_ResampleU8(bufsrc, &wavespec, bufdec, len, gSndPlayer.wavePlayer.resampler);
 		   /* Free the original buffer and reset the pointer for simpler later operations */
 		   /* Free the original buffer and reset the pointer for simpler later operations */
 		   free(buf); buf = bufdec;
 		   free(buf); buf = bufdec;
-		   wavespec.format = AUDIO_S16;
+		   wavespec.format = AUDIO_S16SYS;
 		   wavespec.freq = gSndPlayer.spec.freq;
 		   wavespec.freq = gSndPlayer.spec.freq;
 	   }
 	   }
 	   else
 	   else
@@ -934,7 +1023,7 @@ SOUND_PlayChannel(
    // Build the audio converter and create conversion buffers
    // Build the audio converter and create conversion buffers
    //
    //
    if (SDL_BuildAudioCVT(&wavecvt, wavespec.format, wavespec.channels, wavespec.freq,
    if (SDL_BuildAudioCVT(&wavecvt, wavespec.format, wavespec.channels, wavespec.freq,
-      gSndPlayer.spec.format, gSndPlayer.spec.channels, gSndPlayer.spec.freq) < 0)
+	   AUDIO_S16SYS, gSndPlayer.spec.channels, gSndPlayer.spec.freq) < 0)
    {
    {
       free(buf);
       free(buf);
       return;
       return;
@@ -953,26 +1042,52 @@ SOUND_PlayChannel(
    //
    //
    // Run the audio converter
    // Run the audio converter
    //
    //
-   if (SDL_ConvertAudio(&wavecvt) < 0)
+   if (SDL_ConvertAudio(&wavecvt) == 0)
    {
    {
-      free(wavecvt.buf);
-      return;
-   }
+      WAVEPLAYER *player = &gSndPlayer.wavePlayer;
 
 
-   SDL_mutexP(gSndPlayer.mtx);
-   if (gSndPlayer.buf[iChannel] != NULL)
-   {
-	   free(gSndPlayer.buf[iChannel]);
-	   gSndPlayer.buf[iChannel] = NULL;
+      wavecvt.len = (int)(wavecvt.len * wavecvt.len_ratio) >> 1;
+
+      SDL_mutexP(gSndPlayer.mtx);
+
+      //
+      // Check if the current sound buffer is large enough
+      //
+      if (gSndPlayer.wavePlayer.buf_len < wavecvt.len)
+      {
+         if (player->pos + player->len > player->buf_len)
+         {
+            short *old_buf = player->buf;
+            player->buf = (short *)malloc(wavecvt.len << 1);
+            memcpy(player->buf, old_buf + player->pos, (player->buf_len - player->pos) << 1);
+            memcpy(player->buf + player->buf_len - player->pos, old_buf, (player->pos + player->len - player->buf_len) << 1);
+            player->pos = 0; free(old_buf);
+         }
+         else
+            player->buf = (short *)realloc(player->buf, wavecvt.len << 1);
+         memset(player->buf + player->pos + player->len, 0, ((player->buf_len = wavecvt.len) - player->pos - player->len) << 1);
+      }
+
+      //
+      // Mix the current sound buffer with newly played sound and adjust the length of valid data
+      //
+      if (player->pos + wavecvt.len > player->buf_len)
+      {
+         AUDIO_MixNative(player->buf + player->pos, (short *)wavecvt.buf, player->buf_len - player->pos);
+         AUDIO_MixNative(player->buf, (short *)wavecvt.buf + player->buf_len - player->pos, player->pos + wavecvt.len - player->buf_len);
+      }
+      else
+         AUDIO_MixNative(player->buf + player->pos, (short *)wavecvt.buf, wavecvt.len);
+      player->len = max(player->len, wavecvt.len);
+
+      SDL_mutexV(gSndPlayer.mtx);
    }
    }
-   gSndPlayer.buf[iChannel] = wavecvt.buf;
-   gSndPlayer.audio_len[iChannel] = wavecvt.len * wavecvt.len_mult;
-   gSndPlayer.pos[iChannel] = wavecvt.buf;
-   SDL_mutexV(gSndPlayer.mtx);
+
+   free(wavecvt.buf);
 }
 }
 
 
 VOID
 VOID
-SOUND_PlayMUS(
+AUDIO_PlayMusic(
    INT       iNumRIX,
    INT       iNumRIX,
    BOOL      fLoop,
    BOOL      fLoop,
    FLOAT     flFadeTime
    FLOAT     flFadeTime
@@ -991,7 +1106,7 @@ SOUND_PlayMUS(
 }
 }
 
 
 BOOL
 BOOL
-SOUND_PlayCDA(
+AUDIO_PlayCDTrack(
    INT    iNumTrack
    INT    iNumTrack
 )
 )
 /*++
 /*++
@@ -1019,7 +1134,7 @@ SOUND_PlayCDA(
 
 
          if (iNumTrack != -1)
          if (iNumTrack != -1)
          {
          {
-            SOUND_PlayMUS(-1, FALSE, 0);
+            AUDIO_PlayMusic(-1, FALSE, 0);
 
 
             if (SDL_CDPlayTracks(gSndPlayer.pCD, iNumTrack - 1, 0, 1, 0) == 0)
             if (SDL_CDPlayTracks(gSndPlayer.pCD, iNumTrack - 1, 0, 1, 0) == 0)
             {
             {
@@ -1034,7 +1149,7 @@ SOUND_PlayCDA(
    {
    {
 	   if (iNumTrack != -1)
 	   if (iNumTrack != -1)
 	   {
 	   {
-		   SOUND_PlayMUS(-1, FALSE, 0);
+		   AUDIO_PlayMusic(-1, FALSE, 0);
 		   ret = gSndPlayer.pCDPlayer->Play(gSndPlayer.pCDPlayer, PAL_CDTRACK_BASE + iNumTrack, TRUE, 0);
 		   ret = gSndPlayer.pCDPlayer->Play(gSndPlayer.pCDPlayer, PAL_CDTRACK_BASE + iNumTrack, TRUE, 0);
 	   }
 	   }
 	   else
 	   else
@@ -1047,6 +1162,38 @@ SOUND_PlayCDA(
    return ret;
    return ret;
 }
 }
 
 
+VOID
+AUDIO_EnableMusic(
+   BOOL   fEnable
+)
+{
+   gSndPlayer.fMusicEnabled = fEnable;
+}
+
+BOOL
+AUDIO_MusicEnabled(
+   VOID
+)
+{
+   return gSndPlayer.fMusicEnabled;
+}
+
+VOID
+AUDIO_EnableSound(
+   BOOL   fEnable
+)
+{
+	gSndPlayer.fSoundEnabled = fEnable;
+}
+
+BOOL
+AUDIO_SoundEnabled(
+   VOID
+)
+{
+   return gSndPlayer.fSoundEnabled;
+}
+
 #ifdef PSP
 #ifdef PSP
 void
 void
 SOUND_Reload(
 SOUND_Reload(

+ 30 - 21
sound.h

@@ -30,43 +30,62 @@ extern "C"
 #endif
 #endif
 
 
 INT
 INT
-SOUND_OpenAudio(
+AUDIO_OpenDevice(
    VOID
    VOID
 );
 );
 
 
 VOID
 VOID
-SOUND_CloseAudio(
+AUDIO_CloseDevice(
    VOID
    VOID
 );
 );
 
 
 VOID
 VOID
-SOUND_PlayChannel(
-   INT    iSoundNum,
-   INT    iChannel
+AUDIO_PlaySound(
+   INT    iSoundNum
 );
 );
 
 
 SDL_AudioSpec*
 SDL_AudioSpec*
-SOUND_GetAudioSpec(
+AUDIO_GetDeviceSpec(
    VOID
    VOID
 );
 );
 
 
 VOID
 VOID
-SOUND_AdjustVolume(
-   INT    iDirectory
+AUDIO_AdjustVolume(
+   INT    iDirection
 );
 );
 
 
 VOID
 VOID
-SOUND_PlayMUS(
+AUDIO_PlayMusic(
    INT       iNumRIX,
    INT       iNumRIX,
    BOOL      fLoop,
    BOOL      fLoop,
    FLOAT     flFadeTime
    FLOAT     flFadeTime
 );
 );
 
 
 BOOL
 BOOL
-SOUND_PlayCDA(
+AUDIO_PlayCDTrack(
    INT    iNumTrack
    INT    iNumTrack
 );
 );
 
 
+VOID
+AUDIO_EnableMusic(
+   BOOL   fEnable
+);
+
+BOOL
+AUDIO_MusicEnabled(
+   VOID
+);
+
+VOID
+AUDIO_EnableSound(
+   BOOL   fEnable
+);
+
+BOOL
+AUDIO_SoundEnabled(
+   VOID
+);
+
 #ifdef PSP
 #ifdef PSP
 VOID
 VOID
 SOUND_Reload(
 SOUND_Reload(
@@ -74,17 +93,7 @@ SOUND_Reload(
 );
 );
 #endif
 #endif
 
 
-#ifdef PAL_CLASSIC
-extern int g_iCurrChannel;
-#define SOUND_Play(i) SOUND_PlayChannel((i), (g_iCurrChannel ^= 1))
-#else
-#define SOUND_Play(i) SOUND_PlayChannel((i), 0)
-#endif
-
-extern BOOL       g_fNoSound;
-extern BOOL       g_fNoMusic;
-
-#define SOUND_IsIntegerConversion(a) ((((a) % gConfig.iSampleRate) | (gConfig.iSampleRate % (a))) == 0)
+#define AUDIO_IsIntegerConversion(a) ((((a) % gConfig.iSampleRate) | (gConfig.iSampleRate % (a))) == 0)
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 7 - 14
uigame.c

@@ -96,7 +96,7 @@ PAL_OpeningMenu(
    //
    //
    // Play the background music
    // Play the background music
    //
    //
-   SOUND_PlayMUS(RIX_NUM_OPENINGMENU, TRUE, 1);
+   AUDIO_PlayMusic(RIX_NUM_OPENINGMENU, TRUE, 1);
 
 
    //
    //
    // Draw the background
    // Draw the background
@@ -136,7 +136,7 @@ PAL_OpeningMenu(
    //
    //
    // Fade out the screen and the music
    // Fade out the screen and the music
    //
    //
-   SOUND_PlayMUS(0, FALSE, 1);
+   AUDIO_PlayMusic(0, FALSE, 1);
    PAL_FadeOut(1);
    PAL_FadeOut(1);
 
 
    return (INT)wItemSelected;
    return (INT)wItemSelected;
@@ -609,7 +609,7 @@ PAL_SystemMenu(
       iSlot = PAL_SaveSlotMenu(gpGlobals->bCurrentSaveSlot);
       iSlot = PAL_SaveSlotMenu(gpGlobals->bCurrentSaveSlot);
       if (iSlot != MENUITEM_VALUE_CANCELLED)
       if (iSlot != MENUITEM_VALUE_CANCELLED)
       {
       {
-         SOUND_PlayMUS(0, FALSE, 1);
+         AUDIO_PlayMusic(0, FALSE, 1);
          PAL_FadeOut(1);
          PAL_FadeOut(1);
          PAL_InitGameData(iSlot);
          PAL_InitGameData(iSlot);
       }
       }
@@ -619,17 +619,10 @@ PAL_SystemMenu(
       //
       //
       // Music
       // Music
       //
       //
-      g_fNoMusic = !PAL_SwitchMenu(!g_fNoMusic);
+      AUDIO_EnableMusic(PAL_SwitchMenu(AUDIO_MusicEnabled()));
       if (gConfig.eMusicType == MUSIC_MIDI)
       if (gConfig.eMusicType == MUSIC_MIDI)
       {
       {
-         if (g_fNoMusic)
-         {
-            SOUND_PlayMUS(0, FALSE, 0);
-         }
-         else
-         {
-            SOUND_PlayMUS(gpGlobals->wNumMusic, TRUE, 0);
-         }
+         AUDIO_PlayMusic(AUDIO_MusicEnabled() ? gpGlobals->wNumMusic : 0, AUDIO_MusicEnabled(), 0);
       }
       }
       break;
       break;
 
 
@@ -637,7 +630,7 @@ PAL_SystemMenu(
       //
       //
       // Sound
       // Sound
       //
       //
-      g_fNoSound = !PAL_SwitchMenu(!g_fNoSound);
+      AUDIO_EnableSound(PAL_SwitchMenu(AUDIO_SoundEnabled()));
       break;
       break;
 
 
    case 5:
    case 5:
@@ -2000,7 +1993,7 @@ PAL_QuitGame(
 	{
 	{
 		if (wReturnValue == 2) gConfig.fLaunchSetting = TRUE;
 		if (wReturnValue == 2) gConfig.fLaunchSetting = TRUE;
 		PAL_SaveConfig();		// Keep the fullscreen state
 		PAL_SaveConfig();		// Keep the fullscreen state
-		SOUND_PlayMUS(0, FALSE, 2);
+		AUDIO_PlayMusic(0, FALSE, 2);
 		PAL_FadeOut(2);
 		PAL_FadeOut(2);
 		PAL_Shutdown(0);
 		PAL_Shutdown(0);
 	}
 	}

+ 22 - 13
unix/unix.cpp

@@ -37,7 +37,8 @@ struct {
    Fl_Check_Button* surround;
    Fl_Check_Button* surround;
    Fl_Int_Input* buffer;
    Fl_Int_Input* buffer;
    Fl_Hor_Value_Slider* quality;
    Fl_Hor_Value_Slider* quality;
-   Fl_Hor_Value_Slider* volume;
+   Fl_Hor_Value_Slider* music;
+   Fl_Hor_Value_Slider* sound;
 } gWidgets;
 } gWidgets;
 
 
 struct {
 struct {
@@ -62,7 +63,8 @@ struct {
    const char* surround;
    const char* surround;
    const char* buffer;
    const char* buffer;
    const char* quality;
    const char* quality;
-   const char* volume;
+   const char* musvol;
+   const char* sndvol;
    const char* exit;
    const char* exit;
    const char* launch;
    const char* launch;
    const char* def;
    const char* def;
@@ -71,17 +73,17 @@ struct {
      "&Traditional Chinese", "&Simplified Chinese", "Message file:", "Use &embedded font",
      "&Traditional Chinese", "&Simplified Chinese", "Message file:", "Use &embedded font",
      "Use touc&h overlay", "&Keep aspect ratio", "&Full screen", "&CD type:", "&BGM type:",
      "Use touc&h overlay", "&Keep aspect ratio", "&Full screen", "&CD type:", "&BGM type:",
      "&OPL type:", "Sample rate:", "Ste&reo", "OPL rate:", "Surround O&PL", "Buffer:",
      "&OPL type:", "Sample rate:", "Ste&reo", "OPL rate:", "Surround O&PL", "Buffer:",
-     "Quality:", "Volume:", "E&xit", "&Launch game", "&Default" },
+     "Quality:", "Music volume:", "Sound volume:", "E&xit", "&Launch game", "&Default" },
    { "SDLPAL 启动器", "游戏语言设置", "显示设置", "音频设置", "游戏资源目录:",
    { "SDLPAL 启动器", "游戏语言设置", "显示设置", "音频设置", "游戏资源目录:",
      "繁体中文(&T)", "简体中文(&S)", "语言文件:", "使用游戏资源内嵌字体(&E)",
      "繁体中文(&T)", "简体中文(&S)", "语言文件:", "使用游戏资源内嵌字体(&E)",
      "启用触屏辅助(&H)", "保持纵横比(&K)", "全屏模式(&F)", "&CD 音源:", "&BGM 音源:",
      "启用触屏辅助(&H)", "保持纵横比(&K)", "全屏模式(&F)", "&CD 音源:", "&BGM 音源:",
      "&OPL 类型:", "采样率:", "立体声(&R)", "OPL 采样率:", "环绕声 O&PL", "缓冲区:",
      "&OPL 类型:", "采样率:", "立体声(&R)", "OPL 采样率:", "环绕声 O&PL", "缓冲区:",
-     "质量:", "音量:", "退出(&X)", "启动游戏(&L)", "默认设置(&D)" },
+     "质量:", "音乐音量:", "音效音量:", "退出(&X)", "启动游戏(&L)", "默认设置(&D)" },
    { "SDLPAL 啟動器", "遊戲語言設置", "顯示設定", "音訊設定", "遊戲資源目錄:",
    { "SDLPAL 啟動器", "遊戲語言設置", "顯示設定", "音訊設定", "遊戲資源目錄:",
      "繁體中文(&T)", "簡體中文(&S)", "語言檔:", "使用遊戲資源內嵌字體(&E)",
      "繁體中文(&T)", "簡體中文(&S)", "語言檔:", "使用遊戲資源內嵌字體(&E)",
      "啟用觸屏輔助(&H)", "保持縱橫比(&K)", "全屏模式(&F)", "&CD 音源:", "&BGM 音源:",
      "啟用觸屏輔助(&H)", "保持縱橫比(&K)", "全屏模式(&F)", "&CD 音源:", "&BGM 音源:",
      "&OPL 類型:", "取樣速率:", "立體聲(&R)", "OPL 取樣速率:", "環繞聲 O&PL", "緩衝區:",
      "&OPL 類型:", "取樣速率:", "立體聲(&R)", "OPL 取樣速率:", "環繞聲 O&PL", "緩衝區:",
-     "品質:", "音量:", "退出(&X)", "啟動遊戲(&L)", "默認設定(&D)" },
+     "品質:", "音樂音量:", "音效音量:", "退出(&X)", "啟動遊戲(&L)", "默認設定(&D)" },
 };
 };
 
 
 void InitControls()
 void InitControls()
@@ -104,7 +106,8 @@ void InitControls()
    gWidgets.surround->value(gConfig.fUseSurroundOPL ? 1 : 0);
    gWidgets.surround->value(gConfig.fUseSurroundOPL ? 1 : 0);
    sprintf(buffer, "%d", gConfig.wAudioBufferSize); gWidgets.buffer->value(buffer);
    sprintf(buffer, "%d", gConfig.wAudioBufferSize); gWidgets.buffer->value(buffer);
    gWidgets.quality->value(gConfig.iResampleQuality);
    gWidgets.quality->value(gConfig.iResampleQuality);
-   gWidgets.volume->value(gConfig.iVolume * 100 / SDL_MIX_MAXVOLUME);
+   gWidgets.music->value(gConfig.iMusicVolume);
+   gWidgets.sound->value(gConfig.iSoundVolume);
 }
 }
 
 
 void SaveControls()
 void SaveControls()
@@ -127,7 +130,8 @@ void SaveControls()
    gConfig.fUseSurroundOPL = gWidgets.surround->value();
    gConfig.fUseSurroundOPL = gWidgets.surround->value();
    gConfig.wAudioBufferSize = atoi(gWidgets.buffer->value());
    gConfig.wAudioBufferSize = atoi(gWidgets.buffer->value());
    gConfig.iResampleQuality = (int)gWidgets.quality->value();
    gConfig.iResampleQuality = (int)gWidgets.quality->value();
-   gConfig.iVolume = (int)gWidgets.volume->value() * SDL_MIX_MAXVOLUME / 100;
+   gConfig.iMusicVolume = (int)gWidgets.music->value();
+   gConfig.iSoundVolume = (int)gWidgets.sound->value();
    gConfig.fLaunchSetting = FALSE;
    gConfig.fLaunchSetting = FALSE;
 }
 }
 
 
@@ -164,7 +168,7 @@ Fl_Window* InitWindow()
    gWidgets.aspect = new Fl_Check_Button(330, 140, 160, 20, gLabels[lang].aspect);
    gWidgets.aspect = new Fl_Check_Button(330, 140, 160, 20, gLabels[lang].aspect);
    gWidgets.fullscreen = new Fl_Check_Button(520, 140, 120, 20, gLabels[lang].fullscreen);
    gWidgets.fullscreen = new Fl_Check_Button(520, 140, 120, 20, gLabels[lang].fullscreen);
 
 
-   (new Fl_Box(FL_BORDER_BOX, 5, 210, 630, 110, gLabels[lang].audio))->align(FL_ALIGN_TOP);
+   (new Fl_Box(FL_BORDER_BOX, 5, 210, 630, 130, gLabels[lang].audio))->align(FL_ALIGN_TOP);
    (gWidgets.cd = new Fl_Choice(84, 219, lang ? 100 : 120, 22, gLabels[lang].cd))->add("MP3|OGG");
    (gWidgets.cd = new Fl_Choice(84, 219, lang ? 100 : 120, 22, gLabels[lang].cd))->add("MP3|OGG");
    (gWidgets.bgm = new Fl_Choice(285, 219, 60, 22, gLabels[lang].bgm))->add("RIX|MP3|OGG");
    (gWidgets.bgm = new Fl_Choice(285, 219, 60, 22, gLabels[lang].bgm))->add("RIX|MP3|OGG");
    gWidgets.stereo = new Fl_Check_Button(365, 220, 60, 20, gLabels[lang].stereo);
    gWidgets.stereo = new Fl_Check_Button(365, 220, 60, 20, gLabels[lang].stereo);
@@ -174,15 +178,20 @@ Fl_Window* InitWindow()
    gWidgets.surround = new Fl_Check_Button(365, 250, 60, 20, gLabels[lang].surround);
    gWidgets.surround = new Fl_Check_Button(365, 250, 60, 20, gLabels[lang].surround);
    gWidgets.buffer = new Fl_Int_Input(570, 249, 60, 22, gLabels[lang].buffer);
    gWidgets.buffer = new Fl_Int_Input(570, 249, 60, 22, gLabels[lang].buffer);
 
 
-   gWidgets.quality = new Fl_Hor_Value_Slider(72, 289, 230, 22, gLabels[lang].quality);
+   gWidgets.quality = new Fl_Hor_Value_Slider(72, 279, 180, 22, gLabels[lang].quality);
    gWidgets.quality->align(FL_ALIGN_LEFT);
    gWidgets.quality->align(FL_ALIGN_LEFT);
    gWidgets.quality->bounds(0, 4);
    gWidgets.quality->bounds(0, 4);
    gWidgets.quality->precision(0);
    gWidgets.quality->precision(0);
 
 
-   gWidgets.volume = new Fl_Hor_Value_Slider(400, 289, 230, 22, gLabels[lang].volume);
-   gWidgets.volume->align(FL_ALIGN_LEFT);
-   gWidgets.volume->bounds(0, 100);
-   gWidgets.volume->precision(0);
+   gWidgets.music = new Fl_Hor_Value_Slider(380, 279, 250, 22, gLabels[lang].musvol);
+   gWidgets.music->align(FL_ALIGN_LEFT);
+   gWidgets.music->bounds(0, 100);
+   gWidgets.music->precision(0);
+
+   gWidgets.sound = new Fl_Hor_Value_Slider(380, 309, 250, 22, gLabels[lang].sndvol);
+   gWidgets.sound->align(FL_ALIGN_LEFT);
+   gWidgets.sound->bounds(0, 100);
+   gWidgets.sound->precision(0);
 
 
    (new Fl_Button(5, 370, 120, 24, gLabels[lang].exit))->callback([](Fl_Widget* ctrl, void* window) {
    (new Fl_Button(5, 370, 120, 24, gLabels[lang].exit))->callback([](Fl_Widget* ctrl, void* window) {
       if (ctrl->when() == FL_WHEN_RELEASE)
       if (ctrl->when() == FL_WHEN_RELEASE)

+ 21 - 24
win32/resource.h

@@ -6,29 +6,26 @@
 #define IDD_LAUNCHER                    101
 #define IDD_LAUNCHER                    101
 #define IDS_CONFIRM                     103
 #define IDS_CONFIRM                     103
 #define IDC_GAMEPATH                    1000
 #define IDC_GAMEPATH                    1000
-#define IDC_CHT                         1005
-#define IDC_CHS                         1006
-#define IDC_EMBEDFONT                   1009
-#define IDC_WIDTH                       1012
-#define IDC_HEIGHT                      1013
-#define IDC_ASPECTRATIO                 1014
-#define IDC_FULLSCREEN                  1015
-#define IDC_FULLSCREEN2                 1016
-#define IDC_TOUCHOVERLAY                1016
-#define IDC_MSGFILE                     1017
-#define IDC_CD                          1019
-#define IDC_BGM                         1020
-#define IDC_OPL                         1021
-#define IDC_STEREO                      1022
-#define IDC_DEFAULT                     1024
-#define IDC_SURROUNDOPL                 1025
-#define IDC_SAMPLERATE                  1027
-#define IDC_OPLSR                       1028
-#define IDC_QUALITY                     1029
-#define IDC_VOLUME                      1030
-#define IDC_OPLOFFSET                   1031
-#define IDC_AUDIOBUFFER                 1032
-#define IDC_BRGAME                      1033
+#define IDC_CHT                         1001
+#define IDC_CHS                         1002
+#define IDC_EMBEDFONT                   1003
+#define IDC_ASPECTRATIO                 1004
+#define IDC_FULLSCREEN                  1005
+#define IDC_TOUCHOVERLAY                1006
+#define IDC_MSGFILE                     1007
+#define IDC_BRGAME                      1008
+#define IDC_CD                          1009
+#define IDC_BGM                         1010
+#define IDC_OPL                         1011
+#define IDC_STEREO                      1012
+#define IDC_SURROUNDOPL                 1013
+#define IDC_SAMPLERATE                  1014
+#define IDC_OPLSR                       1015
+#define IDC_AUDIOBUFFER                 1016
+#define IDC_QUALITY                     1017
+#define IDC_SOUNDVOLUME                 1018
+#define IDC_MUSICVOLUME                 1019
+#define IDC_DEFAULT                     1020
 #define IDC_STATIC                      -1
 #define IDC_STATIC                      -1
 
 
 // Next default values for new objects
 // Next default values for new objects
@@ -37,7 +34,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        104
 #define _APS_NEXT_RESOURCE_VALUE        104
 #define _APS_NEXT_COMMAND_VALUE         40001
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1035
+#define _APS_NEXT_CONTROL_VALUE         1021
 #define _APS_NEXT_SYMED_VALUE           101
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
 #endif
 #endif

+ 90 - 99
win32/sdlpal.rc

@@ -34,45 +34,42 @@ BEGIN
     PUSHBUTTON      "E&xit",IDCANCEL,7,185,50,14
     PUSHBUTTON      "E&xit",IDCANCEL,7,185,50,14
     LTEXT           "Game resource path:",IDC_STATIC,14,10,68,8
     LTEXT           "Game resource path:",IDC_STATIC,14,10,68,8
     EDITTEXT        IDC_GAMEPATH,84,7,256,14,ES_AUTOHSCROLL | ES_READONLY
     EDITTEXT        IDC_GAMEPATH,84,7,256,14,ES_AUTOHSCROLL | ES_READONLY
-    LTEXT           "CD source:",IDC_STATIC,14,114,36,8
-    GROUPBOX        "Game Language",IDC_STATIC,7,28,192,64
-    CONTROL         "&Traditional Chinese",IDC_CHT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,14,60,77,10
-    CONTROL         "Simplified &Chinese",IDC_CHS,"Button",BS_AUTORADIOBUTTON,102,60,73,10
+    LTEXT           "CD source:",IDC_STATIC,14,106,36,8
+    GROUPBOX        "Game Language",IDC_STATIC,7,28,192,50
+    CONTROL         "&Traditional Chinese",IDC_CHT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,14,44,77,10
+    CONTROL         "Simplified &Chinese",IDC_CHS,"Button",BS_AUTORADIOBUTTON,102,44,73,10
     CONTROL         "Use &embedded font",IDC_EMBEDFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,44,79,10
     CONTROL         "Use &embedded font",IDC_EMBEDFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,44,79,10
-    GROUPBOX        "Display",IDC_STATIC,206,28,192,64
-    LTEXT           "Window size:",IDC_STATIC,215,76,43,8
-    EDITTEXT        IDC_WIDTH,260,73,32,14,ES_AUTOHSCROLL | ES_NUMBER
-    CTEXT           "X",IDC_STATIC,295,76,8,8
-    EDITTEXT        IDC_HEIGHT,306,73,32,14,ES_AUTOHSCROLL | ES_NUMBER
+    GROUPBOX        "Display",IDC_STATIC,206,28,192,50
     CONTROL         "&Keep aspect ratio",IDC_ASPECTRATIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,60,72,10
     CONTROL         "&Keep aspect ratio",IDC_ASPECTRATIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,60,72,10
-    LTEXT           "BGM source:",IDC_STATIC,115,114,41,8
+    LTEXT           "BGM source:",IDC_STATIC,115,106,41,8
     CONTROL         "&Full screen",IDC_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,44,50,10
     CONTROL         "&Full screen",IDC_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,44,50,10
-    EDITTEXT        IDC_MSGFILE,59,73,131,14,ES_AUTOHSCROLL
-    GROUPBOX        "Audio",IDC_STATIC,7,100,391,78
-    COMBOBOX        IDC_CD,54,114,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    COMBOBOX        IDC_BGM,157,114,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "OPL type:",IDC_STATIC,14,135,33,8
-    COMBOBOX        IDC_OPL,54,132,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    CONTROL         "S&tereo",IDC_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,114,37,10
+    EDITTEXT        IDC_MSGFILE,59,57,131,14,ES_AUTOHSCROLL
+    GROUPBOX        "Audio",IDC_STATIC,7,86,391,85
+    COMBOBOX        IDC_CD,54,103,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_BGM,157,103,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "OPL type:",IDC_STATIC,14,125,33,8
+    COMBOBOX        IDC_OPL,54,122,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "S&tereo",IDC_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,106,37,10
     PUSHBUTTON      "&Default",IDC_DEFAULT,348,185,50,14
     PUSHBUTTON      "&Default",IDC_DEFAULT,348,185,50,14
-    CONTROL         "Surround &OPL",IDC_SURROUNDOPL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,245,135,55,10
-    LTEXT           "Audio sample rate:                      Hz",IDC_STATIC,280,114,113,8
-    EDITTEXT        IDC_SAMPLERATE,342,111,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "OPL sample rate:                       Hz",IDC_STATIC,115,135,110,8
-    EDITTEXT        IDC_OPLSR,172,132,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "Audio quality:",IDC_STATIC,14,154,45,8
-    LTEXT           "Low                                   High",IDC_STATIC,47,164,98,8
-    CONTROL         "",IDC_QUALITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,59,153,70,15
-    LTEXT           "Volume:",IDC_STATIC,145,154,26,8
-    CONTROL         "",IDC_VOLUME,"msctls_trackbar32",WS_TABSTOP,170,153,100,15
-    LTEXT           "Low                                              High",IDC_STATIC,163,164,120,8
-    LTEXT           "parameter:                       Hz",IDC_STATIC,304,135,94,8
-    EDITTEXT        IDC_OPLOFFSET,343,132,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "Audio buffer:",IDC_STATIC,299,154,44,8
-    EDITTEXT        IDC_AUDIOBUFFER,343,151,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    CONTROL         "Surround &OPL",IDC_SURROUNDOPL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,125,55,10
+    LTEXT           "Audio sample rate:                      Hz",IDC_STATIC,280,106,113,8
+    EDITTEXT        IDC_SAMPLERATE,342,103,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "OPL sample rate:                       Hz",IDC_STATIC,108,125,110,8
+    EDITTEXT        IDC_OPLSR,165,122,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "Audio buffer:",IDC_STATIC,298,125,44,8
+    EDITTEXT        IDC_AUDIOBUFFER,342,122,40,14,ES_AUTOHSCROLL | ES_NUMBER
     PUSHBUTTON      "&Browse",IDC_BRGAME,348,7,50,14
     PUSHBUTTON      "&Browse",IDC_BRGAME,348,7,50,14
-    LTEXT           "Message file:",IDC_STATIC,14,76,43,8
+    LTEXT           "Message file:",IDC_STATIC,14,60,43,8
     CONTROL         "Enable &touch overlay",IDC_TOUCHOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,60,83,10
     CONTROL         "Enable &touch overlay",IDC_TOUCHOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,60,83,10
+    LTEXT           "Quality:",IDC_STATIC,14,144,26,8
+    LTEXT           "Low                              High",IDC_STATIC,31,154,88,8
+    CONTROL         "",IDC_QUALITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,43,143,60,15
+    LTEXT           "Music volume:",IDC_STATIC,118,144,46,8
+    CONTROL         "",IDC_MUSICVOLUME,"msctls_trackbar32",WS_TABSTOP,165,143,80,15
+    LTEXT           "Low                                      High",IDC_STATIC,153,154,104,8
+    LTEXT           "Sound volume:",IDC_STATIC,256,145,48,8
+    CONTROL         "",IDC_SOUNDVOLUME,"msctls_trackbar32",WS_TABSTOP,303,144,80,15
+    LTEXT           "Low                                      High",IDC_STATIC,291,155,104,8
 END
 END
 
 
 
 
@@ -174,45 +171,42 @@ BEGIN
     PUSHBUTTON      "退出(&X)",IDCANCEL,7,185,50,14
     PUSHBUTTON      "退出(&X)",IDCANCEL,7,185,50,14
     LTEXT           "游戏资源目录:",IDC_STATIC,14,10,57,8
     LTEXT           "游戏资源目录:",IDC_STATIC,14,10,57,8
     EDITTEXT        IDC_GAMEPATH,71,7,270,14,ES_AUTOHSCROLL | ES_READONLY
     EDITTEXT        IDC_GAMEPATH,71,7,270,14,ES_AUTOHSCROLL | ES_READONLY
-    LTEXT           "CD 音源:",IDC_STATIC,14,114,36,8
-    GROUPBOX        "游戏语言设置",IDC_STATIC,7,28,192,64
-    CONTROL         "繁体中文(&T)",IDC_CHT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,14,60,57,10
-    CONTROL         "简体中文(&C)",IDC_CHS,"Button",BS_AUTORADIOBUTTON,102,60,58,10
+    LTEXT           "CD 音源:",IDC_STATIC,14,106,36,8
+    GROUPBOX        "游戏语言设置",IDC_STATIC,7,28,192,50
+    CONTROL         "繁体中文(&T)",IDC_CHT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,14,44,57,10
+    CONTROL         "简体中文(&C)",IDC_CHS,"Button",BS_AUTORADIOBUTTON,102,44,58,10
     CONTROL         "使用游戏内字体(&E)",IDC_EMBEDFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,44,81,10
     CONTROL         "使用游戏内字体(&E)",IDC_EMBEDFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,44,81,10
-    GROUPBOX        "显示设置",IDC_STATIC,206,28,192,64
-    LTEXT           "窗口尺寸:",IDC_STATIC,215,76,41,8
-    EDITTEXT        IDC_WIDTH,260,73,32,14,ES_AUTOHSCROLL | ES_NUMBER
-    CTEXT           "X",IDC_STATIC,295,76,8,8
-    EDITTEXT        IDC_HEIGHT,306,73,32,14,ES_AUTOHSCROLL | ES_NUMBER
+    GROUPBOX        "显示设置",IDC_STATIC,206,28,192,50
     CONTROL         "保持纵横比(&K)",IDC_ASPECTRATIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,60,65,10
     CONTROL         "保持纵横比(&K)",IDC_ASPECTRATIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,60,65,10
-    LTEXT           "BGM 音源:",IDC_STATIC,115,114,41,8
+    LTEXT           "BGM 音源:",IDC_STATIC,115,106,41,8
     CONTROL         "全屏启动游戏(&F)",IDC_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,44,73,10
     CONTROL         "全屏启动游戏(&F)",IDC_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,44,73,10
-    EDITTEXT        IDC_MSGFILE,57,73,133,14,ES_AUTOHSCROLL
-    GROUPBOX        "音频设置",IDC_STATIC,7,100,391,78
-    COMBOBOX        IDC_CD,54,113,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    COMBOBOX        IDC_BGM,157,113,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "OPL 类型:",IDC_STATIC,14,135,40,8
-    COMBOBOX        IDC_OPL,54,132,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    CONTROL         "立体声(&T)",IDC_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,114,49,10
+    EDITTEXT        IDC_MSGFILE,57,57,133,14,ES_AUTOHSCROLL
+    GROUPBOX        "音频设置",IDC_STATIC,7,86,391,85
+    COMBOBOX        IDC_CD,54,103,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_BGM,157,103,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "OPL 类型:",IDC_STATIC,14,125,40,8
+    COMBOBOX        IDC_OPL,54,122,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "立体声(&T)",IDC_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,106,49,10
     PUSHBUTTON      "默认设置(&D)",IDC_DEFAULT,348,185,50,14
     PUSHBUTTON      "默认设置(&D)",IDC_DEFAULT,348,185,50,14
-    CONTROL         "环绕声 &OPL",IDC_SURROUNDOPL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,135,55,10
-    LTEXT           "音频采样率:                      Hz",IDC_STATIC,285,114,101,8
-    EDITTEXT        IDC_SAMPLERATE,335,111,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "OPL 采样率:                       Hz",IDC_STATIC,115,135,102,8
-    EDITTEXT        IDC_OPLSR,165,132,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "音频质量:",IDC_STATIC,14,154,41,8
-    LTEXT           "低                                   高",IDC_STATIC,47,164,87,8
-    CONTROL         "",IDC_QUALITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,55,153,70,15
-    LTEXT           "音量:",IDC_STATIC,145,154,25,8
-    CONTROL         "",IDC_VOLUME,"msctls_trackbar32",WS_TABSTOP,170,153,100,15
-    LTEXT           "低                                                  高",IDC_STATIC,163,164,117,8
-    LTEXT           "参数:                     Hz",IDC_STATIC,285,135,75,8
-    EDITTEXT        IDC_OPLOFFSET,308,132,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "音频缓冲区:",IDC_STATIC,291,154,49,8
-    EDITTEXT        IDC_AUDIOBUFFER,341,151,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    CONTROL         "环绕声 &OPL",IDC_SURROUNDOPL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,125,55,10
+    LTEXT           "音频采样率:                      Hz",IDC_STATIC,285,106,101,8
+    EDITTEXT        IDC_SAMPLERATE,335,103,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "OPL 采样率:                       Hz",IDC_STATIC,115,125,102,8
+    EDITTEXT        IDC_OPLSR,165,122,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "音频缓冲区:",IDC_STATIC,285,125,49,8
+    EDITTEXT        IDC_AUDIOBUFFER,335,122,40,14,ES_AUTOHSCROLL | ES_NUMBER
     PUSHBUTTON      "浏览(&B)",IDC_BRGAME,348,7,50,14
     PUSHBUTTON      "浏览(&B)",IDC_BRGAME,348,7,50,14
-    LTEXT           "语言文件:",IDC_STATIC,14,76,41,8
+    LTEXT           "语言文件:",IDC_STATIC,14,60,41,8
     CONTROL         "启用触屏辅助(&T)",IDC_TOUCHOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,60,73,10
     CONTROL         "启用触屏辅助(&T)",IDC_TOUCHOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,60,73,10
+    LTEXT           "音频质量:",IDC_STATIC,14,144,41,8
+    LTEXT           "低                              高",IDC_STATIC,47,154,77,8
+    CONTROL         "",IDC_QUALITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,55,143,60,15
+    LTEXT           "音乐音量:",IDC_STATIC,131,144,41,8
+    CONTROL         "",IDC_MUSICVOLUME,"msctls_trackbar32",WS_TABSTOP,172,143,80,15
+    LTEXT           "低                                      高",IDC_STATIC,165,154,93,8
+    LTEXT           "音效音量:",IDC_STATIC,266,145,41,8
+    CONTROL         "",IDC_SOUNDVOLUME,"msctls_trackbar32",WS_TABSTOP,307,144,80,15
+    LTEXT           "低                                      高",IDC_STATIC,300,155,93,8
 END
 END
 
 
 
 
@@ -389,45 +383,42 @@ BEGIN
     PUSHBUTTON      "癶�(&X)",IDCANCEL,7,185,50,14
     PUSHBUTTON      "癶�(&X)",IDCANCEL,7,185,50,14
     LTEXT           "笴栏戈方郎Ж�",IDC_STATIC,14,10,57,8
     LTEXT           "笴栏戈方郎Ж�",IDC_STATIC,14,10,57,8
     EDITTEXT        IDC_GAMEPATH,71,7,270,14,ES_AUTOHSCROLL | ES_READONLY
     EDITTEXT        IDC_GAMEPATH,71,7,270,14,ES_AUTOHSCROLL | ES_READONLY
-    LTEXT           "CD �方�",IDC_STATIC,14,114,36,8
-    GROUPBOX        "笴栏粂ē砞﹚",IDC_STATIC,7,28,192,64
-    CONTROL         "羉砰いゅ(&T)",IDC_CHT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,14,60,57,10
-    CONTROL         "虏砰いゅ(&C)",IDC_CHS,"Button",BS_AUTORADIOBUTTON,102,60,58,10
+    LTEXT           "CD �方�",IDC_STATIC,14,106,36,8
+    GROUPBOX        "笴栏粂ē砞﹚",IDC_STATIC,7,28,192,50
+    CONTROL         "羉砰いゅ(&T)",IDC_CHT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,14,44,57,10
+    CONTROL         "虏砰いゅ(&C)",IDC_CHS,"Button",BS_AUTORADIOBUTTON,102,44,58,10
     CONTROL         "ㄏノ笴栏ず�砰(&E)",IDC_EMBEDFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,44,81,10
     CONTROL         "ㄏノ笴栏ず�砰(&E)",IDC_EMBEDFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,44,81,10
-    GROUPBOX        "陪ボ砞﹚",IDC_STATIC,206,28,192,64
-    LTEXT           "跌怠へ��",IDC_STATIC,215,76,41,8
-    EDITTEXT        IDC_WIDTH,260,73,32,14,ES_AUTOHSCROLL | ES_NUMBER
-    CTEXT           "X",IDC_STATIC,295,76,8,8
-    EDITTEXT        IDC_HEIGHT,306,73,32,14,ES_AUTOHSCROLL | ES_NUMBER
+    GROUPBOX        "陪ボ砞﹚",IDC_STATIC,206,28,192,50
     CONTROL         "玂�羇绢ゑ(&K)",IDC_ASPECTRATIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,60,65,10
     CONTROL         "玂�羇绢ゑ(&K)",IDC_ASPECTRATIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,215,60,65,10
-    LTEXT           "BGM �方�",IDC_STATIC,115,114,41,8
+    LTEXT           "BGM �方�",IDC_STATIC,115,106,41,8
     CONTROL         "��币笆笴栏(&F)",IDC_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,44,73,10
     CONTROL         "��币笆笴栏(&F)",IDC_FULLSCREEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,44,73,10
-    EDITTEXT        IDC_MSGFILE,57,73,133,14,ES_AUTOHSCROLL
-    GROUPBOX        "�癟砞﹚",IDC_STATIC,7,100,391,78
-    COMBOBOX        IDC_CD,54,114,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    COMBOBOX        IDC_BGM,157,114,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "OPL 摸��",IDC_STATIC,14,135,40,8
-    COMBOBOX        IDC_OPL,54,132,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    CONTROL         "ミ砰羘(&T)",IDC_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,225,114,49,10
+    EDITTEXT        IDC_MSGFILE,57,57,133,14,ES_AUTOHSCROLL
+    GROUPBOX        "�癟砞﹚",IDC_STATIC,7,86,391,85
+    COMBOBOX        IDC_CD,54,103,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_BGM,157,103,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "OPL 摸��",IDC_STATIC,14,124,40,8
+    COMBOBOX        IDC_OPL,54,121,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "ミ砰羘(&T)",IDC_STEREO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,230,106,49,10
     PUSHBUTTON      "纐粄砞﹚(&D)",IDC_DEFAULT,348,185,50,14
     PUSHBUTTON      "纐粄砞﹚(&D)",IDC_DEFAULT,348,185,50,14
-    CONTROL         "吏露羘 &OPL",IDC_SURROUNDOPL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,235,135,55,10
-    LTEXT           "�癟�妓硉瞯�                      Hz",IDC_STATIC,285,114,109,8
-    EDITTEXT        IDC_SAMPLERATE,342,111,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "OPL �妓硉瞯�                       Hz",IDC_STATIC,115,135,110,8
-    EDITTEXT        IDC_OPLSR,172,132,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "�癟珇借�",IDC_STATIC,14,154,41,8
-    LTEXT           "�                                   蔼",IDC_STATIC,47,164,87,8
-    CONTROL         "",IDC_QUALITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,55,153,70,15
-    LTEXT           "�秖�",IDC_STATIC,145,154,25,8
-    CONTROL         "",IDC_VOLUME,"msctls_trackbar32",WS_TABSTOP,170,153,100,15
-    LTEXT           "�                                                  蔼",IDC_STATIC,163,164,117,8
-    LTEXT           "把计�                     Hz",IDC_STATIC,297,135,75,8
-    EDITTEXT        IDC_OPLOFFSET,320,132,40,14,ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "�癟絯侥跋�",IDC_STATIC,291,154,49,8
-    EDITTEXT        IDC_AUDIOBUFFER,341,151,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    CONTROL         "吏露羘 &OPL",IDC_SURROUNDOPL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,230,124,55,10
+    LTEXT           "�癟�妓硉瞯�                      Hz",IDC_STATIC,285,106,109,8
+    EDITTEXT        IDC_SAMPLERATE,342,103,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "OPL �妓硉瞯�                       Hz",IDC_STATIC,115,124,110,8
+    EDITTEXT        IDC_OPLSR,172,121,40,14,ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "�癟珇借�",IDC_STATIC,14,144,41,8
+    CONTROL         "",IDC_QUALITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,55,143,60,15
+    LTEXT           "�癟絯侥跋�",IDC_STATIC,293,124,48,8
+    EDITTEXT        IDC_AUDIOBUFFER,342,121,40,14,ES_AUTOHSCROLL | ES_NUMBER
     PUSHBUTTON      "聅凝(&B)",IDC_BRGAME,348,7,50,14
     PUSHBUTTON      "聅凝(&B)",IDC_BRGAME,348,7,50,14
-    LTEXT           "粂ē郎�",IDC_STATIC,14,76,33,8
+    LTEXT           "粂ē郎�",IDC_STATIC,14,60,33,8
     CONTROL         "币ノ牟�徊�(&T)",IDC_TOUCHOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,60,73,10
     CONTROL         "币ノ牟�徊�(&T)",IDC_TOUCHOVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,60,73,10
+    LTEXT           "�                              蔼",IDC_STATIC,47,154,77,8
+    LTEXT           "�贾�秖�",IDC_STATIC,131,144,41,8
+    CONTROL         "",IDC_MUSICVOLUME,"msctls_trackbar32",WS_TABSTOP,172,143,80,15
+    LTEXT           "�                                      蔼",IDC_STATIC,165,154,93,8
+    LTEXT           "���秖�",IDC_STATIC,266,145,41,8
+    CONTROL         "",IDC_SOUNDVOLUME,"msctls_trackbar32",WS_TABSTOP,307,144,80,15
+    LTEXT           "�                                      蔼",IDC_STATIC,300,155,93,8
 END
 END
 
 
 
 

+ 9 - 12
win32/win32.cpp

@@ -11,6 +11,7 @@
 #include "../global.h"
 #include "../global.h"
 #include "../util.h"
 #include "../util.h"
 #include "../palcfg.h"
 #include "../palcfg.h"
+#include "../resampler.h"
 
 
 #pragma comment(lib, "comctl32.lib")
 #pragma comment(lib, "comctl32.lib")
 #pragma comment(linker,"\"/manifestdependency:type='win32' \
 #pragma comment(linker,"\"/manifestdependency:type='win32' \
@@ -102,21 +103,19 @@ void SaveSettings(HWND hwndDlg, BOOL fWriteFile)
 	gConfig.fUseTouchOverlay = IsDlgButtonChecked(hwndDlg, IDC_TOUCHOVERLAY);
 	gConfig.fUseTouchOverlay = IsDlgButtonChecked(hwndDlg, IDC_TOUCHOVERLAY);
 	gConfig.fUseEmbeddedFonts = IsDlgButtonChecked(hwndDlg, IDC_EMBEDFONT);
 	gConfig.fUseEmbeddedFonts = IsDlgButtonChecked(hwndDlg, IDC_EMBEDFONT);
 	gConfig.fKeepAspectRatio = IsDlgButtonChecked(hwndDlg, IDC_ASPECTRATIO);
 	gConfig.fKeepAspectRatio = IsDlgButtonChecked(hwndDlg, IDC_ASPECTRATIO);
-	gConfig.dwScreenWidth = GetDlgItemInt(hwndDlg, IDC_WIDTH, nullptr, FALSE);
-	gConfig.dwScreenHeight = GetDlgItemInt(hwndDlg, IDC_HEIGHT, nullptr, FALSE);
 	gConfig.eCDType = (MUSICTYPE)(ComboBox_GetCurSel(hwndDlg, IDC_CD) + MUSIC_MP3);
 	gConfig.eCDType = (MUSICTYPE)(ComboBox_GetCurSel(hwndDlg, IDC_CD) + MUSIC_MP3);
 	gConfig.eMusicType = (MUSICTYPE)ComboBox_GetCurSel(hwndDlg, IDC_BGM);
 	gConfig.eMusicType = (MUSICTYPE)ComboBox_GetCurSel(hwndDlg, IDC_BGM);
 	gConfig.eOPLType = (OPLTYPE)(ComboBox_GetCurSel(hwndDlg, IDC_OPL));
 	gConfig.eOPLType = (OPLTYPE)(ComboBox_GetCurSel(hwndDlg, IDC_OPL));
 	gConfig.iAudioChannels = IsDlgButtonChecked(hwndDlg, IDC_STEREO) ? 2 : 1;
 	gConfig.iAudioChannels = IsDlgButtonChecked(hwndDlg, IDC_STEREO) ? 2 : 1;
 	gConfig.iSampleRate = GetDlgItemInt(hwndDlg, IDC_SAMPLERATE, nullptr, FALSE);
 	gConfig.iSampleRate = GetDlgItemInt(hwndDlg, IDC_SAMPLERATE, nullptr, FALSE);
 	gConfig.wAudioBufferSize = GetDlgItemInt(hwndDlg, IDC_AUDIOBUFFER, nullptr, FALSE);
 	gConfig.wAudioBufferSize = GetDlgItemInt(hwndDlg, IDC_AUDIOBUFFER, nullptr, FALSE);
-	gConfig.iVolume = TrackBar_GetPos(hwndDlg, IDC_VOLUME) * SDL_MIX_MAXVOLUME / 100;
+	gConfig.iMusicVolume = TrackBar_GetPos(hwndDlg, IDC_MUSICVOLUME);
+	gConfig.iSoundVolume = TrackBar_GetPos(hwndDlg, IDC_SOUNDVOLUME);
 	gConfig.iResampleQuality = TrackBar_GetPos(hwndDlg, IDC_QUALITY);
 	gConfig.iResampleQuality = TrackBar_GetPos(hwndDlg, IDC_QUALITY);
 	if (gConfig.eMusicType == MUSIC_RIX)
 	if (gConfig.eMusicType == MUSIC_RIX)
 	{
 	{
 		gConfig.fUseSurroundOPL = IsDlgButtonChecked(hwndDlg, IDC_SURROUNDOPL);
 		gConfig.fUseSurroundOPL = IsDlgButtonChecked(hwndDlg, IDC_SURROUNDOPL);
 		gConfig.iOPLSampleRate = GetDlgItemInt(hwndDlg, IDC_OPLSR, nullptr, FALSE);
 		gConfig.iOPLSampleRate = GetDlgItemInt(hwndDlg, IDC_OPLSR, nullptr, FALSE);
-		gConfig.iSurroundOPLOffset = GetDlgItemInt(hwndDlg, IDC_OPLOFFSET, nullptr, TRUE);
 	}
 	}
 
 
 	if (fWriteFile) PAL_SaveConfig();
 	if (fWriteFile) PAL_SaveConfig();
@@ -128,7 +127,6 @@ void ResetControls(HWND hwndDlg)
 
 
 	EnableDlgItem(hwndDlg, IDC_OPL, gConfig.eMusicType == MUSIC_RIX);
 	EnableDlgItem(hwndDlg, IDC_OPL, gConfig.eMusicType == MUSIC_RIX);
 	EnableDlgItem(hwndDlg, IDC_SURROUNDOPL, gConfig.eMusicType == MUSIC_RIX);
 	EnableDlgItem(hwndDlg, IDC_SURROUNDOPL, gConfig.eMusicType == MUSIC_RIX);
-	EnableDlgItem(hwndDlg, IDC_OPLOFFSET, gConfig.eMusicType == MUSIC_RIX);
 	EnableDlgItem(hwndDlg, IDC_OPLSR, gConfig.eMusicType == MUSIC_RIX);
 	EnableDlgItem(hwndDlg, IDC_OPLSR, gConfig.eMusicType == MUSIC_RIX);
 
 
 	CheckRadioButton(hwndDlg, IDC_CHT, IDC_CHS, IDC_CHT + gConfig.uCodePage);
 	CheckRadioButton(hwndDlg, IDC_CHT, IDC_CHS, IDC_CHT + gConfig.uCodePage);
@@ -144,20 +142,16 @@ void ResetControls(HWND hwndDlg)
 	ComboBox_SetCurSel(hwndDlg, IDC_BGM, gConfig.eMusicType);
 	ComboBox_SetCurSel(hwndDlg, IDC_BGM, gConfig.eMusicType);
 	ComboBox_SetCurSel(hwndDlg, IDC_OPL, gConfig.eOPLType);
 	ComboBox_SetCurSel(hwndDlg, IDC_OPL, gConfig.eOPLType);
 
 
-	SetDlgItemText(hwndDlg, IDC_WIDTH, _ultot(gConfig.dwScreenWidth, buffer, 10));
-	SetDlgItemText(hwndDlg, IDC_HEIGHT, _ultot(gConfig.dwScreenHeight, buffer, 10));
 	SetDlgItemText(hwndDlg, IDC_SAMPLERATE, _itot(gConfig.iSampleRate, buffer, 10));
 	SetDlgItemText(hwndDlg, IDC_SAMPLERATE, _itot(gConfig.iSampleRate, buffer, 10));
 	SetDlgItemText(hwndDlg, IDC_OPLSR, _itot(gConfig.iOPLSampleRate, buffer, 10));
 	SetDlgItemText(hwndDlg, IDC_OPLSR, _itot(gConfig.iOPLSampleRate, buffer, 10));
-	SetDlgItemText(hwndDlg, IDC_OPLOFFSET, _itot((int)gConfig.iSurroundOPLOffset, buffer, 10));
 	SetDlgItemText(hwndDlg, IDC_AUDIOBUFFER, _itot(gConfig.wAudioBufferSize, buffer, 10));
 	SetDlgItemText(hwndDlg, IDC_AUDIOBUFFER, _itot(gConfig.wAudioBufferSize, buffer, 10));
 
 
 	if (gConfig.pszGamePath) SetDlgItemTextA(hwndDlg, IDC_GAMEPATH, gConfig.pszGamePath);
 	if (gConfig.pszGamePath) SetDlgItemTextA(hwndDlg, IDC_GAMEPATH, gConfig.pszGamePath);
 	if (gConfig.pszMsgFile) SetDlgItemTextA(hwndDlg, IDC_MSGFILE, gConfig.pszMsgFile);
 	if (gConfig.pszMsgFile) SetDlgItemTextA(hwndDlg, IDC_MSGFILE, gConfig.pszMsgFile);
 
 
-	TrackBar_SetRange(hwndDlg, IDC_QUALITY, 0, 4, FALSE);
 	TrackBar_SetPos(hwndDlg, IDC_QUALITY, gConfig.iResampleQuality, TRUE);
 	TrackBar_SetPos(hwndDlg, IDC_QUALITY, gConfig.iResampleQuality, TRUE);
-	TrackBar_SetRange(hwndDlg, IDC_VOLUME, 0, 100, FALSE);
-	TrackBar_SetPos(hwndDlg, IDC_VOLUME, gConfig.iVolume * 100 / SDL_MIX_MAXVOLUME, TRUE);
+	TrackBar_SetPos(hwndDlg, IDC_MUSICVOLUME, gConfig.iMusicVolume, TRUE);
+	TrackBar_SetPos(hwndDlg, IDC_SOUNDVOLUME, gConfig.iSoundVolume, TRUE);
 }
 }
 
 
 INT_PTR InitProc(HWND hwndDlg, HWND hwndCtrl, LPARAM lParam)
 INT_PTR InitProc(HWND hwndDlg, HWND hwndCtrl, LPARAM lParam)
@@ -176,6 +170,10 @@ INT_PTR InitProc(HWND hwndDlg, HWND hwndCtrl, LPARAM lParam)
 	ComboBox_AddString(hwndDlg, IDC_OPL, TEXT("MAME"));
 	ComboBox_AddString(hwndDlg, IDC_OPL, TEXT("MAME"));
 	ComboBox_AddString(hwndDlg, IDC_OPL, TEXT("DOSBOXNEW"));
 	ComboBox_AddString(hwndDlg, IDC_OPL, TEXT("DOSBOXNEW"));
 
 
+	TrackBar_SetRange(hwndDlg, IDC_QUALITY, RESAMPLER_QUALITY_MIN, RESAMPLER_QUALITY_MAX, FALSE);
+	TrackBar_SetRange(hwndDlg, IDC_MUSICVOLUME, 0, PAL_MAX_VOLUME, FALSE);
+	TrackBar_SetRange(hwndDlg, IDC_SOUNDVOLUME, 0, PAL_MAX_VOLUME, FALSE);
+
 	ResetControls(hwndDlg);
 	ResetControls(hwndDlg);
 
 
 	WINDOWINFO wi = { sizeof(WINDOWINFO) };
 	WINDOWINFO wi = { sizeof(WINDOWINFO) };
@@ -236,7 +234,6 @@ INT_PTR ComboBoxProc(HWND hwndDlg, WORD idControl, HWND hwndCtrl)
 	case IDC_BGM:
 	case IDC_BGM:
 		EnableDlgItem(hwndDlg, IDC_OPL, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		EnableDlgItem(hwndDlg, IDC_OPL, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		EnableDlgItem(hwndDlg, IDC_SURROUNDOPL, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		EnableDlgItem(hwndDlg, IDC_SURROUNDOPL, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
-		EnableDlgItem(hwndDlg, IDC_OPLOFFSET, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		EnableDlgItem(hwndDlg, IDC_OPLSR, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		EnableDlgItem(hwndDlg, IDC_OPLSR, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		return TRUE;
 		return TRUE;
 
 

+ 2 - 1
winrt/SDLPal.Common/MainPage.xaml

@@ -24,7 +24,8 @@
                 <ToggleSwitch x:Name="tsTouchOverlay" x:Uid="TouchOverlay" Header="启用触屏辅助" OffContent="否" OnContent="是" />
                 <ToggleSwitch x:Name="tsTouchOverlay" x:Uid="TouchOverlay" Header="启用触屏辅助" OffContent="否" OnContent="是" />
                 <ToggleSwitch x:Name="tsKeepAspect" x:Uid="AspectRatio" Header="保持纵横比" OffContent="否" OnContent="是" />
                 <ToggleSwitch x:Name="tsKeepAspect" x:Uid="AspectRatio" Header="保持纵横比" OffContent="否" OnContent="是" />
                 <ToggleSwitch x:Name="tsStereo" x:Uid="Stereo" Header="立体声" OffContent="否" OnContent="是" />
                 <ToggleSwitch x:Name="tsStereo" x:Uid="Stereo" Header="立体声" OffContent="否" OnContent="是" />
-                <Slider x:Name="slVolume" x:Uid="Volume" Header="音量" TickPlacement="Inline" TickFrequency="10" />
+                <Slider x:Name="slMusicVolume" x:Uid="MusicVolume" Header="音乐音量" TickPlacement="Inline" TickFrequency="10" />
+                <Slider x:Name="slSoundVolume" x:Uid="SoundVolume" Header="音效音量" TickPlacement="Inline" TickFrequency="10" />
                 <Slider x:Name="slQuality" x:Uid="Quality" Header="音频质量" Maximum="4" LargeChange="1" TickFrequency="1" />
                 <Slider x:Name="slQuality" x:Uid="Quality" Header="音频质量" Maximum="4" LargeChange="1" TickFrequency="1" />
                 <ComboBox x:Name="cbSampleRate" x:Uid="Samplerate" HorizontalAlignment="Stretch" Header="音频输出采样率" PlaceholderText="音频输出采样率">
                 <ComboBox x:Name="cbSampleRate" x:Uid="Samplerate" HorizontalAlignment="Stretch" Header="音频输出采样率" PlaceholderText="音频输出采样率">
                     <ComboBoxItem Content="11025"/>
                     <ComboBoxItem Content="11025"/>

+ 4 - 2
winrt/SDLPal.Common/MainPage.xaml.cpp

@@ -49,7 +49,8 @@ void SDLPal::MainPage::LoadControlContents()
 	tsSurroundOPL->IsOn = (gConfig.fUseSurroundOPL == TRUE);
 	tsSurroundOPL->IsOn = (gConfig.fUseSurroundOPL == TRUE);
 	tsTouchOverlay->IsOn = (gConfig.fUseTouchOverlay == TRUE);
 	tsTouchOverlay->IsOn = (gConfig.fUseTouchOverlay == TRUE);
 
 
-	slVolume->Value = gConfig.iVolume * 100 / SDL_MIX_MAXVOLUME;
+	slMusicVolume->Value = gConfig.iMusicVolume;
+	slSoundVolume->Value = gConfig.iSoundVolume;
 	slQuality->Value = gConfig.iResampleQuality;
 	slQuality->Value = gConfig.iResampleQuality;
 
 
 	cbCD->SelectedIndex = (gConfig.eCDType == MUSIC_MP3) ? 0 : 1;
 	cbCD->SelectedIndex = (gConfig.eCDType == MUSIC_MP3) ? 0 : 1;
@@ -97,7 +98,8 @@ void SDLPal::MainPage::SaveControlContents()
 	gConfig.fUseSurroundOPL = tsSurroundOPL->IsOn ? TRUE : FALSE;
 	gConfig.fUseSurroundOPL = tsSurroundOPL->IsOn ? TRUE : FALSE;
 	gConfig.fUseTouchOverlay = tsTouchOverlay->IsOn ? TRUE : FALSE;
 	gConfig.fUseTouchOverlay = tsTouchOverlay->IsOn ? TRUE : FALSE;
 
 
-	gConfig.iVolume = (int)slVolume->Value * SDL_MIX_MAXVOLUME / 100;
+	gConfig.iMusicVolume = (int)slMusicVolume->Value;
+	gConfig.iSoundVolume = (int)slSoundVolume->Value;
 	gConfig.iResampleQuality = (int)slQuality->Value;
 	gConfig.iResampleQuality = (int)slQuality->Value;
 	gConfig.uCodePage = tsLanguage->IsOn ? CP_GBK : CP_BIG5;
 	gConfig.uCodePage = tsLanguage->IsOn ? CP_GBK : CP_BIG5;
 
 

+ 6 - 3
winrt/SDLPal.Common/Strings/en/Resources.resw

@@ -214,6 +214,9 @@ You can use the main menu option inside the game to return to this page.</value>
   <data name="MessageFile.PlaceholderText" xml:space="preserve">
   <data name="MessageFile.PlaceholderText" xml:space="preserve">
     <value>No customized message file</value>
     <value>No customized message file</value>
   </data>
   </data>
+  <data name="MusicVolume.Header" xml:space="preserve">
+    <value>Music volume</value>
+  </data>
   <data name="OPL.Header" xml:space="preserve">
   <data name="OPL.Header" xml:space="preserve">
     <value>Type of OPL simulator</value>
     <value>Type of OPL simulator</value>
   </data>
   </data>
@@ -238,6 +241,9 @@ You can use the main menu option inside the game to return to this page.</value>
   <data name="Samplerate.PlaceholderText" xml:space="preserve">
   <data name="Samplerate.PlaceholderText" xml:space="preserve">
     <value>Sample rate of audio output</value>
     <value>Sample rate of audio output</value>
   </data>
   </data>
+  <data name="SoundVolume.Header" xml:space="preserve">
+    <value>Sound volume</value>
+  </data>
   <data name="Stereo.Header" xml:space="preserve">
   <data name="Stereo.Header" xml:space="preserve">
     <value>Stereo</value>
     <value>Stereo</value>
   </data>
   </data>
@@ -268,7 +274,4 @@ You can use the main menu option inside the game to return to this page.</value>
   <data name="TouchOverlay.OnContent" xml:space="preserve">
   <data name="TouchOverlay.OnContent" xml:space="preserve">
     <value>Yes</value>
     <value>Yes</value>
   </data>
   </data>
-  <data name="Volume.Header" xml:space="preserve">
-    <value>Volume</value>
-  </data>
 </root>
 </root>

+ 6 - 3
winrt/SDLPal.Common/Strings/zh-hans/Resources.resw

@@ -214,6 +214,9 @@
   <data name="MessageFile.PlaceholderText" xml:space="preserve">
   <data name="MessageFile.PlaceholderText" xml:space="preserve">
     <value>无自定义语言文件</value>
     <value>无自定义语言文件</value>
   </data>
   </data>
+  <data name="MusicVolume.Header" xml:space="preserve">
+    <value>音乐音量</value>
+  </data>
   <data name="OPL.Header" xml:space="preserve">
   <data name="OPL.Header" xml:space="preserve">
     <value>OPL 模拟器</value>
     <value>OPL 模拟器</value>
   </data>
   </data>
@@ -238,6 +241,9 @@
   <data name="Samplerate.PlaceholderText" xml:space="preserve">
   <data name="Samplerate.PlaceholderText" xml:space="preserve">
     <value>音频输出采样率</value>
     <value>音频输出采样率</value>
   </data>
   </data>
+  <data name="SoundVolume.Header" xml:space="preserve">
+    <value>音效音量</value>
+  </data>
   <data name="Stereo.Header" xml:space="preserve">
   <data name="Stereo.Header" xml:space="preserve">
     <value>立体声</value>
     <value>立体声</value>
   </data>
   </data>
@@ -268,7 +274,4 @@
   <data name="TouchOverlay.OnContent" xml:space="preserve">
   <data name="TouchOverlay.OnContent" xml:space="preserve">
     <value>是</value>
     <value>是</value>
   </data>
   </data>
-  <data name="Volume.Header" xml:space="preserve">
-    <value>音量</value>
-  </data>
 </root>
 </root>

+ 6 - 3
winrt/SDLPal.Common/Strings/zh-hant/Resources.resw

@@ -214,6 +214,9 @@
   <data name="MessageFile.PlaceholderText" xml:space="preserve">
   <data name="MessageFile.PlaceholderText" xml:space="preserve">
     <value>無自訂語言檔案</value>
     <value>無自訂語言檔案</value>
   </data>
   </data>
+  <data name="MusicVolume.Header" xml:space="preserve">
+    <value>音樂音量</value>
+  </data>
   <data name="OPL.Header" xml:space="preserve">
   <data name="OPL.Header" xml:space="preserve">
     <value>OPL 模擬器</value>
     <value>OPL 模擬器</value>
   </data>
   </data>
@@ -238,6 +241,9 @@
   <data name="Samplerate.PlaceholderText" xml:space="preserve">
   <data name="Samplerate.PlaceholderText" xml:space="preserve">
     <value>音訊輸出取樣速率</value>
     <value>音訊輸出取樣速率</value>
   </data>
   </data>
+  <data name="SoundVolume.Header" xml:space="preserve">
+    <value>音效音量</value>
+  </data>
   <data name="Stereo.Header" xml:space="preserve">
   <data name="Stereo.Header" xml:space="preserve">
     <value>立體聲</value>
     <value>立體聲</value>
   </data>
   </data>
@@ -268,7 +274,4 @@
   <data name="TouchOverlay.OnContent" xml:space="preserve">
   <data name="TouchOverlay.OnContent" xml:space="preserve">
     <value>是</value>
     <value>是</value>
   </data>
   </data>
-  <data name="Volume.Header" xml:space="preserve">
-    <value>音量</value>
-  </data>
 </root>
 </root>