Lines 30-46
Link Here
|
30 |
} |
30 |
} |
31 |
|
31 |
|
32 |
SOUND::SOUND() : |
32 |
SOUND::SOUND() : |
|
|
33 |
log_error(0), |
33 |
deviceinfo(0, 0, 0, 0), |
34 |
deviceinfo(0, 0, 0, 0), |
|
|
35 |
sound_volume(0), |
34 |
initdone(false), |
36 |
initdone(false), |
35 |
disable(false), |
37 |
disable(false), |
36 |
paused(true), |
|
|
37 |
sampler_lock(0), |
38 |
sampler_lock(0), |
38 |
source_lock(0), |
39 |
source_lock(0), |
|
|
40 |
set_pause(true), |
39 |
max_active_sources(64), |
41 |
max_active_sources(64), |
40 |
sources_num(0), |
42 |
sources_num(0), |
41 |
samplers_num(0) |
43 |
sources_pause(true), |
|
|
44 |
samplers_num(0), |
45 |
samplers_pause(true) |
42 |
{ |
46 |
{ |
43 |
volume_filter.SetFilterOrder0(1.0); |
|
|
44 |
sources.reserve(64); |
47 |
sources.reserve(64); |
45 |
samplers.reserve(64); |
48 |
samplers.reserve(64); |
46 |
} |
49 |
} |
Lines 115-125
Link Here
|
115 |
} |
118 |
} |
116 |
|
119 |
|
117 |
deviceinfo = SOUNDINFO(samples, frequency, channels, bytespersample); |
120 |
deviceinfo = SOUNDINFO(samples, frequency, channels, bytespersample); |
118 |
|
121 |
log_error = &error_output; |
119 |
initdone = true; |
122 |
initdone = true; |
120 |
|
|
|
121 |
SetVolume(1.0); |
123 |
SetVolume(1.0); |
122 |
|
124 |
|
|
|
125 |
// enable sound, run callback |
126 |
SDL_PauseAudio(false); |
127 |
|
123 |
return true; |
128 |
return true; |
124 |
} |
129 |
} |
125 |
|
130 |
|
Lines 138-183
Link Here
|
138 |
disable = true; |
143 |
disable = true; |
139 |
} |
144 |
} |
140 |
|
145 |
|
141 |
void SOUND::Pause(bool value) |
146 |
void SOUND::Update(bool pause) |
142 |
{ |
|
|
143 |
if (paused != value) |
144 |
{ |
145 |
SDL_PauseAudio(value); |
146 |
paused = value; |
147 |
} |
148 |
} |
149 |
|
150 |
void SOUND::Update() |
151 |
{ |
147 |
{ |
152 |
if (disable) return; |
148 |
if (disable) return; |
153 |
|
149 |
|
|
|
150 |
set_pause = pause; |
151 |
|
154 |
GetSourceChanges(); |
152 |
GetSourceChanges(); |
155 |
|
153 |
|
156 |
ProcessSourceStop(); |
154 |
ProcessSourceStop(); |
157 |
|
155 |
|
158 |
ProcessSourceRemove(); |
|
|
159 |
|
160 |
ProcessSources(); |
156 |
ProcessSources(); |
161 |
|
157 |
|
162 |
SetSamplerChanges(); |
158 |
ProcessSourceRemove(); |
163 |
|
|
|
164 |
// short circuit if paused(sound thread blocked) |
165 |
if (paused) |
166 |
{ |
167 |
GetSamplerChanges(); |
168 |
|
169 |
ProcessSamplerAdd(); |
170 |
|
171 |
ProcessSamplerRemove(); |
172 |
|
173 |
SetSourceChanges(); |
174 |
|
175 |
GetSourceChanges(); |
176 |
|
177 |
ProcessSourceStop(); |
178 |
|
159 |
|
179 |
ProcessSourceRemove(); |
160 |
SetSamplerChanges(); |
180 |
} |
|
|
181 |
} |
161 |
} |
182 |
|
162 |
|
183 |
void SOUND::SetMaxActiveSources(size_t value) |
163 |
void SOUND::SetMaxActiveSources(size_t value) |
Lines 192-209
Link Here
|
192 |
size_t id = item_num; |
172 |
size_t id = item_num; |
193 |
if (id < items.size()) |
173 |
if (id < items.size()) |
194 |
{ |
174 |
{ |
|
|
175 |
// reuse free slot |
195 |
size_t idn = items[id].id; |
176 |
size_t idn = items[id].id; |
196 |
if (idn != id) |
177 |
if (idn != id) |
197 |
{ |
178 |
{ |
198 |
// swap back redirected item |
179 |
// free slot is redirecting to other item |
199 |
assert(idn < id); |
180 |
assert(idn < id); |
|
|
181 |
|
182 |
// swap redirected item back |
200 |
items[id] = items[idn]; |
183 |
items[id] = items[idn]; |
|
|
184 |
|
185 |
// use now free slot |
201 |
id = idn; |
186 |
id = idn; |
202 |
} |
187 |
} |
203 |
items[id] = item; |
188 |
items[id] = item; |
204 |
} |
189 |
} |
205 |
else |
190 |
else |
206 |
{ |
191 |
{ |
|
|
192 |
// add item to new slot |
207 |
items.push_back(item); |
193 |
items.push_back(item); |
208 |
} |
194 |
} |
209 |
items[id].id = id; |
195 |
items[id].id = id; |
Lines 217-225
Link Here
|
217 |
inline void RemoveItem(size_t id, std::vector<T> & items, size_t & item_num) |
203 |
inline void RemoveItem(size_t id, std::vector<T> & items, size_t & item_num) |
218 |
{ |
204 |
{ |
219 |
assert(id < items.size()); |
205 |
assert(id < items.size()); |
|
|
206 |
|
207 |
// get item true id |
220 |
size_t idn = items[id].id; |
208 |
size_t idn = items[id].id; |
221 |
assert(idn < item_num); |
209 |
assert(idn < item_num); |
|
|
210 |
|
211 |
// pop last item |
222 |
--item_num; |
212 |
--item_num; |
|
|
213 |
|
223 |
// swap last item with current |
214 |
// swap last item with current |
224 |
size_t idl = items[item_num].id; |
215 |
size_t idl = items[item_num].id; |
225 |
if (idl != item_num) |
216 |
if (idl != item_num) |
Lines 270-283
Link Here
|
270 |
ns.id = -1; |
261 |
ns.id = -1; |
271 |
sampler_add.getFirst().push_back(ns); |
262 |
sampler_add.getFirst().push_back(ns); |
272 |
|
263 |
|
273 |
//std::cout << "Add sound source: " << id << " " << buffer->GetName() << std::endl; |
264 |
//*log_error << "Add sound source: " << id << " " << buffer->GetName() << std::endl; |
274 |
return id; |
265 |
return id; |
275 |
} |
266 |
} |
276 |
|
267 |
|
277 |
void SOUND::RemoveSource(size_t id) |
268 |
void SOUND::RemoveSource(size_t id) |
278 |
{ |
269 |
{ |
279 |
// notify sound thread, it will notify main thread to remove the source |
270 |
// notify sound and main thread to remove the source/sampler |
280 |
//std::cout << "To be removed source: " << id << " " << sources[sources[id].id].buffer->GetName() << std::endl; |
|
|
281 |
sampler_remove.getFirst().push_back(id); |
271 |
sampler_remove.getFirst().push_back(id); |
282 |
} |
272 |
} |
283 |
|
273 |
|
Lines 343-356
Link Here
|
343 |
|
333 |
|
344 |
void SOUND::SetVolume(float value) |
334 |
void SOUND::SetVolume(float value) |
345 |
{ |
335 |
{ |
346 |
volume_filter.SetFilterOrder0(clamp(value, 0.f, 1.f)); |
336 |
sound_volume = value; |
347 |
} |
337 |
} |
348 |
|
338 |
|
349 |
void SOUND::GetSourceChanges() |
339 |
void SOUND::GetSourceChanges() |
350 |
{ |
340 |
{ |
351 |
Lock(source_lock); |
341 |
Lock(source_lock); |
352 |
source_stop.swapFirst(); |
342 |
source_stop.swapFirst(); |
353 |
source_remove.swapFirst(); |
|
|
354 |
Unlock(source_lock); |
343 |
Unlock(source_lock); |
355 |
} |
344 |
} |
356 |
|
345 |
|
Lines 368-384
Link Here
|
368 |
|
357 |
|
369 |
void SOUND::ProcessSourceRemove() |
358 |
void SOUND::ProcessSourceRemove() |
370 |
{ |
359 |
{ |
371 |
std::vector<size_t> & sremove = source_remove.getFirst(); |
360 |
std::vector<size_t> & sremove = sampler_remove.getFirst(); |
372 |
for (size_t i = 0; i < sremove.size(); ++i) |
361 |
for (size_t i = 0; i < sremove.size(); ++i) |
373 |
{ |
362 |
{ |
374 |
size_t id = sremove[i]; |
363 |
size_t id = sremove[i]; |
375 |
assert(id < sources.size()); |
364 |
assert(id < sources.size()); |
|
|
365 |
|
376 |
size_t idn = sources[id].id; |
366 |
size_t idn = sources[id].id; |
377 |
assert(idn < sources_num); |
367 |
assert(idn < sources_num); |
378 |
//std::cout << "Remove sound source: " << id << " " << sources[idn].buffer->GetName() << std::endl; |
368 |
//*log_error << "Remove sound source: " << id << " " << sources[idn].buffer->GetName() << std::endl; |
|
|
369 |
|
379 |
RemoveItem(id, sources, sources_num); |
370 |
RemoveItem(id, sources, sources_num); |
380 |
} |
371 |
} |
381 |
sremove.clear(); |
|
|
382 |
} |
372 |
} |
383 |
|
373 |
|
384 |
void SOUND::ProcessSources() |
374 |
void SOUND::ProcessSources() |
Lines 436-443
Link Here
|
436 |
} |
426 |
} |
437 |
} |
427 |
} |
438 |
|
428 |
|
439 |
supdate[i].gain1 = gain1 * Sampler::denom; |
429 |
// fade sound volume |
440 |
supdate[i].gain2 = gain2 * Sampler::denom; |
430 |
float volume = set_pause ? 0 : sound_volume; |
|
|
431 |
|
432 |
supdate[i].gain1 = volume * gain1 * Sampler::denom; |
433 |
supdate[i].gain2 = volume * gain2 * Sampler::denom; |
441 |
supdate[i].pitch = src.pitch * Sampler::denom; |
434 |
supdate[i].pitch = src.pitch * Sampler::denom; |
442 |
} |
435 |
} |
443 |
|
436 |
|
Lines 471-476
Link Here
|
471 |
if (sampler_update.getFirst().size()) sampler_update.swapFirst(); |
464 |
if (sampler_update.getFirst().size()) sampler_update.swapFirst(); |
472 |
if (sampler_add.getFirst().size()) sampler_add.swapFirst(); |
465 |
if (sampler_add.getFirst().size()) sampler_add.swapFirst(); |
473 |
if (sampler_remove.getFirst().size()) sampler_remove.swapFirst(); |
466 |
if (sampler_remove.getFirst().size()) sampler_remove.swapFirst(); |
|
|
467 |
sources_pause = set_pause; |
474 |
Unlock(sampler_lock); |
468 |
Unlock(sampler_lock); |
475 |
} |
469 |
} |
476 |
|
470 |
|
Lines 478-510
Link Here
|
478 |
{ |
472 |
{ |
479 |
Lock(sampler_lock); |
473 |
Lock(sampler_lock); |
480 |
sampler_update.swapLast(); |
474 |
sampler_update.swapLast(); |
481 |
sampler_remove.swapLast(); |
|
|
482 |
sampler_add.swapLast(); |
475 |
sampler_add.swapLast(); |
|
|
476 |
sampler_remove.swapLast(); |
477 |
samplers_fade = samplers_pause != sources_pause; |
478 |
samplers_pause = sources_pause; |
483 |
Unlock(sampler_lock); |
479 |
Unlock(sampler_lock); |
484 |
} |
480 |
} |
485 |
|
481 |
|
486 |
void SOUND::ProcessSamplerUpdate() |
482 |
void SOUND::ProcessSamplerUpdate() |
487 |
{ |
483 |
{ |
488 |
std::vector<SamplerUpdate> & supdate = sampler_update.getLast(); |
484 |
std::vector<SamplerUpdate> & supdate = sampler_update.getLast(); |
489 |
if (samplers_num == supdate.size()) |
485 |
if (supdate.empty()) return; |
|
|
486 |
|
487 |
assert(samplers_num == supdate.size()); |
488 |
for (size_t i = 0; i < samplers_num; ++i) |
490 |
{ |
489 |
{ |
491 |
for (size_t i = 0; i < samplers_num; ++i) |
490 |
samplers[i].gain1 = supdate[i].gain1; |
492 |
{ |
491 |
samplers[i].gain2 = supdate[i].gain2; |
493 |
samplers[i].gain1 = supdate[i].gain1; |
492 |
samplers[i].pitch = supdate[i].pitch; |
494 |
samplers[i].gain2 = supdate[i].gain2; |
|
|
495 |
samplers[i].pitch = supdate[i].pitch; |
496 |
} |
497 |
} |
493 |
} |
498 |
supdate.clear(); |
494 |
supdate.clear(); |
499 |
} |
495 |
} |
500 |
|
496 |
|
501 |
void SOUND::ProcessSamplers(unsigned char *stream, int len) |
497 |
void SOUND::ProcessSamplers(unsigned char *stream, int len) |
502 |
{ |
498 |
{ |
503 |
// set buffers and clear stream |
499 |
// clear stream |
|
|
500 |
memset(stream, 0, len); |
501 |
|
502 |
// pause sampling |
503 |
if (samplers_pause && !samplers_fade) |
504 |
return; |
505 |
|
506 |
// init sampling buffers |
504 |
int len4 = len / 4; |
507 |
int len4 = len / 4; |
505 |
buffer1.resize(len4); |
508 |
buffer1.resize(len4); |
506 |
buffer2.resize(len4); |
509 |
buffer2.resize(len4); |
507 |
memset(stream, 0, len); |
|
|
508 |
|
510 |
|
509 |
// run samplers |
511 |
// run samplers |
510 |
short * sstream = (short*)stream; |
512 |
short * sstream = (short*)stream; |
Lines 519-531
Link Here
|
519 |
{ |
521 |
{ |
520 |
SampleAndAdvanceWithPitch16bit(smp, &buffer1[0], &buffer2[0], len4); |
522 |
SampleAndAdvanceWithPitch16bit(smp, &buffer1[0], &buffer2[0], len4); |
521 |
|
523 |
|
522 |
volume_filter.Filter(&buffer1[0], &buffer2[0], len4); |
|
|
523 |
|
524 |
for (int n = 0; n < len4; ++n) |
524 |
for (int n = 0; n < len4; ++n) |
525 |
{ |
525 |
{ |
526 |
int pos = n * 2; |
526 |
int pos = n * 2; |
527 |
sstream[pos] = clamp(sstream[pos] + buffer1[n], -32768, 32767); |
527 |
int val1 = sstream[pos] + buffer1[n]; |
528 |
sstream[pos + 1] = clamp(sstream[pos + 1] + buffer2[n], -32768, 32767); |
528 |
int val2 = sstream[pos + 1] + buffer2[n]; |
|
|
529 |
|
530 |
val1 = clamp(val1, -32768, 32767); |
531 |
val2 = clamp(val2, -32768, 32767); |
532 |
|
533 |
sstream[pos] = val1; |
534 |
sstream[pos + 1] = val2; |
529 |
} |
535 |
} |
530 |
} |
536 |
} |
531 |
else |
537 |
else |
Lines 541-557
Link Here
|
541 |
void SOUND::ProcessSamplerRemove() |
547 |
void SOUND::ProcessSamplerRemove() |
542 |
{ |
548 |
{ |
543 |
std::vector<size_t> & sremove = sampler_remove.getLast(); |
549 |
std::vector<size_t> & sremove = sampler_remove.getLast(); |
544 |
if (!sremove.empty()) |
550 |
for (size_t i = 0; i < sremove.size(); ++i) |
545 |
{ |
551 |
{ |
546 |
for (size_t i = 0; i < sremove.size(); ++i) |
552 |
size_t id = sremove[i]; |
547 |
{ |
553 |
assert(id < samplers.size()); |
548 |
size_t id = sremove[i]; |
554 |
RemoveItem(id, samplers, samplers_num); |
549 |
assert(id < samplers.size()); |
|
|
550 |
RemoveItem(id, samplers, samplers_num); |
551 |
} |
552 |
source_remove.getLast() = sremove; |
553 |
sremove.clear(); |
554 |
} |
555 |
} |
|
|
556 |
sremove.clear(); |
555 |
} |
557 |
} |
556 |
|
558 |
|
557 |
void SOUND::ProcessSamplerAdd() |
559 |
void SOUND::ProcessSamplerAdd() |
Lines 589-595
Link Here
|
589 |
{ |
591 |
{ |
590 |
Lock(source_lock); |
592 |
Lock(source_lock); |
591 |
if (source_stop.getLast().size()) source_stop.swapLast(); |
593 |
if (source_stop.getLast().size()) source_stop.swapLast(); |
592 |
if (source_remove.getLast().size()) source_remove.swapLast(); |
|
|
593 |
Unlock(source_lock); |
594 |
Unlock(source_lock); |
594 |
} |
595 |
} |
595 |
|
596 |
|
Lines 600-611
Link Here
|
600 |
|
601 |
|
601 |
GetSamplerChanges(); |
602 |
GetSamplerChanges(); |
602 |
|
603 |
|
|
|
604 |
ProcessSamplerAdd(); |
605 |
|
603 |
ProcessSamplerUpdate(); |
606 |
ProcessSamplerUpdate(); |
604 |
|
607 |
|
605 |
ProcessSamplers(stream, len); |
608 |
ProcessSamplers(stream, len); |
606 |
|
609 |
|
607 |
ProcessSamplerAdd(); |
|
|
608 |
|
609 |
ProcessSamplerRemove(); |
610 |
ProcessSamplerRemove(); |
610 |
|
611 |
|
611 |
SetSourceChanges(); |
612 |
SetSourceChanges(); |
Lines 622-630
Link Here
|
622 |
assert(len > 0); |
623 |
assert(len > 0); |
623 |
assert(sampler.buffer); |
624 |
assert(sampler.buffer); |
624 |
|
625 |
|
625 |
// if not playing, fill output buffers with silence, should not happen |
626 |
// if not playing, fill output buffers with silence |
626 |
if (!sampler.playing) |
627 |
if (!sampler.playing) |
627 |
{ |
628 |
{ |
|
|
629 |
// should be dealt with before getting here |
628 |
assert(0); |
630 |
assert(0); |
629 |
for (int i = 0; i < len; ++i) |
631 |
for (int i = 0; i < len; ++i) |
630 |
{ |
632 |
{ |