Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/SDK/decode_postprocessor.h @ 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/SDK/decode_postprocessor.h Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,174 @@ +#pragma once + +#ifdef FOOBAR2000_HAVE_DSP +#include "dsp.h" +#include "file_info_impl.h" +#include "input.h" + +//! \since 1.1 +//! This service is essentially a special workaround to easily decode DTS/HDCD content stored in files pretending to contain plain PCM data. \n +//! Callers: Instead of calling this directly, you probably want to use input_postprocessed template. \n +//! Implementers: This service is called only by specific decoders, not by all of them! Implementing your own to provide additional functionality is not recommended! +class decode_postprocessor_instance : public service_base { + FB2K_MAKE_SERVICE_INTERFACE(decode_postprocessor_instance, service_base); +public: + enum { + //! End of stream. Flush any buffered data during this call. + flag_eof = 1 << 0, + //! Stream has already been altered by another instance. + flag_altered = 1 << 1, + }; + //! @returns True if the chunk list has been altered by the call, false if not - to tell possible other running instances whether the stream has already been altered or not. + virtual bool run(dsp_chunk_list & p_chunk_list,t_uint32 p_flags,abort_callback & p_abort) = 0; + //! Manipulate live info (bit depth, bitrate, whatever) that might be altered by us. + virtual bool get_dynamic_info(file_info & p_out) = 0; + //! Called after seek. + virtual void flush() = 0; + //! Return >0 to signal that, after each flush(), you require <amount> of audio before your output becomes valid. \n + //! This causes decoder to seek to position-<amount> instead of <position> then discard first <amount> of your output. + virtual double get_buffer_ahead() = 0; +}; + +//! \since 1.1 +//! Entrypoint class for instantiating decode_postprocessor_instance. See decode_postprocessor_instance documentation for more information. \n +//! Instead of calling this directly, you probably want to use input_postprocessed template. +class decode_postprocessor_entry : public service_base { + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(decode_postprocessor_entry) +public: + virtual bool instantiate(const file_info & info, decode_postprocessor_instance::ptr & out) = 0; +}; + + +//! Helper class for managing decode_postprocessor_instance objects. See also: input_postprocessed. +class decode_postprocessor { +public: + typedef decode_postprocessor_instance::ptr item; + void initialize(const file_info & info) { + m_items.remove_all(); + for (auto ptr : decode_postprocessor_entry::enumerate()) { + item i; + if (ptr->instantiate(info, i)) m_items += i; + } + } + void run(dsp_chunk_list & p_chunk_list,bool p_eof,abort_callback & p_abort) { + t_uint32 flags = p_eof ? decode_postprocessor_instance::flag_eof : 0; + for (auto& item : m_items) { + if (item->run(p_chunk_list, flags, p_abort)) flags |= decode_postprocessor_instance::flag_altered; + } + } + void flush() { + for (auto& item : m_items) item->flush(); + } + static bool should_bother() { + return service_factory_base::is_service_present(decode_postprocessor_entry::class_guid); + } + bool is_active() const { + return m_items.get_size() > 0; + } + bool get_dynamic_info(file_info & p_out) { + bool rv = false; + for (auto& item : m_items) { + if (item->get_dynamic_info(p_out)) rv = true; + } + return rv; + } + void close() { + m_items.remove_all(); + } + double get_buffer_ahead() { + double acc = 0; + for (auto& item : m_items) { + pfc::max_acc(acc, item->get_buffer_ahead()); + } + return acc; + } +private: + pfc::list_t<item> m_items; +}; + +//! Generic template to add decode_postprocessor support to your input class. Works with both single-track and multi-track inputs. +template<typename baseclass> class input_postprocessed : public baseclass { +public: + void decode_initialize(t_uint32 p_subsong,unsigned p_flags,abort_callback & p_abort) { + m_chunks.remove_all(); + m_haveEOF = false; + m_toSkip = 0; + m_postproc.close(); + if ((p_flags & input_flag_no_postproc) == 0 && m_postproc.should_bother()) { + file_info_impl info; + this->get_info(p_subsong, info, p_abort); + m_postproc.initialize(info); + } + baseclass::decode_initialize(p_subsong, p_flags, p_abort); + } + void decode_initialize(unsigned p_flags,abort_callback & p_abort) { + m_chunks.remove_all(); + m_haveEOF = false; + m_toSkip = 0; + m_postproc.close(); + if ((p_flags & input_flag_no_postproc) == 0 && m_postproc.should_bother()) { + file_info_impl info; + this->get_info(info, p_abort); + m_postproc.initialize(info); + } + baseclass::decode_initialize(p_flags, p_abort); + } + bool decode_run(audio_chunk & p_chunk,abort_callback & p_abort) { + if (m_postproc.is_active()) { + for(;;) { + p_abort.check(); + if (m_chunks.get_count() > 0) { + audio_chunk * c = m_chunks.get_item(0); + if (m_toSkip > 0) { + if (!c->process_skip(m_toSkip)) { + m_chunks.remove_by_idx(0); + continue; + } + } + p_chunk = *c; + m_chunks.remove_by_idx(0); + return true; + } + if (m_haveEOF) return false; + if (!baseclass::decode_run(*m_chunks.insert_item(0), p_abort)) { + m_haveEOF = true; + m_chunks.remove_by_idx(0); + } + m_postproc.run(m_chunks, m_haveEOF, p_abort); + } + } else { + return baseclass::decode_run(p_chunk, p_abort); + } + } + bool decode_run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) { + if (m_postproc.is_active()) { + throw pfc::exception_not_implemented(); + } else { + return baseclass::decode_run_raw(p_chunk, p_raw, p_abort); + } + } + bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { + bool rv = baseclass::decode_get_dynamic_info(p_out, p_timestamp_delta); + if (m_postproc.get_dynamic_info(p_out)) rv = true; + return rv; + } + void decode_seek(double p_seconds,abort_callback & p_abort) { + m_chunks.remove_all(); + m_haveEOF = false; + m_postproc.flush(); + double target = pfc::max_t<double>(0, p_seconds - m_postproc.get_buffer_ahead()); + m_toSkip = p_seconds - target; + baseclass::decode_seek(target, p_abort); + } +private: + dsp_chunk_list_impl m_chunks; + bool m_haveEOF; + double m_toSkip; + decode_postprocessor m_postproc; +}; + +#else // FOOBAR2000_HAVE_DSP + +template<typename baseclass> class input_postprocessed : public baseclass {}; + +#endif // FOOBAR2000_HAVE_DSP
