11#ifndef SOUND_SOUND_QUEUE_H
22#define SOUND_SOUND_QUEUE_H
33
4+ class SoundToPlayBase {
5+ public:
6+ virtual bool Play (BufferedWavPlayer* player) = 0;
7+ virtual ~SoundToPlayBase () {}
8+ };
9+
10+ class SoundToPlayInSameDirAs : public SoundToPlayBase {
11+ public:
12+ SoundToPlayInSameDirAs (const char * filename, Effect* e) : filename_(filename), effect_(e) {}
13+ bool Play (BufferedWavPlayer* player) override {
14+ player->PlayInSameDirAs (filename_, effect_);
15+ return true ;
16+ }
17+
18+ private:
19+ const char * filename_;
20+ Effect* effect_;
21+ };
22+
23+ class SoundToPlayInCurrentDir : public SoundToPlayBase {
24+ public:
25+ SoundToPlayInCurrentDir (const char * filename) : filename_(filename) {}
26+ bool Play (BufferedWavPlayer* player) override {
27+ return player->PlayInCurrentDir (filename_);
28+ }
29+
30+ private:
31+ const char * filename_;
32+ };
33+
34+ class SoundToPlayFileID : public SoundToPlayBase {
35+ public:
36+ SoundToPlayFileID (Effect::FileID id) : file_id_(id) {}
37+ bool Play (BufferedWavPlayer* player) override {
38+ player->PlayOnce (file_id_);
39+ return true ;
40+ }
41+
42+ private:
43+ Effect::FileID file_id_;
44+ };
45+
46+ class SoundToPlayColor : public SoundToPlayBase {
47+ public:
48+ SoundToPlayColor (unsigned char r,
49+ unsigned char g,
50+ unsigned char b) : r_(r), g_(g), b_(b) {
51+ }
52+ bool Play (BufferedWavPlayer* player) override {
53+ // color
54+ char filename[32 ];
55+ strcpy (filename, " colors/" );
56+ char * tmp = filename + strlen (filename);
57+ *(tmp++) = " 0123456789abcdef" [r_ >> 4 ];
58+ *(tmp++) = " 0123456789abcdef" [r_ & 15 ];
59+ *(tmp++) = " 0123456789abcdef" [g_ >> 4 ];
60+ *(tmp++) = " 0123456789abcdef" [g_ & 15 ];
61+ *(tmp++) = " 0123456789abcdef" [b_ >> 4 ];
62+ *(tmp++) = " 0123456789abcdef" [b_ & 15 ];
63+ strcpy (tmp, " .wav" );
64+ return player->PlayInCurrentDir (filename);
65+ }
66+ unsigned char r_, g_, b_;
67+ };
68+
69+ // Fixed-size deque of objects with shared base class.
70+ // Similar to deque<shared_ptr<BASE>>, size is fixed and
71+ // all memory allocations are done from internal memory.
72+ // push_back/emplace_back will fail and return false/nullptr
73+ // if insufficient space is available.
74+ template <class BASE , size_t N = 8 , size_t SIZE = N * 12 >
75+ class VirtVec {
76+ public:
77+ size_t size () const { return elements_.size (); }
78+ BASE* operator [](size_t n) { return elements_[n]; }
79+ BASE* first () { return elements_[0 ]; }
80+
81+ template <class T , class ... Args>
82+ T* emplace_back (Args&&... args) {
83+ char * ptr = allocate (sizeof (T), alignof (T));
84+ if (ptr == nullptr ) return nullptr ;
85+ return new (ptr) T (args...);
86+ }
87+
88+ template <class T > bool push_back (T value) {
89+ char * ptr = allocate (sizeof (T), alignof (T));
90+ if (ptr == nullptr ) return false ;
91+ return new (ptr) T (value);
92+ }
93+
94+ // Stack
95+ void pop_back () {
96+ if (elements_.empty ()) return ;
97+ int n = elements_.size () -1 ;
98+ (*this )[n]->~BASE ();
99+ buffer_.unpush (element_size (n));
100+ elements_.unpush (-1 );
101+ }
102+
103+ // Queue
104+ void pop_front () {
105+ if (elements_.empty ()) return ;
106+ (*this )[0 ]->~BASE ();
107+ buffer_.pop (element_size (0 ));
108+ elements_.pop ();
109+ }
110+
111+ void clear () {
112+ while (size ()) pop_front ();
113+ }
114+
115+ private:
116+ // May return a larger number, but not smaller.
117+ size_t element_size (size_t n) {
118+ char *a = reinterpret_cast <char *>(elements_[n]);
119+ char *b;
120+ if (n == size () - 1 ) {
121+ // Last element
122+ b = buffer_.space ();
123+ } else {
124+ b = reinterpret_cast <char *>(elements_[n + 1 ]);
125+ }
126+ if (b < a) {
127+ b = buffer_.data () + buffer_.continuous_data ();
128+ }
129+ return b - a;
130+ }
131+
132+ char * allocate (size_t size, size_t alignment) {
133+ if (elements_.space_available () == 0 ) return nullptr ;
134+ while (true ) {
135+ if (buffer_.space_available () < size) return nullptr ;
136+ if (((size_t )buffer_.space ()) % alignment) {
137+ // Fix alignment
138+ size_t misalignment = alignment - ((size_t )buffer_.space ()) % alignment;
139+ if (buffer_.space_available () < misalignment) return nullptr ;
140+ buffer_.push (misalignment);
141+ continue ; // retry
142+ }
143+ if (buffer_.continuous_space () < size) {
144+ // Not enough space at end of buffer,
145+ // jump back to beginning of buffer.
146+ // (If there is enough space there.)
147+ if (buffer_.space_available () - buffer_.continuous_space () < size) return nullptr ;
148+ buffer_.push (buffer_.continuous_space ());
149+ continue ; // retry
150+ }
151+ break ;
152+ }
153+ char * ret = buffer_.space ();
154+ buffer_.push (size);
155+ elements_.push_back (reinterpret_cast <BASE*>(ret));
156+ }
157+
158+ // Pointers to each of the elements in the VirtVec
159+ CircularBuffer<BASE*, N> elements_;
160+
161+ // Memory for storing the elements.
162+ CircularBuffer<char , SIZE> buffer_;
163+ };
164+
4165struct SoundToPlay {
5166 const char * filename_;
6167 Effect::FileID file_id_;
7168
8169 SoundToPlay () :filename_(nullptr ), file_id_(nullptr , 0xffff , 0 , 0 ) {}
9170 explicit SoundToPlay (const char * file) : filename_(file) { }
171+ explicit SoundToPlay (const char * file, Effect* effect) : filename_(file), file_id_(effect, 0 ,0 ,0 ) { }
10172 SoundToPlay (Effect* effect) : filename_(nullptr ), file_id_(effect->RandomFile ()) {}
11173 SoundToPlay (Effect* effect, int selection) : filename_(nullptr ), file_id_((effect->Select (selection),effect->RandomFile())) {}
12174 SoundToPlay (uint8_t R, uint8_t G, uint8_t B) :filename_(nullptr ), file_id_(nullptr , R, G, B) {}
@@ -40,17 +202,24 @@ struct SoundToPlay {
40202template <int QueueLength>
41203class SoundQueue {
42204public:
205+ template <class T >
206+ bool Play (T p) { queue_.push_back (p); }
207+
208+ // For backwards compatibility only.
43209 bool Play (SoundToPlay p) {
44- if (sounds_ < QueueLength) {
45- queue_[sounds_++] = p;
46- return true ;
210+ if (p.filename_ ) {
211+ return Play (SoundToPlayInCurrentDir (p.filename_ ));
47212 }
48- return false ;
49- }
50- bool Play (const char * p) {
51- return Play (SoundToPlay (p));
213+ if (p.file_id_ ) {
214+ return Play (SoundToPlayFileID (p.file_id_ ));
215+ }
216+ return Play (SoundToPlayColor (p.file_id_ .GetFileNum (),
217+ p.file_id_ .GetSubId (),
218+ p.file_id_ .GetAlt ()));
52219 }
53220
221+ bool Play (const char * p) { return Play (SoundToPlayInCurrentDir (p)); }
222+
54223 // Called from Loop()
55224 void PollSoundQueue (RefPtr<BufferedWavPlayer>& player) {
56225 busy_ = player && player->isPlaying ();
@@ -59,42 +228,40 @@ class SoundQueue {
59228 if (busy_) {
60229 // We really should add the time since the fadeout was scheduled here.
61230 // However, if polling is frequent, it would be a fraction of a milli
62- // which basically dones 't matter.
231+ // which basically doesn 't matter.
63232 player->set_fade_time (fadeout_len_);
64233 player->FadeAndStop ();
65234 }
66235 }
67236 if (!busy_) {
68- if (sounds_ ) {
237+ if (queue_. size () ) {
69238 busy_ = true ;
70239 if (!player) {
71240 player = GetFreeWavPlayer ();
72241 if (!player) return ;
73242 }
74243 player->set_volume_now (1 .0f );
75- queue_[0 ].Play (player.get ());
76- sounds_--;
77- for (int i = 0 ; i < sounds_; i++) queue_[i] = queue_[i+1 ];
244+ queue_[0 ]->Play (player.get ());
245+ queue_.pop_front ();
78246 } else {
79247 if (player) player.Free ();
80248 }
81249 }
82250 }
83251 bool busy () const { return busy_; }
84252 void fadeout (float len) {
85- sounds_ = 0 ;
253+ queue_. clear () ;
86254 fadeout_ = true ;
87255 fadeout_len_ = len;
88256 }
89257 void clear_pending () {
90- sounds_ = 0 ;
258+ queue_. clear () ;
91259 }
92260private:
93- int sounds_;
94261 bool busy_ = false ;
95262 bool fadeout_;
96263 bool fadeout_len_;
97- SoundToPlay queue_[ QueueLength] ;
264+ VirtVec<SoundToPlayBase, QueueLength, QueueLength * 12 > queue_ ;
98265};
99266
100267#endif // SOUND_SOUND_QUEUE_H
0 commit comments