|
1
|
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); }
|