1 /*
2  * tuple.h
3  * Copyright 2007-2013 Ariadne Conill, Christian Birchinger, Matti Hämäläinen,
4  *                     Giacomo Lozito, Eugene Zagidullin, and John Lindgren
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions, and the following disclaimer in the documentation
14  *    provided with the distribution.
15  *
16  * This software is provided "as is" and without any warranty, express or
17  * implied. In no event shall the authors be liable for any damages arising from
18  * the use of this software.
19  */
20 
21 /**
22  * @file tuple.h
23  * @brief Basic Tuple handling API.
24  */
25 
26 #ifndef LIBAUDCORE_TUPLE_H
27 #define LIBAUDCORE_TUPLE_H
28 
29 #include <libaudcore/objects.h>
30 
31 struct ReplayGainInfo;
32 struct TupleData;
33 class PluginHandle;
34 class VFSFile;
35 
36 class Tuple
37 {
38 public:
39     /* Smart pointer to the actual TupleData struct.
40      * Uses create-on-write and copy-on-write. */
41 
42     enum State
43     {
44         Initial, /* Song info has not yet been read */
45         Valid,   /* Song info has been successfully read */
46         Failed   /* Song info could not be read */
47     };
48 
49     enum Field
50     {
51         Invalid = -1,
52 
53         Title = 0,   /* Song title */
54         Artist,      /* Song artist */
55         Album,       /* Album name */
56         AlbumArtist, /* Artist for entire album, if different than song artist
57                       */
58         Comment,     /* Freeform comment */
59         Genre,       /* Song's genre */
60         Year,        /* Year of production, performance, etc. */
61 
62         Composer,  /* Composer, if different than artist */
63         Performer, /* Performer, if different than artist */
64         Copyright, /* Copyright declaration */
65         Date,      /* Date of production, performance, etc. */
66 
67         Track,  /* Track number */
68         Length, /* Track length in milliseconds */
69 
70         Bitrate, /* Bitrate in kilobits (1000 bits)/sec */
71         Codec,   /* Codec name, such as "Ogg Vorbis" */
72         Quality, /* String representing quality, such as "Stereo, 44 kHz" */
73 
74         Basename, /* Base filename, not including the folder path */
75         Path,     /* Folder path, including the trailing "/" */
76         Suffix,   /* Filename extension, not including the "." */
77 
78         AudioFile, /* URI of audio file, if different from the nominal URI
79                     * (e.g. for a cuesheet entry, where the nominal URI
80                     * points to the .cue file) */
81 
82         Subtune,     /* Index number of subtune */
83         NumSubtunes, /* Total number of subtunes in the file */
84 
85         StartTime, /* Playback start point (used for cuesheets) */
86         EndTime,   /* Playback end point (used for cuesheets) */
87 
88         /* Preserving replay gain information accurately is a challenge since
89          * there are several different formats around.  We use an integer
90          * fraction, with the denominator stored in the *Divisor fields.  For
91          * example, if AlbumGain is 512 and GainDivisor is 256, then the album
92          * gain is +2 dB.  If TrackPeak is 787 and PeakDivisor is 1000, then the
93          * peak volume is 0.787 in a -1.0 to 1.0 range. */
94         AlbumGain,
95         AlbumPeak,
96         TrackGain,
97         TrackPeak,
98         GainDivisor,
99         PeakDivisor,
100 
101         /* Title formatted for display; input plugins do not need to set this
102            field */
103         FormattedTitle,
104 
105         /* TODO: reorder these at next ABI break! */
106         Description,   /* Track description */
107         MusicBrainzID, /* MusicBrainz identifier */
108         Channels, /* Track channels count */
109 
110         n_fields
111     };
112 
113     typedef aud::range<Field, Field(0), Field(n_fields - 1)> all_fields;
114 
115     enum ValueType
116     {
117         String,
118         Int,
119         Empty
120     };
121 
122     static Field field_by_name(const char * name);
123     static const char * field_get_name(Field field);
124     static ValueType field_get_type(Field field);
125 
Tuple()126     constexpr Tuple() : data(nullptr) {}
127 
128     ~Tuple();
129 
Tuple(Tuple && b)130     Tuple(Tuple && b) : data(b.data) { b.data = nullptr; }
131 
132     Tuple & operator=(Tuple && b)
133     {
134         return aud::move_assign(*this, std::move(b));
135     }
136 
137     bool operator==(const Tuple & b) const;
138     bool operator!=(const Tuple & b) const { return !operator==(b); }
139 
140     Tuple ref() const;
141 
142     /* Gets/sets the state of the song info.  Before setting the state to Valid,
143      * you should ensure that, at a minimum, set_filename() has been called. */
144     State state() const;
145     void set_state(State st);
146 
147     /* Returns the value type of a field if set, otherwise Empty. */
148     ValueType get_value_type(Field field) const;
149 
150     /* Convenience functions */
valid()151     bool valid() const { return state() == Valid; }
is_set(Field field)152     bool is_set(Field field) const { return get_value_type(field) != Empty; }
153 
154     /* Returns the integer value of a field if set, otherwise -1.  If you need
155      * to distinguish between a value of -1 and an unset value, use
156      * get_value_type(). */
157     int get_int(Field field) const;
158 
159     /* Returns the string value of a field if set, otherwise null. */
160     ::String get_str(Field field) const;
161 
162     /* Sets a field to the integer value <x>. */
163     void set_int(Field field, int x);
164 
165     /* Sets a field to the string value <str>.  If <str> is not valid UTF-8, it
166      * will be converted according to the user's character set detection rules.
167      * Equivalent to unset() if <str> is null. */
168     void set_str(Field field, const char * str);
169 
170     /* Clears any value that a field is currently set to. */
171     void unset(Field field);
172 
173     /* Parses the URI <filename> and sets Basename, Path, Suffix, and Subtune
174      * accordingly. */
175     void set_filename(const char * filename);
176 
177     /* Fills in format-related fields (specifically Codec, Quality,
178      * and Bitrate).  Plugins should use this function instead of setting
179      * these fields individually to allow a consistent style across file
180      * formats.  <format> should be a brief description such as "Ogg Vorbis",
181      * "MPEG-1 layer 3", "Audio CD", and so on.  <samplerate> is in Hertz.
182      * <bitrate> is in (decimal) kbps. */
183     void set_format(const char * format, int channels, int samplerate,
184                     int bitrate);
185 
186     /* In addition to the normal fields, tuples contain an integer array of
187      * subtune ID numbers.  This function sets that array.  It also sets
188      * NumSubtunes to the value <n_subtunes>. */
189     void set_subtunes(short n_subtunes, const short * subtunes);
190 
191     /* Returns the length of the subtune array.  If the array has not been set,
192      * returns zero.  Note that if NumSubtunes is changed after
193      * set_subtunes() is called, this function returns the value <n_subtunes>
194      * passed to set_subtunes(), not the value of NumSubtunes. */
195     short get_n_subtunes() const;
196 
197     /* Returns the <n>th member of the subtune array. */
198     short get_nth_subtune(short n) const;
199 
200     /* Sets a Replay Gain field pair from a decimal string. */
201     void set_gain(Field field, Field unit_field, const char * str);
202 
203     /* Returns true if minimal ReplayGainInfo is present. */
204     bool has_replay_gain() const;
205     /* Fills ReplayGainInfo struct from various fields. */
206     ReplayGainInfo get_replay_gain() const;
207 
208     /* Set various fields based on the ICY metadata of <stream>.  Returns true
209      * if any fields were changed. */
210     bool fetch_stream_info(VFSFile & stream);
211 
212     /* Guesses the song title, artist, and album, if not already set, from the
213      * filename. */
214     void generate_fallbacks();
215 
216     /* Guesses only the song title, if not already set, from the filename. */
217     void generate_title();
218 
219     /* Removes guesses made by generate_fallbacks().  This function should be
220      * called, for example, before writing a song tag from the tuple. */
221     void delete_fallbacks();
222 
223 private:
224     TupleData * data;
225 };
226 
227 /* somewhat out of place here */
228 struct PlaylistAddItem
229 {
230     String filename;
231     Tuple tuple;
232     PluginHandle * decoder;
233 
copyPlaylistAddItem234     PlaylistAddItem copy() const { return {filename, tuple.ref(), decoder}; }
235 };
236 
237 #endif /* LIBAUDCORE_TUPLE_H */
238