Mercurial > foo_out_sdl
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 |
