comparison foosdk/sdk/foobar2000/helpers/input_helper_cue.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 "StdAfx.h"
2 #include "input_helper_cue.h"
3 #include <SDK/mem_block_container.h>
4 #include <SDK/input.h>
5 #include <SDK/file_info_impl.h>
6
7
8 namespace {
9 class input_dec_binary : public input_decoder_v2 {
10 enum {
11 m_rate = 44100,
12 m_bps = 16,
13 m_channels = 2,
14 m_channelMask = audio_chunk::channel_config_stereo,
15 m_sampleBytes = (m_bps/8)*m_channels,
16 m_readAtOnce = 588,
17 m_readAtOnceBytes = m_readAtOnce * m_sampleBytes
18 };
19 public:
20 input_dec_binary( file::ptr f ) : m_file(f) {}
21 t_uint32 get_subsong_count() override {return 0;}
22 t_uint32 get_subsong(t_uint32 p_index) override {return 0;}
23
24 void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) override {
25 p_info.reset();
26 p_info.info_set_int("samplerate", m_rate);
27 p_info.info_set_int("channels", m_channels);
28 p_info.info_set_int("bitspersample", m_bps);
29 p_info.info_set("encoding","lossless");
30 p_info.info_set_bitrate((m_bps * m_channels * m_rate + 500 /* rounding for bps to kbps*/ ) / 1000 /* bps to kbps */);
31 p_info.info_set("codec", "PCM");
32
33 try {
34 auto stats = get_file_stats(p_abort);
35 if ( stats.m_size != filesize_invalid ) {
36 p_info.set_length( audio_math::samples_to_time( stats.m_size / 4, 44100 ) );
37 }
38 } catch(exception_io) {}
39 }
40
41
42 t_filestats get_file_stats(abort_callback & p_abort) override {
43 return m_file->get_stats(p_abort);
44 }
45 void initialize(t_uint32 p_subsong,unsigned p_flags,abort_callback & p_abort) override {
46 m_file->reopen( p_abort );
47 }
48 bool run(audio_chunk & p_chunk,abort_callback & p_abort) override {
49 mem_block_container_impl stfu;
50 return run_raw(p_chunk, stfu, p_abort);
51 }
52 bool run_raw(audio_chunk & out, mem_block_container & outRaw, abort_callback & abort) override {
53 size_t bytes = m_readAtOnceBytes;
54 outRaw.set_size( bytes );
55 size_t got = m_file->read(outRaw.get_ptr(), bytes, abort);
56 got -= got % m_sampleBytes;
57 if ( got == 0 ) return false;
58 if ( got < bytes ) outRaw.set_size( got );
59 out.set_data_fixedpoint_signed( outRaw.get_ptr(), got, m_rate, m_channels, m_bps, m_channelMask);
60 return true;
61 }
62 void seek(double p_seconds,abort_callback & p_abort) override {
63 m_file->seek( audio_math::time_to_samples( p_seconds, m_rate ) * m_sampleBytes, p_abort );
64 }
65 bool can_seek() override {
66 return m_file->can_seek();
67 }
68 bool get_dynamic_info(file_info & p_out, double & p_timestamp_delta) override {return false;}
69 bool get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) override {return false;}
70 void on_idle(abort_callback & p_abort) override {}
71 void set_logger(event_logger::ptr ptr) override {}
72 private:
73 const file::ptr m_file;
74 };
75 }
76
77
78 void input_helper_cue::get_info_binary( const char * path, file_info & out, abort_callback & abort ) {
79 auto f = fileOpenReadExisting( path, abort );
80 auto obj = fb2k::service_new< input_dec_binary > ( f );
81 obj->get_info( 0, out, abort );
82 }
83
84 void input_helper_cue::open(service_ptr_t<file> p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,double p_start,double p_length, bool binary) {
85 p_abort.check();
86
87 m_start = p_start;
88 m_position = 0;
89 m_dynamic_info_trigger = false;
90 m_dynamic_info_track_trigger = false;
91
92 if ( binary ) {
93 {
94 const char * path = p_location.get_path();
95 auto f = fileOpenReadExisting( path, p_abort );
96 auto obj = fb2k::service_new< input_dec_binary > ( f );
97
98 m_input.attach( obj, path );
99 m_input.open_decoding( 0, p_flags, p_abort );
100 }
101 } else {
102 m_input.open(p_filehint,p_location,p_flags,p_abort,true,true);
103 }
104
105
106 if (!m_input.can_seek()) throw exception_io_object_not_seekable();
107
108 if (m_start > 0) {
109 m_input.seek(m_start,p_abort);
110 }
111
112 if (p_length > 0) {
113 m_length = p_length;
114 } else {
115 file_info_impl temp;
116 m_input.get_info(0,temp,p_abort);
117 double ref_length = temp.get_length();
118 if (ref_length <= 0) throw exception_io_data();
119 m_length = ref_length - m_start + p_length /* negative or zero */;
120 if (m_length <= 0) throw exception_io_data();
121 }
122 }
123
124 void input_helper_cue::close() {m_input.close();}
125 bool input_helper_cue::is_open() {return m_input.is_open();}
126
127 bool input_helper_cue::_m_input_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) {
128 if (p_raw == NULL) {
129 return m_input.run(p_chunk, p_abort);
130 } else {
131 return m_input.run_raw(p_chunk, *p_raw, p_abort);
132 }
133 }
134 bool input_helper_cue::_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) {
135 p_abort.check();
136
137 if (m_length > 0) {
138 if (m_position >= m_length) return false;
139
140 if (!_m_input_run(p_chunk, p_raw, p_abort)) return false;
141
142 m_dynamic_info_trigger = true;
143 m_dynamic_info_track_trigger = true;
144
145 t_uint64 max = (t_uint64)audio_math::time_to_samples(m_length - m_position, p_chunk.get_sample_rate());
146 if (max == 0)
147 {//handle rounding accidents, this normally shouldn't trigger
148 m_position = m_length;
149 return false;
150 }
151
152 t_size samples = p_chunk.get_sample_count();
153 if ((t_uint64)samples > max)
154 {
155 p_chunk.set_sample_count((unsigned)max);
156 if (p_raw != NULL) {
157 const t_size rawSize = p_raw->get_size();
158 PFC_ASSERT(rawSize % samples == 0);
159 p_raw->set_size((t_size)((t_uint64)rawSize * max / samples));
160 }
161 m_position = m_length;
162 }
163 else
164 {
165 m_position += p_chunk.get_duration();
166 }
167 return true;
168 }
169 else
170 {
171 if (!_m_input_run(p_chunk, p_raw, p_abort)) return false;
172 m_position += p_chunk.get_duration();
173 return true;
174 }
175 }
176 bool input_helper_cue::run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) {
177 return _run(p_chunk, &p_raw, p_abort);
178 }
179
180 bool input_helper_cue::run(audio_chunk & p_chunk, abort_callback & p_abort) {
181 return _run(p_chunk, NULL, p_abort);
182 }
183
184 void input_helper_cue::seek(double p_seconds, abort_callback & p_abort)
185 {
186 m_dynamic_info_trigger = false;
187 m_dynamic_info_track_trigger = false;
188 if (m_length <= 0 || p_seconds < m_length) {
189 m_input.seek(p_seconds + m_start, p_abort);
190 m_position = p_seconds;
191 }
192 else {
193 m_position = m_length;
194 }
195 }
196
197 bool input_helper_cue::can_seek() { return true; }
198
199 void input_helper_cue::on_idle(abort_callback & p_abort) { m_input.on_idle(p_abort); }
200
201 bool input_helper_cue::get_dynamic_info(file_info & p_out, double & p_timestamp_delta) {
202 if (m_dynamic_info_trigger) {
203 m_dynamic_info_trigger = false;
204 return m_input.get_dynamic_info(p_out, p_timestamp_delta);
205 }
206 else {
207 return false;
208 }
209 }
210
211 bool input_helper_cue::get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) {
212 if (m_dynamic_info_track_trigger) {
213 m_dynamic_info_track_trigger = false;
214 return m_input.get_dynamic_info_track(p_out, p_timestamp_delta);
215 }
216 else {
217 return false;
218 }
219 }
220
221 const char * input_helper_cue::get_path() const { return m_input.get_path(); }
222
223 void input_helper_cue::get_info(t_uint32 p_subsong, file_info & p_info, abort_callback & p_abort) { m_input.get_info(p_subsong, p_info, p_abort); }