annotate foosdk/sdk/foobar2000/foo_sample/input_raw.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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #include "stdafx.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 enum {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4 raw_bits_per_sample = 16,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5 raw_channels = 2,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6 raw_sample_rate = 44100,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 raw_bytes_per_sample = raw_bits_per_sample / 8,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 raw_total_sample_width = raw_bytes_per_sample * raw_channels,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 // Note that input class does *not* implement virtual methods or derive from interface classes.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 // Our methods get called over input framework templates. See input_singletrack_impl for descriptions of what each method does.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 // input_stubs just provides stub implementations of mundane methods that are irrelevant for most implementations.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 class input_raw : public input_stubs {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 void open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 if (p_reason == input_open_info_write) throw exception_tagging_unsupported();//our input does not support retagging.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 m_file = p_filehint;//p_filehint may be null, hence next line
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 input_open_file_helper(m_file,p_path,p_reason,p_abort);//if m_file is null, opens file with appropriate privileges for our operation (read/write for writing tags, read-only otherwise).
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 void get_info(file_info & p_info,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 t_filesize size = m_file->get_size(p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 //note that the file size is not always known, for an example, live streams and alike have no defined size and filesize_invalid is returned
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 if (size != filesize_invalid) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 //file size is known, let's set length
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28 p_info.set_length(audio_math::samples_to_time( size / raw_total_sample_width, raw_sample_rate));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 //note that the values below should be based on contents of the file itself, NOT on user-configurable variables for an example. To report info that changes independently from file contents, use get_dynamic_info/get_dynamic_info_track instead.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 p_info.info_set_int("samplerate",raw_sample_rate);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 p_info.info_set_int("channels",raw_channels);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 p_info.info_set_int("bitspersample",raw_bits_per_sample);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 // Indicate whether this is a fixedpoint or floatingpoint stream, when using bps >= 32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 // As 32bit fixedpoint can't be decoded losslessly by fb2k, does not fit in float32 audio_sample.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 if ( raw_bits_per_sample >= 32 ) p_info.info_set("bitspersample_extra", "fixed-point");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 p_info.info_set("encoding","lossless");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40 p_info.info_set_bitrate((raw_bits_per_sample * raw_channels * raw_sample_rate + 500 /* rounding for bps to kbps*/ ) / 1000 /* bps to kbps */);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 t_filestats2 get_stats2(unsigned f, abort_callback& a) {return m_file->get_stats2_(f, a);}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 t_filestats get_file_stats(abort_callback & p_abort) {return m_file->get_stats(p_abort);}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46 void decode_initialize(unsigned p_flags,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 m_file->reopen(p_abort);//equivalent to seek to zero, except it also works on nonseekable streams
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 bool decode_run(audio_chunk & p_chunk,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 enum {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 deltaread = 1024,
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 const size_t deltaReadBytes = deltaread * raw_total_sample_width;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 // Prepare buffer
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 m_buffer.set_size(deltaReadBytes);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 // Read bytes
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 size_t got = m_file->read(m_buffer.get_ptr(), deltaReadBytes,p_abort) / raw_total_sample_width;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 // EOF?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 if (got == 0) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 // This converts the data that we've read to the audio_chunk's internal format, audio_sample (float 32-bit).
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 // audio_sample is the audio data format that all fb2k code works with.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 p_chunk.set_data_fixedpoint(m_buffer.get_ptr(), got * raw_total_sample_width,raw_sample_rate,raw_channels,raw_bits_per_sample,audio_chunk::g_guess_channel_config(raw_channels));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 //processed successfully, no EOF
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 void decode_seek(double p_seconds,abort_callback & p_abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 m_file->ensure_seekable();//throw exceptions if someone called decode_seek() despite of our input having reported itself as nonseekable.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 // IMPORTANT: convert time to sample offset with proper rounding! audio_math::time_to_samples does this properly for you.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 t_filesize target = audio_math::time_to_samples(p_seconds,raw_sample_rate) * raw_total_sample_width;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 // get_size_ex fails (throws exceptions) if size is not known (where get_size would return filesize_invalid). Should never fail on seekable streams (if it does it's not our problem anymore).
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 t_filesize max = m_file->get_size_ex(p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 if (target > max) target = max;//clip seek-past-eof attempts to legal range (next decode_run() call will just signal EOF).
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 m_file->seek(target,p_abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 bool decode_can_seek() {return m_file->can_seek();}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) {return false;} // deals with dynamic information such as VBR bitrates
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) {return false;} // deals with dynamic information such as track changes in live streams
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 void decode_on_idle(abort_callback & p_abort) {m_file->on_idle(p_abort);}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 // Note that open() already rejects requests to open for tag writing, so these two should never get called.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 void retag(const file_info & p_info,abort_callback & p_abort) {throw exception_tagging_unsupported();}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 void remove_tags(abort_callback&) { throw exception_tagging_unsupported(); }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90 static bool g_is_our_content_type(const char * p_content_type) {return false;} // match against supported mime types here
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 static bool g_is_our_path(const char * p_path,const char * p_extension) {return stricmp_utf8(p_extension,"raw") == 0;}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 static const char * g_get_name() { return "foo_sample raw input"; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 static const GUID g_get_guid() {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 // GUID of the decoder. Replace with your own when reusing code.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 static const GUID I_am_foo_sample_and_this_is_my_decoder_GUID = { 0xd9c01c8d, 0x69c5, 0x4eec,{ 0xa2, 0x1c, 0x1d, 0x14, 0xef, 0x65, 0xbf, 0x8b } };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 return I_am_foo_sample_and_this_is_my_decoder_GUID;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 public:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 service_ptr_t<file> m_file;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 pfc::array_t<t_uint8> m_buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103 static input_singletrack_factory_t<input_raw> g_input_raw_factory;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 // Declare .RAW as a supported file type to make it show in "open file" dialog etc.
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 DECLARE_FILE_TYPE("Raw files","*.RAW");