mirror of
https://github.com/minetest/minetest.git
synced 2024-09-12 00:26:50 +02:00
Sound API: Add fading sounds
This commit is contained in:
parent
f1d7a26b7c
commit
bd921a7916
@ -456,11 +456,13 @@ Examples of sound parameter tables:
|
|||||||
-- Play locationless on all clients
|
-- Play locationless on all clients
|
||||||
{
|
{
|
||||||
gain = 1.0, -- default
|
gain = 1.0, -- default
|
||||||
|
fade = 0.0, -- default, change to a value > 0 to fade the sound in
|
||||||
}
|
}
|
||||||
-- Play locationless to one player
|
-- Play locationless to one player
|
||||||
{
|
{
|
||||||
to_player = name,
|
to_player = name,
|
||||||
gain = 1.0, -- default
|
gain = 1.0, -- default
|
||||||
|
fade = 0.0, -- default, change to a value > 0 to fade the sound in
|
||||||
}
|
}
|
||||||
-- Play locationless to one player, looped
|
-- Play locationless to one player, looped
|
||||||
{
|
{
|
||||||
@ -2587,6 +2589,11 @@ These functions return the leftover itemstack.
|
|||||||
* `spec` is a `SimpleSoundSpec`
|
* `spec` is a `SimpleSoundSpec`
|
||||||
* `parameters` is a sound parameter table
|
* `parameters` is a sound parameter table
|
||||||
* `minetest.sound_stop(handle)`
|
* `minetest.sound_stop(handle)`
|
||||||
|
* `minetest.sound_fade(handle, step, gain)`
|
||||||
|
* `handle` is a handle returned by minetest.sound_play
|
||||||
|
* `step` determines how fast a sound will fade.
|
||||||
|
Negative step will lower the sound volume, positive step will increase the sound volume
|
||||||
|
* `gain` the target gain for the fade.
|
||||||
|
|
||||||
### Timing
|
### Timing
|
||||||
* `minetest.after(time, func, ...)`
|
* `minetest.after(time, func, ...)`
|
||||||
|
@ -407,6 +407,7 @@ void Client::step(float dtime)
|
|||||||
|
|
||||||
// Step environment
|
// Step environment
|
||||||
m_env.step(dtime);
|
m_env.step(dtime);
|
||||||
|
m_sound->step(dtime);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get events
|
Get events
|
||||||
|
@ -328,6 +328,7 @@ public:
|
|||||||
void handleCommand_ItemDef(NetworkPacket* pkt);
|
void handleCommand_ItemDef(NetworkPacket* pkt);
|
||||||
void handleCommand_PlaySound(NetworkPacket* pkt);
|
void handleCommand_PlaySound(NetworkPacket* pkt);
|
||||||
void handleCommand_StopSound(NetworkPacket* pkt);
|
void handleCommand_StopSound(NetworkPacket* pkt);
|
||||||
|
void handleCommand_FadeSound(NetworkPacket *pkt);
|
||||||
void handleCommand_Privileges(NetworkPacket* pkt);
|
void handleCommand_Privileges(NetworkPacket* pkt);
|
||||||
void handleCommand_InventoryFormSpec(NetworkPacket* pkt);
|
void handleCommand_InventoryFormSpec(NetworkPacket* pkt);
|
||||||
void handleCommand_DetachedInventory(NetworkPacket* pkt);
|
void handleCommand_DetachedInventory(NetworkPacket* pkt);
|
||||||
|
@ -109,7 +109,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||||||
{ "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52
|
{ "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52
|
||||||
{ "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53
|
{ "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53
|
||||||
{ "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
|
{ "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
|
||||||
null_command_handler,
|
{ "TOCLIENT_FADE_SOUND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55
|
||||||
null_command_handler,
|
null_command_handler,
|
||||||
null_command_handler,
|
null_command_handler,
|
||||||
null_command_handler,
|
null_command_handler,
|
||||||
|
@ -755,21 +755,39 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
|
|||||||
|
|
||||||
void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
[0] u32 server_id
|
||||||
|
[4] u16 name length
|
||||||
|
[6] char name[len]
|
||||||
|
[ 6 + len] f32 gain
|
||||||
|
[10 + len] u8 type
|
||||||
|
[11 + len] (f32 * 3) pos
|
||||||
|
[23 + len] u16 object_id
|
||||||
|
[25 + len] bool loop
|
||||||
|
[26 + len] f32 fade
|
||||||
|
*/
|
||||||
|
|
||||||
s32 server_id;
|
s32 server_id;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
float gain;
|
float gain;
|
||||||
u8 type; // 0=local, 1=positional, 2=object
|
u8 type; // 0=local, 1=positional, 2=object
|
||||||
v3f pos;
|
v3f pos;
|
||||||
u16 object_id;
|
u16 object_id;
|
||||||
bool loop;
|
bool loop;
|
||||||
|
float fade = 0;
|
||||||
|
|
||||||
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
|
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
|
||||||
|
|
||||||
|
try {
|
||||||
|
*pkt >> fade;
|
||||||
|
} catch (SerializationError &e) {};
|
||||||
|
|
||||||
// Start playing
|
// Start playing
|
||||||
int client_id = -1;
|
int client_id = -1;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 0: // local
|
case 0: // local
|
||||||
client_id = m_sound->playSound(name, loop, gain);
|
client_id = m_sound->playSound(name, loop, gain, fade);
|
||||||
break;
|
break;
|
||||||
case 1: // positional
|
case 1: // positional
|
||||||
client_id = m_sound->playSoundAt(name, loop, gain, pos);
|
client_id = m_sound->playSoundAt(name, loop, gain, pos);
|
||||||
@ -808,6 +826,21 @@ void Client::handleCommand_StopSound(NetworkPacket* pkt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::handleCommand_FadeSound(NetworkPacket *pkt)
|
||||||
|
{
|
||||||
|
s32 sound_id;
|
||||||
|
float step;
|
||||||
|
float gain;
|
||||||
|
|
||||||
|
*pkt >> sound_id >> step >> gain;
|
||||||
|
|
||||||
|
UNORDERED_MAP<s32, int>::iterator i =
|
||||||
|
m_sounds_server_to_client.find(sound_id);
|
||||||
|
|
||||||
|
if (i != m_sounds_server_to_client.end())
|
||||||
|
m_sound->fadeSound(i->second, step, gain);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::handleCommand_Privileges(NetworkPacket* pkt)
|
void Client::handleCommand_Privileges(NetworkPacket* pkt)
|
||||||
{
|
{
|
||||||
m_privileges.clear();
|
m_privileges.clear();
|
||||||
|
@ -153,9 +153,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
PROTOCOL VERSION 31:
|
PROTOCOL VERSION 31:
|
||||||
Add tile overlay
|
Add tile overlay
|
||||||
Stop sending TOSERVER_CLIENT_READY
|
Stop sending TOSERVER_CLIENT_READY
|
||||||
|
PROTOCOL VERSION 32:
|
||||||
|
Add fading sounds
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LATEST_PROTOCOL_VERSION 31
|
#define LATEST_PROTOCOL_VERSION 32
|
||||||
|
|
||||||
// Server's supported network protocol range
|
// Server's supported network protocol range
|
||||||
#define SERVER_PROTOCOL_VERSION_MIN 24
|
#define SERVER_PROTOCOL_VERSION_MIN 24
|
||||||
@ -620,6 +622,13 @@ enum ToClientCommand
|
|||||||
v2f1000 speed
|
v2f1000 speed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
TOCLIENT_FADE_SOUND = 0x55,
|
||||||
|
/*
|
||||||
|
s32 sound_id
|
||||||
|
float step
|
||||||
|
float gain
|
||||||
|
*/
|
||||||
|
|
||||||
TOCLIENT_SRP_BYTES_S_B = 0x60,
|
TOCLIENT_SRP_BYTES_S_B = 0x60,
|
||||||
/*
|
/*
|
||||||
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP.
|
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP.
|
||||||
|
@ -680,6 +680,7 @@ void read_server_sound_params(lua_State *L, int index,
|
|||||||
if(lua_istable(L, index)){
|
if(lua_istable(L, index)){
|
||||||
getfloatfield(L, index, "gain", params.gain);
|
getfloatfield(L, index, "gain", params.gain);
|
||||||
getstringfield(L, index, "to_player", params.to_player);
|
getstringfield(L, index, "to_player", params.to_player);
|
||||||
|
getfloatfield(L, index, "fade", params.fade);
|
||||||
lua_getfield(L, index, "pos");
|
lua_getfield(L, index, "pos");
|
||||||
if(!lua_isnil(L, -1)){
|
if(!lua_isnil(L, -1)){
|
||||||
v3f p = read_v3f(L, -1)*BS;
|
v3f p = read_v3f(L, -1)*BS;
|
||||||
@ -712,6 +713,7 @@ void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
|
|||||||
} else if(lua_istable(L, index)){
|
} else if(lua_istable(L, index)){
|
||||||
getstringfield(L, index, "name", spec.name);
|
getstringfield(L, index, "name", spec.name);
|
||||||
getfloatfield(L, index, "gain", spec.gain);
|
getfloatfield(L, index, "gain", spec.gain);
|
||||||
|
getfloatfield(L, index, "fade", spec.fade);
|
||||||
} else if(lua_isstring(L, index)){
|
} else if(lua_isstring(L, index)){
|
||||||
spec.name = lua_tostring(L, index);
|
spec.name = lua_tostring(L, index);
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,8 @@ void setfloatfield(lua_State *L, int table,
|
|||||||
const char *fieldname, float value);
|
const char *fieldname, float value);
|
||||||
void setboolfield(lua_State *L, int table,
|
void setboolfield(lua_State *L, int table,
|
||||||
const char *fieldname, bool value);
|
const char *fieldname, bool value);
|
||||||
|
void setstringfield(lua_State *L, int table,
|
||||||
|
const char *fieldname, const char *value);
|
||||||
|
|
||||||
v3f checkFloatPos (lua_State *L, int index);
|
v3f checkFloatPos (lua_State *L, int index);
|
||||||
v2f check_v2f (lua_State *L, int index);
|
v2f check_v2f (lua_State *L, int index);
|
||||||
|
@ -455,6 +455,16 @@ int ModApiServer::l_sound_stop(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ModApiServer::l_sound_fade(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
s32 handle = luaL_checkinteger(L, 1);
|
||||||
|
float step = luaL_checknumber(L, 2);
|
||||||
|
float gain = luaL_checknumber(L, 3);
|
||||||
|
getServer(L)->fadeSound(handle, step, gain);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// is_singleplayer()
|
// is_singleplayer()
|
||||||
int ModApiServer::l_is_singleplayer(lua_State *L)
|
int ModApiServer::l_is_singleplayer(lua_State *L)
|
||||||
{
|
{
|
||||||
@ -518,6 +528,7 @@ void ModApiServer::Initialize(lua_State *L, int top)
|
|||||||
API_FCT(show_formspec);
|
API_FCT(show_formspec);
|
||||||
API_FCT(sound_play);
|
API_FCT(sound_play);
|
||||||
API_FCT(sound_stop);
|
API_FCT(sound_stop);
|
||||||
|
API_FCT(sound_fade);
|
||||||
|
|
||||||
API_FCT(get_player_information);
|
API_FCT(get_player_information);
|
||||||
API_FCT(get_player_privs);
|
API_FCT(get_player_privs);
|
||||||
|
@ -68,6 +68,9 @@ private:
|
|||||||
// sound_stop(handle)
|
// sound_stop(handle)
|
||||||
static int l_sound_stop(lua_State *L);
|
static int l_sound_stop(lua_State *L);
|
||||||
|
|
||||||
|
// sound_fade(handle, step, gain)
|
||||||
|
static int l_sound_fade(lua_State *L);
|
||||||
|
|
||||||
// get_player_privs(name, text)
|
// get_player_privs(name, text)
|
||||||
static int l_get_player_privs(lua_State *L);
|
static int l_get_player_privs(lua_State *L);
|
||||||
|
|
||||||
|
@ -2100,15 +2100,23 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
|
|||||||
m_playing_sounds[id] = ServerPlayingSound();
|
m_playing_sounds[id] = ServerPlayingSound();
|
||||||
ServerPlayingSound &psound = m_playing_sounds[id];
|
ServerPlayingSound &psound = m_playing_sounds[id];
|
||||||
psound.params = params;
|
psound.params = params;
|
||||||
|
psound.spec = spec;
|
||||||
|
|
||||||
|
float gain = params.gain * spec.gain;
|
||||||
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
|
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
|
||||||
pkt << id << spec.name << (float) (spec.gain * params.gain)
|
pkt << id << spec.name << gain
|
||||||
<< (u8) params.type << pos << params.object << params.loop;
|
<< (u8) params.type << pos << params.object
|
||||||
|
<< params.loop << params.fade;
|
||||||
|
|
||||||
for(std::vector<u16>::iterator i = dst_clients.begin();
|
// Backwards compability
|
||||||
|
bool play_sound = gain > 0;
|
||||||
|
|
||||||
|
for (std::vector<u16>::iterator i = dst_clients.begin();
|
||||||
i != dst_clients.end(); ++i) {
|
i != dst_clients.end(); ++i) {
|
||||||
psound.clients.insert(*i);
|
if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
|
||||||
m_clients.send(*i, 0, &pkt, true);
|
psound.clients.insert(*i);
|
||||||
|
m_clients.send(*i, 0, &pkt, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -2132,6 +2140,52 @@ void Server::stopSound(s32 handle)
|
|||||||
m_playing_sounds.erase(i);
|
m_playing_sounds.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Server::fadeSound(s32 handle, float step, float gain)
|
||||||
|
{
|
||||||
|
// Get sound reference
|
||||||
|
UNORDERED_MAP<s32, ServerPlayingSound>::iterator i =
|
||||||
|
m_playing_sounds.find(handle);
|
||||||
|
if (i == m_playing_sounds.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ServerPlayingSound &psound = i->second;
|
||||||
|
psound.params.gain = gain;
|
||||||
|
|
||||||
|
NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
|
||||||
|
pkt << handle << step << gain;
|
||||||
|
|
||||||
|
// Backwards compability
|
||||||
|
bool play_sound = gain > 0;
|
||||||
|
ServerPlayingSound compat_psound = psound;
|
||||||
|
compat_psound.clients.clear();
|
||||||
|
|
||||||
|
NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
|
||||||
|
compat_pkt << handle;
|
||||||
|
|
||||||
|
for (UNORDERED_SET<u16>::iterator it = psound.clients.begin();
|
||||||
|
it != psound.clients.end();) {
|
||||||
|
if (m_clients.getProtocolVersion(*it) >= 32) {
|
||||||
|
// Send as reliable
|
||||||
|
m_clients.send(*it, 0, &pkt, true);
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
compat_psound.clients.insert(*it);
|
||||||
|
// Stop old sound
|
||||||
|
m_clients.send(*it, 0, &compat_pkt, true);
|
||||||
|
psound.clients.erase(it++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove sound reference
|
||||||
|
if (!play_sound || psound.clients.size() == 0)
|
||||||
|
m_playing_sounds.erase(i);
|
||||||
|
|
||||||
|
if (play_sound && compat_psound.clients.size() > 0) {
|
||||||
|
// Play new sound volume on older clients
|
||||||
|
playSound(compat_psound.spec, compat_psound.params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
|
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
|
||||||
std::vector<u16> *far_players, float far_d_nodes)
|
std::vector<u16> *far_players, float far_d_nodes)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +115,7 @@ struct ServerSoundParams
|
|||||||
u16 object;
|
u16 object;
|
||||||
float max_hear_distance;
|
float max_hear_distance;
|
||||||
bool loop;
|
bool loop;
|
||||||
|
float fade;
|
||||||
|
|
||||||
ServerSoundParams():
|
ServerSoundParams():
|
||||||
gain(1.0),
|
gain(1.0),
|
||||||
@ -123,7 +124,8 @@ struct ServerSoundParams
|
|||||||
pos(0,0,0),
|
pos(0,0,0),
|
||||||
object(0),
|
object(0),
|
||||||
max_hear_distance(32*BS),
|
max_hear_distance(32*BS),
|
||||||
loop(false)
|
loop(false),
|
||||||
|
fade(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
|
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
|
||||||
@ -132,6 +134,7 @@ struct ServerSoundParams
|
|||||||
struct ServerPlayingSound
|
struct ServerPlayingSound
|
||||||
{
|
{
|
||||||
ServerSoundParams params;
|
ServerSoundParams params;
|
||||||
|
SimpleSoundSpec spec;
|
||||||
UNORDERED_SET<u16> clients; // peer ids
|
UNORDERED_SET<u16> clients; // peer ids
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -231,6 +234,7 @@ public:
|
|||||||
// Envlock
|
// Envlock
|
||||||
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
|
||||||
void stopSound(s32 handle);
|
void stopSound(s32 handle);
|
||||||
|
void fadeSound(s32 handle, float step, float gain);
|
||||||
|
|
||||||
// Envlock
|
// Envlock
|
||||||
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
|
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
|
||||||
|
28
src/sound.h
28
src/sound.h
@ -34,8 +34,8 @@ public:
|
|||||||
|
|
||||||
struct SimpleSoundSpec
|
struct SimpleSoundSpec
|
||||||
{
|
{
|
||||||
SimpleSoundSpec(const std::string &name = "", float gain = 1.0)
|
SimpleSoundSpec(const std::string &name = "", float gain = 1.0, float fade = 0.0)
|
||||||
: name(name), gain(gain)
|
: name(name), gain(gain), fade(fade)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,13 +43,13 @@ struct SimpleSoundSpec
|
|||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
float gain;
|
float gain;
|
||||||
|
float fade;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISoundManager
|
class ISoundManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ISoundManager() {}
|
virtual ~ISoundManager() {}
|
||||||
|
|
||||||
// Multiple sounds can be loaded per name; when played, the sound
|
// Multiple sounds can be loaded per name; when played, the sound
|
||||||
// should be chosen randomly from alternatives
|
// should be chosen randomly from alternatives
|
||||||
// Return value determines success/failure
|
// Return value determines success/failure
|
||||||
@ -63,16 +63,21 @@ public:
|
|||||||
|
|
||||||
// playSound functions return -1 on failure, otherwise a handle to the
|
// playSound functions return -1 on failure, otherwise a handle to the
|
||||||
// sound. If name=="", call should be ignored without error.
|
// sound. If name=="", call should be ignored without error.
|
||||||
virtual int playSound(const std::string &name, bool loop, float volume) = 0;
|
virtual int playSound(const std::string &name, bool loop, float volume,
|
||||||
virtual int playSoundAt(
|
float fade = 0) = 0;
|
||||||
const std::string &name, bool loop, float volume, v3f pos) = 0;
|
virtual int playSoundAt(const std::string &name, bool loop, float volume,
|
||||||
|
v3f pos) = 0;
|
||||||
virtual void stopSound(int sound) = 0;
|
virtual void stopSound(int sound) = 0;
|
||||||
virtual bool soundExists(int sound) = 0;
|
virtual bool soundExists(int sound) = 0;
|
||||||
virtual void updateSoundPosition(int sound, v3f pos) = 0;
|
virtual void updateSoundPosition(int sound, v3f pos) = 0;
|
||||||
|
virtual bool updateSoundGain(int id, float gain) = 0;
|
||||||
|
virtual float getSoundGain(int id) = 0;
|
||||||
|
virtual void step(float dtime) = 0;
|
||||||
|
virtual void fadeSound(int sound, float step, float gain) = 0;
|
||||||
|
|
||||||
int playSound(const SimpleSoundSpec &spec, bool loop)
|
int playSound(const SimpleSoundSpec &spec, bool loop)
|
||||||
{
|
{
|
||||||
return playSound(spec.name, loop, spec.gain);
|
return playSound(spec.name, loop, spec.gain, spec.fade);
|
||||||
}
|
}
|
||||||
int playSoundAt(const SimpleSoundSpec &spec, bool loop, v3f pos)
|
int playSoundAt(const SimpleSoundSpec &spec, bool loop, v3f pos)
|
||||||
{
|
{
|
||||||
@ -93,7 +98,10 @@ public:
|
|||||||
}
|
}
|
||||||
void updateListener(v3f pos, v3f vel, v3f at, v3f up) {}
|
void updateListener(v3f pos, v3f vel, v3f at, v3f up) {}
|
||||||
void setListenerGain(float gain) {}
|
void setListenerGain(float gain) {}
|
||||||
int playSound(const std::string &name, bool loop, float volume) { return 0; }
|
int playSound(const std::string &name, bool loop, float volume, float fade)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
|
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -101,6 +109,10 @@ public:
|
|||||||
void stopSound(int sound) {}
|
void stopSound(int sound) {}
|
||||||
bool soundExists(int sound) { return false; }
|
bool soundExists(int sound) { return false; }
|
||||||
void updateSoundPosition(int sound, v3f pos) {}
|
void updateSoundPosition(int sound, v3f pos) {}
|
||||||
|
bool updateSoundGain(int id, float gain) { return false; }
|
||||||
|
float getSoundGain(int id) { return 0; }
|
||||||
|
void step(float dtime) { }
|
||||||
|
void fadeSound(int sound, float step, float gain) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global DummySoundManager singleton
|
// Global DummySoundManager singleton
|
||||||
|
@ -274,6 +274,19 @@ private:
|
|||||||
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> > m_buffers;
|
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> > m_buffers;
|
||||||
UNORDERED_MAP<int, PlayingSound*> m_sounds_playing;
|
UNORDERED_MAP<int, PlayingSound*> m_sounds_playing;
|
||||||
v3f m_listener_pos;
|
v3f m_listener_pos;
|
||||||
|
struct FadeState {
|
||||||
|
FadeState() {}
|
||||||
|
FadeState(float step, float current_gain, float target_gain):
|
||||||
|
step(step),
|
||||||
|
current_gain(current_gain),
|
||||||
|
target_gain(target_gain) {}
|
||||||
|
float step;
|
||||||
|
float current_gain;
|
||||||
|
float target_gain;
|
||||||
|
};
|
||||||
|
|
||||||
|
UNORDERED_MAP<int, FadeState> m_sounds_fading;
|
||||||
|
float m_fade_delay;
|
||||||
public:
|
public:
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
OpenALSoundManager(OnDemandSoundFetcher *fetcher):
|
OpenALSoundManager(OnDemandSoundFetcher *fetcher):
|
||||||
@ -281,6 +294,7 @@ public:
|
|||||||
m_device(NULL),
|
m_device(NULL),
|
||||||
m_context(NULL),
|
m_context(NULL),
|
||||||
m_next_id(1),
|
m_next_id(1),
|
||||||
|
m_fade_delay(0),
|
||||||
m_is_initialized(false)
|
m_is_initialized(false)
|
||||||
{
|
{
|
||||||
ALCenum error = ALC_NO_ERROR;
|
ALCenum error = ALC_NO_ERROR;
|
||||||
@ -349,6 +363,11 @@ public:
|
|||||||
infostream<<"Audio: Deinitialized."<<std::endl;
|
infostream<<"Audio: Deinitialized."<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void step(float dtime)
|
||||||
|
{
|
||||||
|
doFades(dtime);
|
||||||
|
}
|
||||||
|
|
||||||
void addBuffer(const std::string &name, SoundBuffer *buf)
|
void addBuffer(const std::string &name, SoundBuffer *buf)
|
||||||
{
|
{
|
||||||
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> >::iterator i =
|
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> >::iterator i =
|
||||||
@ -515,6 +534,7 @@ public:
|
|||||||
addBuffer(name, buf);
|
addBuffer(name, buf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadSoundData(const std::string &name,
|
bool loadSoundData(const std::string &name,
|
||||||
const std::string &filedata)
|
const std::string &filedata)
|
||||||
{
|
{
|
||||||
@ -541,7 +561,7 @@ public:
|
|||||||
alListenerf(AL_GAIN, gain);
|
alListenerf(AL_GAIN, gain);
|
||||||
}
|
}
|
||||||
|
|
||||||
int playSound(const std::string &name, bool loop, float volume)
|
int playSound(const std::string &name, bool loop, float volume, float fade)
|
||||||
{
|
{
|
||||||
maintain();
|
maintain();
|
||||||
if(name == "")
|
if(name == "")
|
||||||
@ -552,8 +572,16 @@ public:
|
|||||||
<<std::endl;
|
<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return playSoundRaw(buf, loop, volume);
|
int handle = -1;
|
||||||
|
if (fade > 0) {
|
||||||
|
handle = playSoundRaw(buf, loop, 0);
|
||||||
|
fadeSound(handle, fade, volume);
|
||||||
|
} else {
|
||||||
|
handle = playSoundRaw(buf, loop, volume);
|
||||||
|
}
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
|
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
|
||||||
{
|
{
|
||||||
maintain();
|
maintain();
|
||||||
@ -567,16 +595,55 @@ public:
|
|||||||
}
|
}
|
||||||
return playSoundRawAt(buf, loop, volume, pos);
|
return playSoundRawAt(buf, loop, volume, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopSound(int sound)
|
void stopSound(int sound)
|
||||||
{
|
{
|
||||||
maintain();
|
maintain();
|
||||||
deleteSound(sound);
|
deleteSound(sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fadeSound(int soundid, float step, float gain)
|
||||||
|
{
|
||||||
|
m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doFades(float dtime)
|
||||||
|
{
|
||||||
|
m_fade_delay += dtime;
|
||||||
|
|
||||||
|
if (m_fade_delay < 0.1f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float chkGain = 0;
|
||||||
|
for (UNORDERED_MAP<int, FadeState>::iterator i = m_sounds_fading.begin();
|
||||||
|
i != m_sounds_fading.end();) {
|
||||||
|
if (i->second.step < 0.f)
|
||||||
|
chkGain = -(i->second.current_gain);
|
||||||
|
else
|
||||||
|
chkGain = i->second.current_gain;
|
||||||
|
|
||||||
|
if (chkGain < i->second.target_gain) {
|
||||||
|
i->second.current_gain += (i->second.step * m_fade_delay);
|
||||||
|
i->second.current_gain = rangelim(i->second.current_gain, 0, 1);
|
||||||
|
|
||||||
|
updateSoundGain(i->first, i->second.current_gain);
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
if (i->second.target_gain <= 0.f)
|
||||||
|
stopSound(i->first);
|
||||||
|
|
||||||
|
m_sounds_fading.erase(i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_fade_delay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool soundExists(int sound)
|
bool soundExists(int sound)
|
||||||
{
|
{
|
||||||
maintain();
|
maintain();
|
||||||
return (m_sounds_playing.count(sound) != 0);
|
return (m_sounds_playing.count(sound) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSoundPosition(int id, v3f pos)
|
void updateSoundPosition(int id, v3f pos)
|
||||||
{
|
{
|
||||||
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
|
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
|
||||||
@ -589,6 +656,29 @@ public:
|
|||||||
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
|
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
|
||||||
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
|
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool updateSoundGain(int id, float gain)
|
||||||
|
{
|
||||||
|
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
|
||||||
|
if (i == m_sounds_playing.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PlayingSound *sound = i->second;
|
||||||
|
alSourcef(sound->source_id, AL_GAIN, gain);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getSoundGain(int id)
|
||||||
|
{
|
||||||
|
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
|
||||||
|
if (i == m_sounds_playing.end())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
PlayingSound *sound = i->second;
|
||||||
|
ALfloat gain;
|
||||||
|
alGetSourcef(sound->source_id, AL_GAIN, &gain);
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
|
ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
|
||||||
|
Loading…
Reference in New Issue
Block a user