The Battle for Wesnoth  1.19.5+dev
soundsource.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2024
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 "random.hpp"
18 #include "serialization/chrono.hpp"
19 #include "sound.hpp"
20 #include "soundsource.hpp"
21 
22 namespace soundsource {
23 
24 using namespace std::chrono_literals;
25 const unsigned DEFAULT_CHANCE = 100;
26 const auto DEFAULT_DELAY = 1000ms;
27 
28 unsigned int positional_source::last_id = 0;
29 
30 manager::manager(const display &disp) :
31  observer(),
32  sources_(),
33  disp_(disp)
34 {
37 }
38 
40 {
41  sources_.clear();
42 }
43 
44 void manager::handle_generic_event(const std::string &event_name)
45 {
46  if(event_name == "scrolled")
48 }
49 
50 void manager::add(const sourcespec &spec)
51 {
52  sources_[spec.id()].reset(new positional_source(spec));
53 }
54 
55 sourcespec manager::get(const std::string &id)
56 {
57  config cfg;
59  if(it != sources_.end()) {
60  it->second->write_config(cfg);
61  }
62  return cfg;
63 }
64 
65 void manager::remove(const std::string &id)
66 {
68 
69  if((it = sources_.find(id)) == sources_.end())
70  return;
71  else {
72  sources_.erase(it);
73  }
74 }
75 
76 bool manager::contains(const std::string& id)
77 {
78  return sources_.find(id) != sources_.end();
79 }
80 
82 {
83  auto time = std::chrono::steady_clock::now();
84 
85  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
86  (*it).second->update(time, disp_);
87  }
88 }
89 
91 {
92  auto time = std::chrono::steady_clock::now();
93 
94  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
95  (*it).second->update_positions(time, disp_);
96  }
97 }
98 
100 {
101  for(positional_source_const_iterator i = sources_.begin(); i != sources_.end(); ++i) {
102  assert(i->second);
103 
104  config& child = cfg.add_child("sound_source");
105  child["id"] = i->first;
106  i->second->write_config(child);
107  }
108 }
109 
111  last_played_(),
112  min_delay_(spec.minimum_delay()),
113  chance_(spec.chance()),
114  loops_(spec.loops()),
115  id_(last_id++),
116  range_(spec.full_range()),
117  faderange_(spec.fade_range()),
118  check_fogged_(spec.check_fogged()),
119  check_shrouded_(spec.check_shrouded()),
120  files_(spec.files()),
121  locations_(spec.get_locations())
122 {
123  assert(range_ >= 0);
124  assert(faderange_ >= 0);
125 }
126 
128 {
130 }
131 
133 {
134  return locations_.empty();
135 }
136 
137 void positional_source::update(const std::chrono::steady_clock::time_point& time, const display &disp)
138 {
140  return;
141 
143 
144  if(i <= chance_) {
145  last_played_ = time;
146 
147  // If no locations have been specified, treat the source as if
148  // it was present everywhere on the map
149  if(locations_.empty()) {
150  sound::play_sound_positioned(files_, id_, loops_, 0); // max volume
151  return;
152  }
153 
154  int distance_volume = DISTANCE_SILENT;
155  for(const map_location& l : locations_) {
156  int v = calculate_volume(l, disp);
157  if(v < distance_volume) {
158  distance_volume = v;
159  }
160  }
161 
162  if(distance_volume >= DISTANCE_SILENT)
163  return;
164 
165  sound::play_sound_positioned(files_, id_, loops_, distance_volume);
166  }
167 }
168 
169 void positional_source::update_positions(const std::chrono::steady_clock::time_point& time, const display &disp)
170 {
171  if(is_global()) {
172  return;
173  }
174 
175  int distance_volume = DISTANCE_SILENT;
176  for(std::vector<map_location>::iterator i = locations_.begin(); i != locations_.end(); ++i) {
177  int v = calculate_volume(*i, disp);
178  if(v < distance_volume) {
179  distance_volume = v;
180  }
181  }
182 
184  sound::reposition_sound(id_, distance_volume);
185  } else {
186  update(time, disp);
187  }
188 }
189 
191 {
192  assert(range_ >= 0);
193  assert(faderange_ >= 0);
194 
195  if((check_shrouded_ && disp.shrouded(loc)) || (check_fogged_ && disp.fogged(loc)))
196  return DISTANCE_SILENT;
197 
198  SDL_Rect area = disp.map_area();
199  map_location center = disp.hex_clicked_on(area.x + area.w / 2, area.y + area.h / 2);
200  int distance = distance_between(loc, center);
201 
202  if(distance <= range_) {
203  return 0;
204  }
205 
206  if(faderange_ == 0) {
207  return DISTANCE_SILENT;
208  }
209 
210  return static_cast<int>((((distance - range_)
211  / static_cast<double>(faderange_)) * DISTANCE_SILENT));
212 }
213 
215 {
216  cfg["sounds"] = files_;
217  cfg["delay"] = min_delay_;
218  cfg["chance"] = chance_;
219  cfg["check_fogged"] = check_fogged_;
220  cfg["check_shrouded"] = check_shrouded_;
221  cfg["loop"] = loops_;
222  cfg["full_range"] = range_;
223  cfg["fade_range"] = faderange_;
225 }
226 
227 void sourcespec::write(config& cfg) const
228 {
229  cfg["id"] = id_;
230  cfg["sounds"] = files_;
231  cfg["delay"] = min_delay_;
232  cfg["chance"] = chance_;
233  cfg["check_fogged"] = check_fogged_;
234  cfg["check_shrouded"] = check_shrouded_;
235  cfg["loop"] = loops_;
236  cfg["full_range"] = range_;
237  cfg["fade_range"] = faderange_;
239 }
240 
242  : id_(cfg["id"])
243  , files_(cfg["sounds"])
244  , min_delay_(chrono::parse_duration(cfg["delay"], DEFAULT_DELAY))
245  , chance_(cfg["chance"].to_int(DEFAULT_CHANCE))
246  , loops_(cfg["loop"].to_int())
247  , range_(cfg["full_range"].to_int(3))
248  , faderange_(cfg["fade_range"].to_int(14))
249  , check_fogged_(cfg["check_fogged"].to_bool(true))
250  , check_shrouded_(cfg["check_shrouded"].to_bool(true))
251  , locations_()
252 {
254 }
255 
256 } // namespace soundsource
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
config & add_child(config_key_type key)
Definition: config.cpp:440
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:97
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:674
events::generic_event & scroll_event() const
Expose the event, so observers can be notified about map scrolling.
Definition: display.hpp:537
rect map_area() const
Returns the area used for the map.
Definition: display.cpp:495
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:538
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:669
virtual bool attach_handler(observer *obs)
static rng & default_instance()
Definition: random.cpp:73
int get_random_int(int min, int max)
Definition: random.hpp:51
void handle_generic_event(const std::string &event_name)
Definition: soundsource.cpp:44
sourcespec get(const std::string &id)
Definition: soundsource.cpp:55
positional_source_map sources_
Definition: soundsource.hpp:83
const display & disp_
Definition: soundsource.hpp:84
positional_source_map::iterator positional_source_iterator
Definition: soundsource.hpp:80
manager(const display &disp)
Definition: soundsource.cpp:30
void write_sourcespecs(config &cfg) const
Serializes information into cfg as new children of key "sound_source", appended to existing content.
Definition: soundsource.cpp:99
void add(const sourcespec &source)
Definition: soundsource.cpp:50
positional_source_map::const_iterator positional_source_const_iterator
Definition: soundsource.hpp:81
bool contains(const std::string &id)
Definition: soundsource.cpp:76
void remove(const std::string &id)
Definition: soundsource.cpp:65
std::chrono::steady_clock::time_point last_played_
Definition: soundsource.hpp:36
void update(const std::chrono::steady_clock::time_point &time, const display &disp)
void write_config(config &cfg) const
Serializes attributes as WML config.
std::vector< map_location > locations_
Definition: soundsource.hpp:46
int calculate_volume(const map_location &loc, const display &disp)
positional_source(const sourcespec &spec)
static unsigned int last_id
Definition: soundsource.hpp:50
std::chrono::milliseconds min_delay_
Definition: soundsource.hpp:37
void update_positions(const std::chrono::steady_clock::time_point &time, const display &disp)
Sound source info class.
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_
sourcespec(const std::string &id, const std::string &files, const std::chrono::milliseconds &min_delay, int chance)
Parameter-list constructor.
std::chrono::milliseconds min_delay_
const std::string & id() const
map_display and display: classes which take care of displaying the map and game-data on the screen.
std::size_t i
Definition: function.cpp:1028
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:550
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:459
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:447
auto parse_duration(const config_attribute_value &val, const Duration &def=Duration{0})
Definition: chrono.hpp:70
std::string observer
void play_sound_positioned(const std::string &files, int id, int repeats, unsigned int distance)
Definition: sound.cpp:1053
bool is_sound_playing(int id)
Definition: sound.cpp:897
void reposition_sound(int id, unsigned int distance)
Definition: sound.cpp:881
void stop_sound()
Definition: sound.cpp:565
const unsigned DEFAULT_CHANCE
Definition: soundsource.cpp:25
const auto DEFAULT_DELAY
Definition: soundsource.cpp:26
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:45