foobar2000 SDK  2015-08-03
cue_parser.h
Go to the documentation of this file.
1 //HINT: for info on how to generate an embedded cuesheet enabled input, see the end of this header.
2 
3 //to be moved somewhere else later
5 
7  public:
9  void operator() (const char * p_name,const char * p_value) {m_out.__info_add_unsafe(p_name,p_value);}
10  private:
12  };
13 
15  public:
17  template<typename t_value> void operator() (const char * p_name,const t_value & p_value) {
18  t_size index = ~0;
19  for(typename t_value::const_iterator iter = p_value.first(); iter.is_valid(); ++iter) {
20  if (index == ~0) index = m_out.__meta_add_unsafe(p_name,*iter);
21  else m_out.meta_add_value(index,*iter);
22  }
23  }
24  private:
26  };
27 
29  public:
33 
34  file_info_record() : m_replaygain(replaygain_info_invalid), m_length(0) {}
35 
36  replaygain_info get_replaygain() const {return m_replaygain;}
37  void set_replaygain(const replaygain_info & p_replaygain) {m_replaygain = p_replaygain;}
38  double get_length() const {return m_length;}
39  void set_length(double p_length) {m_length = p_length;}
40 
41  void reset() {
42  m_meta.remove_all(); m_info.remove_all();
43  m_length = 0;
44  m_replaygain = replaygain_info_invalid;
45  }
46 
47  void from_info_overwrite_info(const file_info & p_info) {
48  for(t_size infowalk = 0, infocount = p_info.info_get_count(); infowalk < infocount; ++infowalk) {
49  m_info.set(p_info.info_enum_name(infowalk),p_info.info_enum_value(infowalk));
50  }
51  }
52  void from_info_overwrite_meta(const file_info & p_info) {
53  for(t_size metawalk = 0, metacount = p_info.meta_get_count(); metawalk < metacount; ++metawalk) {
54  const t_size valuecount = p_info.meta_enum_value_count(metawalk);
55  if (valuecount > 0) {
56  t_meta_value & entry = m_meta.find_or_add(p_info.meta_enum_name(metawalk));
57  entry.remove_all();
58  for(t_size valuewalk = 0; valuewalk < valuecount; ++valuewalk) {
59  entry.add_item(p_info.meta_enum_value(metawalk,valuewalk));
60  }
61  }
62  }
63  }
64 
65  void from_info_overwrite_rg(const file_info & p_info) {
66  m_replaygain = replaygain_info::g_merge(m_replaygain,p_info.get_replaygain());
67  }
68 
69  template<typename t_source>
70  void overwrite_meta(const t_source & p_meta) {
71  m_meta.overwrite(p_meta);
72  }
73  template<typename t_source>
74  void overwrite_info(const t_source & p_info) {
75  m_info.overwrite(p_info);
76  }
77 
78  void merge_overwrite(const file_info & p_info) {
79  from_info_overwrite_info(p_info);
80  from_info_overwrite_meta(p_info);
81  from_info_overwrite_rg(p_info);
82  }
83 
84  void transfer_meta_entry(const char * p_name,const file_info & p_info,t_size p_index) {
85  const t_size count = p_info.meta_enum_value_count(p_index);
86  if (count == 0) {
87  m_meta.remove(p_name);
88  } else {
89  t_meta_value & val = m_meta.find_or_add(p_name);
90  val.remove_all();
91  for(t_size walk = 0; walk < count; ++walk) {
92  val.add_item(p_info.meta_enum_value(p_index,walk));
93  }
94  }
95  }
96 
97  void meta_set(const char * p_name,const char * p_value) {
98  m_meta.find_or_add(p_name).set_single(p_value);
99  }
100 
101  const t_meta_value * meta_query_ptr(const char * p_name) const {
102  return m_meta.query_ptr(p_name);
103  }
104 
105 
106  void from_info_set_meta(const file_info & p_info) {
107  m_meta.remove_all();
108  from_info_overwrite_meta(p_info);
109  }
110 
111  void from_info(const file_info & p_info) {
112  reset();
113  m_length = p_info.get_length();
114  m_replaygain = p_info.get_replaygain();
115  from_info_overwrite_meta(p_info);
116  from_info_overwrite_info(p_info);
117  }
118  void to_info(file_info & p_info) const {
119  p_info.reset();
120  p_info.set_length(m_length);
121  p_info.set_replaygain(m_replaygain);
122 
123  {
125  m_info.enumerate( e );
126  }
127  {
129  m_meta.enumerate( e );
130  }
131  }
132 
133  template<typename t_callback> void enumerate_meta(t_callback & p_callback) const {m_meta.enumerate(p_callback);}
134  template<typename t_callback> void enumerate_meta(t_callback & p_callback) {m_meta.enumerate(p_callback);}
135 
136  //private:
137  t_meta_map m_meta;
138  t_info_map m_info;
140  double m_length;
141  };
142 
143 }//namespace file_info_record_helper
144 
145 
146 namespace cue_parser
147 {
148  struct cue_entry {
150  unsigned m_track_number;
152  };
153 
155 
156 
157  PFC_DECLARE_EXCEPTION(exception_bad_cuesheet,exception_io_data,"Invalid cuesheet");
158 
160  void parse(const char *p_cuesheet,t_cue_entry_list & p_out);
162  void parse_info(const char *p_cuesheet,file_info & p_info,unsigned p_index);
164  void parse_full(const char * p_cuesheet,cue_creator::t_entry_list & p_out);
165 
166 
167 
168  struct track_record {
172  };
173 
175 
177  public:
178  void get_tag(file_info & p_info) const;
179  void set_tag(file_info const & p_info);
180 
181  void get_track_info(unsigned p_track,file_info & p_info) const;
182  void set_track_info(unsigned p_track,file_info const & p_info);
183  void query_track_offsets(unsigned p_track,double & p_begin,double & p_length) const;
184  bool have_cuesheet() const;
185  unsigned remap_trackno(unsigned p_index) const;
186  t_size get_cue_track_count() const;
187  private:
188  track_record_list m_content;
189  };
190 
191 
192 
193 
194 
195  template<typename t_base>
197  public:
200 
201  void open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
202  m_impl.open( p_filehint, p_path, p_reason, p_abort );
204  m_impl.get_info(info,p_abort);
205  m_meta.set_tag(info);
206  }
207 
209  return m_meta.have_cuesheet() ? (uint32_t) m_meta.get_cue_track_count() : 1;
210  }
211 
213  return m_meta.have_cuesheet() ? m_meta.remap_trackno(p_index) : 0;
214  }
215 
216  void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) {
217  if (p_subsong == 0) {
218  m_meta.get_tag(p_info);
219  } else {
220  m_meta.get_track_info(p_subsong,p_info);
221  }
222  }
223 
224  t_filestats get_file_stats(abort_callback & p_abort) {return m_impl.get_file_stats(p_abort);}
225 
226  void decode_initialize(t_uint32 p_subsong,unsigned p_flags,abort_callback & p_abort) {
227  if (p_subsong == 0) {
228  m_impl.decode_initialize(p_flags, p_abort);
229  m_decodeFrom = 0; m_decodeLength = -1; m_decodePos = 0;
230  } else {
231  double start, length;
232  m_meta.query_track_offsets(p_subsong,start,length);
233  unsigned flags2 = p_flags;
234  if (start > 0) flags2 &= ~input_flag_no_seeking;
235  m_impl.decode_initialize(flags2, p_abort);
236  m_impl.decode_seek(start, p_abort);
237  m_decodeFrom = start; m_decodeLength = length; m_decodePos = 0;
238  }
239  }
240 
241  bool decode_run(audio_chunk & p_chunk,abort_callback & p_abort) {
242  return _run(p_chunk, NULL, p_abort);
243  }
244 
245  void decode_seek(double p_seconds,abort_callback & p_abort) {
246  if (this->m_decodeLength >= 0 && p_seconds > m_decodeLength) p_seconds = m_decodeLength;
247  m_impl.decode_seek(m_decodeFrom + p_seconds,p_abort);
248  m_decodePos = p_seconds;
249  }
250 
251  bool decode_can_seek() {return m_impl.decode_can_seek();}
252 
253  bool decode_run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) {
254  return _run(p_chunk, &p_raw, p_abort);
255  }
256  void set_logger(event_logger::ptr ptr) {
257  m_impl.set_logger(ptr);
258  }
259 
260  bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) {
261  return m_impl.decode_get_dynamic_info(p_out, p_timestamp_delta);
262  }
263 
264  bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) {
265  return m_impl.decode_get_dynamic_info_track(p_out, p_timestamp_delta);
266  }
267 
268  void decode_on_idle(abort_callback & p_abort) {
269  m_impl.decode_on_idle(p_abort);
270  }
271 
272  void retag_set_info(t_uint32 p_subsong,const file_info & p_info,abort_callback & p_abort) {
273  if (p_subsong == 0) {
274  m_meta.set_tag(p_info);
275  } else {
276  m_meta.set_track_info(p_subsong,p_info);
277  }
278  }
279 
280  void retag_commit(abort_callback & p_abort) {
282  m_meta.get_tag(info);
283  m_impl.retag(pfc::implicit_cast<const file_info&>(info), p_abort);
284  info.reset();
285  m_impl.get_info(info, p_abort);
286  m_meta.set_tag( info );
287  }
288 
289  inline static bool g_is_our_content_type(const char * p_content_type) {return t_base::g_is_our_content_type(p_content_type);}
290  inline static bool g_is_our_path(const char * p_path,const char * p_extension) {return t_base::g_is_our_path(p_path,p_extension);}
291 
292  private:
293  bool _run(audio_chunk & chunk, mem_block_container * raw, abort_callback & aborter) {
294  if (m_decodeLength >= 0 && m_decodePos >= m_decodeLength) return false;
295  if (raw == NULL) {
296  if (!m_impl.decode_run(chunk, aborter)) return false;
297  } else {
298  if (!m_impl.decode_run_raw(chunk, *raw, aborter)) return false;
299  }
300 
301  if (m_decodeLength >= 0) {
302  const uint64_t remaining = audio_math::time_to_samples( m_decodeLength - m_decodePos, chunk.get_sample_rate() );
303  const size_t samplesGot = chunk.get_sample_count();
304  if (remaining < samplesGot) {
305  m_decodePos = m_decodeLength;
306  if (remaining == 0) { // rare but possible as a result of rounding SNAFU - we're EOF but we didn't notice earlier
307  return false;
308  }
309 
310  chunk.set_sample_count( (size_t) remaining );
311  if (raw != NULL) {
312  const t_size rawSize = raw->get_size();
313  PFC_ASSERT( rawSize % samplesGot == 0 );
314  raw->set_size( (t_size) ( (t_uint64) rawSize * remaining / samplesGot ) );
315  }
316  } else {
317  m_decodePos += chunk.get_duration();
318  }
319  } else {
320  m_decodePos += chunk.get_duration();
321  }
322  return true;
323  }
325  double m_decodeFrom, m_decodeLength, m_decodePos;
326 
328  };
329 #ifndef APP_IS_BOOM
330  template<typename I>
332  {
333  public:
334  bool is_our_path(const char * p_path) {
335  return I::g_is_our_path(p_path, pfc::string_extension(p_path));
336  }
337 
338  void set_chapters(const char * p_path,chapter_list const & p_list,abort_callback & p_abort) {
339  input_wrapper_cue_t<I> instance;
340  instance.open(0,p_path,input_open_info_write,p_abort);
341 
342  //stamp the cuesheet first
343  {
345  instance.get_info(0,info,p_abort);
346 
347  pfc::string_formatter cuesheet;
348 
349  {
351  t_size n, m = p_list.get_chapter_count();
352  const double pregap = p_list.get_pregap();
353  double offset_acc = pregap;
354  for(n=0;n<m;n++)
355  {
357  entry = entries.insert_last();
358  entry->m_infos = p_list.get_info(n);
359  entry->m_file = "CDImage.wav";
360  entry->m_track_number = (unsigned)(n+1);
361  entry->m_index_list.from_infos(entry->m_infos,offset_acc);
362  if (n == 0) entry->m_index_list.m_positions[0] = 0;
363  offset_acc += entry->m_infos.get_length();
364  }
365  cue_creator::create(cuesheet,entries);
366  }
367 
368  info.meta_set("cuesheet",cuesheet);
369 
370  instance.retag_set_info(0,info,p_abort);
371  }
372  //stamp per-chapter infos
373  for(t_size walk = 0, total = p_list.get_chapter_count(); walk < total; ++walk) {
374  instance.retag_set_info( (uint32_t)( walk + 1 ), p_list.get_info(walk),p_abort);
375  }
376 
377  instance.retag_commit(p_abort);
378  }
379 
380  void get_chapters(const char * p_path,chapter_list & p_list,abort_callback & p_abort) {
381 
382  input_wrapper_cue_t<I> instance;
383  instance.open(0,p_path,input_open_info_read,p_abort);
384  const t_uint32 total = instance.get_subsong_count();
385 
386  p_list.set_chapter_count(total);
387  for(t_uint32 walk = 0; walk < total; ++walk) {
389  instance.get_info(instance.get_subsong(walk),info,p_abort);
390  p_list.set_info(walk,info);
391  }
392  }
393 
395  return true;
396  }
397  };
398 #endif
399 };
400 
404 template<typename t_input_impl, unsigned t_flags = 0>
406 public:
408 #ifndef APP_IS_BOOM
410 #endif
411 };
virtual void set_size(t_size p_size)=0
replaygain_info get_replaygain() const
Definition: cue_parser.h:36
void decode_initialize(t_uint32 p_subsong, unsigned p_flags, abort_callback &p_abort)
Definition: cue_parser.h:226
virtual double get_length() const =0
Retrieves audio duration, in seconds. Note that the reported duration should not be assumed to be th...
void operator()(const char *p_name, const char *p_value)
Definition: cue_parser.h:9
pfc::chain_list_v2_t< cue_entry > t_cue_entry_list
Definition: cue_parser.h:154
Extended version of input_factory_t, with non-default flags and supported interfaces. See: input_factory_t, input_entry::get_flags().
Definition: input_impl.h:338
void add_item(const t_source &p_source)
void meta_set(const char *p_name, const char *p_value)
Definition: cue_parser.h:97
Definition: cue_parser.h:148
Interface for object storing list of chapters.
Definition: chapterizer.h:2
t_cuesheet_index_list m_index_list
Definition: cue_parser.h:171
uint64_t t_uint64
Definition: int_types.h:3
void merge_overwrite(const file_info &p_info)
Definition: cue_parser.h:78
void from_info(const file_info &p_info)
Definition: cue_parser.h:111
service_factory_single_t< cue_parser::chapterizer_impl_t< t_input_impl > > m_chapterizer_factory
Definition: cue_parser.h:409
void set_replaygain(const replaygain_info &p_replaygain)
Definition: cue_parser.h:37
void set_chapters(const char *p_path, chapter_list const &p_list, abort_callback &p_abort)
Writes new chapter list to specified file.
Definition: cue_parser.h:338
void retag_commit(abort_callback &p_abort)
Definition: cue_parser.h:280
bool decode_get_dynamic_info_track(file_info &p_out, double &p_timestamp_delta)
Definition: cue_parser.h:264
void info(const char *p_message)
Definition: console.cpp:4
This service implements chapter list editing operations for various file formats, e...
Definition: chapterizer.h:59
bool decode_run(audio_chunk &p_chunk, abort_callback &p_abort)
Definition: cue_parser.h:241
bool is_our_path(const char *p_path)
Tests whether specified path is supported by this implementation.
Definition: cue_parser.h:334
unsigned get_sample_rate() const
Helper, same as get_srate().
Definition: audio_chunk.h:103
virtual t_size meta_enum_value_count(t_size p_index) const =0
Retrieves count of values in metadata entry of specified index. The value is always equal to or great...
virtual const file_info & get_info(t_size p_chapter) const =0
Queries description of specified chapter.
virtual void set_info(t_size p_chapter, const file_info &p_info)=0
Modifies description of specified chapter.
Differences between chain_list_v2_t<> and old chain_list_t<>: Iterators pointing to removed items as...
Definition: chain_list_v2.h:26
Interface to container of a chunk of audio data. See audio_chunk_impl for an implementation.
Definition: audio_chunk.h:5
pfc::map_t< pfc::string8, t_meta_value, file_info::field_name_comparator > t_meta_map
Definition: cue_parser.h:31
t_input_open_reason
Definition: input_impl.h:1
pfc::string8 m_file
Definition: cue_parser.h:149
virtual const char * info_enum_value(t_size p_index) const =0
Retrieves the value of specified technical info entry. Return value is a null-terminated UTF-8 encode...
file_info_record_helper::file_info_record m_info
Definition: cue_parser.h:169
virtual const char * meta_enum_value(t_size p_index, t_size p_value_number) const =0
Retrieves specified value from specified metadata entry. Return value is a null-terminated UTF-8 enco...
static const replaygain_info replaygain_info_invalid
Definition: file_info.h:69
void retag_set_info(t_uint32 p_subsong, const file_info &p_info, abort_callback &p_abort)
Definition: cue_parser.h:272
const t_meta_value * meta_query_ptr(const char *p_name) const
Definition: cue_parser.h:101
void meta_add_value(t_size p_index, const char *p_value)
Definition: file_info.h:159
Structure containing ReplayGain scan results from some playable object, also providing various helper...
Definition: file_info.h:2
void transfer_meta_entry(const char *p_name, const file_info &p_info, t_size p_index)
Definition: cue_parser.h:84
void overwrite_meta(const t_source &p_meta)
Definition: cue_parser.h:70
t_size __meta_add_unsafe(const char *p_name, const char *p_value)
Unsafe - does not check whether the field already exists and will result in duplicates if it does - c...
Definition: file_info.h:238
static bool g_is_our_content_type(const char *p_content_type)
Definition: cue_parser.h:289
void decode_on_idle(abort_callback &p_abort)
Definition: cue_parser.h:268
void enumerate_meta(t_callback &p_callback)
Definition: cue_parser.h:134
t_filestats get_file_stats(abort_callback &p_abort)
Definition: cue_parser.h:224
Main interface class for information about some playable object.
Definition: file_info.h:73
t_cuesheet_index_list m_indexes
Definition: cue_parser.h:151
void get_chapters(const char *p_path, chapter_list &p_list, abort_callback &p_abort)
Retrieves chapter list from specified file.
Definition: cue_parser.h:380
void overwrite_info(const t_source &p_info)
Definition: cue_parser.h:74
size_t t_size
Definition: int_types.h:48
string8_fastalloc string_formatter
Definition: string_base.h:615
virtual void set_chapter_count(t_size p_count)=0
Sets number of chapters.
void reset()
Definition: file_info.cpp:287
virtual t_size meta_get_count() const =0
Retrieves count of metadata entries.
t_uint32 get_subsong(t_uint32 p_index)
Definition: cue_parser.h:212
bool _run(audio_chunk &chunk, mem_block_container *raw, abort_callback &aborter)
Definition: cue_parser.h:293
void parse(const char *p_cuesheet, t_cue_entry_list &p_out)
Throws exception_bad_cuesheet on failure.
Definition: cue_parser.cpp:621
t_size __info_add_unsafe(const char *p_name, const char *p_value)
Unsafe - does not check whether the field already exists and will result in duplicates if it does - c...
Definition: file_info.h:243
void enumerate_meta(t_callback &p_callback) const
Definition: cue_parser.h:133
embeddedcue_metadata_manager m_meta
Definition: cue_parser.h:327
virtual t_size get_chapter_count() const =0
Returns number of chapters.
virtual double get_pregap() const =0
virtual void set_replaygain(const replaygain_info &p_info)=0
Sets ReplayGain information.
void set_logger(event_logger::ptr ptr)
Definition: cue_parser.h:256
PFC_DECLARE_EXCEPTION(exception_bad_cuesheet, exception_io_data,"Invalid cuesheet")
input_factory_ex_t< cue_parser::input_wrapper_cue_t< t_input_impl >, t_flags, input_decoder_v2 > m_input_factory
Definition: cue_parser.h:407
void from_info_overwrite_info(const file_info &p_info)
Definition: cue_parser.h:47
void decode_seek(double p_seconds, abort_callback &p_abort)
Definition: cue_parser.h:245
void create(pfc::string_formatter &p_out, const t_entry_list &p_data)
Definition: cue_creator.cpp:44
pfc::chain_list_v2_t< pfc::string8 > t_meta_value
Definition: cue_parser.h:30
static replaygain_info g_merge(replaygain_info r1, replaygain_info r2)
Wrapper template for generating embedded cuesheet enabled inputs. t_input_impl is a singletrack input...
Definition: cue_parser.h:405
pfc::map_t< unsigned, track_record > track_record_list
Definition: cue_parser.h:174
pfc::map_t< pfc::string8, pfc::string8, file_info::field_name_comparator > t_info_map
Definition: cue_parser.h:32
bool decode_run_raw(audio_chunk &p_chunk, mem_block_container &p_raw, abort_callback &p_abort)
Definition: cue_parser.h:253
void from_info_overwrite_meta(const file_info &p_info)
Definition: cue_parser.h:52
void from_info_overwrite_rg(const file_info &p_info)
Definition: cue_parser.h:65
void parse_full(const char *p_cuesheet, cue_creator::t_entry_list &p_out)
Throws exception_bad_cuesheet on failure.
Definition: cue_parser.cpp:744
void from_info_set_meta(const file_info &p_info)
Definition: cue_parser.h:106
t_size meta_set(const char *p_name, const char *p_value)
Definition: file_info.h:157
void open(service_ptr_t< file > p_filehint, const char *p_path, t_input_open_reason p_reason, abort_callback &p_abort)
Definition: cue_parser.h:201
Implements file_info.
void parse_info(const char *p_cuesheet, file_info &p_info, unsigned p_index)
Throws exception_bad_cuesheet on failure.
Definition: cue_parser.cpp:630
Generic interface for a memory block; used by various other interfaces to return memory blocks while ...
virtual replaygain_info get_replaygain() const =0
Retrieves ReplayGain information.
double get_duration() const
Retrieves duration of contained audio data, in seconds.
Definition: audio_chunk.h:116
static bool g_is_our_path(const char *p_path, const char *p_extension)
Definition: cue_parser.h:290
virtual t_size get_sample_count() const =0
Retrieves number of valid samples in the buffer. Note that a "sample" means a unit of interleaved PC...
virtual void set_sample_count(t_size val)=0
Sets number of valid samples in the buffer. WARNING: sample count * channel count should never be abo...
virtual t_size get_size() const =0
virtual const char * info_enum_name(t_size p_index) const =0
Retrieves the name of specified technical info entry. Return value is a null-terminated UTF-8 encoded...
bool decode_get_dynamic_info(file_info &p_out, double &p_timestamp_delta)
Definition: cue_parser.h:260
virtual void set_length(double p_length)=0
Sets audio duration, in seconds. Note that the reported duration should not be assumed to be the exa...
uint32_t t_uint32
Definition: int_types.h:5
virtual t_size info_get_count() const =0
Retrieves number of technical info entries.
void to_info(file_info &p_info) const
Definition: cue_parser.h:118
void get_info(t_uint32 p_subsong, file_info &p_info, abort_callback &p_abort)
Definition: cue_parser.h:216
virtual const char * meta_enum_name(t_size p_index) const =0
Retrieves the name of metadata entry of specified index. Return value is a null-terminated UTF-8 enco...