Mercurial > foo_out_sdl
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); } |
