The Battle for Wesnoth  1.19.0-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 "sound.hpp"
19 #include "soundsource.hpp"
20 
21 #include <SDL2/SDL_timer.h>
22 
23 namespace soundsource {
24 
25 const unsigned DEFAULT_CHANCE = 100;
26 const unsigned DEFAULT_DELAY = 1000;
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  unsigned int time = SDL_GetTicks();
84 
85  for(positional_source_iterator it = sources_.begin(); it != sources_.end(); ++it) {
86  (*it).second->update(time, disp_);
87  }
88 }
89 
91 {
92  unsigned int time = SDL_GetTicks();
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_(0),
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(unsigned int time, const display &disp)
138 {
139  if (time - last_played_ < static_cast<unsigned>(min_delay_) || sound::is_sound_playing(id_))
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(unsigned int 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  return static_cast<int>((((distance - range_)
207  / static_cast<double>(faderange_)) * DISTANCE_SILENT));
208 }
209 
211 {
212  cfg["sounds"] = files_;
213  cfg["delay"] = min_delay_;
214  cfg["chance"] = chance_;
215  cfg["check_fogged"] = check_fogged_;
216  cfg["check_shrouded"] = check_shrouded_;
217  cfg["loop"] = loops_;
218  cfg["full_range"] = range_;
219  cfg["fade_range"] = faderange_;
221 }
222 
223 void sourcespec::write(config& cfg) const
224 {
225  cfg["id"] = id_;
226  cfg["sounds"] = files_;
227  cfg["delay"] = min_delay_;
228  cfg["chance"] = chance_;
229  cfg["check_fogged"] = check_fogged_;
230  cfg["check_shrouded"] = check_shrouded_;
231  cfg["loop"] = loops_;
232  cfg["full_range"] = range_;
233  cfg["fade_range"] = faderange_;
235 }
236 
238  id_(cfg["id"]),
239  files_(cfg["sounds"]),
240  min_delay_(cfg["delay"].to_int(DEFAULT_DELAY)),
241  chance_(cfg["chance"].to_int(DEFAULT_CHANCE)),
242  loops_(cfg["loop"]),
243  range_(cfg["full_range"].to_int(3)),
244  faderange_(cfg["fade_range"].to_int(14)),
245  check_fogged_(cfg["check_fogged"].to_bool(true)),
246  check_shrouded_(cfg["check_shrouded"].to_bool(true)),
247  locations_()
248 {
250 }
251 
252 } // namespace soundsource
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
config & add_child(config_key_type key)
Definition: config.cpp:441
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:81
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:557
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:702
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:514
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:697
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
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)
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:50
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:545
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:454
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:442
std::string observer
void play_sound_positioned(const std::string &files, int id, int repeats, unsigned int distance)
Definition: sound.cpp:1040
bool is_sound_playing(int id)
Definition: sound.cpp:890
void reposition_sound(int id, unsigned int distance)
Definition: sound.cpp:874
void stop_sound()
Definition: sound.cpp:563
const unsigned DEFAULT_CHANCE
Definition: soundsource.cpp:25
const unsigned 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:38