Skip to content

Commit bd921a7

Browse files
Bremawebparamat
authored andcommittedMay 3, 2017
Sound API: Add fading sounds
1 parent f1d7a26 commit bd921a7

14 files changed

+248
-19
lines changed
 

Diff for: ‎doc/lua_api.txt

+7
Original file line numberDiff line numberDiff line change
@@ -456,11 +456,13 @@ Examples of sound parameter tables:
456456
-- Play locationless on all clients
457457
{
458458
gain = 1.0, -- default
459+
fade = 0.0, -- default, change to a value > 0 to fade the sound in
459460
}
460461
-- Play locationless to one player
461462
{
462463
to_player = name,
463464
gain = 1.0, -- default
465+
fade = 0.0, -- default, change to a value > 0 to fade the sound in
464466
}
465467
-- Play locationless to one player, looped
466468
{
@@ -2587,6 +2589,11 @@ These functions return the leftover itemstack.
25872589
* `spec` is a `SimpleSoundSpec`
25882590
* `parameters` is a sound parameter table
25892591
* `minetest.sound_stop(handle)`
2592+
* `minetest.sound_fade(handle, step, gain)`
2593+
* `handle` is a handle returned by minetest.sound_play
2594+
* `step` determines how fast a sound will fade.
2595+
Negative step will lower the sound volume, positive step will increase the sound volume
2596+
* `gain` the target gain for the fade.
25902597

25912598
### Timing
25922599
* `minetest.after(time, func, ...)`

Diff for: ‎src/client.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ void Client::step(float dtime)
407407

408408
// Step environment
409409
m_env.step(dtime);
410+
m_sound->step(dtime);
410411

411412
/*
412413
Get events

Diff for: ‎src/client.h

+1
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
328328
void handleCommand_ItemDef(NetworkPacket* pkt);
329329
void handleCommand_PlaySound(NetworkPacket* pkt);
330330
void handleCommand_StopSound(NetworkPacket* pkt);
331+
void handleCommand_FadeSound(NetworkPacket *pkt);
331332
void handleCommand_Privileges(NetworkPacket* pkt);
332333
void handleCommand_InventoryFormSpec(NetworkPacket* pkt);
333334
void handleCommand_DetachedInventory(NetworkPacket* pkt);

Diff for: ‎src/network/clientopcodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
109109
{ "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52
110110
{ "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53
111111
{ "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54
112-
null_command_handler,
112+
{ "TOCLIENT_FADE_SOUND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55
113113
null_command_handler,
114114
null_command_handler,
115115
null_command_handler,

Diff for: ‎src/network/clientpackethandler.cpp

+34-1
Original file line numberDiff line numberDiff line change
@@ -755,21 +755,39 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
755755

756756
void Client::handleCommand_PlaySound(NetworkPacket* pkt)
757757
{
758+
/*
759+
[0] u32 server_id
760+
[4] u16 name length
761+
[6] char name[len]
762+
[ 6 + len] f32 gain
763+
[10 + len] u8 type
764+
[11 + len] (f32 * 3) pos
765+
[23 + len] u16 object_id
766+
[25 + len] bool loop
767+
[26 + len] f32 fade
768+
*/
769+
758770
s32 server_id;
759771
std::string name;
772+
760773
float gain;
761774
u8 type; // 0=local, 1=positional, 2=object
762775
v3f pos;
763776
u16 object_id;
764777
bool loop;
778+
float fade = 0;
765779

766780
*pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
767781

782+
try {
783+
*pkt >> fade;
784+
} catch (SerializationError &e) {};
785+
768786
// Start playing
769787
int client_id = -1;
770788
switch(type) {
771789
case 0: // local
772-
client_id = m_sound->playSound(name, loop, gain);
790+
client_id = m_sound->playSound(name, loop, gain, fade);
773791
break;
774792
case 1: // positional
775793
client_id = m_sound->playSoundAt(name, loop, gain, pos);
@@ -808,6 +826,21 @@ void Client::handleCommand_StopSound(NetworkPacket* pkt)
808826
}
809827
}
810828

829+
void Client::handleCommand_FadeSound(NetworkPacket *pkt)
830+
{
831+
s32 sound_id;
832+
float step;
833+
float gain;
834+
835+
*pkt >> sound_id >> step >> gain;
836+
837+
UNORDERED_MAP<s32, int>::iterator i =
838+
m_sounds_server_to_client.find(sound_id);
839+
840+
if (i != m_sounds_server_to_client.end())
841+
m_sound->fadeSound(i->second, step, gain);
842+
}
843+
811844
void Client::handleCommand_Privileges(NetworkPacket* pkt)
812845
{
813846
m_privileges.clear();

Diff for: ‎src/network/networkprotocol.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
153153
PROTOCOL VERSION 31:
154154
Add tile overlay
155155
Stop sending TOSERVER_CLIENT_READY
156+
PROTOCOL VERSION 32:
157+
Add fading sounds
156158
*/
157159

158-
#define LATEST_PROTOCOL_VERSION 31
160+
#define LATEST_PROTOCOL_VERSION 32
159161

160162
// Server's supported network protocol range
161163
#define SERVER_PROTOCOL_VERSION_MIN 24
@@ -620,6 +622,13 @@ enum ToClientCommand
620622
v2f1000 speed
621623
*/
622624

625+
TOCLIENT_FADE_SOUND = 0x55,
626+
/*
627+
s32 sound_id
628+
float step
629+
float gain
630+
*/
631+
623632
TOCLIENT_SRP_BYTES_S_B = 0x60,
624633
/*
625634
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP.

Diff for: ‎src/script/common/c_content.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ void read_server_sound_params(lua_State *L, int index,
680680
if(lua_istable(L, index)){
681681
getfloatfield(L, index, "gain", params.gain);
682682
getstringfield(L, index, "to_player", params.to_player);
683+
getfloatfield(L, index, "fade", params.fade);
683684
lua_getfield(L, index, "pos");
684685
if(!lua_isnil(L, -1)){
685686
v3f p = read_v3f(L, -1)*BS;
@@ -712,6 +713,7 @@ void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
712713
} else if(lua_istable(L, index)){
713714
getstringfield(L, index, "name", spec.name);
714715
getfloatfield(L, index, "gain", spec.gain);
716+
getfloatfield(L, index, "fade", spec.fade);
715717
} else if(lua_isstring(L, index)){
716718
spec.name = lua_tostring(L, index);
717719
}

Diff for: ‎src/script/common/c_converter.h

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ void setfloatfield(lua_State *L, int table,
7777
const char *fieldname, float value);
7878
void setboolfield(lua_State *L, int table,
7979
const char *fieldname, bool value);
80+
void setstringfield(lua_State *L, int table,
81+
const char *fieldname, const char *value);
8082

8183
v3f checkFloatPos (lua_State *L, int index);
8284
v2f check_v2f (lua_State *L, int index);

Diff for: ‎src/script/lua_api/l_server.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,16 @@ int ModApiServer::l_sound_stop(lua_State *L)
455455
return 0;
456456
}
457457

458+
int ModApiServer::l_sound_fade(lua_State *L)
459+
{
460+
NO_MAP_LOCK_REQUIRED;
461+
s32 handle = luaL_checkinteger(L, 1);
462+
float step = luaL_checknumber(L, 2);
463+
float gain = luaL_checknumber(L, 3);
464+
getServer(L)->fadeSound(handle, step, gain);
465+
return 0;
466+
}
467+
458468
// is_singleplayer()
459469
int ModApiServer::l_is_singleplayer(lua_State *L)
460470
{
@@ -518,6 +528,7 @@ void ModApiServer::Initialize(lua_State *L, int top)
518528
API_FCT(show_formspec);
519529
API_FCT(sound_play);
520530
API_FCT(sound_stop);
531+
API_FCT(sound_fade);
521532

522533
API_FCT(get_player_information);
523534
API_FCT(get_player_privs);

Diff for: ‎src/script/lua_api/l_server.h

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class ModApiServer : public ModApiBase
6868
// sound_stop(handle)
6969
static int l_sound_stop(lua_State *L);
7070

71+
// sound_fade(handle, step, gain)
72+
static int l_sound_fade(lua_State *L);
73+
7174
// get_player_privs(name, text)
7275
static int l_get_player_privs(lua_State *L);
7376

Diff for: ‎src/server.cpp

+59-5
Original file line numberDiff line numberDiff line change
@@ -2100,15 +2100,23 @@ s32 Server::playSound(const SimpleSoundSpec &spec,
21002100
m_playing_sounds[id] = ServerPlayingSound();
21012101
ServerPlayingSound &psound = m_playing_sounds[id];
21022102
psound.params = params;
2103+
psound.spec = spec;
21032104

2105+
float gain = params.gain * spec.gain;
21042106
NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2105-
pkt << id << spec.name << (float) (spec.gain * params.gain)
2106-
<< (u8) params.type << pos << params.object << params.loop;
2107+
pkt << id << spec.name << gain
2108+
<< (u8) params.type << pos << params.object
2109+
<< params.loop << params.fade;
21072110

2108-
for(std::vector<u16>::iterator i = dst_clients.begin();
2111+
// Backwards compability
2112+
bool play_sound = gain > 0;
2113+
2114+
for (std::vector<u16>::iterator i = dst_clients.begin();
21092115
i != dst_clients.end(); ++i) {
2110-
psound.clients.insert(*i);
2111-
m_clients.send(*i, 0, &pkt, true);
2116+
if (play_sound || m_clients.getProtocolVersion(*i) >= 32) {
2117+
psound.clients.insert(*i);
2118+
m_clients.send(*i, 0, &pkt, true);
2119+
}
21122120
}
21132121
return id;
21142122
}
@@ -2132,6 +2140,52 @@ void Server::stopSound(s32 handle)
21322140
m_playing_sounds.erase(i);
21332141
}
21342142

2143+
void Server::fadeSound(s32 handle, float step, float gain)
2144+
{
2145+
// Get sound reference
2146+
UNORDERED_MAP<s32, ServerPlayingSound>::iterator i =
2147+
m_playing_sounds.find(handle);
2148+
if (i == m_playing_sounds.end())
2149+
return;
2150+
2151+
ServerPlayingSound &psound = i->second;
2152+
psound.params.gain = gain;
2153+
2154+
NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2155+
pkt << handle << step << gain;
2156+
2157+
// Backwards compability
2158+
bool play_sound = gain > 0;
2159+
ServerPlayingSound compat_psound = psound;
2160+
compat_psound.clients.clear();
2161+
2162+
NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2163+
compat_pkt << handle;
2164+
2165+
for (UNORDERED_SET<u16>::iterator it = psound.clients.begin();
2166+
it != psound.clients.end();) {
2167+
if (m_clients.getProtocolVersion(*it) >= 32) {
2168+
// Send as reliable
2169+
m_clients.send(*it, 0, &pkt, true);
2170+
++it;
2171+
} else {
2172+
compat_psound.clients.insert(*it);
2173+
// Stop old sound
2174+
m_clients.send(*it, 0, &compat_pkt, true);
2175+
psound.clients.erase(it++);
2176+
}
2177+
}
2178+
2179+
// Remove sound reference
2180+
if (!play_sound || psound.clients.size() == 0)
2181+
m_playing_sounds.erase(i);
2182+
2183+
if (play_sound && compat_psound.clients.size() > 0) {
2184+
// Play new sound volume on older clients
2185+
playSound(compat_psound.spec, compat_psound.params);
2186+
}
2187+
}
2188+
21352189
void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
21362190
std::vector<u16> *far_players, float far_d_nodes)
21372191
{

Diff for: ‎src/server.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ struct ServerSoundParams
115115
u16 object;
116116
float max_hear_distance;
117117
bool loop;
118+
float fade;
118119

119120
ServerSoundParams():
120121
gain(1.0),
@@ -123,7 +124,8 @@ struct ServerSoundParams
123124
pos(0,0,0),
124125
object(0),
125126
max_hear_distance(32*BS),
126-
loop(false)
127+
loop(false),
128+
fade(0)
127129
{}
128130

129131
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
@@ -132,6 +134,7 @@ struct ServerSoundParams
132134
struct ServerPlayingSound
133135
{
134136
ServerSoundParams params;
137+
SimpleSoundSpec spec;
135138
UNORDERED_SET<u16> clients; // peer ids
136139
};
137140

@@ -231,6 +234,7 @@ class Server : public con::PeerHandler, public MapEventReceiver,
231234
// Envlock
232235
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
233236
void stopSound(s32 handle);
237+
void fadeSound(s32 handle, float step, float gain);
234238

235239
// Envlock
236240
std::set<std::string> getPlayerEffectivePrivs(const std::string &name);

Diff for: ‎src/sound.h

+20-8
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,22 @@ class OnDemandSoundFetcher
3434

3535
struct SimpleSoundSpec
3636
{
37-
SimpleSoundSpec(const std::string &name = "", float gain = 1.0)
38-
: name(name), gain(gain)
37+
SimpleSoundSpec(const std::string &name = "", float gain = 1.0, float fade = 0.0)
38+
: name(name), gain(gain), fade(fade)
3939
{
4040
}
4141

4242
bool exists() const { return name != ""; }
4343

4444
std::string name;
4545
float gain;
46+
float fade;
4647
};
4748

4849
class ISoundManager
4950
{
5051
public:
5152
virtual ~ISoundManager() {}
52-
5353
// Multiple sounds can be loaded per name; when played, the sound
5454
// should be chosen randomly from alternatives
5555
// Return value determines success/failure
@@ -63,16 +63,21 @@ class ISoundManager
6363

6464
// playSound functions return -1 on failure, otherwise a handle to the
6565
// sound. If name=="", call should be ignored without error.
66-
virtual int playSound(const std::string &name, bool loop, float volume) = 0;
67-
virtual int playSoundAt(
68-
const std::string &name, bool loop, float volume, v3f pos) = 0;
66+
virtual int playSound(const std::string &name, bool loop, float volume,
67+
float fade = 0) = 0;
68+
virtual int playSoundAt(const std::string &name, bool loop, float volume,
69+
v3f pos) = 0;
6970
virtual void stopSound(int sound) = 0;
7071
virtual bool soundExists(int sound) = 0;
7172
virtual void updateSoundPosition(int sound, v3f pos) = 0;
73+
virtual bool updateSoundGain(int id, float gain) = 0;
74+
virtual float getSoundGain(int id) = 0;
75+
virtual void step(float dtime) = 0;
76+
virtual void fadeSound(int sound, float step, float gain) = 0;
7277

7378
int playSound(const SimpleSoundSpec &spec, bool loop)
7479
{
75-
return playSound(spec.name, loop, spec.gain);
80+
return playSound(spec.name, loop, spec.gain, spec.fade);
7681
}
7782
int playSoundAt(const SimpleSoundSpec &spec, bool loop, v3f pos)
7883
{
@@ -93,14 +98,21 @@ class DummySoundManager : public ISoundManager
9398
}
9499
void updateListener(v3f pos, v3f vel, v3f at, v3f up) {}
95100
void setListenerGain(float gain) {}
96-
int playSound(const std::string &name, bool loop, float volume) { return 0; }
101+
int playSound(const std::string &name, bool loop, float volume, float fade)
102+
{
103+
return 0;
104+
}
97105
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
98106
{
99107
return 0;
100108
}
101109
void stopSound(int sound) {}
102110
bool soundExists(int sound) { return false; }
103111
void updateSoundPosition(int sound, v3f pos) {}
112+
bool updateSoundGain(int id, float gain) { return false; }
113+
float getSoundGain(int id) { return 0; }
114+
void step(float dtime) { }
115+
void fadeSound(int sound, float step, float gain) { }
104116
};
105117

106118
// Global DummySoundManager singleton

Diff for: ‎src/sound_openal.cpp

+92-2
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,27 @@ class OpenALSoundManager: public ISoundManager
274274
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> > m_buffers;
275275
UNORDERED_MAP<int, PlayingSound*> m_sounds_playing;
276276
v3f m_listener_pos;
277+
struct FadeState {
278+
FadeState() {}
279+
FadeState(float step, float current_gain, float target_gain):
280+
step(step),
281+
current_gain(current_gain),
282+
target_gain(target_gain) {}
283+
float step;
284+
float current_gain;
285+
float target_gain;
286+
};
287+
288+
UNORDERED_MAP<int, FadeState> m_sounds_fading;
289+
float m_fade_delay;
277290
public:
278291
bool m_is_initialized;
279292
OpenALSoundManager(OnDemandSoundFetcher *fetcher):
280293
m_fetcher(fetcher),
281294
m_device(NULL),
282295
m_context(NULL),
283296
m_next_id(1),
297+
m_fade_delay(0),
284298
m_is_initialized(false)
285299
{
286300
ALCenum error = ALC_NO_ERROR;
@@ -349,6 +363,11 @@ class OpenALSoundManager: public ISoundManager
349363
infostream<<"Audio: Deinitialized."<<std::endl;
350364
}
351365

366+
void step(float dtime)
367+
{
368+
doFades(dtime);
369+
}
370+
352371
void addBuffer(const std::string &name, SoundBuffer *buf)
353372
{
354373
UNORDERED_MAP<std::string, std::vector<SoundBuffer*> >::iterator i =
@@ -515,6 +534,7 @@ class OpenALSoundManager: public ISoundManager
515534
addBuffer(name, buf);
516535
return false;
517536
}
537+
518538
bool loadSoundData(const std::string &name,
519539
const std::string &filedata)
520540
{
@@ -541,7 +561,7 @@ class OpenALSoundManager: public ISoundManager
541561
alListenerf(AL_GAIN, gain);
542562
}
543563

544-
int playSound(const std::string &name, bool loop, float volume)
564+
int playSound(const std::string &name, bool loop, float volume, float fade)
545565
{
546566
maintain();
547567
if(name == "")
@@ -552,8 +572,16 @@ class OpenALSoundManager: public ISoundManager
552572
<<std::endl;
553573
return -1;
554574
}
555-
return playSoundRaw(buf, loop, volume);
575+
int handle = -1;
576+
if (fade > 0) {
577+
handle = playSoundRaw(buf, loop, 0);
578+
fadeSound(handle, fade, volume);
579+
} else {
580+
handle = playSoundRaw(buf, loop, volume);
581+
}
582+
return handle;
556583
}
584+
557585
int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
558586
{
559587
maintain();
@@ -567,16 +595,55 @@ class OpenALSoundManager: public ISoundManager
567595
}
568596
return playSoundRawAt(buf, loop, volume, pos);
569597
}
598+
570599
void stopSound(int sound)
571600
{
572601
maintain();
573602
deleteSound(sound);
574603
}
604+
605+
void fadeSound(int soundid, float step, float gain)
606+
{
607+
m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain);
608+
}
609+
610+
void doFades(float dtime)
611+
{
612+
m_fade_delay += dtime;
613+
614+
if (m_fade_delay < 0.1f)
615+
return;
616+
617+
float chkGain = 0;
618+
for (UNORDERED_MAP<int, FadeState>::iterator i = m_sounds_fading.begin();
619+
i != m_sounds_fading.end();) {
620+
if (i->second.step < 0.f)
621+
chkGain = -(i->second.current_gain);
622+
else
623+
chkGain = i->second.current_gain;
624+
625+
if (chkGain < i->second.target_gain) {
626+
i->second.current_gain += (i->second.step * m_fade_delay);
627+
i->second.current_gain = rangelim(i->second.current_gain, 0, 1);
628+
629+
updateSoundGain(i->first, i->second.current_gain);
630+
++i;
631+
} else {
632+
if (i->second.target_gain <= 0.f)
633+
stopSound(i->first);
634+
635+
m_sounds_fading.erase(i++);
636+
}
637+
}
638+
m_fade_delay = 0;
639+
}
640+
575641
bool soundExists(int sound)
576642
{
577643
maintain();
578644
return (m_sounds_playing.count(sound) != 0);
579645
}
646+
580647
void updateSoundPosition(int id, v3f pos)
581648
{
582649
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
@@ -589,6 +656,29 @@ class OpenALSoundManager: public ISoundManager
589656
alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
590657
alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
591658
}
659+
660+
bool updateSoundGain(int id, float gain)
661+
{
662+
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
663+
if (i == m_sounds_playing.end())
664+
return false;
665+
666+
PlayingSound *sound = i->second;
667+
alSourcef(sound->source_id, AL_GAIN, gain);
668+
return true;
669+
}
670+
671+
float getSoundGain(int id)
672+
{
673+
UNORDERED_MAP<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
674+
if (i == m_sounds_playing.end())
675+
return 0;
676+
677+
PlayingSound *sound = i->second;
678+
ALfloat gain;
679+
alGetSourcef(sound->source_id, AL_GAIN, &gain);
680+
return gain;
681+
}
592682
};
593683

594684
ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)

0 commit comments

Comments
 (0)
Please sign in to comment.