1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2011 by The Allacrost Project
3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 // All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See https://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "modes/map/map_objects/map_sound.h"
12
13 #include "modes/map/map_mode.h"
14 #include "modes/map/map_object_supervisor.h"
15
16 #include "engine/audio/audio.h"
17
18 using namespace vt_common;
19
20 namespace vt_map
21 {
22
23 namespace private_map
24 {
25
SoundObject(const std::string & sound_filename,float x,float y,float strength)26 SoundObject::SoundObject(const std::string& sound_filename, float x, float y, float strength):
27 MapObject(NO_LAYER_OBJECT), // This is a special object
28 _strength(strength),
29 _sound_volume(0.0f),
30 _max_sound_volume(1.0f),
31 _time_remaining(0.0f),
32 _activated(true),
33 _playing(false)
34 {
35 _object_type = SOUND_TYPE;
36
37 // We use the AudioManager to mutualize the sound descriptors instances.
38 bool loaded = true;
39 loaded = vt_audio::AudioManager->LoadSound(sound_filename, MapMode::CurrentInstance());
40 _sound = vt_audio::AudioManager->RetrieveSound(sound_filename);
41 if (!loaded || _sound == nullptr) {
42 PRINT_WARNING << "Couldn't load environmental sound file: "
43 << sound_filename << std::endl;
44 }
45
46 // Invalidates negative or near 0 values.
47 if (_strength <= 0.2f)
48 _strength = 0.0f;
49
50 _tile_position.x = x;
51 _tile_position.y = y;
52
53 _collision_mask = NO_COLLISION;
54
55 if (_sound) {
56 _sound->SetLooping(true);
57 _sound->SetVolume(0.0f);
58 _sound->Stop();
59 }
60
61 // Register the object to the sound vector
62 MapMode::CurrentInstance()->GetObjectSupervisor()->AddAmbientSound(this);
63 }
64
Create(const std::string & sound_filename,float x,float y,float strength)65 SoundObject* SoundObject::Create(const std::string& sound_filename,
66 float x, float y, float strength)
67 {
68 // The object auto registers to the object supervisor
69 // and will later handle deletion.
70 return new SoundObject(sound_filename, x, y, strength);
71 }
72
SetMaxVolume(float max_volume)73 void SoundObject::SetMaxVolume(float max_volume)
74 {
75 _max_sound_volume = max_volume;
76
77 if (_max_sound_volume < 0.0f)
78 _max_sound_volume = 0.0f;
79 else if (_max_sound_volume > 1.0f)
80 _max_sound_volume = 1.0f;
81 }
82
UpdateVolume()83 void SoundObject::UpdateVolume()
84 {
85 // Don't activate a sound which is too weak to be heard anyway.
86 if (_strength < 1.0f || _max_sound_volume <= 0.0f) {
87 _sound_volume = 0.0f;
88 return;
89 }
90
91 if (!_activated) {
92 _sound_volume = 0.0f;
93 return;
94 }
95
96 // Update the volume only every 100ms
97 _time_remaining -= static_cast<int32_t>(vt_system::SystemManager->GetUpdateTime());
98 if (_time_remaining > 0)
99 return;
100 _time_remaining = 100;
101
102 // N.B.: The distance between two point formula is:
103 // squareroot((x2 - x1)^2+(y2 - y1)^2)
104 MapMode *mm = MapMode::CurrentInstance();
105 if(!mm)
106 return;
107
108 const MapFrame& frame = mm->GetMapFrame();
109
110 Position2D center;
111 center.x = frame.screen_edges.left + (frame.screen_edges.right - frame.screen_edges.left) / 2.0f;
112 center.y = frame.screen_edges.top + (frame.screen_edges.bottom - frame.screen_edges.top) / 2.0f;
113
114 float distance = _tile_position.GetDistance2(center);
115 //distance = sqrtf(_distance); <-- We don't actually need it as it is slow.
116
117 float strength2 = _strength * _strength;
118
119 if (distance >= strength2) {
120 if (_playing) {
121 _sound_volume = 0.0f;
122 _playing = false;
123 }
124 return;
125 }
126
127 // We add a one-half-tile neutral margin where nothing happens
128 // to avoid the edge case where the sound repeatedly starts/stops
129 // because of the camera position rounding.
130 if (distance >= (strength2 - 0.5f))
131 return;
132
133 _sound_volume = _max_sound_volume - (_max_sound_volume * (distance / strength2));
134 _playing = true;
135 }
136
ApplyVolume()137 void SoundObject::ApplyVolume()
138 {
139 if (!_sound)
140 return;
141
142 // Stop sound if needed.
143 if (_sound_volume <= 0.1f) {
144 if (_sound->GetState() == vt_audio::AUDIO_STATE_PLAYING
145 || _sound->GetState() == vt_audio::AUDIO_STATE_FADE_IN) {
146 _sound->FadeOut(1000.0f);
147 }
148 return;
149 }
150
151 if (_sound->GetState() != vt_audio::AUDIO_STATE_PLAYING
152 && _sound->GetState() != vt_audio::AUDIO_STATE_FADE_IN) {
153 _sound->FadeIn(1000.0f);
154 }
155 _sound->SetVolume(_sound_volume);
156 }
157
Stop()158 void SoundObject::Stop()
159 {
160 if (!_activated)
161 return;
162
163 if (_sound)
164 _sound->FadeOut(1000.0f);
165 _activated = false;
166 }
167
Start()168 void SoundObject::Start()
169 {
170 if (_activated)
171 return;
172
173 _activated = true;
174
175 // Restores the sound state
176 UpdateVolume();
177 }
178
179 } // namespace private_map
180
181 } // namespace vt_map
182