1 /****************************************************************************************
2  * Copyright (c) 2010-2012 Leo Franchi <lfranchi@kde.org>                               *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 
18 #ifndef ECHONEST_SONG_H
19 #define ECHONEST_SONG_H
20 
21 #include "echonest_export.h"
22 #include "Track.h"
23 #include "TypeInformation.h"
24 
25 #include <QSharedData>
26 #include <QHash>
27 #include <QVariant>
28 #include <QDebug>
29 #include <QVector>
30 #include "Config.h"
31 
32 class QNetworkReply;
33 class SongData;
34 
35 namespace Echonest{
36 
37 class DynamicPlaylist; // forward declare for friend declaration
38 class Catalog;
39 class AudioSummary;
40 
41 /**
42  * This encapsulates an Echo Nest song---use it if you wish to get information about a song,
43  *   search for a song, etc.
44  *
45  * This class is implicitly shared.
46  */
47 class ECHONEST_EXPORT Song
48 {
49 
50 public:
51 
52   enum SearchParam {
53       Title,
54       Artist,
55       Combined,
56       Description,
57       ArtistId,
58       Start,
59       Results,
60       MaxTempo,
61       MinTempo,
62       MaxDanceability,
63       MinDanceability,
64       MaxComplexity,
65       MinComplexity,
66       MaxDuration,
67       MinDuration,
68       MaxLoudness,
69       MinLoudness,
70       MaxFamiliarity,
71       MinFamiliarity,
72       MaxHotttnesss,
73       MinHotttnesss,
74       MaxLongitude,
75       MinLongitude,
76       MaxEnergy,
77       MinEnergy,
78       Mode,
79       Key,
80       Sort,
81       SongType,
82       ArtistStartYearBefore,
83       ArtistStartYearAfter,
84       ArtistEndYearBefore,
85       ArtistEndYearAfter,
86       MaxAcousticness,
87       MinAcousticness,
88       MaxSpeechiness,
89       MinSpeechiness,
90       MaxLiveness,
91       MinLiveness,
92       MaxValence,
93       MinValence
94   };
95   typedef QPair< Echonest::Song::SearchParam, QVariant > SearchParamData;
96   typedef QVector< SearchParamData > SearchParams;
97 
98   enum IdentifyParam {
99       Code,
100       IdentifyArtist,
101       IdentifyTitle,
102       IdentifyRelease,
103       IdentifyDuration,
104       IdentifyGenre
105   };
106   typedef QPair< Echonest::Song::IdentifyParam, QVariant > IdentifyParamData;
107   typedef QVector< IdentifyParamData > IdentifyParams;
108 
109   Song();
110   Song( const QByteArray& id, const QString& title, const QByteArray& artistId, const QString& artistName );
111   Song( const QByteArray& id );
112   Song( const Song& other );
113   Song& operator=(const Song& song);
114   virtual ~Song();
115 
116   /**
117    * The following pieces of data are present in all Song objects, and do not require
118    *   on-demand fetching.
119    */
120   QByteArray id() const;
121   void setId( const QByteArray& id );
122 
123   QString title() const;
124   void setTitle( const QString& title );
125 
126   QString artistName() const;
127   void setArtistName( const QString& artistName );
128 
129   QByteArray artistId() const;
130   void setArtistId( const QByteArray& artistId );
131 
132   QString release() const;
133   void setRelease( const QString& release );
134 
135   /**
136    * The following require fetching from The Echo Nest, so call
137    *    fetchInformation() with the type of data you want first.
138    *
139    * If you ask for this information before calling parseInformation()
140    *  with the respective data, the result is undefined.
141    */
142 
143   /**
144    * The full audio summary and analysis of this song.
145    *
146    * NOTE: This will return a copy of the AudioSummary object, which
147    *       is implicitly shared. If you make modifications to the returned
148    *       summary, for example by calling parseFullAnalysis(), it will detach
149    *       and you will have to call setAudioSummary() to save the changes back
150    *       to this Song object.
151    */
152    AudioSummary audioSummary() const;
153    void setAudioSummary( const AudioSummary& summary );
154 
155   /**
156    * The associated Track objects with acoustic track information
157    */
158   QVector< Track > tracks() const;
159   void setTracks( const QVector< Track >& tracks );
160 
161   /**
162    * The "hotttnesss" metric of this song.
163    */
164   qreal hotttnesss() const;
165   void setHotttnesss( qreal hotttnesss );
166 
167   /**
168    * The "hotttnesss" metric of this song's artist.
169    */
170   qreal artistHotttnesss() const;
171   void setArtistHotttnesss( qreal artistHotttnesss );
172 
173   /**
174    * The familiarity metric of this song's artist.
175    */
176   qreal artistFamiliarity() const;
177   void setArtistFamiliarity( qreal artistFamiliarity );
178 
179   /**
180    * The location of this artist.
181    */
182   ArtistLocation artistLocation() const;
183   void setArtistLocation( const ArtistLocation& artistLocation );
184 
185   /**
186    * The type of the song (atm: christmas, studio, live)
187    */
188   QList< QString > songTypes() const;
189   void setSongTypes( const QList< QString >& songTypes );
190   void addSongType( const QString& songType );
191 
192   /**
193    *  This fetches the data from The Echo Nest for the requested data, so it
194    *   returns a QNetworkReply*. When the finished() signal is emitted
195    *   from the QNetworkReply object call parseInformation() to save the
196    *   data back to this Song object.
197    *
198    */
199   QNetworkReply* fetchInformation( SongInformation information = SongInformation() ) const;
200 
201   /**
202    * Search for a song from The Echo Nest with the given search parameters. See
203    *  http://developer.echonest.com/docs/v4/song.html#search for a description of the
204    *  parameters and data types.
205    *
206    * The result will contain the requested information from the SongInformation flags, and
207    *  can be extracted in the parseSearch() function.
208    *
209    */
210   static QNetworkReply* search( const SearchParams& params, SongInformation information = SongInformation()  );
211 
212   /**
213    * Identify a song from a given Echo Nest fingerprint hash code.
214    * NOTE: SongInformation is currently not parsed yet.
215    *
216    */
217   static QNetworkReply* identify( const IdentifyParams& params, const SongInformation& information = SongInformation() );
218 
219   /**
220    * Identify a song from the Echoprint hash code, this time using the output of the 'echoprint-codegen' command-line
221    * tool
222    */
223 //   static QNetworkReply* identify( const QByteArray& jsonData );
224 
225   /**
226    * Parses the reply of the identify call and returns a list of songs found.
227    *
228    */
229   static QVector< Song > parseIdentify( QNetworkReply* ) throw( ParseError );
230 
231   /**
232    * Parse the result of the fetchInformation() call.
233    * For each requested SongInformationFlag in the original request, the respective
234    *  data will be saved to this Song object.
235    */
236   void parseInformation( QNetworkReply* reply ) throw( ParseError );
237 
238   /**
239    * Parse the result of the search() call.
240    */
241   static QVector<Song> parseSearch( QNetworkReply* reply ) throw( ParseError );
242 
243   QString toString() const;
244 
245   friend class DynamicPlaylist;
246   friend class Catalog; // for access to searchParamToString
247 private:
248     static QByteArray searchParamToString( SearchParam param );
249     static QByteArray identifyParamToString( IdentifyParam param );
250     static void addQueryInformation( QUrl& url, SongInformation information );
251 
252   QSharedDataPointer<SongData> d;
253 };
254 
255 typedef QVector< Song > SongList;
256 
257 ECHONEST_EXPORT QDebug operator<<(QDebug d, const Song &song);
258 
259 } // namespace
260 
261 Q_DECLARE_METATYPE( Echonest::Song )
262 
263 #endif
264