|
1
|
1 #include "foobar2000-sdk-pch.h"
|
|
|
2 #include "dsp_manager.h"
|
|
|
3
|
|
|
4 #ifdef FOOBAR2000_HAVE_DSP
|
|
|
5
|
|
|
6 void dsp_manager::close() {
|
|
|
7 m_chain.remove_all();
|
|
|
8 m_config_changed = true;
|
|
|
9 }
|
|
|
10
|
|
|
11 void dsp_manager::set_config( const dsp_chain_config & p_data )
|
|
|
12 {
|
|
|
13 //dsp_chain_config::g_instantiate(m_dsp_list,p_data);
|
|
|
14 m_config.copy(p_data);
|
|
|
15 m_config_changed = true;
|
|
|
16 }
|
|
|
17
|
|
|
18 bool dsp_manager::need_track_change_mark() const {
|
|
|
19 for ( auto i = this->m_chain.first(); i.is_valid(); ++ i ) {
|
|
|
20 if ( i->m_dsp->need_track_change_mark() ) return true;
|
|
|
21 }
|
|
|
22 return false;
|
|
|
23 }
|
|
|
24
|
|
|
25 void dsp_manager::dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * p_list,const dsp_track_t & cur_file,unsigned flags,double & latency,abort_callback & p_abort)
|
|
|
26 {
|
|
|
27 p_list->remove_bad_chunks();
|
|
|
28
|
|
|
29 TRACK_CODE("dsp::run",p_iter->m_dsp->run_abortable(p_list,cur_file,flags,p_abort));
|
|
|
30 TRACK_CODE("dsp::get_latency",latency += p_iter->m_dsp->get_latency());
|
|
|
31 }
|
|
|
32
|
|
|
33 double dsp_manager::run(dsp_chunk_list * p_list,const dsp_track_t & p_cur_file,unsigned p_flags,abort_callback & p_abort) {
|
|
|
34 TRACK_CALL_TEXT("dsp_manager::run");
|
|
|
35
|
|
|
36 try {
|
|
|
37 #if defined(_MSC_VER) && defined(_M_IX86)
|
|
|
38 fpu_control_default l_fpu_control;
|
|
|
39 #endif
|
|
|
40 double latency=0;
|
|
|
41 bool done = false;
|
|
|
42
|
|
|
43 t_dsp_chain::const_iterator flush_mark;
|
|
|
44 if ((p_flags & dsp::END_OF_TRACK) && ! (p_flags & dsp::FLUSH)) {
|
|
|
45 for(t_dsp_chain::const_iterator iter = m_chain.first(); iter.is_valid(); ++iter) {
|
|
|
46 if (iter->m_dsp->need_track_change_mark()) flush_mark = iter;
|
|
|
47 }
|
|
|
48 }
|
|
|
49
|
|
|
50 if (m_config_changed)
|
|
|
51 {
|
|
|
52 t_dsp_chain newchain;
|
|
|
53 bool recycle_available = true;
|
|
|
54
|
|
|
55 for(t_size n=0;n<m_config.get_count();n++) {
|
|
|
56 service_ptr_t<dsp> temp;
|
|
|
57
|
|
|
58 const dsp_preset & preset = m_config.get_item(n);
|
|
|
59 const GUID owner = preset.get_owner();
|
|
|
60 if (dsp_entry::g_dsp_exists(owner) || dsp_entry_hidden::g_dsp_exists(owner)) {
|
|
|
61 t_dsp_chain::iterator iter = newchain.insert_last();
|
|
|
62 iter->m_preset = m_config.get_item(n);
|
|
|
63 iter->m_recycle_flag = false;
|
|
|
64 }
|
|
|
65 }
|
|
|
66
|
|
|
67
|
|
|
68 // Recycle existing DSPs in a special case when user has apparently only altered settings of one of DSPs.
|
|
|
69 if (newchain.get_count() == m_chain.get_count()) {
|
|
|
70 t_size data_mismatch_count = 0;
|
|
|
71 t_size owner_mismatch_count = 0;
|
|
|
72 t_dsp_chain::iterator iter_src, iter_dst;
|
|
|
73 iter_src = m_chain.first(); iter_dst = newchain.first();
|
|
|
74 while(iter_src.is_valid() && iter_dst.is_valid()) {
|
|
|
75 if (iter_src->m_preset.get_owner() != iter_dst->m_preset.get_owner()) {
|
|
|
76 owner_mismatch_count++;
|
|
|
77 } else if (iter_src->m_preset != iter_dst->m_preset) {
|
|
|
78 data_mismatch_count++;
|
|
|
79 }
|
|
|
80 ++iter_src; ++iter_dst;
|
|
|
81 }
|
|
|
82 recycle_available = (owner_mismatch_count == 0 && data_mismatch_count <= 1);
|
|
|
83 } else {
|
|
|
84 recycle_available = false;
|
|
|
85 }
|
|
|
86
|
|
|
87 if (recycle_available) {
|
|
|
88 t_dsp_chain::iterator iter_src, iter_dst;
|
|
|
89 iter_src = m_chain.first(); iter_dst = newchain.first();
|
|
|
90 while(iter_src.is_valid() && iter_dst.is_valid()) {
|
|
|
91 if (iter_src->m_preset == iter_dst->m_preset) {
|
|
|
92 iter_src->m_recycle_flag = true;
|
|
|
93 iter_dst->m_dsp = iter_src->m_dsp;
|
|
|
94 }
|
|
|
95 ++iter_src; ++iter_dst;
|
|
|
96 }
|
|
|
97 }
|
|
|
98
|
|
|
99 for( auto & iter : newchain ) {
|
|
|
100 if (iter.m_dsp.is_empty()) {
|
|
|
101 if (!dsp_entry::g_instantiate(iter.m_dsp,iter.m_preset, m_creationFlags) && !dsp_entry_hidden::g_instantiate(iter.m_dsp, iter.m_preset)) uBugCheck();
|
|
|
102 }
|
|
|
103 }
|
|
|
104
|
|
|
105 if (m_chain.get_count()>0) {
|
|
|
106 bool flushflag = flush_mark.is_valid();
|
|
|
107 for(t_dsp_chain::const_iterator iter = m_chain.first(); iter.is_valid(); ++iter) {
|
|
|
108 unsigned flags2 = p_flags;
|
|
|
109 if (iter == flush_mark) flushflag = false;
|
|
|
110 if (flushflag || !iter->m_recycle_flag) flags2|=dsp::FLUSH;
|
|
|
111 dsp_run(iter,p_list,p_cur_file,flags2,latency,p_abort);
|
|
|
112 }
|
|
|
113 done = true;
|
|
|
114 }
|
|
|
115
|
|
|
116 m_chain = newchain;
|
|
|
117 m_config_changed = false;
|
|
|
118 }
|
|
|
119
|
|
|
120 if (!done)
|
|
|
121 {
|
|
|
122 bool flushflag = flush_mark.is_valid();
|
|
|
123 for(t_dsp_chain::const_iterator iter = m_chain.first(); iter.is_valid(); ++iter) {
|
|
|
124 unsigned flags2 = p_flags;
|
|
|
125 if (iter == flush_mark) flushflag = false;
|
|
|
126 if (flushflag) flags2|=dsp::FLUSH;
|
|
|
127 dsp_run(iter,p_list,p_cur_file,flags2,latency,p_abort);
|
|
|
128 }
|
|
|
129 done = true;
|
|
|
130 }
|
|
|
131
|
|
|
132 p_list->remove_bad_chunks();
|
|
|
133
|
|
|
134 return latency;
|
|
|
135 } catch(...) {
|
|
|
136 p_list->remove_all();
|
|
|
137 throw;
|
|
|
138 }
|
|
|
139 }
|
|
|
140
|
|
|
141 void dsp_manager::flush()
|
|
|
142 {
|
|
|
143 for(t_dsp_chain::const_iterator iter = m_chain.first(); iter.is_valid(); ++iter) {
|
|
|
144 TRACK_CODE("dsp::flush",iter->m_dsp->flush());
|
|
|
145 }
|
|
|
146 }
|
|
|
147
|
|
|
148
|
|
|
149 bool dsp_manager::is_active() const {return m_config.get_count()>0;}
|
|
|
150
|
|
|
151 void dsp_config_manager::core_enable_dsp(const dsp_preset & preset, default_insert_t insertWhere ) {
|
|
|
152 dsp_chain_config_impl cfg;
|
|
|
153 get_core_settings(cfg);
|
|
|
154
|
|
|
155 bool found = false;
|
|
|
156 bool changed = false;
|
|
|
157 t_size n,m = cfg.get_count();
|
|
|
158 for(n=0;n<m;n++) {
|
|
|
159 if (cfg.get_item(n).get_owner() == preset.get_owner()) {
|
|
|
160 found = true;
|
|
|
161 if (cfg.get_item(n) != preset) {
|
|
|
162 cfg.replace_item(preset,n);
|
|
|
163 changed = true;
|
|
|
164 }
|
|
|
165 break;
|
|
|
166 }
|
|
|
167 }
|
|
|
168 if (!found) {
|
|
|
169 if ( insertWhere == default_insert_last ) {
|
|
|
170 cfg.add_item( preset );
|
|
|
171 } else {
|
|
|
172 cfg.insert_item(preset,0);
|
|
|
173 }
|
|
|
174
|
|
|
175 changed = true;
|
|
|
176 }
|
|
|
177
|
|
|
178 if (changed) set_core_settings(cfg);
|
|
|
179 }
|
|
|
180 void dsp_config_manager::core_disable_dsp(const GUID & id) {
|
|
|
181 dsp_chain_config_impl cfg;
|
|
|
182 get_core_settings(cfg);
|
|
|
183
|
|
|
184 t_size n,m = cfg.get_count();
|
|
|
185 pfc::bit_array_bittable mask(m);
|
|
|
186 bool changed = false;
|
|
|
187 for(n=0;n<m;n++) {
|
|
|
188 bool axe = (cfg.get_item(n).get_owner() == id) ? true : false;
|
|
|
189 if (axe) changed = true;
|
|
|
190 mask.set(n,axe);
|
|
|
191 }
|
|
|
192 if (changed) {
|
|
|
193 cfg.remove_mask(mask);
|
|
|
194 set_core_settings(cfg);
|
|
|
195 }
|
|
|
196 }
|
|
|
197
|
|
|
198 bool dsp_config_manager::core_query_dsp(const GUID & id, dsp_preset & out) {
|
|
|
199 dsp_chain_config_impl cfg;
|
|
|
200 get_core_settings(cfg);
|
|
|
201 for(t_size n=0;n<cfg.get_count();n++) {
|
|
|
202 const dsp_preset & entry = cfg.get_item(n);
|
|
|
203 if (entry.get_owner() == id) {
|
|
|
204 out = entry; return true;
|
|
|
205 }
|
|
|
206 }
|
|
|
207 return false;
|
|
|
208 }
|
|
|
209
|
|
|
210 #endif
|