Changes

Jump to navigation Jump to search
→‎Manage audio in C#: rewrite playing sound effects for Stardew Valley 1.6, add TODOs for other sections
Line 2,997: Line 2,997:     
==Manage audio in C#==
 
==Manage audio in C#==
===Overview===
+
===Play sound effects===
Here is a reference chart for sound methods which you can use for various cases:
+
The game mostly handles sound effects through the <samp>Game1.sounds</samp> field. This has low-level methods like <samp>PlayLocal</samp>, <samp>PlayAll</samp>, <samp>GetVolumeForDistance</samp>, etc.
 +
 
 +
However, you should rarely call <samp>Game1.sounds</samp> directly. Instead the game has four main methods for playing a sound effect:
    
{| class="wikitable"
 
{| class="wikitable"
|+ Singleplayer and multiplayer sound functions
  −
|-
  −
! Singleplayer only name !! Multiplayer equivalent !! Use case
  −
|-
  −
| <samp>Game1.playSound</samp> || N/A || UI and menu sounds; playing a sound for one player only
   
|-
 
|-
| <samp>GameLocation.localSound</samp> || <samp>GameLocation.playSound</samp> || For any in-game interactions on specific maps only
+
! method
 +
! usage
 
|-
 
|-
| <samp>GameLocation.localSoundAt</samp> || <samp>GameLocation.playSoundAt</samp> || For playing spatial sounds in specific tiles or coordinates, which change volume and location based on player proximity
+
| <samp>Game1.playSound</samp>
|-
+
| Play a sound for the current player only, which isn't synced in multiplayer and isn't affected by location or distance. This is mainly used for UI and menu sounds.
| <samp>Game1.playSoundPitched</samp> || <samp>GameLocation.playSoundPitched</samp> || For playing any sounds at a different pitch than the original sound
  −
|-
  −
| <samp>DelayedAction.playSoundAfterDelay</samp> || N/A || For playing sounds after a specific period of time has passed
  −
|}
     −
===Play client-side sounds===
+
For example:
<dt><samp>Game1.playSound</samp></dt>
  −
<dd>
  −
You can play a sound for the current player only, played from no specific location, by calling the <samp>Game1.playSound()</samp> method. For example:
   
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// For UI elements, such as when the player crafts a new item.
+
// for UI elements (e.g. crafting an item)
 
Game1.playSound("crafting");
 
Game1.playSound("crafting");
 
</syntaxhighlight>
 
</syntaxhighlight>
This is useful for playing sounds in user interfaces, such as menus, where you don't need to play the sound from any particular map or player location.
+
|-
</dd>
+
| <samp>GameLocation.localSound</samp><br /><samp>GameLocation.playSound</samp>
 +
| Play a sound for the current player (<samp>localSound</samp>) or all players (<samp>playSound</samp>) if they're in this location.
 +
 
 +
You can optionally specify...
 +
* a tile position (which attenuates volume for each player based on their distance from the sound's source);
 +
* and/or pitch (from 0 to 2400 with intervals of 100 between every half step, where 1200 is the default pitch).
   −
<dt><samp>GameLocation.localSound</samp></dt>
+
For example:
<dd>
  −
Similarly, you can play a sound for the current player only, played from a specific map, by calling the <samp>GameLocation.localSound()</samp> method:
   
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// For playing sounds in specific maps, such as a shipping bin on a farm.
+
// play sound for the current player if they're anywhere on the farm
if (this.shippingBinLid.pingPongMotion != 1 && Game1.currentLocation.Equals(this.farm))
+
Game1.getFarm().localSound("doorCreak");
{
  −
    this.farm.localSound("doorCreak");
  −
}
  −
</syntaxhighlight>
  −
You can use this to assure that a sound is being played and heard only from a specific map.
  −
</dd>
     −
<dt><samp>GameLocation.localSoundAt</samp></dt>
+
// play sound for the current player if they're on the farm near the mailbox (fading with distance)
<dd>
+
Farm farm = Game1.getFarm();
This works just like the <samp>localSound</samp> method, except that it plays spatial audio, and will adjust the played sound's volume and position based on its proximity from the player. Sounds played from <samp>GameLocation.localSoundAt()</samp> will not be heard if the provided position is off-screen.
+
farm.localSound("doorCreak", farm.GetMainMailboxPosition());
<syntaxhighlight lang="c#">
  −
// You can use this method to play sounds
  −
// that are far from, or close to the player.
  −
// This is some of the code used for the running sounds, played while riding on a horse.
  −
public virtual void PerformDefaultHorseFootstep(string step_type)
  −
{
  −
    // ...
  −
    if (step_type == "Wood")
  −
    {
  −
        if (this.rider.ShouldHandleAnimationSound())
  −
        {
  −
            this.rider.currentLocation.localSoundAt("woodyStep", base.getTileLocation());
  −
        }
  −
    // ...
  −
</syntaxhighlight>
  −
</dd>
     −
<dt><samp>Game1.playSoundPitched</samp></dt>
+
// play sound for all players on the farm near the mailbox (fading with distance), with a -200 pitch shift
<dd>
+
Farm farm = Game1.getFarm();
If desired, you can pitch shift a sound at intervals of 100 per half step, with 1200 being the pitch of the original sample.
+
farm.playSound("doorCreak", farm.GetMainMailboxPosition(), 1000);
<br />
  −
To play a sound at a higher or lower pitch, for the current player only with no specific location, you can call the <samp>Game1.playSoundPitched()</samp> method:
  −
<syntaxhighlight lang="c#">
  −
// The singleplayer code for Elliott's piano,
  −
// located in his cabin.
  −
switch (key)
  −
{
  −
  case 1:
  −
    this.playSoundPitched("toyPiano", 1100);
  −
    break;
  −
  case 2:
  −
    this.playSoundPitched("toyPiano", 1500);
  −
    break;
  −
  case 3:
  −
    this.playSoundPitched("toyPiano", 1600);
  −
    break;
  −
  case 4:
  −
    this.playSoundPitched("toyPiano", 1800);
  −
    break;
  −
}
   
</syntaxhighlight>
 
</syntaxhighlight>
</dd>
+
|-
 +
| <samp>DelayedAction.playSoundAfterDelay</samp>
 +
| Play a sound for the current or all players after a specified delay in milliseconds. You can optionally specify a location, tile position, and pitch (which works the same way as the <samp>GameLocation</samp> methods). You can call this method repeatedly to play multiple sounds (e.g. for a sequence of sounds with different delays).
   −
<dt><samp>DelayedAction.playSoundAfterDelay</samp></dt>
+
For example:
<dd>
  −
Sometimes, you need to play a sound after waiting a certain period of time, for the current player at no particular location. In this case, you can call the <samp>DelayedAction.playSoundAfterDelay()</samp> method:
  −
<syntaxhighlight lang="c#">
  −
// During a lightning storm, if the random chance is met,
  −
// the screen will flash, and then
  −
// a distant lightning strike sound will play after a
  −
// randomly generated duration of time in milliseconds
  −
if (Game1.random.NextDouble() < 0.5)
  −
  DelayedAction.screenFlashAfterDelay((float) (0.3 + Game1.random.NextDouble()), Game1.random.Next(500, 1000));
  −
DelayedAction.playSoundAfterDelay("thunder_small", Game1.random.Next(500, 1500));
  −
// ...
  −
</syntaxhighlight>
  −
You can also change the sound's pitch with this function, or call this function several times at once to call them in a predetermined order:
   
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// When using the phone that is purchasable from the Carpenter's Shop,
+
// play sound for the current player after 1.5 seconds, no matter where they are
// it will play a specific sequence of dial beeps at predetermined times:
+
DelayedAction.playSoundAfterDelay("thunder_small", 1500);
private void playShopPhoneNumberSounds(string whichShop)
  −
{
  −
  Random random = new Random(whichShop.GetHashCode());
  −
  DelayedAction.playSoundAfterDelay("telephone_dialtone", 495, pitch: 1200);
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 1200, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 1370, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 1600, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 1850, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 2030, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 2250, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_buttonPush", 2410, pitch: (1200 + random.Next(-4, 5) * 100));
  −
  DelayedAction.playSoundAfterDelay("telephone_ringingInEar", 3150);
  −
}
  −
</syntaxhighlight>
  −
</dd>
     −
===Play multiplayer sounds===
+
// play sound for all players on the farm after 1.5 seconds, fading with distance from the mailbox
The methods in this section will let you play sounds across different clients in a multiplayer game.
+
Farm farm = Game1.getFarm();
<br />
+
DelayedAction.playSoundAfterDelay("doorCreak", farm, farm.GetMainMailboxPosition());
Sounds played with multiplayer methods will run in singleplayer as well as multiplayer.
     −
<dt><samp>GameLocation.playSound</samp></dt>
+
// play sound for the current player only if they'rte on the farm after 1.5 seconds, fading with distance from the mailbox
<dd>
+
Farm farm = Game1.getFarm();
This method will play a sound for all players located on the same map, but not from a particular position:
+
DelayedAction.playSoundAfterDelay("doorCreak", farm, farm.GetMainMailboxPosition(), local: true);
<syntaxhighlight lang="c#">
  −
// When a player places a new structure, a sound will be played
  −
// for the players that are at the same location,
  −
// ie. on the farm.
  −
public virtual void performActionOnConstruction(GameLocation location)
  −
{
  −
    this.load();
  −
    location.playSound("axchop");
  −
    // ...
   
</syntaxhighlight>
 
</syntaxhighlight>
</dd>
+
|}
   −
<dt><samp>GameLocation.playSoundAt</samp></dt>
+
===Add custom audio===
<dd>
+
'''TODO: update for [[Modding:Migrate to Stardew Valley 1.6#Custom audio|custom audio in Stardew Valley 1.6]]'''
Like <samp>localSoundAt</samp>, this method can be used to play sounds spatially at a specific map and location, and will adjust the played sound's volume and position based on its proximity from a nearby player. A player will not hear any sound played from the <samp>GameLocation.playSoundAt()</samp> method if the provided position is off-screen:
  −
<syntaxhighlight lang="c#">
  −
// The sound code for when Clint is metalworking in the Blacksmith.
  −
private void clintHammerSound(Farmer who)
  −
{
  −
    base.currentLocation.playSoundAt("hammer", base.getTileLocation());
  −
}
  −
</syntaxhighlight>
  −
</dd>
     −
<dt><samp>GameLocation.playSoundPitched</samp></dt>
  −
<dd>
  −
Like <samp>Game1.playSoundPitched</samp>, you can repitch sounds by providing a pitch from 0 to 2400, with intervals of 100 between every half step. However, with the <samp>GameLocation.playSoundPitched</samp> function, you must specify a map location to play the sound in, which any player in that location will hear.
  −
</dd>
  −
  −
===Add custom audio===
   
Game audio is split up into components:
 
Game audio is split up into components:
 
*The SoundEffect is the object that stores the sound audio itself.
 
*The SoundEffect is the object that stores the sound audio itself.
Line 3,207: Line 3,108:     
===Edit existing audio===
 
===Edit existing audio===
 +
'''TODO: update for [[Modding:Migrate to Stardew Valley 1.6#Custom audio|custom audio in Stardew Valley 1.6]]'''
 +
 
To modify a cue that exists in the game, you can declare it from an existing cue as a new cue definition, and invoke <samp>CueDefinition.SetSound</samp> to apply your new audio to the cue.
 
To modify a cue that exists in the game, you can declare it from an existing cue as a new cue definition, and invoke <samp>CueDefinition.SetSound</samp> to apply your new audio to the cue.
  
manager
8,549

edits

Navigation menu