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
    //
-   SOUND_PlayMUS(0, FALSE, 1);
+   AUDIO_PlayMusic(0, FALSE, 1);
    UTIL_Delay(200);
 
    //
@@ -337,7 +337,7 @@ PAL_BattleMain(
    //
    // Play the battle music
    //
-   SOUND_PlayMUS(gpGlobals->wNumBattleMusic, TRUE, 0);
+   AUDIO_PlayMusic(gpGlobals->wNumBattleMusic, TRUE, 0);
 
    //
    // Fade in the screen when needed
@@ -646,7 +646,7 @@ PAL_BattleWon(
       //
       // 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
@@ -973,7 +973,7 @@ PAL_BattleEnemyEscape(
    int j, x, y, w;
    BOOL f = TRUE;
 
-   SOUND_Play(45);
+   AUDIO_PlaySound(45);
 
    //
    // Show the animation
@@ -1035,7 +1035,7 @@ PAL_BattlePlayerEscape(
    int         i, j;
    WORD        wPlayerRole;
 
-   SOUND_Play(45);
+   AUDIO_PlaySound(45);
 
    PAL_BattleUpdateFighters();
 
@@ -1441,7 +1441,7 @@ PAL_StartBattle(
 
    gpGlobals->fInBattle = FALSE;
 
-   SOUND_PlayMUS(gpGlobals->wNumMusic, TRUE, 1);
+   AUDIO_PlayMusic(gpGlobals->wNumMusic, TRUE, 1);
 
    //
    // Restore the screen waving effects

+ 9 - 9
ending.c

@@ -434,13 +434,13 @@ PAL_EndingScreen(
    VOID
 )
 {
-	SOUND_PlayMUS(0x1a, TRUE, 0);
+	AUDIO_PlayMusic(0x1a, TRUE, 0);
 	PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 110, 150, 7);
 	PAL_RNGPlay(gpGlobals->iCurPlayingRNG, 151, 999, 9);
 
 	PAL_FadeOut(2);
 
-	SOUND_PlayMUS(0x19, TRUE, 0);
+	AUDIO_PlayMusic(0x19, TRUE, 0);
 
 	PAL_ShowFBP(75, 0);
 	PAL_FadeIn(5, FALSE, 1);
@@ -453,12 +453,12 @@ PAL_EndingScreen(
 	gpGlobals->fNeedToFadeIn = TRUE;
 	PAL_EndingAnimation();
 
-	SOUND_PlayMUS(0, FALSE, 2);
+	AUDIO_PlayMusic(0, FALSE, 2);
 	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);
@@ -491,12 +491,12 @@ PAL_EndingScreen(
 	PAL_ShowFBP(68, 6);
 
 	PAL_WaitForKey(0);
-	SOUND_PlayMUS(0, FALSE, 1);
+	AUDIO_PlayMusic(0, FALSE, 1);
 	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);
@@ -509,7 +509,7 @@ PAL_EndingScreen(
 	PAL_ScrollFBP(60, 0xf, TRUE);
 	PAL_ScrollFBP(59, 0xf, TRUE);
 
-	SOUND_PlayMUS(0, FALSE, 6);
+	AUDIO_PlayMusic(0, FALSE, 6);
 	PAL_FadeOut(3);
 }
 

+ 24 - 24
fight.c

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

+ 4 - 4
input.c

@@ -92,10 +92,10 @@ PAL_KeyboardEventFilter(
          VIDEO_ToggleScaleScreen();
          break;
       case SDLK_1:
-         SOUND_AdjustVolume(0);
+         AUDIO_AdjustVolume(0);
          break;
       case SDLK_3:
-         SOUND_AdjustVolume(1);
+         AUDIO_AdjustVolume(1);
          break;
 #endif
       case SDLK_UP:
@@ -415,14 +415,14 @@ PAL_MouseEventFilter(
       case 2:
         if( isLeftMouseDBClick )
        {
-          SOUND_AdjustVolume(1);
+          AUDIO_AdjustVolume(1);
           break;
        }
       case 6:
       case 0:
         if( isLeftMouseDBClick )
        {
-          SOUND_AdjustVolume(0);
+          AUDIO_AdjustVolume(0);
           break;
        }
       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);
   mp3_mad->frames_read = 0;
   mad_timer_reset(&mp3_mad->next_frame_start);
-  mp3_mad->volume = 128;
   mp3_mad->status = 0;
   mp3_mad->output_begin = 0;
   mp3_mad->output_end = 0;
@@ -93,6 +92,29 @@ mad_isPlaying(mad_data *mp3_mad) {
   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
    false on failure. */
 static int
@@ -224,8 +246,13 @@ decode_frame(mad_data *mp3_mad) {
         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 */
@@ -236,18 +263,12 @@ decode_frame(mad_data *mp3_mad) {
   right_ch  = pcm->samples[1];
 
   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) {
-      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
 		   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 ------------------------------- */
+		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]) {
 		  int dst_samples = 0, pos = 0, i;
 		  if (mp3_mad->upsample) {
@@ -313,7 +337,7 @@ mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
             while(src_samples > 0) {
               int to_write = resampler_get_free_count(mp3_mad->resampler[i]), 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_samples -= to_write;
@@ -334,12 +358,7 @@ mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
 	  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;
 	mp3_mad->output_begin += 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
 	 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;
   int frames_read;
   mad_timer_t next_frame_start;
-  int volume;
   int status;
   int output_begin, output_end;
   int upsample; /* SDLPAL: Is upsample or downsample */
   int resampler_quality; /* SDLPAL:resampler quality */
   SDL_AudioSpec mixer;
-  SDL_AudioCVT cvt;
+  void (*converter)(signed short *, int);
 
   unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
   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_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_InitResources();
-   SOUND_OpenAudio();
+   AUDIO_OpenDevice();
 
    if (gConfig.fIsWIN95)
    {
@@ -169,7 +169,7 @@ PAL_Shutdown(
 
 --*/
 {
-   SOUND_CloseAudio();
+   AUDIO_CloseDevice();
    PAL_FreeFont();
    PAL_FreeResources();
    PAL_FreeGlobals();
@@ -315,10 +315,10 @@ PAL_SplashScreen(
    //
    // Play the title music
    //
-   if (!SOUND_PlayCDA(7))
+   if (!AUDIO_PlayCDTrack(7))
    {
       fUseCD = FALSE;
-      SOUND_PlayMUS(NUM_RIX_TITLE, TRUE, 2);
+      AUDIO_PlayMusic(NUM_RIX_TITLE, TRUE, 2);
    }
 
    //
@@ -487,7 +487,7 @@ PAL_SplashScreen(
 
    if (!fUseCD)
    {
-      SOUND_PlayMUS(0, FALSE, 1);
+      AUDIO_PlayMusic(0, FALSE, 1);
    }
 
    PAL_FadeOut(1);

+ 2 - 2
midi.c

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

+ 5 - 8
mp3play.c

@@ -33,7 +33,7 @@
 
 typedef struct tagMP3PLAYER
 {
-	MUSICPLAYER_FUNCTIONS;
+	MUSICPLAYER_COMMONS;
 
 	mad_data           *pMP3;
 	INT                 iMusic;
@@ -62,17 +62,14 @@ MP3_FillBuffer(
 {
 	LPMP3PLAYER player = (LPMP3PLAYER)object;
 	if (player->pMP3) {
-		player->pMP3->volume = gConfig.iVolume * 3 / 4;
-
-		mad_getSamples(player->pMP3, stream, len);
-
 		if (!mad_isPlaying(player->pMP3) && player->fLoop)
 		{
 			mad_seek(player->pMP3, 0);
 			mad_start(player->pMP3);
+		}
 
+		if (mad_isPlaying(player->pMP3))
 			mad_getSamples(player->pMP3, stream, len);
-		}
 	}
 }
 
@@ -117,9 +114,9 @@ MP3_Play(
 
 	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)

+ 13 - 14
oggplay.c

@@ -49,7 +49,7 @@
 
 typedef struct tagOGGPLAYER
 {
-	MUSICPLAYER_FUNCTIONS;
+	MUSICPLAYER_COMMONS;
 
 	ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
 	ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
@@ -70,9 +70,9 @@ typedef struct tagOGGPLAYER
 	BOOL             fUseResampler;
 } 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 */
 	if (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)
 {
 	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 {
 		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 {
-			*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;
 			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_clear(player->resampler[i]);
 			}
@@ -264,7 +264,6 @@ OGG_FillBuffer(
 
 	if (player->fReady) {
 		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;
 
 		while (total_bytes < len) {
@@ -331,7 +330,7 @@ OGG_FillBuffer(
 								for (i = 0; i < min(player->vi.channels, 2); i++) {
 									float *mono = pcm[i] + bout;
 									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;
 						for (i = 0; i < bout; i++) {
 							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 {
 								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 {
-									ptr[0] = SDL_SwapLE16(OGG_GetSample(pcm[0][i], volume));
+									ptr[0] = OGG_GetSample(pcm[0][i]);
 								}
 							}
 							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_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_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_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.uCodePage = values[PALCFG_CODEPAGE].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))
 	{
@@ -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_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_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_WINDOWWIDTH), gConfig.dwScreenWidth); fputs(buf, fp);
 

+ 5 - 2
palcfg.h

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

+ 4 - 4
players.h

@@ -20,8 +20,8 @@
 // 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"
 
@@ -33,12 +33,12 @@ extern "C"
 
 typedef struct tagMUSICPLAYER
 {
-#define MUSICPLAYER_FUNCTIONS \
+#define MUSICPLAYER_COMMONS \
 	VOID (*Shutdown)(VOID*); \
 	BOOL (*Play)(VOID*, INT, BOOL, FLOAT); \
 	VOID (*FillBuffer)(VOID*, LPBYTE, INT)
 
-	MUSICPLAYER_FUNCTIONS;
+	MUSICPLAYER_COMMONS;
 } MUSICPLAYER, *LPMUSICPLAYER;
 
 /* RIX */

+ 14 - 17
rixplay.cpp

@@ -34,8 +34,6 @@
 #include "adplug/surroundopl.h"
 #include "adplug/rix.h"
 
-extern "C" BOOL g_fNoMusic;
-
 typedef struct tagRIXPLAYER :
 	public MUSICPLAYER
 {
@@ -81,7 +79,7 @@ RIX_FillBuffer(
 --*/
 {
 	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)
 	{
@@ -116,7 +114,7 @@ RIX_FillBuffer(
 			if (pRixPlayer->iTotalFadeOutSamples == pRixPlayer->iRemainingFadeSamples && pRixPlayer->iTotalFadeOutSamples > 0)
 			{
 				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;
 			}
 			if (pRixPlayer->iCurrentMusic == -1 || pRixPlayer->iRemainingFadeSamples <= 0)
@@ -216,17 +214,16 @@ RIX_FillBuffer(
 						if (to_write)
 						{
 							short *tempBuf = (short*)alloca(to_write * gConfig.iAudioChannels * sizeof(short));
+							int temp_buf_read = 0;
 							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]);
 						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;
 					}
 				}
@@ -241,14 +238,13 @@ RIX_FillBuffer(
 
 			//
 			// Put audio data into buffer and adjust volume
-			// WARNING: for signed 16-bit little-endian only
 			//
 			SHORT* ptr = (SHORT*)stream;
 			if (pRixPlayer->FadeType == RIXPLAYER::NONE)
 			{
 				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);
 				}
 			}
@@ -256,12 +252,13 @@ RIX_FillBuffer(
 			{
 				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->iRemainingFadeSamples -= delta_samples;
+					pRixPlayer->iRemainingFadeSamples -= j;
 				}
 				fContinue = (pRixPlayer->iRemainingFadeSamples > 0);
 			}
@@ -342,7 +339,7 @@ RIX_Play(
 	//
 	// Stop the current CD music.
 	//
-	SOUND_PlayCDA(-1);
+	AUDIO_PlayCDTrack(-1);
 
 	if (iNumRIX == pRixPlayer->iCurrentMusic && pRixPlayer->iNextMusic == -1)
 	{
@@ -482,7 +479,7 @@ RIX_Init(
 		for (int i = 0; i < gConfig.iAudioChannels; i++)
 		{
 			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);
 		}
 	}

+ 7 - 7
script.c

@@ -1587,7 +1587,7 @@ PAL_InterpretInstruction(
       // Set background music
       //
       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;
 
    case 0x0044:
@@ -1648,7 +1648,7 @@ PAL_InterpretInstruction(
       //
       // Play sound effect
       //
-      SOUND_Play(pScript->rgwOperand[0]);
+      AUDIO_PlaySound(pScript->rgwOperand[0]);
       break;
 
    case 0x0049:
@@ -2162,7 +2162,7 @@ PAL_InterpretInstruction(
       //
       // Stop current playing music
       //
-      SOUND_PlayMUS(0, FALSE,
+      AUDIO_PlayMusic(0, FALSE,
          (pScript->rgwOperand[0] == 0) ? 2.0f : (FLOAT)(pScript->rgwOperand[0]) * 2);
       gpGlobals->wNumMusic = 0;
       break;
@@ -2854,7 +2854,7 @@ PAL_InterpretInstruction(
          PAL_BattleBackupScene();
          PAL_LoadBattleSprites();
          PAL_BattleMakeScene();
-         SOUND_Play(212);
+         AUDIO_PlaySound(212);
          PAL_BattleFadeScene();
 
          for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)
@@ -2894,7 +2894,7 @@ PAL_InterpretInstruction(
 
          g_Battle.rgEnemy[wEventObjectID].iColorShift = 0;
 
-		 SOUND_Play(47);
+		 AUDIO_PlaySound(47);
          PAL_BattleBackupScene();
          PAL_LoadBattleSprites();
          PAL_BattleMakeScene();
@@ -2941,9 +2941,9 @@ PAL_InterpretInstruction(
       //
       // 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;
 

+ 287 - 140
sound.c

@@ -33,37 +33,144 @@
 #include <vorbis/codec.h>
 #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
 
 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
 {
    FILE                     *mkf;
    SDL_AudioSpec             spec;
+   SDL_AudioCVT              cvt;
    SDL_mutex                *mtx;
-   LPBYTE                    buf[2], pos[2];
-   INT                       audio_len[2];
-   void                     *resampler;
    MUSICPLAYER              *pMusPlayer;
    MUSICPLAYER              *pCDPlayer;
 #if PAL_HAS_SDLCD
    SDL_CD                   *pCD;
 #endif
-   FNLoadSoundData           LoadSoundData;
+   WAVEPLAYER                wavePlayer;
+   BOOL                      fOpened;
+   BOOL                      fMusicEnabled;
+   BOOL                      fSoundEnabled;
 } SNDPLAYER;
 
 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
 {
 	DWORD   riff_sig;	/* 'RIFF' */
@@ -318,7 +425,7 @@ SOUND_ResampleU8(
 			src_samples -= to_write;
 			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);
 			}
 		}
@@ -330,7 +437,7 @@ SOUND_ResampleU8(
 				resampler_write_sample(resampler, (src[-lpSpec->channels] ^ 0x80) << 8);
 			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);
 			}
 		}
@@ -391,7 +498,7 @@ SOUND_ResampleS16(
 			src_samples -= to_write;
 			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);
 			}
 		}
@@ -404,7 +511,7 @@ SOUND_ResampleS16(
 				resampler_write_sample(resampler, val);
 			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);
 			}
 		}
@@ -412,7 +519,7 @@ SOUND_ResampleS16(
 }
 
 static VOID SDLCALL
-SOUND_FillAudio(
+AUDIO_FillBuffer(
    LPVOID          udata,
    LPBYTE          stream,
    INT             len
@@ -436,18 +543,20 @@ SOUND_FillAudio(
 
 --*/
 {
-   int        i;
-
 #if SDL_VERSION_ATLEAST(2,0,0)
    memset(stream, 0, len);
 #endif
 
+   SDL_mutexP(gSndPlayer.mtx);
+
+   gSndPlayer.cvt.buf = stream;
+   gSndPlayer.cvt.len = len;
+
    //
    // Play music
    //
-   if (!g_fNoMusic)
+   if (gSndPlayer.fMusicEnabled)
    {
-	   SDL_mutexP(gSndPlayer.mtx);
 	   if (gSndPlayer.pMusPlayer)
 	   {
 		   gSndPlayer.pMusPlayer->FillBuffer(gSndPlayer.pMusPlayer, stream, len);
@@ -457,47 +566,43 @@ SOUND_FillAudio(
 	   {
 		   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);
 }
 
@@ -540,14 +645,14 @@ SOUND_LoadMKF(
 		gSndPlayer.mkf = UTIL_OpenFile(mkfs[i]);
 		if (gSndPlayer.mkf)
 		{
-			gSndPlayer.LoadSoundData = func[i];
+			gSndPlayer.wavePlayer.LoadSoundData = func[i];
 			break;
 		}
 	}
 }
 
 INT
-SOUND_OpenAudio(
+AUDIO_OpenDevice(
    VOID
 )
 /*++
@@ -567,7 +672,7 @@ SOUND_OpenAudio(
 {
    SDL_AudioSpec spec;
 
-   if (gSndOpened)
+   if (gSndPlayer.fOpened)
    {
       //
       // Already opened
@@ -575,7 +680,9 @@ SOUND_OpenAudio(
       return -1;
    }
 
-   gSndOpened = FALSE;
+   gSndPlayer.fOpened = FALSE;
+   gSndPlayer.fMusicEnabled = TRUE;
+   gSndPlayer.fSoundEnabled = TRUE;
 
    //
    // Load the MKF file.
@@ -590,7 +697,7 @@ SOUND_OpenAudio(
    // Initialize the resampler
    //
    resampler_init();
-   gSndPlayer.resampler = resampler_create();
+   gSndPlayer.wavePlayer.resampler = resampler_create();
 
    //
    // Open the sound subsystem.
@@ -599,7 +706,7 @@ SOUND_OpenAudio(
    gSndPlayer.spec.format = AUDIO_S16;
    gSndPlayer.spec.channels = gConfig.iAudioChannels;
    gSndPlayer.spec.samples = gConfig.wAudioBufferSize;
-   gSndPlayer.spec.callback = SOUND_FillAudio;
+   gSndPlayer.spec.callback = AUDIO_FillBuffer;
 
    if (SDL_OpenAudio(&gSndPlayer.spec, &spec) < 0)
    {
@@ -608,19 +715,18 @@ SOUND_OpenAudio(
       //
       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();
-   gSndOpened = TRUE;
+   gSndPlayer.fOpened = TRUE;
 
    //
    // Initialize the music subsystem.
@@ -708,7 +814,7 @@ SOUND_OpenAudio(
 }
 
 VOID
-SOUND_CloseAudio(
+AUDIO_CloseDevice(
    VOID
 )
 /*++
@@ -730,16 +836,13 @@ SOUND_CloseAudio(
 
    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)
@@ -763,17 +866,17 @@ SOUND_CloseAudio(
 #if PAL_HAS_SDLCD
    if (gSndPlayer.pCD != NULL)
    {
-      SOUND_PlayCDA(-1);
+      AUDIO_PlayCDTrack(-1);
       SDL_CDClose(gSndPlayer.pCD);
    }
 #endif
 
    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);
@@ -781,15 +884,29 @@ SOUND_CloseAudio(
 }
 
 SDL_AudioSpec*
-SOUND_GetAudioSpec(
+AUDIO_GetDeviceSpec(
 	VOID
 )
 {
 	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
-SOUND_AdjustVolume(
+AUDIO_AdjustVolume(
    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
-SOUND_PlayChannel(
-   INT    iSoundNum,
-   INT    iChannel
+AUDIO_PlaySound(
+   INT    iSoundNum
 )
 /*++
   Purpose:
@@ -839,8 +941,6 @@ SOUND_PlayChannel(
 
     [IN]  iSoundNum - number of the sound; the absolute value is used.
 
-    [IN]  iChannel - the number of channel (0 or 1).
-
   Return value:
 
     None.
@@ -853,22 +953,11 @@ SOUND_PlayChannel(
    LPCBYTE         bufsrc;
    int             len;
 
-   if (!gSndOpened || g_fNoSound)
+   if (!gSndPlayer.fOpened || !gSndPlayer.fSoundEnabled)
    {
       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)
    {
       iSoundNum = -iSoundNum;
@@ -894,7 +983,7 @@ SOUND_PlayChannel(
    //
    PAL_MKFReadChunk(buf, len, iSoundNum, gSndPlayer.mkf);
 
-   bufsrc = gSndPlayer.LoadSoundData(buf, len, &wavespec);
+   bufsrc = gSndPlayer.wavePlayer.LoadSoundData(buf, len, &wavespec);
    if (bufsrc == NULL)
    {
 	   free(buf);
@@ -904,18 +993,18 @@ SOUND_PlayChannel(
    if (wavespec.freq != gSndPlayer.spec.freq)
    {
 	   /* 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 (wavespec.format == AUDIO_S16)
-			   SOUND_ResampleS16(bufsrc, &wavespec, bufdec, len, gSndPlayer.resampler);
+			   SOUND_ResampleS16(bufsrc, &wavespec, bufdec, len, gSndPlayer.wavePlayer.resampler);
 		   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(buf); buf = bufdec;
-		   wavespec.format = AUDIO_S16;
+		   wavespec.format = AUDIO_S16SYS;
 		   wavespec.freq = gSndPlayer.spec.freq;
 	   }
 	   else
@@ -934,7 +1023,7 @@ SOUND_PlayChannel(
    // Build the audio converter and create conversion buffers
    //
    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);
       return;
@@ -953,26 +1042,52 @@ SOUND_PlayChannel(
    //
    // 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
-SOUND_PlayMUS(
+AUDIO_PlayMusic(
    INT       iNumRIX,
    BOOL      fLoop,
    FLOAT     flFadeTime
@@ -991,7 +1106,7 @@ SOUND_PlayMUS(
 }
 
 BOOL
-SOUND_PlayCDA(
+AUDIO_PlayCDTrack(
    INT    iNumTrack
 )
 /*++
@@ -1019,7 +1134,7 @@ SOUND_PlayCDA(
 
          if (iNumTrack != -1)
          {
-            SOUND_PlayMUS(-1, FALSE, 0);
+            AUDIO_PlayMusic(-1, FALSE, 0);
 
             if (SDL_CDPlayTracks(gSndPlayer.pCD, iNumTrack - 1, 0, 1, 0) == 0)
             {
@@ -1034,7 +1149,7 @@ SOUND_PlayCDA(
    {
 	   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);
 	   }
 	   else
@@ -1047,6 +1162,38 @@ SOUND_PlayCDA(
    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
 void
 SOUND_Reload(

+ 30 - 21
sound.h

@@ -30,43 +30,62 @@ extern "C"
 #endif
 
 INT
-SOUND_OpenAudio(
+AUDIO_OpenDevice(
    VOID
 );
 
 VOID
-SOUND_CloseAudio(
+AUDIO_CloseDevice(
    VOID
 );
 
 VOID
-SOUND_PlayChannel(
-   INT    iSoundNum,
-   INT    iChannel
+AUDIO_PlaySound(
+   INT    iSoundNum
 );
 
 SDL_AudioSpec*
-SOUND_GetAudioSpec(
+AUDIO_GetDeviceSpec(
    VOID
 );
 
 VOID
-SOUND_AdjustVolume(
-   INT    iDirectory
+AUDIO_AdjustVolume(
+   INT    iDirection
 );
 
 VOID
-SOUND_PlayMUS(
+AUDIO_PlayMusic(
    INT       iNumRIX,
    BOOL      fLoop,
    FLOAT     flFadeTime
 );
 
 BOOL
-SOUND_PlayCDA(
+AUDIO_PlayCDTrack(
    INT    iNumTrack
 );
 
+VOID
+AUDIO_EnableMusic(
+   BOOL   fEnable
+);
+
+BOOL
+AUDIO_MusicEnabled(
+   VOID
+);
+
+VOID
+AUDIO_EnableSound(
+   BOOL   fEnable
+);
+
+BOOL
+AUDIO_SoundEnabled(
+   VOID
+);
+
 #ifdef PSP
 VOID
 SOUND_Reload(
@@ -74,17 +93,7 @@ SOUND_Reload(
 );
 #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
 }

+ 7 - 14
uigame.c

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

+ 22 - 13
unix/unix.cpp

@@ -37,7 +37,8 @@ struct {
    Fl_Check_Button* surround;
    Fl_Int_Input* buffer;
    Fl_Hor_Value_Slider* quality;
-   Fl_Hor_Value_Slider* volume;
+   Fl_Hor_Value_Slider* music;
+   Fl_Hor_Value_Slider* sound;
 } gWidgets;
 
 struct {
@@ -62,7 +63,8 @@ struct {
    const char* surround;
    const char* buffer;
    const char* quality;
-   const char* volume;
+   const char* musvol;
+   const char* sndvol;
    const char* exit;
    const char* launch;
    const char* def;
@@ -71,17 +73,17 @@ struct {
      "&Traditional Chinese", "&Simplified Chinese", "Message file:", "Use &embedded font",
      "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:",
-     "Quality:", "Volume:", "E&xit", "&Launch game", "&Default" },
+     "Quality:", "Music volume:", "Sound volume:", "E&xit", "&Launch game", "&Default" },
    { "SDLPAL 启动器", "游戏语言设置", "显示设置", "音频设置", "游戏资源目录:",
      "繁体中文(&T)", "简体中文(&S)", "语言文件:", "使用游戏资源内嵌字体(&E)",
      "启用触屏辅助(&H)", "保持纵横比(&K)", "全屏模式(&F)", "&CD 音源:", "&BGM 音源:",
      "&OPL 类型:", "采样率:", "立体声(&R)", "OPL 采样率:", "环绕声 O&PL", "缓冲区:",
-     "质量:", "音量:", "退出(&X)", "启动游戏(&L)", "默认设置(&D)" },
+     "质量:", "音乐音量:", "音效音量:", "退出(&X)", "启动游戏(&L)", "默认设置(&D)" },
    { "SDLPAL 啟動器", "遊戲語言設置", "顯示設定", "音訊設定", "遊戲資源目錄:",
      "繁體中文(&T)", "簡體中文(&S)", "語言檔:", "使用遊戲資源內嵌字體(&E)",
      "啟用觸屏輔助(&H)", "保持縱橫比(&K)", "全屏模式(&F)", "&CD 音源:", "&BGM 音源:",
      "&OPL 類型:", "取樣速率:", "立體聲(&R)", "OPL 取樣速率:", "環繞聲 O&PL", "緩衝區:",
-     "品質:", "音量:", "退出(&X)", "啟動遊戲(&L)", "默認設定(&D)" },
+     "品質:", "音樂音量:", "音效音量:", "退出(&X)", "啟動遊戲(&L)", "默認設定(&D)" },
 };
 
 void InitControls()
@@ -104,7 +106,8 @@ void InitControls()
    gWidgets.surround->value(gConfig.fUseSurroundOPL ? 1 : 0);
    sprintf(buffer, "%d", gConfig.wAudioBufferSize); gWidgets.buffer->value(buffer);
    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()
@@ -127,7 +130,8 @@ void SaveControls()
    gConfig.fUseSurroundOPL = gWidgets.surround->value();
    gConfig.wAudioBufferSize = atoi(gWidgets.buffer->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;
 }
 
@@ -164,7 +168,7 @@ Fl_Window* InitWindow()
    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);
 
-   (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.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);
@@ -174,15 +178,20 @@ Fl_Window* InitWindow()
    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.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->bounds(0, 4);
    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) {
       if (ctrl->when() == FL_WHEN_RELEASE)

+ 21 - 24
win32/resource.h

@@ -6,29 +6,26 @@
 #define IDD_LAUNCHER                    101
 #define IDS_CONFIRM                     103
 #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
 
 // Next default values for new objects
@@ -37,7 +34,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        104
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1035
+#define _APS_NEXT_CONTROL_VALUE         1021
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

+ 90 - 99
win32/sdlpal.rc

@@ -34,45 +34,42 @@ BEGIN
     PUSHBUTTON      "E&xit",IDCANCEL,7,185,50,14
     LTEXT           "Game resource path:",IDC_STATIC,14,10,68,8
     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
-    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
-    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
-    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
-    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
-    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
+    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
 
 
@@ -174,45 +171,42 @@ BEGIN
     PUSHBUTTON      "退出(&X)",IDCANCEL,7,185,50,14
     LTEXT           "游戏资源目录:",IDC_STATIC,14,10,57,8
     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
-    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
-    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
-    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
-    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
-    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
+    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
 
 
@@ -389,45 +383,42 @@ BEGIN
     PUSHBUTTON      "癶�(&X)",IDCANCEL,7,185,50,14
     LTEXT           "笴栏戈方郎Ж�",IDC_STATIC,14,10,57,8
     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
-    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
-    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
-    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
-    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
-    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
+    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
 
 

+ 9 - 12
win32/win32.cpp

@@ -11,6 +11,7 @@
 #include "../global.h"
 #include "../util.h"
 #include "../palcfg.h"
+#include "../resampler.h"
 
 #pragma comment(lib, "comctl32.lib")
 #pragma comment(linker,"\"/manifestdependency:type='win32' \
@@ -102,21 +103,19 @@ void SaveSettings(HWND hwndDlg, BOOL fWriteFile)
 	gConfig.fUseTouchOverlay = IsDlgButtonChecked(hwndDlg, IDC_TOUCHOVERLAY);
 	gConfig.fUseEmbeddedFonts = IsDlgButtonChecked(hwndDlg, IDC_EMBEDFONT);
 	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.eMusicType = (MUSICTYPE)ComboBox_GetCurSel(hwndDlg, IDC_BGM);
 	gConfig.eOPLType = (OPLTYPE)(ComboBox_GetCurSel(hwndDlg, IDC_OPL));
 	gConfig.iAudioChannels = IsDlgButtonChecked(hwndDlg, IDC_STEREO) ? 2 : 1;
 	gConfig.iSampleRate = GetDlgItemInt(hwndDlg, IDC_SAMPLERATE, 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);
 	if (gConfig.eMusicType == MUSIC_RIX)
 	{
 		gConfig.fUseSurroundOPL = IsDlgButtonChecked(hwndDlg, IDC_SURROUNDOPL);
 		gConfig.iOPLSampleRate = GetDlgItemInt(hwndDlg, IDC_OPLSR, nullptr, FALSE);
-		gConfig.iSurroundOPLOffset = GetDlgItemInt(hwndDlg, IDC_OPLOFFSET, nullptr, TRUE);
 	}
 
 	if (fWriteFile) PAL_SaveConfig();
@@ -128,7 +127,6 @@ void ResetControls(HWND hwndDlg)
 
 	EnableDlgItem(hwndDlg, IDC_OPL, 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);
 
 	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_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_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));
 
 	if (gConfig.pszGamePath) SetDlgItemTextA(hwndDlg, IDC_GAMEPATH, gConfig.pszGamePath);
 	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_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)
@@ -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("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);
 
 	WINDOWINFO wi = { sizeof(WINDOWINFO) };
@@ -236,7 +234,6 @@ INT_PTR ComboBoxProc(HWND hwndDlg, WORD idControl, HWND hwndCtrl)
 	case IDC_BGM:
 		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_OPLOFFSET, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		EnableDlgItem(hwndDlg, IDC_OPLSR, ComboBox_GetCurSel(hwndDlg, IDC_BGM) == MUSIC_RIX);
 		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="tsKeepAspect" x:Uid="AspectRatio" 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" />
                 <ComboBox x:Name="cbSampleRate" x:Uid="Samplerate" HorizontalAlignment="Stretch" Header="音频输出采样率" PlaceholderText="音频输出采样率">
                     <ComboBoxItem Content="11025"/>

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

@@ -49,7 +49,8 @@ void SDLPal::MainPage::LoadControlContents()
 	tsSurroundOPL->IsOn = (gConfig.fUseSurroundOPL == 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;
 
 	cbCD->SelectedIndex = (gConfig.eCDType == MUSIC_MP3) ? 0 : 1;
@@ -97,7 +98,8 @@ void SDLPal::MainPage::SaveControlContents()
 	gConfig.fUseSurroundOPL = tsSurroundOPL->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.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">
     <value>No customized message file</value>
   </data>
+  <data name="MusicVolume.Header" xml:space="preserve">
+    <value>Music volume</value>
+  </data>
   <data name="OPL.Header" xml:space="preserve">
     <value>Type of OPL simulator</value>
   </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">
     <value>Sample rate of audio output</value>
   </data>
+  <data name="SoundVolume.Header" xml:space="preserve">
+    <value>Sound volume</value>
+  </data>
   <data name="Stereo.Header" xml:space="preserve">
     <value>Stereo</value>
   </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">
     <value>Yes</value>
   </data>
-  <data name="Volume.Header" xml:space="preserve">
-    <value>Volume</value>
-  </data>
 </root>

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

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

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

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