mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 13:20:35 +00:00
Merge branch 'music' into 'master'
Rework music system See merge request OpenMW/openmw!3372
This commit is contained in:
commit
12159d95f3
@ -75,6 +75,7 @@
|
||||
Feature #3537: Shader-based water ripples
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
Feature #6149: Dehardcode Lua API_REVISION
|
||||
Feature #6152: Playing music via lua scripts
|
||||
Feature #6447: Add LOD support to Object Paging
|
||||
Feature #6491: Add support for Qt6
|
||||
Feature #6556: Lua API for sounds
|
||||
@ -99,6 +100,7 @@
|
||||
Feature #7477: NegativeLight Magic Effect flag
|
||||
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
||||
Feature #7546: Start the game on Fredas
|
||||
Feature #7568: Uninterruptable scripted music
|
||||
Task #5896: Do not use deprecated MyGUI properties
|
||||
Task #7113: Move from std::atoi to std::from_char
|
||||
Task #7117: Replace boost::scoped_array with std::vector
|
||||
|
@ -71,7 +71,7 @@ message(STATUS "Configuring OpenMW...")
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 49)
|
||||
set(OPENMW_VERSION_RELEASE 0)
|
||||
set(OPENMW_LUA_API_REVISION 47)
|
||||
set(OPENMW_LUA_API_REVISION 48)
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "")
|
||||
set(OPENMW_VERSION_TAGHASH "")
|
||||
|
@ -913,7 +913,13 @@ void OMW::Engine::go()
|
||||
{
|
||||
// start in main menu
|
||||
mWindowManager->pushGuiMode(MWGui::GM_MainMenu);
|
||||
mSoundManager->playPlaylist("Title");
|
||||
|
||||
std::string titlefile = "music/special/morrowind title.mp3";
|
||||
if (mVFS->exists(titlefile))
|
||||
mSoundManager->streamMusic(titlefile, MWSound::MusicType::Special);
|
||||
else
|
||||
Log(Debug::Warning) << "Title music not found";
|
||||
|
||||
std::string_view logo = Fallback::Map::getString("Movies_Morrowind_Logo");
|
||||
if (!logo.empty())
|
||||
mWindowManager->playVideo(logo, /*allowSkipping*/ true, /*overrideSounds*/ false);
|
||||
|
@ -26,6 +26,11 @@ namespace ESM
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
enum class MusicType;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
@ -282,6 +287,9 @@ namespace MWBase
|
||||
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||
|
||||
virtual MWSound::MusicType getMusicType() const = 0;
|
||||
virtual void setMusicType(MWSound::MusicType type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,14 @@ namespace MWSound
|
||||
MaxCount
|
||||
};
|
||||
|
||||
enum class MusicType
|
||||
{
|
||||
Special,
|
||||
Explore,
|
||||
Battle,
|
||||
Scripted
|
||||
};
|
||||
|
||||
class Sound;
|
||||
class Stream;
|
||||
struct Sound_Decoder;
|
||||
@ -101,12 +109,17 @@ namespace MWBase
|
||||
|
||||
virtual void processChangedSettings(const std::set<std::pair<std::string, std::string>>& settings) = 0;
|
||||
|
||||
virtual bool isEnabled() const = 0;
|
||||
///< Returns true if sound system is enabled
|
||||
|
||||
virtual void stopMusic() = 0;
|
||||
///< Stops music if it's playing
|
||||
|
||||
virtual void streamMusic(const std::string& filename) = 0;
|
||||
virtual void streamMusic(const std::string& filename, MWSound::MusicType type, float fade = 1.f) = 0;
|
||||
///< Play a soundifle
|
||||
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||
/// \param filename name of a sound file in the data directory.
|
||||
/// \param type music type.
|
||||
/// \param fade time in seconds to fade out current track before start this one.
|
||||
|
||||
virtual bool isMusicPlaying() = 0;
|
||||
///< Returns true if music is playing
|
||||
|
@ -214,7 +214,8 @@ namespace MWGui
|
||||
center();
|
||||
|
||||
// Play LevelUp Music
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Triumph.mp3");
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(
|
||||
"Music/Special/MW_Triumph.mp3", MWSound::MusicType::Special);
|
||||
}
|
||||
|
||||
void LevelupDialog::onOkButtonClicked(MyGUI::Widget* sender)
|
||||
|
@ -95,6 +95,15 @@ namespace MWLua
|
||||
return MWBase::Environment::get().getSoundManager()->getSoundPlaying(MWWorld::Ptr(), fileName);
|
||||
};
|
||||
|
||||
api["streamMusic"] = [](std::string_view fileName) {
|
||||
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
sndMgr->streamMusic(std::string(fileName), MWSound::MusicType::Scripted);
|
||||
};
|
||||
|
||||
api["isMusicPlaying"] = []() { return MWBase::Environment::get().getSoundManager()->isMusicPlaying(); };
|
||||
|
||||
api["stopMusic"] = []() { MWBase::Environment::get().getSoundManager()->stopMusic(); };
|
||||
|
||||
return LuaUtil::makeReadOnly(api);
|
||||
}
|
||||
|
||||
@ -103,6 +112,8 @@ namespace MWLua
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
api["isEnabled"] = []() { return MWBase::Environment::get().getSoundManager()->isEnabled(); };
|
||||
|
||||
api["playSound3d"]
|
||||
= [](std::string_view soundId, const Object& object, const sol::optional<sol::table>& options) {
|
||||
auto args = getPlaySoundArgs(options);
|
||||
|
@ -1285,7 +1285,7 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::updateCombatMusic()
|
||||
bool Actors::playerHasHostiles() const
|
||||
{
|
||||
const MWWorld::Ptr player = getPlayer();
|
||||
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
||||
@ -1315,19 +1315,7 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
|
||||
// check if we still have any player enemies to switch music
|
||||
if (mCurrentMusic != MusicType::Explore && !hasHostiles
|
||||
&& !(player.getClass().getCreatureStats(player).isDead()
|
||||
&& MWBase::Environment::get().getSoundManager()->isMusicPlaying()))
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
mCurrentMusic = MusicType::Explore;
|
||||
}
|
||||
else if (mCurrentMusic != MusicType::Battle && hasHostiles)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
||||
mCurrentMusic = MusicType::Battle;
|
||||
}
|
||||
return hasHostiles;
|
||||
}
|
||||
|
||||
void Actors::predictAndAvoidCollisions(float duration) const
|
||||
@ -1735,8 +1723,6 @@ namespace MWMechanics
|
||||
killDeadActors();
|
||||
updateSneaking(playerCharacter, duration);
|
||||
}
|
||||
|
||||
updateCombatMusic();
|
||||
}
|
||||
|
||||
void Actors::notifyDied(const MWWorld::Ptr& actor)
|
||||
@ -1806,7 +1792,8 @@ namespace MWMechanics
|
||||
// player's death animation is over
|
||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||
// Play Death Music if it was the player dying
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3");
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(
|
||||
"Music/Special/MW_Death.mp3", MWSound::MusicType::Special);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -74,9 +74,6 @@ namespace MWMechanics
|
||||
void dropActors(const MWWorld::CellStore* cellStore, const MWWorld::Ptr& ignore);
|
||||
///< Deregister all actors (except for \a ignore) in the given cell.
|
||||
|
||||
void updateCombatMusic();
|
||||
///< Update combat music state
|
||||
|
||||
void update(float duration, bool paused);
|
||||
///< Update actor stats and store desired velocity vectors in \a movement
|
||||
|
||||
@ -159,19 +156,14 @@ namespace MWMechanics
|
||||
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
||||
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
bool playerHasHostiles() const;
|
||||
|
||||
int getGreetingTimer(const MWWorld::Ptr& ptr) const;
|
||||
float getAngleToPlayer(const MWWorld::Ptr& ptr) const;
|
||||
GreetingState getGreetingState(const MWWorld::Ptr& ptr) const;
|
||||
bool isTurningToPlayer(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
private:
|
||||
enum class MusicType
|
||||
{
|
||||
Title,
|
||||
Explore,
|
||||
Battle
|
||||
};
|
||||
|
||||
std::map<ESM::RefId, int> mDeathCount;
|
||||
std::list<Actor> mActors;
|
||||
std::map<const MWWorld::LiveCellRefBase*, std::list<Actor>::iterator> mIndex;
|
||||
@ -182,7 +174,6 @@ namespace MWMechanics
|
||||
float mTimerUpdateHello = 0;
|
||||
float mSneakTimer = 0; // Times update of sneak icon
|
||||
float mSneakSkillTimer = 0; // Times sneak skill progress from "avoid notice"
|
||||
MusicType mCurrentMusic = MusicType::Title;
|
||||
|
||||
void updateVisibility(const MWWorld::Ptr& ptr, CharacterController& ctrl) const;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
@ -257,6 +258,7 @@ namespace MWMechanics
|
||||
, mClassSelected(false)
|
||||
, mRaceSelected(false)
|
||||
, mAI(true)
|
||||
, mMusicType(MWSound::MusicType::Special)
|
||||
{
|
||||
// buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
||||
}
|
||||
@ -340,6 +342,8 @@ namespace MWMechanics
|
||||
|
||||
mActors.update(duration, paused);
|
||||
mObjects.update(duration, paused);
|
||||
|
||||
updateMusicState();
|
||||
}
|
||||
|
||||
void MechanicsManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||
@ -1572,6 +1576,31 @@ namespace MWMechanics
|
||||
return (Misc::Rng::roll0to99(prng) >= target);
|
||||
}
|
||||
|
||||
void MechanicsManager::updateMusicState()
|
||||
{
|
||||
bool musicPlaying = MWBase::Environment::get().getSoundManager()->isMusicPlaying();
|
||||
|
||||
// Can not interrupt scripted music by built-in playlists
|
||||
if (mMusicType == MWSound::MusicType::Scripted && musicPlaying)
|
||||
return;
|
||||
|
||||
const MWWorld::Ptr& player = MWMechanics::getPlayer();
|
||||
bool hasHostiles = mActors.playerHasHostiles();
|
||||
|
||||
// check if we still have any player enemies to switch music
|
||||
if (mMusicType != MWSound::MusicType::Explore && !hasHostiles
|
||||
&& !(player.getClass().getCreatureStats(player).isDead() && musicPlaying))
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
mMusicType = MWSound::MusicType::Explore;
|
||||
}
|
||||
else if (mMusicType != MWSound::MusicType::Battle && hasHostiles)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
||||
mMusicType = MWSound::MusicType::Battle;
|
||||
}
|
||||
}
|
||||
|
||||
void MechanicsManager::startCombat(const MWWorld::Ptr& ptr, const MWWorld::Ptr& target)
|
||||
{
|
||||
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
|
@ -11,6 +11,11 @@
|
||||
#include "npcstats.hpp"
|
||||
#include "objects.hpp"
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
enum class MusicType;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class CellStore;
|
||||
@ -33,6 +38,8 @@ namespace MWMechanics
|
||||
typedef std::map<ESM::RefId, OwnerMap> StolenItemsMap;
|
||||
StolenItemsMap mStolenItems;
|
||||
|
||||
MWSound::MusicType mMusicType;
|
||||
|
||||
public:
|
||||
void buildPlayer();
|
||||
///< build player according to stored class/race/birthsign information. Will
|
||||
@ -232,7 +239,11 @@ namespace MWMechanics
|
||||
GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override;
|
||||
bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override;
|
||||
|
||||
MWSound::MusicType getMusicType() const override { return mMusicType; }
|
||||
void setMusicType(MWSound::MusicType type) override { mMusicType = type; }
|
||||
|
||||
private:
|
||||
void updateMusicState();
|
||||
bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||
bool canReportCrime(
|
||||
const MWWorld::Ptr& actor, const MWWorld::Ptr& victim, std::set<MWWorld::Ptr>& playerFollowers);
|
||||
|
@ -63,10 +63,11 @@ namespace MWScript
|
||||
public:
|
||||
void execute(Interpreter::Runtime& runtime) override
|
||||
{
|
||||
std::string sound{ runtime.getStringLiteral(runtime[0].mInteger) };
|
||||
std::string music{ runtime.getStringLiteral(runtime[0].mInteger) };
|
||||
runtime.pop();
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(sound);
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(
|
||||
Misc::ResourceHelpers::correctMusicPath(music), MWSound::MusicType::Scripted);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <components/vfs/pathutil.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
@ -131,15 +132,6 @@ namespace MWSound
|
||||
|
||||
Log(Debug::Info) << stream.str();
|
||||
}
|
||||
|
||||
// TODO: dehardcode this
|
||||
std::vector<std::string> titleMusic;
|
||||
std::string_view titlefile = "music/special/morrowind title.mp3";
|
||||
if (mVFS->exists(titlefile))
|
||||
titleMusic.emplace_back(titlefile);
|
||||
else
|
||||
Log(Debug::Warning) << "Title music not found";
|
||||
mMusicFiles["Title"] = titleMusic;
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager()
|
||||
@ -250,7 +242,7 @@ namespace MWSound
|
||||
if (filename.empty())
|
||||
return;
|
||||
|
||||
Log(Debug::Info) << "Playing " << filename;
|
||||
Log(Debug::Info) << "Playing \"" << filename << "\"";
|
||||
mLastPlayedMusic = filename;
|
||||
|
||||
DecoderPtr decoder = getDecoder();
|
||||
@ -260,7 +252,7 @@ namespace MWSound
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "Failed to load audio from " << filename << ": " << e.what();
|
||||
Log(Debug::Error) << "Failed to load audio from \"" << filename << "\": " << e.what();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -274,7 +266,7 @@ namespace MWSound
|
||||
mOutput->streamSound(decoder, mMusic.get());
|
||||
}
|
||||
|
||||
void SoundManager::advanceMusic(const std::string& filename)
|
||||
void SoundManager::advanceMusic(const std::string& filename, float fadeOut)
|
||||
{
|
||||
if (!isMusicPlaying())
|
||||
{
|
||||
@ -284,7 +276,7 @@ namespace MWSound
|
||||
|
||||
mNextMusic = filename;
|
||||
|
||||
mMusic->setFadeout(1.f);
|
||||
mMusic->setFadeout(fadeOut);
|
||||
}
|
||||
|
||||
void SoundManager::startRandomTitle()
|
||||
@ -319,16 +311,30 @@ namespace MWSound
|
||||
tracklist.pop_back();
|
||||
}
|
||||
|
||||
void SoundManager::streamMusic(const std::string& filename)
|
||||
{
|
||||
advanceMusic("Music/" + filename);
|
||||
}
|
||||
|
||||
bool SoundManager::isMusicPlaying()
|
||||
{
|
||||
return mMusic && mOutput->isStreamPlaying(mMusic.get());
|
||||
}
|
||||
|
||||
void SoundManager::streamMusic(const std::string& filename, MusicType type, float fade)
|
||||
{
|
||||
const auto mechanicsManager = MWBase::Environment::get().getMechanicsManager();
|
||||
|
||||
// Can not interrupt scripted music by built-in playlists
|
||||
if (mechanicsManager->getMusicType() == MusicType::Scripted && type != MusicType::Scripted
|
||||
&& type != MusicType::Special)
|
||||
return;
|
||||
|
||||
std::string normalizedName = VFS::Path::normalizeFilename(filename);
|
||||
|
||||
mechanicsManager->setMusicType(type);
|
||||
advanceMusic(normalizedName, fade);
|
||||
if (type == MWSound::MusicType::Battle)
|
||||
mCurrentPlaylist = "Battle";
|
||||
else if (type == MWSound::MusicType::Explore)
|
||||
mCurrentPlaylist = "Explore";
|
||||
}
|
||||
|
||||
void SoundManager::playPlaylist(const std::string& playlist)
|
||||
{
|
||||
if (mCurrentPlaylist == playlist)
|
||||
@ -337,7 +343,8 @@ namespace MWSound
|
||||
if (mMusicFiles.find(playlist) == mMusicFiles.end())
|
||||
{
|
||||
std::vector<std::string> filelist;
|
||||
for (const auto& name : mVFS->getRecursiveDirectoryIterator("Music/" + playlist + '/'))
|
||||
auto playlistPath = Misc::ResourceHelpers::correctMusicPath(playlist) + '/';
|
||||
for (const auto& name : mVFS->getRecursiveDirectoryIterator(playlistPath))
|
||||
filelist.push_back(name);
|
||||
|
||||
mMusicFiles[playlist] = filelist;
|
||||
@ -1127,6 +1134,14 @@ namespace MWSound
|
||||
if (!mOutput->isInitialized() || mPlaybackPaused)
|
||||
return;
|
||||
|
||||
MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState();
|
||||
if (state == MWBase::StateManager::State_NoGame && !isMusicPlaying())
|
||||
{
|
||||
std::string titlefile = "music/special/morrowind title.mp3";
|
||||
if (mVFS->exists(titlefile))
|
||||
streamMusic(titlefile, MWSound::MusicType::Special);
|
||||
}
|
||||
|
||||
updateSounds(duration);
|
||||
if (MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame)
|
||||
{
|
||||
|
@ -127,7 +127,7 @@ namespace MWSound
|
||||
StreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f& pos, bool playlocal);
|
||||
|
||||
void streamMusicFull(const std::string& filename);
|
||||
void advanceMusic(const std::string& filename);
|
||||
void advanceMusic(const std::string& filename, float fadeOut = 1.f);
|
||||
void startRandomTitle();
|
||||
|
||||
void cull3DSound(SoundBase* sound);
|
||||
@ -173,12 +173,17 @@ namespace MWSound
|
||||
|
||||
void processChangedSettings(const Settings::CategorySettingVector& settings) override;
|
||||
|
||||
bool isEnabled() const override { return mOutput->isInitialized(); }
|
||||
///< Returns true if sound system is enabled
|
||||
|
||||
void stopMusic() override;
|
||||
///< Stops music if it's playing
|
||||
|
||||
void streamMusic(const std::string& filename) override;
|
||||
void streamMusic(const std::string& filename, MWSound::MusicType type, float fade = 1.f) override;
|
||||
///< Play a soundifle
|
||||
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||
/// \param filename name of a sound file in the data directory.
|
||||
/// \param type music type.
|
||||
/// \param fade time in seconds to fade out current track before start this one.
|
||||
|
||||
bool isMusicPlaying() override;
|
||||
///< Returns true if music is playing
|
||||
|
@ -391,7 +391,12 @@ namespace MWWorld
|
||||
{
|
||||
std::string_view video = Fallback::Map::getString("Movies_New_Game");
|
||||
if (!video.empty())
|
||||
{
|
||||
// Make sure that we do not continue to play a Title music after a new game video.
|
||||
MWBase::Environment::get().getSoundManager()->stopMusic();
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
MWBase::Environment::get().getWindowManager()->playVideo(video, true);
|
||||
}
|
||||
}
|
||||
|
||||
// enable collision
|
||||
|
@ -156,6 +156,11 @@ std::string Misc::ResourceHelpers::correctSoundPath(const std::string& resPath)
|
||||
return "sound\\" + resPath;
|
||||
}
|
||||
|
||||
std::string Misc::ResourceHelpers::correctMusicPath(const std::string& resPath)
|
||||
{
|
||||
return "music\\" + resPath;
|
||||
}
|
||||
|
||||
std::string_view Misc::ResourceHelpers::meshPathForESM3(std::string_view resPath)
|
||||
{
|
||||
constexpr std::string_view prefix = "meshes";
|
||||
|
@ -38,6 +38,9 @@ namespace Misc
|
||||
// Adds "sound\\".
|
||||
std::string correctSoundPath(const std::string& resPath);
|
||||
|
||||
// Adds "music\\".
|
||||
std::string correctMusicPath(const std::string& resPath);
|
||||
|
||||
// Removes "meshes\\".
|
||||
std::string_view meshPathForESM3(std::string_view resPath);
|
||||
|
||||
|
@ -72,4 +72,21 @@
|
||||
-- @return #boolean
|
||||
-- @usage local isPlaying = ambient.isSoundFilePlaying("Sound\\test.mp3");
|
||||
|
||||
---
|
||||
-- Play a sound file as a music track
|
||||
-- @function [parent=#ambient] streamMusic
|
||||
-- @param #string fileName Path to file in VFS
|
||||
-- @usage ambient.streamMusic("Music\\Test\\Test.mp3");
|
||||
|
||||
---
|
||||
-- Stop to play current music
|
||||
-- @function [parent=#ambient] stopMusic
|
||||
-- @usage ambient.stopMusic();
|
||||
|
||||
---
|
||||
-- Check if music is playing
|
||||
-- @function [parent=#ambient] isMusicPlaying
|
||||
-- @return #boolean
|
||||
-- @usage local isPlaying = ambient.isMusicPlaying();
|
||||
|
||||
return nil
|
||||
|
@ -749,6 +749,13 @@
|
||||
--- @{#Sound}: Sounds and Speech
|
||||
-- @field [parent=#core] #Sound sound
|
||||
|
||||
---
|
||||
-- Checks if sound system is enabled (any functions to play sounds are no-ops when it is disabled).
|
||||
-- It can not be enabled or disabled during runtime.
|
||||
-- @function [parent=#Sound] isEnabled
|
||||
-- @return #boolean
|
||||
-- @usage local enabled = core.sound.isEnabled();
|
||||
|
||||
---
|
||||
-- Play a 3D sound, attached to object
|
||||
-- @function [parent=#Sound] playSound3d
|
||||
|
Loading…
x
Reference in New Issue
Block a user