1 #ifndef BL_BLISS_H_
2 #define BL_BLISS_H_
3 
4 #include <stdio.h>
5 #include <libavformat/avformat.h>
6 #include <libavutil/md5.h>
7 
8 #ifndef M_PI
9 #define M_PI 3.14159265358979323846
10 #endif
11 
12 #define BL_VERSION 1.2
13 
14 #if LIBAVUTIL_VERSION_MAJOR < 54
15     #define av_frame_alloc avcodec_alloc_frame
16     #define av_frame_unref avcodec_get_frame_defaults
17     #define av_frame_free avcodec_free_frame
18 #endif
19 
20 #define BL_LOUD 0
21 #define BL_CALM 1
22 #define BL_UNKNOWN 2
23 #define BL_UNEXPECTED -2
24 #define BL_OK 0
25 
26 struct force_vector_s {
27     float tempo;
28     float amplitude;
29     float frequency;
30     float attack;
31 };
32 
33 
34 struct envelope_result_s {
35     float tempo;
36     float attack;
37 };
38 
39 struct thread_result_s {
40     struct bl_song const * const song;
41     float result;
42 };
43 
44 struct thread_envelope_result_s {
45     struct bl_song const * const song;
46     struct envelope_result_s * results;
47 };
48 
49 struct bl_song {
50     float force;
51     struct force_vector_s force_vector;
52     int8_t* sample_array;
53     int channels;
54     int nSamples;
55     int sample_rate;
56     int bitrate;
57     int nb_bytes_per_sample;
58     int calm_or_loud;
59     int resampled;
60     uint64_t duration;
61     char* filename;
62     char* artist;
63     char* title;
64     char* album;
65     char* tracknumber;
66     char* genre;
67 };
68 
69 
70 /**
71  * Run the analysis on the given song.
72  *
73  * @param[in] filename  is the filename of the song to analyze.
74  * @param[out] current_song  is the resulting `bl_song` structure after
75  * analysis.
76  *
77  * @return A value characterizing the song, whether calm, loud or
78  * error-specific.
79  */
80 int bl_analyze(char const * const filename,
81     struct bl_song * current_song);
82 
83 
84 /**
85  * Compute the distance between two songs stored in audio files.
86  *
87  * @remark Distance is computed using a standard euclidian distance between
88  * force vectors.
89  *
90  * @param[in] filename1  is the path to the first song to compare.
91  * @param[in] filename2  is the path to the second song to compare.
92  * @param[out] song1  is the resulting `bl_song` structure for the first song,
93  *                    after analysis.
94  * @param[out] song2  is the resulting `bl_song` structure for the second song,
95  *                    after analysis.
96  *
97  * @return The distance between the two songs stored in audio files.
98  */
99 float bl_distance_file(
100     char const * const filename1,
101     char const * const filename2,
102     struct bl_song * song1,
103     struct bl_song * song2);
104 
105 /**
106  * Compute the distance between two songs.
107  *
108  * @remark Distance is computed using a standard euclidian distance between
109  * force vectors.
110  *
111  * @param[in] v_song1  is the first song's force vector to compare.
112  * @param[in] v_song2  is the second song's force vector to compare.
113  *
114  * @return The distance between the two songs.
115  */
116 float bl_distance(
117     struct force_vector_s v_song1,
118     struct force_vector_s v_song2);
119 
120 
121 /**
122  * Compute the cosine similarity between two songs stored in audio files.
123  *
124  * @remark Returns a value between -1 and 1; -1 means songs are total opposites,
125  * 1 means that they are completely similar.
126  *
127  * @param[in] filename1  is the path to the first song to compare.
128  * @param[in] filename2  is the path to the second song to compare.
129  * @param[out] song1  is the resulting `bl_song` structure for the first song,
130  *                    after analysis.
131  * @param[out] song2  is the resulting `bl_song` structure for the second song,
132  *                    after analysis.
133  *
134  * @return The cosine similarity between the two songs stored in audio files.
135  */
136 float bl_cosine_similarity_file(
137     char const * const filename1,
138     char const * const filename2,
139     struct bl_song * song1,
140     struct bl_song * song2);
141 
142 
143 /**
144  * Compute the cosine similarity between two songs.
145  *
146  * @param[in] v_song1  is the first song's force vector to compare.
147  * @param[in] v_song2  is the second song's force vector to compare.
148  *
149  * @return The cosine similarity between the two songs.
150  */
151 float bl_cosine_similarity(
152     struct force_vector_s v_song1,
153     struct force_vector_s v_song2);
154 
155 
156 /**********************
157  * Specific analyzers *
158  **********************/
159 
160 /**
161  * Compute envelope-related characteristics: tempo and attack ratings.
162  *
163  * The tempo rating draws the envelope of the whole song, and then computes its
164  * DFT, obtaining peaks at the frequency of each dominant beat. The period of
165  * each dominant beat can then be deduced from the frequencies, hinting at the
166  * song's tempo.
167  *
168  * Warning: the tempo is not equal to the force of the song. As an example , a
169  * heavy metal track can have no steady beat at all, giving a very low tempo score
170  * while being very loud.
171  *
172  * The attack rating computes the difference between each value in the envelope
173  * and the next (its derivative).
174  * The final value is obtained by dividing the sum of the positive derivates by
175  * the number of samples, in order to avoid different results just because of
176  * the songs' length.
177  * As you have already guessed, a song with a lot of attacks also tends to wake
178  * humans up very quickly.
179  *
180  * @param[in]  song  the song to analyze.
181  * @param[out] result  an `envelope_result_s` structure to handle the resulting
182  * ratings.
183  */
184 void bl_envelope_sort(struct bl_song const * const song,
185     struct envelope_result_s * result);
186 
187 
188 /**
189  * Compute amplitude rating.
190  *
191  * The amplitude rating reprents the physical « force » of the song, that is,
192  * how much the speaker's membrane will move in order to create the sound.
193  * It is obtained by checking the shape of the histogram of the values of all
194  * the song's samples. The narrower the peak, the louder the song.
195  *
196  * @param[in]  song  the song to analyze.
197  *
198  * @return  the amplitude rating.
199  */
200 float bl_amplitude_sort(struct bl_song const * const song);
201 
202 
203 /**
204  * Compute frequency rating.
205  *
206  * The frequency rating is a ratio between high and low frequencies: a song
207  * with a lot of high-pitched sounds tends to wake humans up far more easily.
208  * This rating is obtained by performing a DFT over the sample array, and
209  * splitting the resulting array in 4 frequency bands: low, mid-low, mid,
210  * mid-high, and high. Using the value in dB for each band, the final formula
211  * corresponds to freq_result = high + mid-high + mid - (low + mid-low)
212  *
213  * @param[in] song  the song to analyze.
214  *
215  * @return  the frequency rating for this song.
216  */
217 float bl_frequency_sort(struct bl_song const * const song);
218 
219 
220 /***********
221  * Decoder *
222  ***********/
223 
224 /**
225  * Decode specified audio file.
226  *
227  * Decode the specified audio file with libAV and fill in the song structure.
228  *
229  * @param[in] filename  name of the file to decode and load.
230  * @param[out] song  the `bl_song` song structure to fill.
231  *
232  * @return `BL_OK` if everything went fine, `BL_UNEXPECTED` otherwise.
233  */
234 int bl_audio_decode(char const * const filename,
235     struct bl_song * const song);
236 
237 
238 /***********
239  * Helpers *
240  * *********/
241 
242 /**
243  * Free the dynamically allocated memory to store song data.
244  *
245  * @param song  a `bl_song` struct representing the song to free.
246  */
247 void bl_free_song(struct bl_song * const song);
248 
249 /**
250  * Display the current version number of bliss
251  *
252  * @return  The current version, as written in `BL_VERSION`
253  */
254 float bl_version(void);
255 
256 /**
257  * Initialize a bl_song by settings pointers to NULL so that it can be freed even
258  * if an analysis couldn't be performed.
259  *
260  * @param song  a `bl_song` struct representing the song to initialize
261  */
262 void bl_initialize_song(struct bl_song * const song);
263 
264 /**
265  * Compute the mean of a double array.
266  *
267  * @param[in] sample_array  an array of samples
268  * @param[in] nSamples  the array's size (in double)
269  */
270 int bl_mean(int16_t *sample_array, int nSamples);
271 
272 /**
273  * Compute the variance of a double array.
274  *
275  * @param[in] sample_array  an array of samples
276  * @param[in] nSamples  the array's size (in double)
277  */
278 int bl_variance(int16_t *sample_array, int nSamples, int mean);
279 
280 /**
281  * A rectangular filter that smoothes an array of samples
282  *
283  * @param[in] sample_array_in   an array of samples
284  * @param[in] nSamples  the array's size (in double)
285  * @param[in] smooth_width  smooth width, e.g. the m adjacents points to average
286  * @param[out] sample_array_out the filtered sample array
287  *
288  */
289 void bl_rectangular_filter(double *sample_array_out, double * sample_array_in,
290     int nSamples, int smooth_width);
291 #endif  // BL_BLISS_H_
292