comparison foosdk/sdk/foobar2000/SDK/dsp.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #include "foobar2000-sdk-pch.h"
2 #include "dsp.h"
3 #include "resampler.h"
4
5 #ifdef FOOBAR2000_HAVE_DSP
6
7 #include <math.h>
8
9 audio_chunk * dsp_chunk_list::add_item(t_size hint_size) { return insert_item(get_count(), hint_size); }
10
11 void dsp_chunk_list::remove_all() { remove_mask(pfc::bit_array_true()); }
12
13 double dsp_chunk_list::get_duration() {
14 double rv = 0;
15 t_size n, m = get_count();
16 for (n = 0; n<m; n++) rv += get_item(n)->get_duration();
17 return rv;
18 }
19
20 void dsp_chunk_list::add_chunk(const audio_chunk * chunk) {
21 audio_chunk * dst = insert_item(get_count(), chunk->get_used_size());
22 if (dst) dst->copy(*chunk);
23 }
24
25 t_size dsp_chunk_list_impl::get_count() const {return m_data.size();}
26
27 audio_chunk * dsp_chunk_list_impl::get_item(t_size n) const {return n<m_data.size() ? m_data[n].get() : 0; }
28
29 void dsp_chunk_list_impl::remove_by_idx(t_size idx)
30 {
31 PFC_ASSERT(idx < get_count());
32 m_recycled.push_back(std::move(m_data[idx]));
33 m_data.erase(m_data.begin() + idx);
34 }
35
36 void dsp_chunk_list_impl::remove_mask(const bit_array & mask)
37 {
38 const auto total = m_data.size();
39 mask.for_each(true, 0, total, [&](size_t idx) {
40 m_recycled.push_back(std::move(m_data[idx]));
41 });
42 pfc::remove_mask_t(m_data, mask);
43 }
44
45 audio_chunk * dsp_chunk_list_impl::insert_item(t_size idx,t_size hint_size)
46 {
47 t_size max = get_count();
48 if (idx>max) idx = max;
49 chunk_ptr_t ret;
50 if (!m_recycled.empty())
51 {
52 t_size best;
53 if (hint_size > 0)
54 {
55 best = 0;
56 t_size best_found = m_recycled[0]->get_data_size(), n, total = m_recycled.size();
57 for (n = 1; n < total; n++)
58 {
59 if (best_found == hint_size) break;
60 t_size size = m_recycled[n]->get_data_size();
61 int delta_old = abs((int)best_found - (int)hint_size), delta_new = abs((int)size - (int)hint_size);
62 if (delta_new < delta_old)
63 {
64 best_found = size;
65 best = n;
66 }
67 }
68 } else best = m_recycled.size() - 1;
69
70 ret = std::move(m_recycled[best]);
71 m_recycled.erase(m_recycled.begin() + best);
72 ret->set_sample_count(0);
73 ret->set_channels(0);
74 ret->set_srate(0);
75 } else ret = std::make_unique<audio_chunk_impl>();
76 auto pRet = &*ret;
77 if (idx == max) m_data.push_back(std::move(ret));
78 else m_data.insert(m_data.begin() + idx, std::move(ret));
79 return pRet;
80 }
81
82 void dsp_chunk_list::remove_bad_chunks()
83 {
84 bool blah = false;
85 t_size idx;
86 for(idx=0;idx<get_count();)
87 {
88 audio_chunk * chunk = get_item(idx);
89 if (!chunk->is_valid())
90 {
91 #if PFC_DEBUG
92 FB2K_console_formatter() << "Removing bad chunk: " << chunk->formatChunkSpec();
93 #endif
94 chunk->reset();
95 remove_by_idx(idx);
96 blah = true;
97 }
98 else idx++;
99 }
100 if (blah) console::info("one or more bad chunks removed from dsp chunk list");
101 }
102
103 bool dsp_entry_hidden::g_dsp_exists(const GUID & p_guid) {
104 dsp_entry_hidden::ptr p;
105 return g_get_interface(p, p_guid);
106 }
107
108 bool dsp_entry_hidden::g_get_interface( dsp_entry_hidden::ptr & out, const GUID & guid ) {
109 for (auto p : enumerate()) {
110 if (p->get_guid() == guid) {
111 out = p; return true;
112 }
113 }
114 return false;
115 }
116
117 bool dsp_entry_hidden::g_instantiate( dsp::ptr & out, const dsp_preset & preset ) {
118 dsp_entry_hidden::ptr i;
119 if (!g_get_interface(i, preset.get_owner())) return false;
120 return i->instantiate(out, preset);
121 }
122
123 bool dsp_entry::g_instantiate(service_ptr_t<dsp> & p_out,const dsp_preset & p_preset, unsigned flags )
124 {
125 service_ptr_t<dsp_entry> ptr;
126 if (!g_get_interface(ptr,p_preset.get_owner())) return false;
127 if ( flags != 0 ) {
128 dsp_entry_v4::ptr v4;
129 if (v4 &= ptr) {
130 p_out = v4->instantiate_v4(p_preset, flags);
131 return true;
132 }
133 }
134 return ptr->instantiate(p_out,p_preset);
135 }
136
137 bool dsp_entry::g_instantiate_default(service_ptr_t<dsp> & p_out,const GUID & p_guid)
138 {
139 service_ptr_t<dsp_entry> ptr;
140 if (!g_get_interface(ptr,p_guid)) return false;
141 dsp_preset_impl preset;
142 if (!ptr->get_default_preset(preset)) return false;
143 return ptr->instantiate(p_out,preset);
144 }
145
146 bool dsp_entry::g_name_from_guid(pfc::string_base & p_out,const GUID & p_guid)
147 {
148 service_ptr_t<dsp_entry> ptr;
149 if (!g_get_interface(ptr,p_guid)) return false;
150 ptr->get_name(p_out);
151 return true;
152 }
153
154 bool dsp_entry::g_dsp_exists(const GUID & p_guid)
155 {
156 service_ptr_t<dsp_entry> blah;
157 return g_get_interface(blah,p_guid);
158 }
159
160 bool dsp_entry::g_get_default_preset(dsp_preset & p_out,const GUID & p_guid)
161 {
162 service_ptr_t<dsp_entry> ptr;
163 if (!g_get_interface(ptr,p_guid)) return false;
164 return ptr->get_default_preset(p_out);
165 }
166
167 void dsp_chain_config::contents_to_stream(stream_writer * p_stream,abort_callback & p_abort) const {
168 uint32_t n, count = pfc::downcast_guarded<uint32_t>( get_count() );
169 p_stream->write_lendian_t(count,p_abort);
170 for(n=0;n<count;n++) {
171 get_item(n).contents_to_stream(p_stream,p_abort);
172 }
173 }
174
175 fb2k::memBlock::ptr dsp_chain_config::to_blob() const {
176 stream_writer_buffer_simple out;
177 this->contents_to_stream(&out, fb2k::noAbort);
178 return fb2k::memBlock::blockWithVector(out.m_buffer);
179 }
180
181 void dsp_chain_config::from_blob(const void* p, size_t size) {
182 if (size == 0) {
183 remove_all(); return;
184 }
185 stream_reader_memblock_ref reader(p, size);
186 this->contents_from_stream(&reader, fb2k::noAbort);
187 }
188
189 void dsp_chain_config::from_blob(fb2k::memBlock::ptr b) {
190 if (b.is_valid()) {
191 from_blob(b->data(), b->size());
192 } else {
193 this->remove_all();
194 }
195 }
196
197 void dsp_chain_config::contents_from_stream(stream_reader * p_stream,abort_callback & p_abort) {
198 t_uint32 n,count;
199
200 remove_all();
201
202 p_stream->read_lendian_t(count,p_abort);
203
204 dsp_preset_impl temp;
205
206 for(n=0;n<count;n++) {
207 temp.contents_from_stream(p_stream,p_abort);
208 add_item(temp);
209 }
210 }
211
212 void dsp_chain_config::remove_item(t_size p_index)
213 {
214 remove_mask(pfc::bit_array_one(p_index));
215 }
216
217 void dsp_chain_config::add_item(const dsp_preset & p_data)
218 {
219 insert_item(p_data,get_count());
220 }
221
222 void dsp_chain_config::remove_all()
223 {
224 remove_mask(pfc::bit_array_true());
225 }
226
227 size_t dsp_chain_config::find_first_of_type( const GUID & dspID ) const {
228 const size_t count = this->get_count();
229 for(size_t w = 0; w < count; ++w) {
230 if (this->get_item(w).get_owner() == dspID) return w;
231 }
232 return SIZE_MAX;
233 }
234
235 bool dsp_chain_config::contains_dsp( const GUID & dspID ) const {
236 return find_first_of_type( dspID ) != pfc_infinite;
237 }
238
239 bool dsp_chain_config::enable_dsp( const GUID & dspID ) {
240 if (this->contains_dsp( dspID )) return false;
241 dsp_preset_impl preset;
242 dsp_entry::g_get_default_preset( preset, dspID );
243 insert_item( preset, 0 );
244 return true;
245 }
246
247 bool dsp_chain_config::disable_dsp( const GUID & dspID ) {
248 const size_t count = this->get_count();
249 if (count == 0) return false;
250 bool rv = false;
251 pfc::bit_array_bittable mask( count );
252 for(size_t w = 0; w < count; ++ w) {
253 if (this->get_item(w).get_owner() == dspID ) {
254 rv = true;
255 mask.set(w, true);
256 }
257 }
258 if (rv) this->remove_mask( mask );
259 return rv;
260 }
261
262 bool dsp_chain_config::enable_dsp( const dsp_preset & preset ) {
263 dsp_chain_config & cfg = *this;
264 bool found = false;
265 bool changed = false;
266 t_size n,m = cfg.get_count();
267 for(n=0;n<m;n++) {
268 if (cfg.get_item(n).get_owner() == preset.get_owner()) {
269 found = true;
270 if (cfg.get_item(n) != preset) {
271 cfg.replace_item(preset,n);
272 changed = true;
273 }
274 break;
275 }
276 }
277 if (!found) {cfg.insert_item(preset,0); changed = true;}
278
279 return changed;
280 }
281
282 void dsp_chain_config_impl::reorder(const size_t * order, size_t count) {
283 PFC_ASSERT( count == m_data.get_count() );
284 m_data.reorder( order );
285 }
286
287 t_size dsp_chain_config_impl::get_count() const
288 {
289 return m_data.get_count();
290 }
291
292 const dsp_preset & dsp_chain_config_impl::get_item(t_size p_index) const
293 {
294 return m_data[p_index]->data;
295 }
296
297 void dsp_chain_config_impl::replace_item(const dsp_preset & p_data,t_size p_index)
298 {
299 auto& obj = *m_data[p_index];
300 if (p_data.get_owner() != obj.data.get_owner()) {
301 obj.dspName = p_data.get_owner_name();
302 }
303 obj.data = p_data;
304 }
305
306 void dsp_chain_config_impl::insert_item(const dsp_preset & p_data,t_size p_index)
307 {
308 this->insert_item_v2(p_data, nullptr, p_index);
309 }
310
311 void dsp_chain_config_impl::remove_mask(const bit_array & p_mask)
312 {
313 m_data.delete_mask(p_mask);
314 }
315
316 dsp_chain_config_impl::~dsp_chain_config_impl()
317 {
318 m_data.delete_all();
319 }
320
321 const char* dsp_chain_config_impl::get_dsp_name(size_t idx) const {
322 auto& n = m_data[idx]->dspName;
323 if (n.is_empty()) return nullptr;
324 return n.c_str();
325 }
326
327 void dsp_chain_config_impl::insert_item_v2(const dsp_preset& data, const char* dspName_, size_t index) {
328 pfc::string8 dspName;
329 if (dspName_) dspName = dspName_;
330 if (dspName.length() == 0) dspName = data.get_owner_name();
331 m_data.insert_item(new entry_t{ data, std::move(dspName) }, index);
332 }
333
334 const char* dsp_chain_config_impl::find_dsp_name(const GUID& guid) const {
335 for (size_t walk = 0; walk < m_data.get_size(); ++walk) {
336 auto& obj = *m_data[walk];
337 if (obj.data.get_owner() == guid && obj.dspName.length() > 0) {
338 return obj.dspName.c_str();
339 }
340 }
341 return nullptr;
342 }
343
344 pfc::string8 dsp_preset::get_owner_name() const {
345 pfc::string8 ret;
346 dsp_entry::ptr obj;
347 if (dsp_entry::g_get_interface(obj, this->get_owner())) {
348 obj->get_name(ret);
349 }
350 return ret;
351 }
352
353 pfc::string8 dsp_preset::get_owner_name_debug() const {
354 pfc::string8 ret;
355 dsp_entry::ptr obj;
356 if (dsp_entry::g_get_interface(obj, this->get_owner())) {
357 obj->get_name(ret);
358 } else {
359 ret = "[unknown]";
360 }
361 return ret;
362 }
363
364 pfc::string8 dsp_preset::debug(const char * knownName) const {
365 pfc::string8 name;
366 if (knownName) name = knownName;
367 else name = this->get_owner_name_debug();
368 pfc::string8 ret;
369 ret << name << " :: " << pfc::print_guid(this->get_owner()) << " :: " << pfc::format_hexdump(this->get_data(), this->get_data_size());
370 return ret;
371 }
372
373 pfc::string8 dsp_chain_config::debug() const {
374 const size_t count = get_count();
375 pfc::string8 ret;
376 ret << "dsp_chain_config: " << count << " items";
377 for (size_t walk = 0; walk < count; ++walk) {
378 ret << "\n" << get_item(walk).debug();
379 }
380 return ret;
381 }
382
383 void dsp_chain_config_impl::add_item_v2(const dsp_preset& data, const char* dspName) {
384 insert_item_v2(data, dspName, get_count());
385 }
386
387 void dsp_chain_config_impl::copy_v2(dsp_chain_config_impl const& p_source) {
388 remove_all();
389 t_size n, m = p_source.get_count();
390 for (n = 0; n < m; n++)
391 add_item_v2(p_source.get_item(n), p_source.get_dsp_name(n));
392 }
393
394 pfc::string8 dsp_chain_config_impl::debug() const {
395 const size_t count = get_count();
396 pfc::string8 ret;
397 ret << "dsp_chain_config_impl: " << count << " items";
398 for (size_t walk = 0; walk < count; ++walk) {
399 ret << "\n" << get_item(walk).debug( this->get_dsp_name(walk) );
400 }
401 return ret;
402 }
403
404 void dsp_preset::contents_to_stream(stream_writer * p_stream,abort_callback & p_abort) const {
405 t_uint32 size = pfc::downcast_guarded<t_uint32>(get_data_size());
406 p_stream->write_lendian_t(get_owner(),p_abort);
407 p_stream->write_lendian_t(size,p_abort);
408 if (size > 0) {
409 p_stream->write_object(get_data(),size,p_abort);
410 }
411 }
412
413 void dsp_preset::contents_from_stream(stream_reader * p_stream,abort_callback & p_abort) {
414 t_uint32 size;
415 GUID guid;
416 p_stream->read_lendian_t(guid,p_abort);
417 set_owner(guid);
418 p_stream->read_lendian_t(size,p_abort);
419 if (size > 1024*1024*32) throw exception_io_data();
420 set_data_from_stream(p_stream,size,p_abort);
421 }
422
423 void dsp_preset::g_contents_from_stream_skip(stream_reader * p_stream,abort_callback & p_abort) {
424 t_uint32 size;
425 GUID guid;
426 p_stream->read_lendian_t(guid,p_abort);
427 p_stream->read_lendian_t(size,p_abort);
428 if (size > 1024*1024*32) throw exception_io_data();
429 p_stream->skip_object(size,p_abort);
430 }
431
432 void dsp_preset_impl::set_data_from_stream(stream_reader * p_stream,t_size p_bytes,abort_callback & p_abort) {
433 m_data.resize(p_bytes);
434 if (p_bytes > 0) p_stream->read_object(m_data.ptr(),p_bytes,p_abort);
435 }
436
437 void dsp_chain_config::add_items(const dsp_chain_config & p_source) {
438 t_size n, m = p_source.get_count();
439 for(n=0;n<m;n++)
440 add_item(p_source.get_item(n));
441 }
442
443 void dsp_chain_config::copy(const dsp_chain_config & p_source) {
444 remove_all();
445 add_items( p_source );
446 }
447
448 bool dsp_entry::g_have_config_popup(const GUID & p_guid)
449 {
450 service_ptr_t<dsp_entry> entry;
451 if (!g_get_interface(entry,p_guid)) return false;
452 return entry->have_config_popup();
453 }
454
455 bool dsp_entry::g_have_config_popup(const dsp_preset & p_preset)
456 {
457 return g_have_config_popup(p_preset.get_owner());
458 }
459
460 #ifdef _WIN32
461 bool dsp_entry::g_show_config_popup(dsp_preset & p_preset,fb2k::hwnd_t p_parent)
462 {
463 service_ptr_t<dsp_entry> entry;
464 if (!g_get_interface(entry,p_preset.get_owner())) return false;
465 return entry->show_config_popup(p_preset,p_parent);
466 }
467
468 bool dsp_entry::show_config_popup_v2_(const dsp_preset& p_preset, fb2k::hwnd_t p_parent, dsp_preset_edit_callback& p_callback) {
469 PFC_ASSERT(p_preset.get_owner() == this->get_guid());
470 try {
471 service_ptr_t<dsp_entry_v2> entry_v2;
472 if (entry_v2 &= this) {
473 entry_v2->show_config_popup_v2(p_preset, p_parent, p_callback);
474 return true;
475 }
476 } catch (pfc::exception_not_implemented const&) {}
477
478 dsp_preset_impl temp(p_preset);
479 bool rv = this->show_config_popup(temp, p_parent);
480 if (rv) p_callback.on_preset_changed(temp);
481 return rv;
482 }
483 namespace {
484 class dsp_preset_edit_callback_callV2 : public dsp_preset_edit_callback {
485 public:
486 dsp_preset_edit_callback_v2::ptr chain;
487 void on_preset_changed(const dsp_preset& arg) override { chain->set_preset(arg); }
488 };
489 }
490 service_ptr dsp_entry::show_config_popup_v3_(fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback) {
491 dsp_entry_v3::ptr v3;
492 if (v3 &= this) {
493 try {
494 return v3->show_config_popup_v3(parent, callback);
495 } catch (pfc::exception_not_implemented const &) {
496 }
497 }
498
499 dsp_preset_edit_callback_callV2 cb;
500 cb.chain = callback;
501
502 dsp_preset_impl initPreset; callback->get_preset(initPreset);
503 bool status = this->show_config_popup_v2_(initPreset, parent, cb);
504 callback->dsp_dialog_done(status);
505 return nullptr;
506
507 }
508 void dsp_entry::g_show_config_popup_v2(const dsp_preset & p_preset,fb2k::hwnd_t p_parent,dsp_preset_edit_callback & p_callback) {
509 auto api = g_get_interface(p_preset.get_owner());
510 if (api.is_valid()) api->show_config_popup_v2_(p_preset, p_parent, p_callback);
511 }
512 #endif
513
514 service_ptr_t<dsp_entry> dsp_entry::g_get_interface(const GUID& guid) {
515 for (auto ptr : enumerate()) {
516 if (ptr->get_guid() == guid) return ptr;
517 }
518 return nullptr;
519 }
520
521 bool dsp_entry::g_get_interface(service_ptr_t<dsp_entry> & p_out,const GUID & p_guid)
522 {
523 for (auto ptr : enumerate()) {
524 if (ptr->get_guid() == p_guid) {
525 p_out = ptr;
526 return true;
527 }
528 }
529 return false;
530 }
531
532 bool resampler_entry::g_get_interface(service_ptr_t<resampler_entry> & p_out,unsigned p_srate_from,unsigned p_srate_to)
533 {
534 #if defined(FOOBAR2000_DESKTOP) && FOOBAR2000_TARGET_VERSION >= 79
535 auto r = resampler_manager::get()->get_resampler( p_srate_from, p_srate_to );
536 bool v = r.is_valid();
537 if ( v ) p_out = std::move(r);
538 return v;
539 #else
540
541 #ifdef FOOBAR2000_DESKTOP
542 {
543 resampler_manager::ptr api;
544 if ( resampler_manager::tryGet(api) ) {
545 auto r = api->get_resampler( p_srate_from, p_srate_to );
546 bool v = r.is_valid();
547 if (v) p_out = std::move(r);
548 return v;
549 }
550 }
551 #endif
552
553 resampler_entry::ptr ptr_resampler;
554 service_enum_t<dsp_entry> e;
555 float found_priority = 0;
556 resampler_entry::ptr found;
557 while(e.next(ptr_resampler))
558 {
559 if (p_srate_from == 0 || ptr_resampler->is_conversion_supported(p_srate_from,p_srate_to))
560 {
561 float priority = ptr_resampler->get_priority();
562 if (found.is_empty() || priority > found_priority)
563 {
564 found = ptr_resampler;
565 found_priority = priority;
566 }
567 }
568 }
569 if (found.is_empty()) return false;
570 p_out = found;
571 return true;
572 #endif
573 }
574
575 bool resampler_entry::g_create_preset(dsp_preset & p_out,unsigned p_srate_from,unsigned p_srate_to,float p_qualityscale)
576 {
577 service_ptr_t<resampler_entry> entry;
578 if (!g_get_interface(entry,p_srate_from,p_srate_to)) return false;
579 return entry->create_preset(p_out,p_srate_to,p_qualityscale);
580 }
581
582 bool resampler_entry::g_create(service_ptr_t<dsp> & p_out,unsigned p_srate_from,unsigned p_srate_to,float p_qualityscale)
583 {
584 service_ptr_t<resampler_entry> entry;
585 if (!g_get_interface(entry,p_srate_from,p_srate_to)) return false;
586 dsp_preset_impl preset;
587 if (!entry->create_preset(preset,p_srate_to,p_qualityscale)) return false;
588 return entry->instantiate(p_out,preset);
589 }
590
591
592 bool dsp_chain_config::equals(dsp_chain_config const & v1, dsp_chain_config const & v2) {
593 const t_size count = v1.get_count();
594 if (count != v2.get_count()) return false;
595 for(t_size walk = 0; walk < count; ++walk) {
596 if (v1.get_item(walk) != v2.get_item(walk)) return false;
597 }
598 return true;
599 }
600 bool dsp_chain_config::equals_debug(dsp_chain_config const& v1, dsp_chain_config const& v2) {
601 FB2K_DebugLog() << "Comparing DSP chains";
602 const t_size count = v1.get_count();
603 if (count != v2.get_count()) {
604 FB2K_DebugLog() << "Count mismatch, " << count << " vs " << v2.get_count();
605 return false;
606 }
607 for (t_size walk = 0; walk < count; ++walk) {
608 if (v1.get_item(walk) != v2.get_item(walk)) {
609 FB2K_DebugLog() << "Item " << (walk+1) << " mismatch";
610 FB2K_DebugLog() << "Item 1: " << v1.get_item(walk).debug();
611 FB2K_DebugLog() << "Item 2: " << v2.get_item(walk).debug();
612 return false;
613 }
614 }
615 FB2K_DebugLog() << "DSP chains are identical";
616 return true;
617 }
618
619 void dsp_chain_config::get_name_list(pfc::string_base & p_out) const {
620 p_out = get_name_list();
621 }
622
623 pfc::string8 dsp_chain_config::get_name_list() const {
624 const size_t count = get_count();
625 pfc::string8 output; output.prealloc(1024);
626 for (size_t n = 0; n < count; n++)
627 {
628 const auto& preset = get_item(n);
629 service_ptr_t<dsp_entry> ptr;
630 if (dsp_entry::g_get_interface(ptr, preset.get_owner()))
631 {
632 pfc::string8 temp;
633 ptr->get_display_name_(preset, temp);
634 if (temp.length() > 0) {
635 if (output.length() > 0) output += ", ";
636 output += temp;
637 }
638 }
639 }
640
641 return output;
642 }
643
644 void dsp::run_abortable(dsp_chunk_list * p_chunk_list,const dsp_track_t & p_cur_file,int p_flags,abort_callback & p_abort) {
645 service_ptr_t<dsp_v2> this_v2;
646 if (this->service_query_t(this_v2)) this_v2->run_v2(p_chunk_list,p_cur_file,p_flags,p_abort);
647 else run(p_chunk_list,p_cur_file,p_flags);
648 }
649
650 bool dsp::apply_preset_(const dsp_preset& arg) {
651 dsp_v3::ptr v3;
652 if (v3 &= this) return v3->apply_preset(arg);
653 return false;
654 }
655
656 namespace {
657 class dsp_preset_edit_callback_impl : public dsp_preset_edit_callback {
658 public:
659 dsp_preset_edit_callback_impl(dsp_preset & p_data) : m_data(p_data) {}
660 void on_preset_changed(const dsp_preset & p_data) {m_data = p_data;}
661 private:
662 dsp_preset & m_data;
663 };
664 };
665
666 #ifdef _WIN32
667 bool dsp_entry_v2::show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) {
668 PFC_ASSERT(p_data.get_owner() == get_guid());
669 dsp_preset_impl temp(p_data);
670
671 {
672 dsp_preset_edit_callback_impl cb(temp);
673 show_config_popup_v2(p_data,p_parent,cb);
674 }
675 PFC_ASSERT(temp.get_owner() == get_guid());
676 if (temp == p_data) return false;
677 p_data = temp;
678 return true;
679 }
680 #endif
681
682 #ifdef FOOBAR2000_MOBILE
683 void dsp_entry::g_show_config_popup( menu_context_ptr ctx, dsp_preset_edit_callback_v2::ptr callback) {
684 GUID dspID;
685 {
686 dsp_preset_impl temp;
687 callback->get_preset( temp );
688 dspID = temp.get_owner();
689 }
690
691 dsp_entry::ptr entry;
692 if (!g_get_interface( entry, dspID)) return;
693 if (!entry->have_config_popup()) return;
694 entry->show_config_popup( ctx, callback );
695 }
696 #endif // FOOBAR2000_MOBILE
697
698 #ifdef FOOBAR2000_DESKTOP
699 void resampler_manager::make_chain_(dsp_chain_config& outChain, unsigned rateFrom, unsigned rateTo, float qualityScale) {
700 resampler_manager_v2::ptr v2;
701 if (v2 &= this) {
702 v2->make_chain(outChain, rateFrom, rateTo, qualityScale);
703 } else {
704 outChain.remove_all();
705 auto obj = this->get_resampler(rateFrom, rateTo);
706 if (obj.is_valid()) {
707 dsp_preset_impl p;
708 if (obj->create_preset(p, rateTo, qualityScale)) {
709 outChain.add_item(p);
710 }
711 }
712 }
713 }
714 #endif
715
716 void dsp_preset_edit_callback_v2::reset() {
717 dsp_preset_impl temp; get_preset( temp );
718 GUID id = temp.get_owner(); temp.set_data(nullptr, 0);
719 if (dsp_entry::g_get_default_preset( temp, id )) {
720 this->set_preset( temp );
721 } else {
722 PFC_ASSERT(!"Should not get here - no such DSP");
723 }
724 }
725
726 bool dsp_entry::get_display_name_supported() {
727 dsp_entry_v3::ptr v3;
728 return v3 &= this;
729 }
730
731 void dsp_entry::get_display_name_(const dsp_preset& arg, pfc::string_base& out) {
732 PFC_ASSERT(arg.get_owner() == this->get_guid());
733 dsp_entry_v3::ptr v3;
734 if (v3 &= this) {
735 v3->get_display_name(arg, out); return;
736 }
737 get_name(out);
738 }
739
740 bool dsp_entry::enumerate_default_presets_(dsp_chain_config& ret) {
741 ret.remove_all();
742 dsp_entry_v5::ptr v5;
743 if (v5 &= this) {
744 bool rv = v5->enumerate_default_presets(ret);
745 #if PFC_DEBUG
746 for (size_t walk = 0; walk < ret.get_count(); ++walk) {
747 PFC_ASSERT(ret.get_item(walk).get_owner() == get_guid());
748 }
749 #endif
750 return rv;
751 }
752 return false;
753 }
754
755 bool dsp_entry::match_preset_subclass_(dsp_preset const& x, dsp_preset const& y) {
756 dsp_entry_v5::ptr v5;
757 if (v5 &= this) return v5->match_preset_subclass(x, y);
758 return true;
759 }
760
761 #endif // FOOBAR2000_HAVE_DSP