Mercurial > foo_out_sdl
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/helpers/input_helper_cue.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,223 @@ +#include "StdAfx.h" +#include "input_helper_cue.h" +#include <SDK/mem_block_container.h> +#include <SDK/input.h> +#include <SDK/file_info_impl.h> + + +namespace { + class input_dec_binary : public input_decoder_v2 { + enum { + m_rate = 44100, + m_bps = 16, + m_channels = 2, + m_channelMask = audio_chunk::channel_config_stereo, + m_sampleBytes = (m_bps/8)*m_channels, + m_readAtOnce = 588, + m_readAtOnceBytes = m_readAtOnce * m_sampleBytes + }; + public: + input_dec_binary( file::ptr f ) : m_file(f) {} + t_uint32 get_subsong_count() override {return 0;} + t_uint32 get_subsong(t_uint32 p_index) override {return 0;} + + void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) override { + p_info.reset(); + p_info.info_set_int("samplerate", m_rate); + p_info.info_set_int("channels", m_channels); + p_info.info_set_int("bitspersample", m_bps); + p_info.info_set("encoding","lossless"); + p_info.info_set_bitrate((m_bps * m_channels * m_rate + 500 /* rounding for bps to kbps*/ ) / 1000 /* bps to kbps */); + p_info.info_set("codec", "PCM"); + + try { + auto stats = get_file_stats(p_abort); + if ( stats.m_size != filesize_invalid ) { + p_info.set_length( audio_math::samples_to_time( stats.m_size / 4, 44100 ) ); + } + } catch(exception_io) {} + } + + + t_filestats get_file_stats(abort_callback & p_abort) override { + return m_file->get_stats(p_abort); + } + void initialize(t_uint32 p_subsong,unsigned p_flags,abort_callback & p_abort) override { + m_file->reopen( p_abort ); + } + bool run(audio_chunk & p_chunk,abort_callback & p_abort) override { + mem_block_container_impl stfu; + return run_raw(p_chunk, stfu, p_abort); + } + bool run_raw(audio_chunk & out, mem_block_container & outRaw, abort_callback & abort) override { + size_t bytes = m_readAtOnceBytes; + outRaw.set_size( bytes ); + size_t got = m_file->read(outRaw.get_ptr(), bytes, abort); + got -= got % m_sampleBytes; + if ( got == 0 ) return false; + if ( got < bytes ) outRaw.set_size( got ); + out.set_data_fixedpoint_signed( outRaw.get_ptr(), got, m_rate, m_channels, m_bps, m_channelMask); + return true; + } + void seek(double p_seconds,abort_callback & p_abort) override { + m_file->seek( audio_math::time_to_samples( p_seconds, m_rate ) * m_sampleBytes, p_abort ); + } + bool can_seek() override { + return m_file->can_seek(); + } + bool get_dynamic_info(file_info & p_out, double & p_timestamp_delta) override {return false;} + bool get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) override {return false;} + void on_idle(abort_callback & p_abort) override {} + void set_logger(event_logger::ptr ptr) override {} + private: + const file::ptr m_file; + }; +} + + +void input_helper_cue::get_info_binary( const char * path, file_info & out, abort_callback & abort ) { + auto f = fileOpenReadExisting( path, abort ); + auto obj = fb2k::service_new< input_dec_binary > ( f ); + obj->get_info( 0, out, abort ); +} + +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) { + p_abort.check(); + + m_start = p_start; + m_position = 0; + m_dynamic_info_trigger = false; + m_dynamic_info_track_trigger = false; + + if ( binary ) { + { + const char * path = p_location.get_path(); + auto f = fileOpenReadExisting( path, p_abort ); + auto obj = fb2k::service_new< input_dec_binary > ( f ); + + m_input.attach( obj, path ); + m_input.open_decoding( 0, p_flags, p_abort ); + } + } else { + m_input.open(p_filehint,p_location,p_flags,p_abort,true,true); + } + + + if (!m_input.can_seek()) throw exception_io_object_not_seekable(); + + if (m_start > 0) { + m_input.seek(m_start,p_abort); + } + + if (p_length > 0) { + m_length = p_length; + } else { + file_info_impl temp; + m_input.get_info(0,temp,p_abort); + double ref_length = temp.get_length(); + if (ref_length <= 0) throw exception_io_data(); + m_length = ref_length - m_start + p_length /* negative or zero */; + if (m_length <= 0) throw exception_io_data(); + } +} + +void input_helper_cue::close() {m_input.close();} +bool input_helper_cue::is_open() {return m_input.is_open();} + +bool input_helper_cue::_m_input_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) { + if (p_raw == NULL) { + return m_input.run(p_chunk, p_abort); + } else { + return m_input.run_raw(p_chunk, *p_raw, p_abort); + } +} +bool input_helper_cue::_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) { + p_abort.check(); + + if (m_length > 0) { + if (m_position >= m_length) return false; + + if (!_m_input_run(p_chunk, p_raw, p_abort)) return false; + + m_dynamic_info_trigger = true; + m_dynamic_info_track_trigger = true; + + t_uint64 max = (t_uint64)audio_math::time_to_samples(m_length - m_position, p_chunk.get_sample_rate()); + if (max == 0) + {//handle rounding accidents, this normally shouldn't trigger + m_position = m_length; + return false; + } + + t_size samples = p_chunk.get_sample_count(); + if ((t_uint64)samples > max) + { + p_chunk.set_sample_count((unsigned)max); + if (p_raw != NULL) { + const t_size rawSize = p_raw->get_size(); + PFC_ASSERT(rawSize % samples == 0); + p_raw->set_size((t_size)((t_uint64)rawSize * max / samples)); + } + m_position = m_length; + } + else + { + m_position += p_chunk.get_duration(); + } + return true; + } + else + { + if (!_m_input_run(p_chunk, p_raw, p_abort)) return false; + m_position += p_chunk.get_duration(); + return true; + } +} +bool input_helper_cue::run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) { + return _run(p_chunk, &p_raw, p_abort); +} + +bool input_helper_cue::run(audio_chunk & p_chunk, abort_callback & p_abort) { + return _run(p_chunk, NULL, p_abort); +} + +void input_helper_cue::seek(double p_seconds, abort_callback & p_abort) +{ + m_dynamic_info_trigger = false; + m_dynamic_info_track_trigger = false; + if (m_length <= 0 || p_seconds < m_length) { + m_input.seek(p_seconds + m_start, p_abort); + m_position = p_seconds; + } + else { + m_position = m_length; + } +} + +bool input_helper_cue::can_seek() { return true; } + +void input_helper_cue::on_idle(abort_callback & p_abort) { m_input.on_idle(p_abort); } + +bool input_helper_cue::get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { + if (m_dynamic_info_trigger) { + m_dynamic_info_trigger = false; + return m_input.get_dynamic_info(p_out, p_timestamp_delta); + } + else { + return false; + } +} + +bool input_helper_cue::get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) { + if (m_dynamic_info_track_trigger) { + m_dynamic_info_track_trigger = false; + return m_input.get_dynamic_info_track(p_out, p_timestamp_delta); + } + else { + return false; + } +} + +const char * input_helper_cue::get_path() const { return m_input.get_path(); } + +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); }
