annotate 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #pragma once
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 #ifdef FOOBAR2000_HAVE_DSP
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4 #include "dsp.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5 #include "file_info_impl.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6 #include "input.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 //! \since 1.1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 //! This service is essentially a special workaround to easily decode DTS/HDCD content stored in files pretending to contain plain PCM data. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 //! Callers: Instead of calling this directly, you probably want to use input_postprocessed template. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 //! Implementers: This service is called only by specific decoders, not by all of them! Implementing your own to provide additional functionality is not recommended!
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 class decode_postprocessor_instance : public service_base {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 FB2K_MAKE_SERVICE_INTERFACE(decode_postprocessor_instance, service_base);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 enum {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 //! End of stream. Flush any buffered data during this call.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 flag_eof = 1 << 0,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 //! Stream has already been altered by another instance.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 flag_altered = 1 << 1,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 //! @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.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 virtual bool run(dsp_chunk_list & p_chunk_list,t_uint32 p_flags,abort_callback & p_abort) = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 //! Manipulate live info (bit depth, bitrate, whatever) that might be altered by us.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 virtual bool get_dynamic_info(file_info & p_out) = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 //! Called after seek.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 virtual void flush() = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 //! Return >0 to signal that, after each flush(), you require <amount> of audio before your output becomes valid. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28 //! This causes decoder to seek to position-<amount> instead of <position> then discard first <amount> of your output.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 virtual double get_buffer_ahead() = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 //! \since 1.1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 //! Entrypoint class for instantiating decode_postprocessor_instance. See decode_postprocessor_instance documentation for more information. \n
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 //! Instead of calling this directly, you probably want to use input_postprocessed template.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 class decode_postprocessor_entry : public service_base {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(decode_postprocessor_entry)
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38 virtual bool instantiate(const file_info & info, decode_postprocessor_instance::ptr & out) = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 //! Helper class for managing decode_postprocessor_instance objects. See also: input_postprocessed.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 class decode_postprocessor {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45 typedef decode_postprocessor_instance::ptr item;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46 void initialize(const file_info & info) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 m_items.remove_all();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 for (auto ptr : decode_postprocessor_entry::enumerate()) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 item i;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 if (ptr->instantiate(info, i)) m_items += i;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 void run(dsp_chunk_list & p_chunk_list,bool p_eof,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 t_uint32 flags = p_eof ? decode_postprocessor_instance::flag_eof : 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 for (auto& item : m_items) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 if (item->run(p_chunk_list, flags, p_abort)) flags |= decode_postprocessor_instance::flag_altered;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 void flush() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 for (auto& item : m_items) item->flush();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62 static bool should_bother() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 return service_factory_base::is_service_present(decode_postprocessor_entry::class_guid);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 bool is_active() const {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 return m_items.get_size() > 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 bool get_dynamic_info(file_info & p_out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 bool rv = false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 for (auto& item : m_items) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 if (item->get_dynamic_info(p_out)) rv = true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 return rv;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 void close() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 m_items.remove_all();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 double get_buffer_ahead() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 double acc = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 for (auto& item : m_items) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 pfc::max_acc(acc, item->get_buffer_ahead());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 return acc;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 pfc::list_t<item> m_items;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 //! Generic template to add decode_postprocessor support to your input class. Works with both single-track and multi-track inputs.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90 template<typename baseclass> class input_postprocessed : public baseclass {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 void decode_initialize(t_uint32 p_subsong,unsigned p_flags,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 m_chunks.remove_all();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 m_haveEOF = false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 m_toSkip = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 m_postproc.close();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 if ((p_flags & input_flag_no_postproc) == 0 && m_postproc.should_bother()) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 file_info_impl info;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 this->get_info(p_subsong, info, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 m_postproc.initialize(info);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102 baseclass::decode_initialize(p_subsong, p_flags, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104 void decode_initialize(unsigned p_flags,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 m_chunks.remove_all();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 m_haveEOF = false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
107 m_toSkip = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
108 m_postproc.close();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
109 if ((p_flags & input_flag_no_postproc) == 0 && m_postproc.should_bother()) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
110 file_info_impl info;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
111 this->get_info(info, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
112 m_postproc.initialize(info);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
113 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
114 baseclass::decode_initialize(p_flags, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
115 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
116 bool decode_run(audio_chunk & p_chunk,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
117 if (m_postproc.is_active()) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
118 for(;;) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
119 p_abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
120 if (m_chunks.get_count() > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
121 audio_chunk * c = m_chunks.get_item(0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
122 if (m_toSkip > 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
123 if (!c->process_skip(m_toSkip)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
124 m_chunks.remove_by_idx(0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
125 continue;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
126 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
127 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
128 p_chunk = *c;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
129 m_chunks.remove_by_idx(0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
130 return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
131 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
132 if (m_haveEOF) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
133 if (!baseclass::decode_run(*m_chunks.insert_item(0), p_abort)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
134 m_haveEOF = true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
135 m_chunks.remove_by_idx(0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
136 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
137 m_postproc.run(m_chunks, m_haveEOF, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
138 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
139 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
140 return baseclass::decode_run(p_chunk, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
141 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
142 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
143 bool decode_run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
144 if (m_postproc.is_active()) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
145 throw pfc::exception_not_implemented();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
146 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
147 return baseclass::decode_run_raw(p_chunk, p_raw, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
148 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
149 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
150 bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
151 bool rv = baseclass::decode_get_dynamic_info(p_out, p_timestamp_delta);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
152 if (m_postproc.get_dynamic_info(p_out)) rv = true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
153 return rv;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
154 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
155 void decode_seek(double p_seconds,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
156 m_chunks.remove_all();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
157 m_haveEOF = false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
158 m_postproc.flush();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
159 double target = pfc::max_t<double>(0, p_seconds - m_postproc.get_buffer_ahead());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
160 m_toSkip = p_seconds - target;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
161 baseclass::decode_seek(target, p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
162 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
163 private:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
164 dsp_chunk_list_impl m_chunks;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
165 bool m_haveEOF;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
166 double m_toSkip;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
167 decode_postprocessor m_postproc;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
168 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
169
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
170 #else // FOOBAR2000_HAVE_DSP
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
171
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
172 template<typename baseclass> class input_postprocessed : public baseclass {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
173
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
174 #endif // FOOBAR2000_HAVE_DSP