The Battle for Wesnoth  1.17.21+dev
soundsource.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2023
3  by Karol Nowak <grzywacz@sul.uni.lodz.pl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "display.hpp"
17 #include "log.hpp"
18 #include "random.hpp"
19 #include "sound.hpp"
20 #include "soundsource.hpp"
21 
22 #include <SDL2/SDL_timer.h>
23 
24 namespace soundsource {
25 
26 const unsigned DEFAULT_CHANCE = 100;
27 const unsigned DEFAULT_DELAY = 1000;
28 
29 unsigned int positional_source::last_id = 0;
30 
31 manager::manager(const display &disp) :
32  observer(),
33  sources_(),
34  disp_(disp)
35 {
38 }
39 
41 {
42  sources_.clear();
43 }
44 
45 void manager::handle_generic_event(const std::string &event_name)
46 {
47  if(event_name == "scrolled")
49 }
50 
51 void manager::add(const sourcespec &spec)
52 {
53  sources_[spec.id()].reset(new positional_source(spec));
54 }
55 
56 sourcespec manager::get(const std::string &id)
57 {
58  config cfg;
60  if(it != sources_.end()) {
61  it->second->write_config(cfg);
62  }
63  return cfg;
64 }
65 
66 void manager::remove(const std::string &id)
67 {
69 
70  if((it = sources_.find(id)) == sources_.end())
71  return;
72  else {
73  sources_.erase(it);
74  }
75 }
76 
77 bool manager::contains(const std::string& id)
78 {
79  return sources_.find(id) != sources_.end();
80 }
81 
83 {
84  unsigned int time = SDL_GetTicks();
85 
86  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
87  (*it).second->update(time, disp_);
88  }
89 }
90 
92 {
93  unsigned int time = SDL_GetTicks();
94 
95  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
96  (*it).second->update_positions(time, disp_);
97  }
98 }
99 
101 {
102  for(positional_source_const_iterator i = sources_.begin(); i != sources_.end(); ++i) {
103  assert(i->second);
104 
105  config& child = cfg.add_child("sound_source");
106  child["id"] = i->first;
107  i->second->write_config(child);
108  }
109 }
110 
112  last_played_(0),
113  min_delay_(spec.minimum_delay()),
114  chance_(spec.chance()),
115  loops_(spec.loops()),
116  id_(last_id++),
117  range_(spec.full_range()),
118  faderange_(spec.fade_range()),
119  check_fogged_(spec.check_fogged()),
120  check_shrouded_(spec.check_shrouded()),
121  files_(spec.files()),
122  locations_(spec.get_locations())
123 {
124  assert(range_ > 0);
125  assert(faderange_ > 0);
126 }
127 
129 {
131 }
132 
134 {
135  return locations_.empty();
136 }
137 
138 void positional_source::update(unsigned int time, const display &disp)
139 {
140  if (time - last_played_ < static_cast<unsigned>(min_delay_) || sound::is_sound_playing(id_))
141  return;
142 
144 
145  if(i <= chance_) {
146  last_played_ = time;
147 
148  // If no locations have been specified, treat the source as if
149  // it was present everywhere on the map
150  if(locations_.empty()) {
151  sound::play_sound_positioned(files_, id_, loops_, 0); // max volume
152  return;
153  }
154 
155  int distance_volume = DISTANCE_SILENT;
156  for(const map_location& l : locations_) {
157  int v = calculate_volume(l, disp);
158  if(v < distance_volume) {
159  distance_volume = v;
160  }
161  }
162 
163  if(distance_volume >= DISTANCE_SILENT)
164  return;
165 
166  sound::play_sound_positioned(files_, id_, loops_, distance_volume);
167  }
168 }
169 
170 void positional_source::update_positions(unsigned int time, const display &disp)
171 {
172  if(is_global()) {
173  return;
174  }
175 
176  int distance_volume = DISTANCE_SILENT;
177  for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
178  int v = calculate_volume(*i, disp);
179  if(v < distance_volume) {
180  distance_volume = v;
181  }
182  }
183 
185  sound::reposition_sound(id_, distance_volume);
186  } else {
187  update(time, disp);
188  }
189 }
190 
192 {
193  assert(range_ > 0);
194  assert(faderange_ > 0);
195 
196  if((check_shrouded_ && disp.shrouded(loc)) || (check_fogged_ && disp.fogged(loc)))
197  return DISTANCE_SILENT;
198 
199  SDL_Rect area = disp.map_area();
200  map_location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
201  int distance = distance_between(loc, center);
202 
203  if(distance <= range_) {
204  return 0;
205  }
206 
207  return static_cast<int>((((distance - range_)
208  / static_cast<double>(faderange_)) * DISTANCE_SILENT));
209 }
210 
212 {
213  cfg["sounds"] = files_;
214  cfg["delay"] = min_delay_;
215  cfg["chance"] = chance_;
216  cfg["check_fogged"] = check_fogged_;
217  cfg["check_shrouded"] = check_shrouded_;
218  cfg["loop"] = loops_;
219  cfg["full_range"] = range_;
220  cfg["fade_range"] = faderange_;
222 }
223 
224 void sourcespec::write(config& cfg) const
225 {
226  cfg["id"] = id_;
227  cfg["sounds"] = files_;
228  cfg["delay"] = min_delay_;
229  cfg["chance"] = chance_;
230  cfg["check_fogged"] = check_fogged_;
231  cfg["check_shrouded"] = check_shrouded_;
232  cfg["loop"] = loops_;
233  cfg["full_range"] = range_;
234  cfg["fade_range"] = faderange_;
236 }
237 
239  id_(cfg["id"]),
240  files_(cfg["sounds"]),
241  min_delay_(cfg["delay"].to_int(DEFAULT_DELAY)),
242  chance_(cfg["chance"].to_int(DEFAULT_CHANCE)),
243  loops_(cfg["loop"]),
244  range_(cfg["full_range"].to_int(3)),
245  faderange_(cfg["fade_range"].to_int(14)),
246  check_fogged_(cfg["check_fogged"].to_bool(true)),
247  check_shrouded_(cfg["check_shrouded"].to_bool(true)),
248  locations_()
249 {
251 }
252 
253 } // namespace soundsource
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
config & add_child(config_key_type key)
Definition: config.cpp:445
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:87
const map_location hex_clicked_on(int x, int y) const
given x,y co-ordinates of an onscreen pixel, will return the location of the hex that this pixel corr...
Definition: display.cpp:562
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:707
events::generic_event & scroll_event() const
Expose the event, so observers can be notified about map scrolling.
Definition: display.hpp:538
rect map_area() const
Returns the area used for the map.
Definition: display.cpp:519
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:702
virtual bool attach_handler(observer *obs)
static rng & default_instance()
Definition: random.cpp:74
int get_random_int(int min, int max)
Definition: random.hpp:52
void handle_generic_event(const std::string &event_name)
Definition: soundsource.cpp:45
sourcespec get(const std::string &id)
Definition: soundsource.cpp:56
positional_source_map sources_
Definition: soundsource.hpp:84
const display & disp_
Definition: soundsource.hpp:85
positional_source_map::iterator positional_source_iterator
Definition: soundsource.hpp:81
manager(const display &disp)
Definition: soundsource.cpp:31
void write_sourcespecs(config &cfg) const
Serializes information into cfg as new children of key "sound_source", appended to existing content.
void add(const sourcespec &source)
Definition: soundsource.cpp:51
positional_source_map::const_iterator positional_source_const_iterator
Definition: soundsource.hpp:82
bool contains(const std::string &id)
Definition: soundsource.cpp:77
void remove(const std::string &id)
Definition: soundsource.cpp:66
void write_config(config &cfg) const
Serializes attributes as WML config.
std::vector< map_location > locations_
Definition: soundsource.hpp:47
int calculate_volume(const map_location &loc, const display &disp)
void update(unsigned int time, const display &disp)
void update_positions(unsigned int time, const display &disp)
positional_source(const sourcespec &spec)
static unsigned int last_id
Definition: soundsource.hpp:51
Sound source info class.
sourcespec(const std::string &id, const std::string &files, int min_delay, int chance)
Parameter-list constructor.
void write(config &cfg) const
Serializes information into cfg as a new (appended) child of key "sound_source".
const std::string id_
std::vector< map_location > locations_
const std::string & id() const
std::size_t i
Definition: function.cpp:968
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.cpp:546
void write_locations(const std::vector< map_location > &locs, config &cfg)
Write a vector of locations into a config adding keys x=x1,x2,..,xn and y=y1,y2,.....
Definition: location.cpp:455
void read_locations(const config &cfg, std::vector< map_location > &locs)
Parse x,y keys of a config into a vector of locations.
Definition: location.cpp:443
Standard logging facilities (interface).
std::string observer
void play_sound_positioned(const std::string &files, int id, int repeats, unsigned int distance)
Definition: sound.cpp:1042
bool is_sound_playing(int id)
Definition: sound.cpp:892
void reposition_sound(int id, unsigned int distance)
Definition: sound.cpp:876
void stop_sound()
Definition: sound.cpp:565
const unsigned DEFAULT_CHANCE
Definition: soundsource.cpp:26
const unsigned DEFAULT_DELAY
Definition: soundsource.cpp:27
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
#define DISTANCE_SILENT
Definition: sound.hpp:76
Encapsulates the map of the game.
Definition: location.hpp:38