Reformat all non-3rd-party C/C++/Objective-C++.

Command line:
find src ext -regex '.*\.\(h\|cpp\|mm\)' -exec clang-format -i
 -style='{BasedOnStyle: Google, DerivePointerBinding: false}' {} \;
This commit is contained in:
John Maguire 2014-02-07 16:34:20 +01:00
parent acfc7e6d21
commit bebd781fdf
803 changed files with 22699 additions and 22831 deletions

View File

@ -18,7 +18,6 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
#include <QCoreApplication>
#include <QStringList>

View File

@ -31,9 +31,7 @@ MediaPipeline::MediaPipeline(int port, quint64 length_msec)
pipeline_(nullptr),
appsrc_(nullptr),
byte_rate_(1),
offset_bytes_(0)
{
}
offset_bytes_(0) {}
MediaPipeline::~MediaPipeline() {
if (pipeline_) {
@ -43,8 +41,7 @@ MediaPipeline::~MediaPipeline() {
}
bool MediaPipeline::Init(int sample_rate, int channels) {
if (is_initialised())
return false;
if (is_initialised()) return false;
pipeline_ = gst_pipeline_new("pipeline");
@ -54,10 +51,21 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
tcpsink_ = gst_element_factory_make("tcpclientsink", nullptr);
if (!pipeline_ || !appsrc_ || !tcpsink_) {
if (pipeline_) { gst_object_unref(GST_OBJECT(pipeline_)); pipeline_ = nullptr; }
if (appsrc_) { gst_object_unref(GST_OBJECT(appsrc_)); appsrc_ = nullptr; }
if (gdppay) { gst_object_unref(GST_OBJECT(gdppay)); }
if (tcpsink_) { gst_object_unref(GST_OBJECT(tcpsink_)); tcpsink_ = nullptr; }
if (pipeline_) {
gst_object_unref(GST_OBJECT(pipeline_));
pipeline_ = nullptr;
}
if (appsrc_) {
gst_object_unref(GST_OBJECT(appsrc_));
appsrc_ = nullptr;
}
if (gdppay) {
gst_object_unref(GST_OBJECT(gdppay));
}
if (tcpsink_) {
gst_object_unref(GST_OBJECT(tcpsink_));
tcpsink_ = nullptr;
}
return false;
}
@ -73,7 +81,8 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
// Try to send 5 seconds of audio in advance to initially fill Clementine's
// buffer.
g_object_set(G_OBJECT(tcpsink_), "ts-offset", qint64(-5 * kNsecPerSec), nullptr);
g_object_set(G_OBJECT(tcpsink_), "ts-offset", qint64(-5 * kNsecPerSec),
nullptr);
// We know the time of each buffer
g_object_set(G_OBJECT(appsrc_), "format", GST_FORMAT_TIME, nullptr);
@ -97,13 +106,10 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
#endif
// Set caps
GstCaps* caps = gst_caps_new_simple("audio/x-raw-int",
"endianness", G_TYPE_INT, endianness,
"signed", G_TYPE_BOOLEAN, TRUE,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16,
"rate", G_TYPE_INT, sample_rate,
"channels", G_TYPE_INT, channels,
GstCaps* caps = gst_caps_new_simple(
"audio/x-raw-int", "endianness", G_TYPE_INT, endianness, "signed",
G_TYPE_BOOLEAN, TRUE, "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16,
"rate", G_TYPE_INT, sample_rate, "channels", G_TYPE_INT, channels,
nullptr);
gst_app_src_set_caps(appsrc_, caps);
@ -115,12 +121,12 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
gst_app_src_set_size(appsrc_, bytes);
// Ready to go
return gst_element_set_state(pipeline_, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE;
return gst_element_set_state(pipeline_, GST_STATE_PLAYING) !=
GST_STATE_CHANGE_FAILURE;
}
void MediaPipeline::WriteData(const char* data, qint64 length) {
if (!is_initialised())
return;
if (!is_initialised()) return;
GstBuffer* buffer = gst_buffer_new_and_alloc(length);
@ -137,8 +143,7 @@ void MediaPipeline::WriteData(const char* data, qint64 length) {
}
void MediaPipeline::EndStream() {
if (!is_initialised())
return;
if (!is_initialised()) return;
gst_app_src_end_of_stream(appsrc_);
}
@ -153,7 +158,8 @@ void MediaPipeline::EnoughDataCallback(GstAppSrc* src, void* data) {
me->accepting_data_ = false;
}
gboolean MediaPipeline::SeekDataCallback(GstAppSrc* src, guint64 offset, void * data) {
gboolean MediaPipeline::SeekDataCallback(GstAppSrc* src, guint64 offset,
void* data) {
// MediaPipeline* me = reinterpret_cast<MediaPipeline*>(data);
qLog(Debug) << "Gstreamer wants seek to" << offset;

View File

@ -31,7 +31,8 @@ namespace utilities {
QString GetCacheDirectory() {
QString user_cache = GetUserDataDirectory();
return user_cache + "/" + QCoreApplication::applicationName() + "/spotify-cache";
return user_cache + "/" + QCoreApplication::applicationName() +
"/spotify-cache";
}
#ifndef Q_OS_DARWIN // See spotify_utilities.mm for Mac implementation.
@ -47,7 +48,8 @@ QString GetSettingsDirectory() {
QString ret;
#ifdef Q_OS_WIN32
ret = GetUserDataDirectory() + "/" + QCoreApplication::applicationName() + "/spotify-settings";
ret = GetUserDataDirectory() + "/" + QCoreApplication::applicationName() +
"/spotify-settings";
#else
ret = QFileInfo(QSettings().fileName()).absolutePath() + "/spotify-settings";
#endif // Q_OS_WIN32

View File

@ -32,7 +32,6 @@ QString GetUserDataDirectory();
QString GetCacheDirectory();
QString GetSettingsDirectory();
}
#endif

View File

@ -10,10 +10,8 @@ QString GetUserDataDirectory() {
NSAutoreleasePool* pool = [NSAutoreleasePool alloc];
[pool init];
NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSCachesDirectory,
NSUserDomainMask,
YES);
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask, YES);
QString ret;
if ([paths count] > 0) {
NSString* user_path = [paths objectAtIndex:0];
@ -28,9 +26,7 @@ QString GetUserDataDirectory() {
QString GetSettingsDirectory() {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory,
NSUserDomainMask,
YES);
NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString* ret;
if ([paths count] > 0) {
ret = [paths objectAtIndex:0];
@ -40,8 +36,7 @@ QString GetSettingsDirectory() {
ret = [ret stringByAppendingString:@"/Clementine/spotify-settings"];
NSFileManager* file_manager = [NSFileManager defaultManager];
[file_manager createDirectoryAtPath:
ret
[file_manager createDirectoryAtPath:ret
withIntermediateDirectories:YES
attributes:nil
error:nil];
@ -50,5 +45,4 @@ QString GetSettingsDirectory() {
[pool drain];
return path;
}
}

View File

@ -36,7 +36,6 @@
const int SpotifyClient::kSpotifyImageIDSize = 20;
const int SpotifyClient::kWaveHeaderSize = 44;
SpotifyClient::SpotifyClient(QObject* parent)
: AbstractMessageHandler<pb::spotify::Message>(nullptr, parent),
api_key_(QByteArray::fromBase64(kSpotifyApiKey)),
@ -47,7 +46,8 @@ SpotifyClient::SpotifyClient(QObject* parent)
memset(&spotify_callbacks_, 0, sizeof(spotify_callbacks_));
memset(&spotify_config_, 0, sizeof(spotify_config_));
memset(&playlistcontainer_callbacks_, 0, sizeof(playlistcontainer_callbacks_));
memset(&playlistcontainer_callbacks_, 0,
sizeof(playlistcontainer_callbacks_));
memset(&get_playlists_callbacks_, 0, sizeof(get_playlists_callbacks_));
memset(&load_playlist_callbacks_, 0, sizeof(load_playlist_callbacks_));
@ -64,15 +64,17 @@ SpotifyClient::SpotifyClient(QObject* parent)
spotify_callbacks_.start_playback = &StartPlaybackCallback;
spotify_callbacks_.stop_playback = &StopPlaybackCallback;
playlistcontainer_callbacks_.container_loaded = &PlaylistContainerLoadedCallback;
playlistcontainer_callbacks_.container_loaded =
&PlaylistContainerLoadedCallback;
playlistcontainer_callbacks_.playlist_added = &PlaylistAddedCallback;
playlistcontainer_callbacks_.playlist_moved = &PlaylistMovedCallback;
playlistcontainer_callbacks_.playlist_removed = &PlaylistRemovedCallback;
get_playlists_callbacks_.playlist_state_changed = &PlaylistStateChangedForGetPlaylists;
get_playlists_callbacks_.playlist_state_changed =
&PlaylistStateChangedForGetPlaylists;
load_playlist_callbacks_.playlist_state_changed = &PlaylistStateChangedForLoadPlaylist;
load_playlist_callbacks_.playlist_state_changed =
&PlaylistStateChangedForLoadPlaylist;
QString cache = utilities::GetCacheDirectory();
qLog(Debug) << "Using:" << cache << "for Spotify cache";
@ -111,9 +113,11 @@ void SpotifyClient::Init(quint16 port) {
}
void SpotifyClient::LoggedInCallback(sp_session* session, sp_error error) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
const bool success = error == SP_ERROR_OK;
pb::spotify::LoginResponse_Error error_code = pb::spotify::LoginResponse_Error_Other;
pb::spotify::LoginResponse_Error error_code =
pb::spotify::LoginResponse_Error_Other;
if (!success) {
qLog(Warning) << "Failed to login" << sp_error_message(error);
@ -137,15 +141,15 @@ void SpotifyClient::LoggedInCallback(sp_session* session, sp_error error) {
me->SendLoginCompleted(success, sp_error_message(error), error_code);
if (success) {
sp_playlistcontainer_add_callbacks(
sp_session_playlistcontainer(session),
sp_playlistcontainer_add_callbacks(sp_session_playlistcontainer(session),
&me->playlistcontainer_callbacks_, me);
sp_session_flush_caches(me->session_);
}
}
void SpotifyClient::NotifyMainThreadCallback(sp_session* session) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
QMetaObject::invokeMethod(me, "ProcessEvents", Qt::QueuedConnection);
}
@ -160,14 +164,11 @@ void SpotifyClient::LogMessageCallback(sp_session* session, const char* data) {
}
void SpotifyClient::Search(const pb::spotify::SearchRequest& req) {
sp_search* search = sp_search_create(
session_, req.query().c_str(),
0, req.limit(),
0, req.limit_album(),
0, 0, // artists
sp_search* search =
sp_search_create(session_, req.query().c_str(), 0, req.limit(), 0,
req.limit_album(), 0, 0, // artists
0, 0, // playlists
SP_SEARCH_STANDARD,
&SearchCompleteCallback, this);
SP_SEARCH_STANDARD, &SearchCompleteCallback, this);
pending_searches_[search] = req;
}
@ -186,8 +187,8 @@ void SpotifyClient::SearchCompleteCallback(sp_search* result, void* userdata) {
if (count != 0) {
for (int i = 0; i < count; ++i) {
sp_album* album = sp_search_album(result, i);
sp_albumbrowse* browse =
sp_albumbrowse_create(me->session_, album, &SearchAlbumBrowseComplete, me);
sp_albumbrowse* browse = sp_albumbrowse_create(
me->session_, album, &SearchAlbumBrowseComplete, me);
me->pending_search_album_browse_responses_[browse] = result;
}
@ -197,7 +198,8 @@ void SpotifyClient::SearchCompleteCallback(sp_search* result, void* userdata) {
me->SendSearchResponse(result);
}
void SpotifyClient::SearchAlbumBrowseComplete(sp_albumbrowse* result, void* userdata) {
void SpotifyClient::SearchAlbumBrowseComplete(sp_albumbrowse* result,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
if (!me->pending_search_album_browse_responses_.contains(result)) {
@ -208,7 +210,8 @@ void SpotifyClient::SearchAlbumBrowseComplete(sp_albumbrowse* result, void* user
sp_search* search = me->pending_search_album_browse_responses_.take(result);
me->pending_search_album_browses_[search].append(result);
if (me->pending_search_album_browses_[search].count() >= sp_search_num_albums(search)) {
if (me->pending_search_album_browses_[search].count() >=
sp_search_num_albums(search)) {
me->SendSearchResponse(search);
}
}
@ -290,16 +293,23 @@ void SpotifyClient::MessageArrived(const pb::spotify::Message& message) {
}
}
void SpotifyClient::SetPlaybackSettings(const pb::spotify::PlaybackSettings& req) {
void SpotifyClient::SetPlaybackSettings(
const pb::spotify::PlaybackSettings& req) {
sp_bitrate bitrate = SP_BITRATE_320k;
switch (req.bitrate()) {
case pb::spotify::Bitrate96k: bitrate = SP_BITRATE_96k; break;
case pb::spotify::Bitrate160k: bitrate = SP_BITRATE_160k; break;
case pb::spotify::Bitrate320k: bitrate = SP_BITRATE_320k; break;
case pb::spotify::Bitrate96k:
bitrate = SP_BITRATE_96k;
break;
case pb::spotify::Bitrate160k:
bitrate = SP_BITRATE_160k;
break;
case pb::spotify::Bitrate320k:
bitrate = SP_BITRATE_320k;
break;
}
qLog(Debug) << "Setting playback settings: bitrate"
<< bitrate << "normalisation" << req.volume_normalisation();
qLog(Debug) << "Setting playback settings: bitrate" << bitrate
<< "normalisation" << req.volume_normalisation();
sp_session_preferred_bitrate(session_, bitrate);
sp_session_preferred_offline_bitrate(session_, bitrate, false);
@ -310,7 +320,8 @@ void SpotifyClient::Login(const pb::spotify::LoginRequest& req) {
sp_error error = sp_session_create(&spotify_config_, &session_);
if (error != SP_ERROR_OK) {
qLog(Warning) << "Failed to create session" << sp_error_message(error);
SendLoginCompleted(false, sp_error_message(error), pb::spotify::LoginResponse_Error_Other);
SendLoginCompleted(false, sp_error_message(error),
pb::spotify::LoginResponse_Error_Other);
return;
}
@ -324,15 +335,14 @@ void SpotifyClient::Login(const pb::spotify::LoginRequest& req) {
pb::spotify::LoginResponse_Error_ReloginFailed);
}
} else {
sp_session_login(session_,
req.username().c_str(),
req.password().c_str(),
sp_session_login(session_, req.username().c_str(), req.password().c_str(),
true, // Remember the password.
nullptr);
}
}
void SpotifyClient::SendLoginCompleted(bool success, const QString& error,
void SpotifyClient::SendLoginCompleted(
bool success, const QString& error,
pb::spotify::LoginResponse_Error error_code) {
pb::spotify::Message message;
@ -347,7 +357,8 @@ void SpotifyClient::SendLoginCompleted(bool success, const QString& error,
SendMessage(message);
}
void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc, void* userdata) {
void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
// Install callbacks on all the playlists
@ -360,7 +371,9 @@ void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc, vo
me->SendPlaylistList();
}
void SpotifyClient::PlaylistAddedCallback(sp_playlistcontainer* pc, sp_playlist* playlist, int position, void* userdata) {
void SpotifyClient::PlaylistAddedCallback(sp_playlistcontainer* pc,
sp_playlist* playlist, int position,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
// Install callbacks on this playlist
@ -369,12 +382,16 @@ void SpotifyClient::PlaylistAddedCallback(sp_playlistcontainer* pc, sp_playlist*
me->SendPlaylistList();
}
void SpotifyClient::PlaylistMovedCallback(sp_playlistcontainer* pc, sp_playlist* playlist, int position, int new_position, void* userdata) {
void SpotifyClient::PlaylistMovedCallback(sp_playlistcontainer* pc,
sp_playlist* playlist, int position,
int new_position, void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
me->SendPlaylistList();
}
void SpotifyClient::PlaylistRemovedCallback(sp_playlistcontainer* pc, sp_playlist* playlist, int position, void* userdata) {
void SpotifyClient::PlaylistRemovedCallback(sp_playlistcontainer* pc,
sp_playlist* playlist, int position,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
// Remove callbacks from this playlist
@ -400,7 +417,8 @@ void SpotifyClient::SendPlaylistList() {
sp_playlist* playlist = sp_playlistcontainer_playlist(container, i);
const bool is_loaded = sp_playlist_is_loaded(playlist);
qLog(Debug) << "Got playlist" << i << is_loaded << type << sp_playlist_name(playlist);
qLog(Debug) << "Got playlist" << i << is_loaded << type
<< sp_playlist_name(playlist);
if (!is_loaded) {
qLog(Info) << "Playlist is not loaded yet, waiting...";
@ -431,7 +449,8 @@ void SpotifyClient::SendPlaylistList() {
SendMessage(message);
}
sp_playlist* SpotifyClient::GetPlaylist(pb::spotify::PlaylistType type, int user_index) {
sp_playlist* SpotifyClient::GetPlaylist(pb::spotify::PlaylistType type,
int user_index) {
sp_playlist* playlist = nullptr;
switch (type) {
case pb::spotify::Inbox:
@ -446,7 +465,8 @@ sp_playlist* SpotifyClient::GetPlaylist(pb::spotify::PlaylistType type, int user
sp_playlistcontainer* pc = sp_session_playlistcontainer(session_);
if (pc && user_index <= sp_playlistcontainer_num_playlists(pc)) {
if (sp_playlistcontainer_playlist_type(pc, user_index) == SP_PLAYLIST_TYPE_PLAYLIST) {
if (sp_playlistcontainer_playlist_type(pc, user_index) ==
SP_PLAYLIST_TYPE_PLAYLIST) {
playlist = sp_playlistcontainer_playlist(pc, user_index);
sp_playlist_add_ref(playlist);
}
@ -469,26 +489,30 @@ void SpotifyClient::LoadPlaylist(const pb::spotify::LoadPlaylistRequest& req) {
qLog(Warning) << "Invalid playlist requested or not logged in";
pb::spotify::Message message;
pb::spotify::LoadPlaylistResponse* response = message.mutable_load_playlist_response();
pb::spotify::LoadPlaylistResponse* response =
message.mutable_load_playlist_response();
*response->mutable_request() = req;
SendMessage(message);
return;
}
sp_playlist_add_callbacks(pending_load.playlist_, &load_playlist_callbacks_, this);
sp_playlist_add_callbacks(pending_load.playlist_, &load_playlist_callbacks_,
this);
pending_load_playlists_ << pending_load;
PlaylistStateChangedForLoadPlaylist(pending_load.playlist_, this);
}
void SpotifyClient::SyncPlaylist(const pb::spotify::SyncPlaylistRequest& req) {
sp_playlist* playlist = GetPlaylist(req.request().type(), req.request().user_playlist_index());
sp_playlist* playlist =
GetPlaylist(req.request().type(), req.request().user_playlist_index());
// The playlist should already be loaded.
sp_playlist_set_offline_mode(session_, playlist, req.offline_sync());
}
void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* userdata) {
void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
// If the playlist isn't loaded yet we have to wait
@ -533,13 +557,13 @@ void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* u
// Everything is loaded so send the response protobuf and unref everything.
pb::spotify::Message message;
pb::spotify::LoadPlaylistResponse* response = message.mutable_load_playlist_response();
pb::spotify::LoadPlaylistResponse* response =
message.mutable_load_playlist_response();
// For some reason, we receive the starred tracks in reverse order but not
// other playlists.
if (pending_load->request_.type() == pb::spotify::Starred) {
std::reverse(pending_load->tracks_.begin(),
pending_load->tracks_.end());
std::reverse(pending_load->tracks_.begin(), pending_load->tracks_.end());
}
*response->mutable_request() = pending_load->request_;
@ -557,7 +581,8 @@ void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* u
me->pending_load_playlists_.removeAt(pending_load_index);
}
void SpotifyClient::PlaylistStateChangedForGetPlaylists(sp_playlist* pl, void* userdata) {
void SpotifyClient::PlaylistStateChangedForGetPlaylists(sp_playlist* pl,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
me->SendPlaylistList();
@ -576,9 +601,8 @@ void SpotifyClient::ConvertTrack(sp_track* track, pb::spotify::Track* pb) {
pb->set_track(sp_track_index(track));
// Album art
const QByteArray art_id(
reinterpret_cast<const char*>(
sp_album_cover(sp_track_album(track), SP_IMAGE_SIZE_LARGE)),
const QByteArray art_id(reinterpret_cast<const char*>(sp_album_cover(
sp_track_album(track), SP_IMAGE_SIZE_LARGE)),
kSpotifyImageIDSize);
const QString art_id_b64 = QString::fromAscii(art_id.toBase64());
pb->set_album_art_id(DataCommaSizeFromQString(art_id_b64));
@ -627,25 +651,29 @@ void SpotifyClient::ConvertAlbum(sp_album* album, pb::spotify::Track* pb) {
pb->set_uri(uri);
}
void SpotifyClient::ConvertAlbumBrowse(sp_albumbrowse* browse, pb::spotify::Track* pb) {
void SpotifyClient::ConvertAlbumBrowse(sp_albumbrowse* browse,
pb::spotify::Track* pb) {
pb->set_track(sp_albumbrowse_num_tracks(browse));
}
void SpotifyClient::MetadataUpdatedCallback(sp_session* session) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
foreach(const PendingLoadPlaylist & load, me->pending_load_playlists_) {
PlaylistStateChangedForLoadPlaylist(load.playlist_, me);
}
foreach (const PendingPlaybackRequest& playback, me->pending_playback_requests_) {
foreach(const PendingPlaybackRequest & playback,
me->pending_playback_requests_) {
me->TryPlaybackAgain(playback);
}
}
int SpotifyClient::MusicDeliveryCallback(
sp_session* session, const sp_audioformat* format,
int SpotifyClient::MusicDeliveryCallback(sp_session* session,
const sp_audioformat* format,
const void* frames, int num_frames) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
if (!me->media_pipeline_) {
return 0;
@ -668,21 +696,23 @@ int SpotifyClient::MusicDeliveryCallback(
return 0;
}
me->media_pipeline_->WriteData(
reinterpret_cast<const char*>(frames),
me->media_pipeline_->WriteData(reinterpret_cast<const char*>(frames),
num_frames * format->channels * 2);
return num_frames;
}
void SpotifyClient::EndOfTrackCallback(sp_session* session) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
me->media_pipeline_.reset();
}
void SpotifyClient::StreamingErrorCallback(sp_session* session, sp_error error) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
void SpotifyClient::StreamingErrorCallback(sp_session* session,
sp_error error) {
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
me->media_pipeline_.reset();
@ -690,11 +720,13 @@ void SpotifyClient::StreamingErrorCallback(sp_session* session, sp_error error)
me->SendPlaybackError(QString::fromUtf8(sp_error_message(error)));
}
void SpotifyClient::ConnectionErrorCallback(sp_session* session, sp_error error) {
void SpotifyClient::ConnectionErrorCallback(sp_session* session,
sp_error error) {
qLog(Debug) << Q_FUNC_INFO << sp_error_message(error);
}
void SpotifyClient::UserMessageCallback(sp_session* session, const char* message) {
void SpotifyClient::UserMessageCallback(sp_session* session,
const char* message) {
qLog(Debug) << Q_FUNC_INFO << message;
}
@ -707,7 +739,8 @@ void SpotifyClient::StopPlaybackCallback(sp_session* session) {
}
void SpotifyClient::OfflineStatusUpdatedCallback(sp_session* session) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
sp_playlistcontainer* container = sp_session_playlistcontainer(session);
if (!container) {
qLog(Warning) << "sp_session_playlistcontainer returned nullptr";
@ -717,7 +750,8 @@ void SpotifyClient::OfflineStatusUpdatedCallback(sp_session* session) {
const int count = sp_playlistcontainer_num_playlists(container);
for (int i = 0; i < count; ++i) {
const sp_playlist_type type = sp_playlistcontainer_playlist_type(container, i);
const sp_playlist_type type =
sp_playlistcontainer_playlist_type(container, i);
sp_playlist* playlist = sp_playlistcontainer_playlist(container, i);
if (type != SP_PLAYLIST_TYPE_PLAYLIST) {
@ -748,10 +782,11 @@ void SpotifyClient::OfflineStatusUpdatedCallback(sp_session* session) {
}
}
void SpotifyClient::SendDownloadProgress(
pb::spotify::PlaylistType type, int index, int download_progress) {
void SpotifyClient::SendDownloadProgress(pb::spotify::PlaylistType type,
int index, int download_progress) {
pb::spotify::Message message;
pb::spotify::SyncPlaylistProgress* progress = message.mutable_sync_playlist_progress();
pb::spotify::SyncPlaylistProgress* progress =
message.mutable_sync_playlist_progress();
progress->mutable_request()->set_type(type);
if (index != -1) {
progress->mutable_request()->set_user_playlist_index(index);
@ -864,8 +899,8 @@ void SpotifyClient::LoadImage(const QString& id_b64) {
PendingImageRequest pending_load;
pending_load.id_ = id;
pending_load.id_b64_ = id_b64;
pending_load.image_ = sp_image_create(session_,
reinterpret_cast<const byte*>(id.constData()));
pending_load.image_ =
sp_image_create(session_, reinterpret_cast<const byte*>(id.constData()));
pending_image_requests_ << pending_load;
if (!image_callbacks_registered_[pending_load.image_]) {
@ -948,16 +983,17 @@ void SpotifyClient::BrowseAlbum(const QString& uri) {
pending_album_browses_[browse] = uri;
}
void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result, void* userdata) {
void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
if (!me->pending_album_browses_.contains(result))
return;
if (!me->pending_album_browses_.contains(result)) return;
QString uri = me->pending_album_browses_.take(result);
pb::spotify::Message message;
pb::spotify::BrowseAlbumResponse* msg = message.mutable_browse_album_response();
pb::spotify::BrowseAlbumResponse* msg =
message.mutable_browse_album_response();
msg->set_uri(DataCommaSizeFromQString(uri));
@ -970,32 +1006,32 @@ void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result, void* userdata)
sp_albumbrowse_release(result);
}
void SpotifyClient::BrowseToplist(const pb::spotify::BrowseToplistRequest& req) {
void SpotifyClient::BrowseToplist(
const pb::spotify::BrowseToplistRequest& req) {
sp_toplistbrowse* browse = sp_toplistbrowse_create(
session_,
SP_TOPLIST_TYPE_TRACKS, // TODO: Support albums and artists.
session_, SP_TOPLIST_TYPE_TRACKS, // TODO: Support albums and artists.
SP_TOPLIST_REGION_EVERYWHERE, // TODO: Support other regions.
nullptr,
&ToplistBrowseComplete,
this);
nullptr, &ToplistBrowseComplete, this);
pending_toplist_browses_[browse] = req;
}
void SpotifyClient::ToplistBrowseComplete(sp_toplistbrowse* result, void* userdata) {
void SpotifyClient::ToplistBrowseComplete(sp_toplistbrowse* result,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
qLog(Debug) << "Toplist browse request took:"
<< sp_toplistbrowse_backend_request_duration(result)
<< "ms";
<< sp_toplistbrowse_backend_request_duration(result) << "ms";
if (!me->pending_toplist_browses_.contains(result)) {
return;
}
const pb::spotify::BrowseToplistRequest& request = me->pending_toplist_browses_.take(result);
const pb::spotify::BrowseToplistRequest& request =
me->pending_toplist_browses_.take(result);
pb::spotify::Message message;
pb::spotify::BrowseToplistResponse* msg = message.mutable_browse_toplist_response();
pb::spotify::BrowseToplistResponse* msg =
message.mutable_browse_toplist_response();
msg->mutable_request()->CopyFrom(request);
const int count = sp_toplistbrowse_num_tracks(result);

View File

@ -18,7 +18,6 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
#ifndef SPOTIFYCLIENT_H
#define SPOTIFYCLIENT_H
@ -64,49 +63,59 @@ private:
// Spotify session callbacks.
static void SP_CALLCONV LoggedInCallback(sp_session* session, sp_error error);
static void SP_CALLCONV NotifyMainThreadCallback(sp_session* session);
static void SP_CALLCONV LogMessageCallback(sp_session* session, const char* data);
static void SP_CALLCONV SearchCompleteCallback(sp_search* result, void* userdata);
static void SP_CALLCONV
LogMessageCallback(sp_session* session, const char* data);
static void SP_CALLCONV
SearchCompleteCallback(sp_search* result, void* userdata);
static void SP_CALLCONV MetadataUpdatedCallback(sp_session* session);
static int SP_CALLCONV MusicDeliveryCallback(
sp_session* session, const sp_audioformat* format,
static int SP_CALLCONV
MusicDeliveryCallback(sp_session* session, const sp_audioformat* format,
const void* frames, int num_frames);
static void SP_CALLCONV EndOfTrackCallback(sp_session* session);
static void SP_CALLCONV StreamingErrorCallback(sp_session* session, sp_error error);
static void SP_CALLCONV
StreamingErrorCallback(sp_session* session, sp_error error);
static void SP_CALLCONV OfflineStatusUpdatedCallback(sp_session* session);
static void SP_CALLCONV ConnectionErrorCallback(sp_session* session, sp_error error);
static void SP_CALLCONV UserMessageCallback(sp_session* session, const char* message);
static void SP_CALLCONV
ConnectionErrorCallback(sp_session* session, sp_error error);
static void SP_CALLCONV
UserMessageCallback(sp_session* session, const char* message);
static void SP_CALLCONV StartPlaybackCallback(sp_session* session);
static void SP_CALLCONV StopPlaybackCallback(sp_session* session);
// Spotify playlist container callbacks.
static void SP_CALLCONV PlaylistAddedCallback(
sp_playlistcontainer* pc, sp_playlist* playlist,
static void SP_CALLCONV PlaylistAddedCallback(sp_playlistcontainer* pc,
sp_playlist* playlist,
int position, void* userdata);
static void SP_CALLCONV PlaylistRemovedCallback(
sp_playlistcontainer* pc, sp_playlist* playlist,
static void SP_CALLCONV PlaylistRemovedCallback(sp_playlistcontainer* pc,
sp_playlist* playlist,
int position, void* userdata);
static void SP_CALLCONV PlaylistMovedCallback(
sp_playlistcontainer* pc, sp_playlist* playlist,
static void SP_CALLCONV
PlaylistMovedCallback(sp_playlistcontainer* pc, sp_playlist* playlist,
int position, int new_position, void* userdata);
static void SP_CALLCONV PlaylistContainerLoadedCallback(
sp_playlistcontainer* pc, void* userdata);
static void SP_CALLCONV
PlaylistContainerLoadedCallback(sp_playlistcontainer* pc, void* userdata);
// Spotify playlist callbacks - when loading the list of playlists
// initially
static void SP_CALLCONV PlaylistStateChangedForGetPlaylists(sp_playlist* pl, void* userdata);
static void SP_CALLCONV
PlaylistStateChangedForGetPlaylists(sp_playlist* pl, void* userdata);
// Spotify playlist callbacks - when loading a playlist
static void SP_CALLCONV PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* userdata);
static void SP_CALLCONV
PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* userdata);
// Spotify image callbacks.
static void SP_CALLCONV ImageLoaded(sp_image* image, void* userdata);
// Spotify album browse callbacks.
static void SP_CALLCONV SearchAlbumBrowseComplete(sp_albumbrowse* result, void* userdata);
static void SP_CALLCONV AlbumBrowseComplete(sp_albumbrowse* result, void* userdata);
static void SP_CALLCONV
SearchAlbumBrowseComplete(sp_albumbrowse* result, void* userdata);
static void SP_CALLCONV
AlbumBrowseComplete(sp_albumbrowse* result, void* userdata);
// Spotify toplist browse callbacks.
static void SP_CALLCONV ToplistBrowseComplete(sp_toplistbrowse* result, void* userdata);
static void SP_CALLCONV
ToplistBrowseComplete(sp_toplistbrowse* result, void* userdata);
// Request handlers.
void Login(const pb::spotify::LoginRequest& req);
@ -157,7 +166,8 @@ private:
void TryPlaybackAgain(const PendingPlaybackRequest& req);
void TryImageAgain(sp_image* image);
int GetDownloadProgress(sp_playlist* playlist);
void SendDownloadProgress(pb::spotify::PlaylistType type, int index, int download_progress);
void SendDownloadProgress(pb::spotify::PlaylistType type, int index,
int download_progress);
QByteArray api_key_;
@ -178,7 +188,8 @@ private:
QMap<sp_image*, int> image_callbacks_registered_;
QMap<sp_search*, pb::spotify::SearchRequest> pending_searches_;
QMap<sp_albumbrowse*, QString> pending_album_browses_;
QMap<sp_toplistbrowse*, pb::spotify::BrowseToplistRequest> pending_toplist_browses_;
QMap<sp_toplistbrowse*, pb::spotify::BrowseToplistRequest>
pending_toplist_browses_;
QMap<sp_search*, QList<sp_albumbrowse*> > pending_search_album_browses_;
QMap<sp_albumbrowse*, sp_search*> pending_search_album_browse_responses_;

View File

@ -18,16 +18,20 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
// The Spotify terms of service require that application keys are not
// accessible to third parties. Therefore this application key is heavily
// encrypted here in the source to prevent third parties from viewing it.
// It is most definitely not base64 encoded.
static const char* kSpotifyApiKey =
"AVlOrvJkKx8T+LEsCk+Kyl24I0MSsjohZAtMFzm2O5Lms1bmAWFWgdZaHkpypzSJPmSd+Wi50wwg"
"JwVCU0sq4Lep1zB4t6Z8h26NK6+z8gmkHVkV9DRPkRgebcUkWTDTflwVPKWF4+gdRjUwprsqBw6O"
"iofRLJzeKaxbmaUGqkSkxVLOiXC9lxylNq6ju7Q7uY8u8XkDUsVM3YIxiWy2+EM7I/lhatzT9xrq"
"rxHe2lg7CzOwF5kuFdwgmi8MQ72xTYXIKnNlOry/hJDlN9lKxkbUBLh+pzbYvO92S2fYKK5PAHvX"
"5+SmSBGbh6dlpHeCGqb8MPdaeZ5I1YxMcDkxa2+tbLA/Muat7gKA9u57TFCtYjun/u/i/ONwdBIQ"
"AVlOrvJkKx8T+LEsCk+Kyl24I0MSsjohZAtMFzm2O5Lms1bmAWFWgdZaHkpypzSJPmSd+"
"Wi50wwg"
"JwVCU0sq4Lep1zB4t6Z8h26NK6+z8gmkHVkV9DRPkRgebcUkWTDTflwVPKWF4+"
"gdRjUwprsqBw6O"
"iofRLJzeKaxbmaUGqkSkxVLOiXC9lxylNq6ju7Q7uY8u8XkDUsVM3YIxiWy2+EM7I/"
"lhatzT9xrq"
"rxHe2lg7CzOwF5kuFdwgmi8MQ72xTYXIKnNlOry/"
"hJDlN9lKxkbUBLh+pzbYvO92S2fYKK5PAHvX"
"5+SmSBGbh6dlpHeCGqb8MPdaeZ5I1YxMcDkxa2+tbLA/Muat7gKA9u57TFCtYjun/u/i/"
"ONwdBIQ"
"rePzXZjipO32kYmQAiCkN1p8sgQEcF43QxaVwXGo2X0rRnJf";

View File

@ -31,8 +31,10 @@ int main(int argc, char** argv) {
QStringList args(a.arguments());
if (args.count() != 2) {
std::cerr << "This program is used internally by Clementine to parse tags in music files\n"
"without exposing the whole application to crashes caused by malformed\n"
std::cerr << "This program is used internally by Clementine to parse tags "
"in music files\n"
"without exposing the whole application to crashes caused by "
"malformed\n"
"files. It is not meant to be run on its own.\n";
return 1;
}

View File

@ -24,11 +24,8 @@
#include <QTextCodec>
#include <QUrl>
TagReaderWorker::TagReaderWorker(QIODevice* socket, QObject* parent)
: AbstractMessageHandler<pb::tagreader::Message>(socket, parent)
{
}
: AbstractMessageHandler<pb::tagreader::Message>(socket, parent) {}
void TagReaderWorker::MessageArrived(const pb::tagreader::Message& message) {
pb::tagreader::Message reply;
@ -42,30 +39,33 @@ void TagReaderWorker::MessageArrived(const pb::tagreader::Message& message) {
#endif
if (message.has_read_file_request()) {
tag_reader_.ReadFile(QStringFromStdString(message.read_file_request().filename()),
tag_reader_.ReadFile(
QStringFromStdString(message.read_file_request().filename()),
reply.mutable_read_file_response()->mutable_metadata());
} else if (message.has_save_file_request()) {
reply.mutable_save_file_response()->set_success(
tag_reader_.SaveFile(QStringFromStdString(message.save_file_request().filename()),
reply.mutable_save_file_response()->set_success(tag_reader_.SaveFile(
QStringFromStdString(message.save_file_request().filename()),
message.save_file_request().metadata()));
} else if (message.has_save_song_statistics_to_file_request()) {
reply.mutable_save_song_statistics_to_file_response()->set_success(
tag_reader_.SaveSongStatisticsToFile(
QStringFromStdString(message.save_song_statistics_to_file_request().filename()),
QStringFromStdString(
message.save_song_statistics_to_file_request().filename()),
message.save_song_statistics_to_file_request().metadata()));
} else if (message.has_save_song_rating_to_file_request()) {
reply.mutable_save_song_rating_to_file_response()->set_success(
tag_reader_.SaveSongRatingToFile(
QStringFromStdString(message.save_song_rating_to_file_request().filename()),
QStringFromStdString(
message.save_song_rating_to_file_request().filename()),
message.save_song_rating_to_file_request().metadata()));
} else if (message.has_is_media_file_request()) {
reply.mutable_is_media_file_response()->set_success(
tag_reader_.IsMediaFile(QStringFromStdString(message.is_media_file_request().filename())));
reply.mutable_is_media_file_response()->set_success(tag_reader_.IsMediaFile(
QStringFromStdString(message.is_media_file_request().filename())));
} else if (message.has_load_embedded_art_request()) {
QByteArray data = tag_reader_.LoadEmbeddedArt(
QStringFromStdString(message.load_embedded_art_request().filename()));
reply.mutable_load_embedded_art_response()->set_data(
data.constData(), data.size());
reply.mutable_load_embedded_art_response()->set_data(data.constData(),
data.size());
} else if (message.has_read_cloud_file_request()) {
#ifdef HAVE_GOOGLE_DRIVE
const pb::tagreader::ReadCloudFileRequest& req =
@ -73,8 +73,7 @@ void TagReaderWorker::MessageArrived(const pb::tagreader::Message& message) {
if (!tag_reader_.ReadCloudFile(
QUrl::fromEncoded(QByteArray(req.download_url().data(),
req.download_url().size())),
QStringFromStdString(req.title()),
req.size(),
QStringFromStdString(req.title()), req.size(),
QStringFromStdString(req.mime_type()),
QStringFromStdString(req.authorisation_header()),
reply.mutable_read_cloud_file_response()->mutable_metadata())) {
@ -86,10 +85,8 @@ void TagReaderWorker::MessageArrived(const pb::tagreader::Message& message) {
SendReply(message, &reply);
}
void TagReaderWorker::DeviceClosed() {
AbstractMessageHandler<pb::tagreader::Message>::DeviceClosed();
qApp->exit();
}

View File

@ -23,32 +23,20 @@
namespace _detail {
ClosureBase::ClosureBase(ObjectHelper* helper)
: helper_(helper) {
}
ClosureBase::ClosureBase(ObjectHelper* helper) : helper_(helper) {}
ClosureBase::~ClosureBase() {
}
ClosureBase::~ClosureBase() {}
CallbackClosure::CallbackClosure(
QObject* sender,
const char* signal,
CallbackClosure::CallbackClosure(QObject* sender, const char* signal,
std::function<void()> callback)
: ClosureBase(new ObjectHelper(sender, signal, this)),
callback_(callback) {
}
callback_(callback) {}
void CallbackClosure::Invoke() {
callback_();
}
void CallbackClosure::Invoke() { callback_(); }
ObjectHelper* ClosureBase::helper() const {
return helper_;
}
ObjectHelper* ClosureBase::helper() const { return helper_; }
ObjectHelper::ObjectHelper(
QObject* sender,
const char* signal,
ObjectHelper::ObjectHelper(QObject* sender, const char* signal,
ClosureBase* closure)
: closure_(closure) {
connect(sender, signal, SLOT(Invoked()));
@ -64,12 +52,9 @@ void Unpack(QList<QGenericArgument>*) {}
} // namespace _detail
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal,
std::function<void()> callback) {
return new _detail::CallbackClosure(
sender, signal, callback);
return new _detail::CallbackClosure(sender, signal, callback);
}
void DoAfter(QObject* receiver, const char* slot, int msec) {

View File

@ -52,10 +52,7 @@ class ClosureBase {
class ObjectHelper : public QObject {
Q_OBJECT
public:
ObjectHelper(
QObject* parent,
const char* signal,
ClosureBase* closure);
ObjectHelper(QObject* parent, const char* signal, ClosureBase* closure);
private slots:
void Invoked();
@ -76,7 +73,8 @@ void Unpack(QList<QGenericArgument>* list, const Arg& arg) {
}
template <typename Head, typename... Tail>
void Unpack(QList<QGenericArgument>* list, const Head& head, const Tail&... tail) {
void Unpack(QList<QGenericArgument>* list, const Head& head,
const Tail&... tail) {
Unpack(list, head);
Unpack(list, tail...);
}
@ -84,12 +82,8 @@ void Unpack(QList<QGenericArgument>* list, const Head& head, const Tail&... tail
template <typename... Args>
class Closure : public ClosureBase {
public:
Closure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
const Args&... args)
Closure(QObject* sender, const char* signal, QObject* receiver,
const char* slot, const Args&... args)
: ClosureBase(new ObjectHelper(sender, signal, this)),
// std::bind is the easiest way to store an argument list.
function_(std::bind(&Closure<Args...>::Call, this, args...)),
@ -99,20 +93,18 @@ class Closure : public ClosureBase {
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
Q_ASSERT(index != -1);
slot_ = meta_receiver->method(index);
QObject::connect(receiver_, SIGNAL(destroyed()), helper_, SLOT(deleteLater()));
QObject::connect(receiver_, SIGNAL(destroyed()), helper_,
SLOT(deleteLater()));
}
virtual void Invoke() {
function_();
}
virtual void Invoke() { function_(); }
private:
void Call(const Args&... args) {
QList<QGenericArgument> arg_list;
Unpack(&arg_list, args...);
slot_.invoke(
receiver_,
slot_.invoke(receiver_,
arg_list.size() > 0 ? arg_list[0] : QGenericArgument(),
arg_list.size() > 1 ? arg_list[1] : QGenericArgument(),
arg_list.size() > 2 ? arg_list[2] : QGenericArgument(),
@ -133,20 +125,10 @@ class Closure : public ClosureBase {
template <typename T, typename... Args>
class SharedClosure : public Closure<Args...> {
public:
SharedClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot,
const Args&... args)
: Closure<Args...>(
sender.data(),
signal,
receiver,
slot,
args...),
data_(sender) {
}
SharedClosure(QSharedPointer<T> sender, const char* signal, QObject* receiver,
const char* slot, const Args&... args)
: Closure<Args...>(sender.data(), signal, receiver, slot, args...),
data_(sender) {}
private:
QSharedPointer<T> data_;
@ -154,9 +136,7 @@ class SharedClosure : public Closure<Args...> {
class CallbackClosure : public ClosureBase {
public:
CallbackClosure(
QObject* sender,
const char* signal,
CallbackClosure(QObject* sender, const char* signal,
std::function<void()> callback);
virtual void Invoke();
@ -168,61 +148,45 @@ class CallbackClosure : public ClosureBase {
} // namespace _detail
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal,
QObject* receiver, const char* slot,
const Args&... args) {
return new _detail::Closure<Args...>(
sender, signal, receiver, slot, args...);
return new _detail::Closure<Args...>(sender, signal, receiver, slot, args...);
}
// QSharedPointer variant
template <typename T, typename... Args>
_detail::ClosureBase* NewClosure(
QSharedPointer<T> sender,
const char* signal,
QObject* receiver,
const char* slot,
_detail::ClosureBase* NewClosure(QSharedPointer<T> sender, const char* signal,
QObject* receiver, const char* slot,
const Args&... args) {
return new _detail::SharedClosure<T, Args...>(
sender, signal, receiver, slot, args...);
return new _detail::SharedClosure<T, Args...>(sender, signal, receiver, slot,
args...);
}
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal,
std::function<void()> callback);
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal,
std::function<void(Args...)> callback,
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, args...));
}
template <typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal,
void (*callback)(Args...),
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, args...));
}
template <typename T, typename Unused, typename... Args>
_detail::ClosureBase* NewClosure(
QObject* sender,
const char* signal,
_detail::ClosureBase* NewClosure(QObject* sender, const char* signal,
T* receiver, Unused (T::*callback)(Args...),
const Args&... args) {
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
}
void DoAfter(QObject* receiver, const char* slot, int msec);
void DoInAMinuteOrSo(QObject* receiver, const char* slot);

View File

@ -41,13 +41,13 @@
ThreadFunctor object and start it.
*/
/*
Base abstract classes ThreadFunctorBase and ThreadFunctor (for void and
non-void result):
*/
template <typename ReturnType>
class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable {
class ThreadFunctorBase : public QFutureInterface<ReturnType>,
public QRunnable {
public:
ThreadFunctorBase() {}
@ -68,10 +68,8 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
template <typename ReturnType, typename... Args>
class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
public:
ThreadFunctor(std::function<ReturnType (Args...)> function,
Args... args)
: function_(std::bind(function, args...)) {
}
ThreadFunctor(std::function<ReturnType(Args...)> function, Args... args)
: function_(std::bind(function, args...)) {}
virtual void run() {
this->reportResult(function_());
@ -86,10 +84,8 @@ class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
template <typename... Args>
class ThreadFunctor<void, Args...> : public ThreadFunctorBase<void> {
public:
ThreadFunctor(std::function<void (Args...)> function,
Args... args)
: function_(std::bind(function, args...)) {
}
ThreadFunctor(std::function<void(Args...)> function, Args... args)
: function_(std::bind(function, args...)) {}
virtual void run() {
function_();
@ -100,7 +96,6 @@ class ThreadFunctor <void, Args...> : public ThreadFunctorBase<void> {
std::function<void()> function_;
};
/*
Run functions
*/
@ -108,30 +103,25 @@ namespace ConcurrentRun {
// Empty argument form.
template <typename ReturnType>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
QFuture<ReturnType> Run(QThreadPool* threadpool,
std::function<ReturnType()> function) {
return (new ThreadFunctor<ReturnType>(function))->Start(threadpool);
}
// Function object with arguments form.
template <typename ReturnType, typename... Args>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
QFuture<ReturnType> Run(QThreadPool* threadpool,
std::function<ReturnType(Args...)> function,
const Args&... args) {
return (new ThreadFunctor<ReturnType, Args...>(
function, args...))->Start(threadpool);
return (new ThreadFunctor<ReturnType, Args...>(function, args...))
->Start(threadpool);
}
// Support passing C function pointers instead of function objects.
template <typename ReturnType, typename... Args>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
ReturnType (*function) (Args...),
const Args&... args) {
return Run(
threadpool, std::function<ReturnType (Args...)>(function), args...);
QFuture<ReturnType> Run(QThreadPool* threadpool,
ReturnType (*function)(Args...), const Args&... args) {
return Run(threadpool, std::function<ReturnType(Args...)>(function), args...);
}
}

View File

@ -33,7 +33,6 @@
#include "logging.h"
namespace logging {
static Level sDefaultLevel = Level_Debug;
@ -46,18 +45,25 @@ static const char* kMessageHandlerMagic = "__logging_message__";
static const int kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);
static QtMsgHandler sOriginalMessageHandler = nullptr;
void GLog(const char* domain, int level, const char* message, void* user_data) {
switch (level) {
case G_LOG_FLAG_RECURSION:
case G_LOG_FLAG_FATAL:
case G_LOG_LEVEL_ERROR:
case G_LOG_LEVEL_CRITICAL: qLog(Error) << message; break;
case G_LOG_LEVEL_WARNING: qLog(Warning) << message; break;
case G_LOG_LEVEL_CRITICAL:
qLog(Error) << message;
break;
case G_LOG_LEVEL_WARNING:
qLog(Warning) << message;
break;
case G_LOG_LEVEL_MESSAGE:
case G_LOG_LEVEL_INFO: qLog(Info) << message; break;
case G_LOG_LEVEL_INFO:
qLog(Info) << message;
break;
case G_LOG_LEVEL_DEBUG:
default: qLog(Debug) << message; break;
default:
qLog(Debug) << message;
break;
}
}
@ -70,10 +76,16 @@ static void MessageHandler(QtMsgType type, const char* message) {
Level level = Level_Debug;
switch (type) {
case QtFatalMsg:
case QtCriticalMsg: level = Level_Error; break;
case QtWarningMsg: level = Level_Warning; break;
case QtCriticalMsg:
level = Level_Error;
break;
case QtWarningMsg:
level = Level_Warning;
break;
case QtDebugMsg:
default: level = Level_Debug; break;
default:
level = Level_Debug;
break;
}
foreach(const QString & line, QString::fromLocal8Bit(message).split('\n')) {
@ -85,7 +97,6 @@ static void MessageHandler(QtMsgType type, const char* message) {
}
}
void Init() {
delete sClassLevels;
delete sNullDevice;
@ -100,8 +111,7 @@ void Init() {
}
void SetLevels(const QString& levels) {
if (!sClassLevels)
return;
if (!sClassLevels) return;
foreach(const QString & item, levels.split(',')) {
const QStringList class_level = item.split(':');
@ -154,11 +164,21 @@ QDebug CreateLogger(Level level, const QString& class_name, int line) {
// Map the level to a string
const char* level_name = nullptr;
switch (level) {
case Level_Debug: level_name = " DEBUG "; break;
case Level_Info: level_name = " INFO "; break;
case Level_Warning: level_name = " WARN "; break;
case Level_Error: level_name = " ERROR "; break;
case Level_Fatal: level_name = " FATAL "; break;
case Level_Debug:
level_name = " DEBUG ";
break;
case Level_Info:
level_name = " INFO ";
break;
case Level_Warning:
level_name = " WARN ";
break;
case Level_Error:
level_name = " ERROR ";
break;
case Level_Fatal:
level_name = " FATAL ";
break;
}
// Check the settings to see if we're meant to show or hide this message.
@ -182,9 +202,11 @@ QDebug CreateLogger(Level level, const QString& class_name, int line) {
}
QDebug ret(type);
ret.nospace() << kMessageHandlerMagic
<< QDateTime::currentDateTime().toString("hh:mm:ss.zzz").toAscii().constData()
<< level_name << function_line.leftJustified(32).toAscii().constData();
ret.nospace() << kMessageHandlerMagic << QDateTime::currentDateTime()
.toString("hh:mm:ss.zzz")
.toAscii()
.constData() << level_name
<< function_line.leftJustified(32).toAscii().constData();
return ret.space();
}
@ -192,10 +214,7 @@ QDebug CreateLogger(Level level, const QString& class_name, int line) {
QString CXXDemangle(const QString& mangled_function) {
int status;
char* demangled_function = abi::__cxa_demangle(
mangled_function.toAscii().constData(),
nullptr,
nullptr,
&status);
mangled_function.toAscii().constData(), nullptr, nullptr, &status);
if (status == 0) {
QString ret = QString::fromAscii(demangled_function);
free(demangled_function);
@ -232,8 +251,10 @@ QString DemangleSymbol(const QString& symbol) {
void DumpStackTrace() {
#ifdef Q_OS_UNIX
void* callstack[128];
int callstack_size = backtrace(reinterpret_cast<void**>(&callstack), sizeof(callstack));
char** symbols = backtrace_symbols(reinterpret_cast<void**>(&callstack), callstack_size);
int callstack_size =
backtrace(reinterpret_cast<void**>(&callstack), sizeof(callstack));
char** symbols =
backtrace_symbols(reinterpret_cast<void**>(&callstack), callstack_size);
// Start from 1 to skip ourself.
for (int i = 1; i < callstack_size; ++i) {
qLog(Debug) << DemangleSymbol(QString::fromAscii(symbols[i]));

View File

@ -18,18 +18,19 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
#ifndef LOGGING_H
#define LOGGING_H
#include <QDebug>
#ifdef QT_NO_DEBUG_STREAM
# define qLog(level) while (false) QNoDebug()
#define qLog(level) \
while (false) QNoDebug()
#else
#define qLog(level) \
logging::CreateLogger(logging::Level_##level, \
logging::ParsePrettyFunction(__PRETTY_FUNCTION__), __LINE__)
logging::ParsePrettyFunction(__PRETTY_FUNCTION__), \
__LINE__)
#endif
namespace logging {

View File

@ -18,7 +18,6 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
#include "messagehandler.h"
#include "core/logging.h"

View File

@ -18,7 +18,6 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
#ifndef MESSAGEHANDLER_H
#define MESSAGEHANDLER_H
@ -37,11 +36,8 @@ class QAbstractSocket;
class QIODevice;
class QLocalSocket;
#define QStringFromStdString(x) \
QString::fromUtf8(x.data(), x.size())
#define DataCommaSizeFromQString(x) \
x.toUtf8().constData(), x.toUtf8().length()
#define QStringFromStdString(x) QString::fromUtf8(x.data(), x.size())
#define DataCommaSizeFromQString(x) x.toUtf8().constData(), x.toUtf8().length()
// Reads and writes uint32 length encoded protobufs to a socket.
// This base QObject is separate from AbstractMessageHandler because moc can't
@ -83,7 +79,6 @@ protected:
bool is_device_closed_;
};
// Reads and writes uint32 length encoded MessageType messages to a socket.
// You should subclass this and implement the MessageArrived(MessageType)
// method.
@ -125,13 +120,10 @@ private:
QMap<int, ReplyType*> pending_replies_;
};
template <typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(
QIODevice* device, QObject* parent)
: _MessageHandlerBase(device, parent)
{
}
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice* device,
QObject* parent)
: _MessageHandlerBase(device, parent) {}
template <typename MT>
void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
@ -144,7 +136,8 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
template <typename MT>
void AbstractMessageHandler<MT>::SendMessageAsync(const MessageType& message) {
std::string data = message.SerializeAsString();
metaObject()->invokeMethod(this, "WriteMessage", Qt::QueuedConnection,
metaObject()->invokeMethod(
this, "WriteMessage", Qt::QueuedConnection,
Q_ARG(QByteArray, QByteArray(data.data(), data.size())));
}
@ -182,12 +175,8 @@ bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
template <typename MT>
void AbstractMessageHandler<MT>::AbortAll() {
foreach (ReplyType* reply, pending_replies_) {
reply->Abort();
}
foreach(ReplyType * reply, pending_replies_) { reply->Abort(); }
pending_replies_.clear();
}
#endif // MESSAGEHANDLER_H

View File

@ -18,11 +18,7 @@
#include "messagereply.h"
_MessageReplyBase::_MessageReplyBase(QObject* parent)
: QObject(parent),
finished_(false),
success_(false)
{
}
: QObject(parent), finished_(false), success_(false) {}
bool _MessageReplyBase::WaitForFinished() {
qLog(Debug) << "Waiting on ID" << id();

View File

@ -53,7 +53,6 @@ protected:
QSemaphore semaphore_;
};
// A reply future class that is returned immediately for requests that will
// occur in the background. Similar to QNetworkReply.
template <typename MessageType>
@ -72,12 +71,10 @@ private:
MessageType reply_message_;
};
template <typename MessageType>
MessageReply<MessageType>::MessageReply(const MessageType& request_message,
QObject* parent)
: _MessageReplyBase(parent)
{
: _MessageReplyBase(parent) {
request_message_.MergeFrom(request_message);
}

View File

@ -18,7 +18,6 @@
// it is used by the Spotify blob which links against libspotify and is not GPL
// compatible.
#ifndef OVERRIDE_H
#define OVERRIDE_H

View File

@ -17,9 +17,4 @@
#include "workerpool.h"
_WorkerPoolBase::_WorkerPoolBase(QObject* parent)
: QObject(parent)
{
}
_WorkerPoolBase::_WorkerPoolBase(QObject* parent) : QObject(parent) {}

View File

@ -32,7 +32,6 @@
#include "core/closure.h"
#include "core/logging.h"
// Base class containing signals and slots - required because moc doesn't do
// templated objects.
class _WorkerPoolBase : public QObject {
@ -53,7 +52,6 @@ protected slots:
virtual void SendQueuedMessages() {}
};
// Manages a pool of one or more external processes. A local socket server is
// started for each process, and the address is passed to the process as
// argv[1]. The process is expected to connect back to the socket server, and
@ -100,7 +98,10 @@ protected:
private:
struct Worker {
Worker() : local_server_(NULL), local_socket_(NULL), process_(NULL),
Worker()
: local_server_(NULL),
local_socket_(NULL),
process_(NULL),
handler_(NULL) {}
QLocalServer* local_server_;
@ -155,26 +156,21 @@ private:
QQueue<ReplyType*> message_queue_;
};
template <typename HandlerType>
WorkerPool<HandlerType>::WorkerPool(QObject* parent)
: _WorkerPoolBase(parent),
next_worker_(0),
next_id_(0)
{
: _WorkerPoolBase(parent), next_worker_(0), next_id_(0) {
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 2);
local_server_name_ = qApp->applicationName().toLower();
if (local_server_name_.isEmpty())
local_server_name_ = "workerpool";
if (local_server_name_.isEmpty()) local_server_name_ = "workerpool";
}
template <typename HandlerType>
WorkerPool<HandlerType>::~WorkerPool() {
foreach(const Worker & worker, workers_) {
if (worker.local_socket_ && worker.process_) {
disconnect(worker.process_, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(ProcessError(QProcess::ProcessError)));
disconnect(worker.process_, SIGNAL(error(QProcess::ProcessError)), this,
SLOT(ProcessError(QProcess::ProcessError)));
// The worker is connected. Close his socket and wait for him to exit.
qLog(Debug) << "Closing worker socket";
@ -192,9 +188,7 @@ WorkerPool<HandlerType>::~WorkerPool() {
}
}
foreach (ReplyType* reply, message_queue_) {
reply->Abort();
}
foreach(ReplyType * reply, message_queue_) { reply->Abort(); }
}
template <typename HandlerType>
@ -204,13 +198,15 @@ void WorkerPool<HandlerType>::SetWorkerCount(int count) {
}
template <typename HandlerType>
void WorkerPool<HandlerType>::SetLocalServerName(const QString& local_server_name) {
void WorkerPool<HandlerType>::SetLocalServerName(
const QString& local_server_name) {
Q_ASSERT(workers_.isEmpty());
local_server_name_ = local_server_name;
}
template <typename HandlerType>
void WorkerPool<HandlerType>::SetExecutableName(const QString& executable_name) {
void WorkerPool<HandlerType>::SetExecutableName(
const QString& executable_name) {
Q_ASSERT(workers_.isEmpty());
executable_name_ = executable_name;
}
@ -264,14 +260,16 @@ void WorkerPool<HandlerType>::StartOneWorker(Worker* worker) {
worker->local_server_ = new QLocalServer(this);
worker->process_ = new QProcess(this);
connect(worker->local_server_, SIGNAL(newConnection()), SLOT(NewConnection()));
connect(worker->local_server_, SIGNAL(newConnection()),
SLOT(NewConnection()));
connect(worker->process_, SIGNAL(error(QProcess::ProcessError)),
SLOT(ProcessError(QProcess::ProcessError)));
// Create a server, find an unused name and start listening
forever {
const int unique_number = qrand() ^ ((int)(quint64(this) & 0xFFFFFFFF));
const QString name = QString("%1_%2").arg(local_server_name_).arg(unique_number);
const QString name =
QString("%1_%2").arg(local_server_name_).arg(unique_number);
if (worker->local_server_->listen(name)) {
break;
@ -284,7 +282,8 @@ void WorkerPool<HandlerType>::StartOneWorker(Worker* worker) {
// Start the process
worker->process_->setProcessChannelMode(QProcess::ForwardedChannels);
worker->process_->start(executable_path_,
QStringList() << worker->local_server_->fullServerName());
QStringList()
<< worker->local_server_->fullServerName());
}
template <typename HandlerType>
@ -295,10 +294,10 @@ void WorkerPool<HandlerType>::NewConnection() {
// Find the worker with this server.
Worker* worker = FindWorker(&Worker::local_server_, server);
if (!worker)
return;
if (!worker) return;
qLog(Debug) << "Worker" << worker << "connected to" << server->fullServerName();
qLog(Debug) << "Worker" << worker << "connected to"
<< server->fullServerName();
// Accept the connection.
worker->local_socket_ = server->nextPendingConnection();
@ -322,8 +321,7 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
// Find the worker with this process.
Worker* worker = FindWorker(&Worker::process_, process);
if (!worker)
return;
if (!worker) return;
switch (error) {
case QProcess::FailedToStart:
@ -336,15 +334,16 @@ void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
default:
// On any other error we just restart the process.
qLog(Debug) << "Worker" << worker << "failed with error" << error << "- restarting";
qLog(Debug) << "Worker" << worker << "failed with error" << error
<< "- restarting";
StartOneWorker(worker);
break;
}
}
template <typename HandlerType>
typename WorkerPool<HandlerType>::ReplyType*
WorkerPool<HandlerType>::NewReply(MessageType* message) {
typename WorkerPool<HandlerType>::ReplyType* WorkerPool<HandlerType>::NewReply(
MessageType* message) {
const int id = next_id_.fetchAndAddOrdered(1);
message->set_id(id);

View File

@ -32,9 +32,9 @@ namespace {
static const int kTaglibSuffixCacheBytes = 8 * 1024;
}
CloudStream::CloudStream(
const QUrl& url, const QString& filename, const long length,
const QString& auth, QNetworkAccessManager* network)
CloudStream::CloudStream(const QUrl& url, const QString& filename,
const long length, const QString& auth,
QNetworkAccessManager* network)
: url_(url),
filename_(filename),
encoded_filename_(filename_.toUtf8()),
@ -43,12 +43,9 @@ CloudStream::CloudStream(
cursor_(0),
network_(network),
cache_(length),
num_requests_(0) {
}
num_requests_(0) {}
TagLib::FileName CloudStream::name() const {
return encoded_filename_.data();
}
TagLib::FileName CloudStream::name() const { return encoded_filename_.data(); }
bool CloudStream::CheckCache(int start, int end) {
for (int i = start; i <= end; ++i) {
@ -113,8 +110,8 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) {
if (!auth_.isEmpty()) {
request.setRawHeader("Authorization", auth_.toUtf8());
}
request.setRawHeader(
"Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8());
request.setRawHeader("Range",
QString("bytes=%1-%2").arg(start).arg(end).toUtf8());
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::AlwaysNetwork);
// The Ubuntu One server applies the byte range to the gzipped data, rather
@ -124,7 +121,8 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) {
}
QNetworkReply* reply = network_->get(request);
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(SSLErrors(QList<QSslError>)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
SLOT(SSLErrors(QList<QSslError>)));
++num_requests_;
QEventLoop loop;
@ -163,9 +161,7 @@ bool CloudStream::readOnly() const {
return true;
}
bool CloudStream::isOpen() const {
return true;
}
bool CloudStream::isOpen() const { return true; }
void CloudStream::seek(long offset, TagLib::IOStream::Position p) {
switch (p) {
@ -184,17 +180,11 @@ void CloudStream::seek(long offset, TagLib::IOStream::Position p) {
}
}
void CloudStream::clear() {
cursor_ = 0;
}
void CloudStream::clear() { cursor_ = 0; }
long CloudStream::tell() const {
return cursor_;
}
long CloudStream::tell() const { return cursor_; }
long CloudStream::length() {
return length_;
}
long CloudStream::length() { return length_; }
void CloudStream::truncate(long) {
qLog(Debug) << Q_FUNC_INFO << "not implemented";

View File

@ -31,11 +31,8 @@ class QNetworkAccessManager;
class CloudStream : public QObject, public TagLib::IOStream {
Q_OBJECT
public:
CloudStream(const QUrl& url,
const QString& filename,
const long length,
const QString& auth,
QNetworkAccessManager* network);
CloudStream(const QUrl& url, const QString& filename, const long length,
const QString& auth, QNetworkAccessManager* network);
// Taglib::IOStream
virtual TagLib::FileName name() const;
@ -55,9 +52,7 @@ class CloudStream : public QObject, public TagLib::IOStream {
return cache_.num_nonempty();
}
int num_requests() const {
return num_requests_;
}
int num_requests() const { return num_requests_; }
// Use educated guess to request the bytes that TagLib will probably want.
void Precache();

View File

@ -25,8 +25,9 @@
using std::placeholders::_1;
using std::placeholders::_2;
FMPSParser::FMPSParser() :
// The float regex ends with (?:$|(?=::|;;)) to ensure it matches all the way
FMPSParser::FMPSParser()
: // The float regex ends with (?:$|(?=::|;;)) to ensure it matches all the
// way
// up to the end of the value. Without it, it would match a string that
// starts with a number, like "123abc".
float_re_("\\s*([+-]?\\d+(?:\\.\\d+)?)\\s*(?:$|(?=::|;;))"),
@ -35,9 +36,7 @@ FMPSParser::FMPSParser() :
string_re_("((?:[^\\\\;:]|(?:\\\\[\\\\:;]))+)(?:$|(?=::|;;))"),
// Used for replacing escaped characters.
escape_re_("\\\\([\\\\:;])")
{
}
escape_re_("\\\\([\\\\:;])") {}
// Parses a list of things (of type T) that are separated by two consecutive
// Separator characters. Each individual thing is parsed by the F function.
@ -59,16 +58,16 @@ static int ParseContainer(const QStringRef& data, F f, QList<T>* ret) {
int pos = 0;
while (pos < data.length()) {
const int len = data.length() - pos;
int matched_len = f(QStringRef(data.string(), data.position() + pos, len), &value);
if (matched_len == -1 || matched_len > len)
break;
int matched_len =
f(QStringRef(data.string(), data.position() + pos, len), &value);
if (matched_len == -1 || matched_len > len) break;
ret->append(value);
pos += matched_len;
// Expect two separators in a row
if (pos + 2 <= data.length() && data.at(pos) == Separator
&& data.at(pos+1) == Separator) {
if (pos + 2 <= data.length() && data.at(pos) == Separator &&
data.at(pos + 1) == Separator) {
pos += 2;
} else {
break;

View File

@ -59,7 +59,8 @@
#include "core/timeconstants.h"
// Taglib added support for FLAC pictures in 1.7.0
#if (TAGLIB_MAJOR_VERSION > 1) || (TAGLIB_MAJOR_VERSION == 1 && TAGLIB_MINOR_VERSION >= 7)
#if (TAGLIB_MAJOR_VERSION > 1) || \
(TAGLIB_MAJOR_VERSION == 1 && TAGLIB_MINOR_VERSION >= 7)
#define TAGLIB_HAS_FLAC_PICTURELIST
#endif
@ -67,7 +68,8 @@
#include "cloudstream.h"
#endif
#define NumberToASFAttribute(x) TagLib::ASF::Attribute(QStringToTaglibString(QString::number(x)))
#define NumberToASFAttribute(x) \
TagLib::ASF::Attribute(QStringToTaglibString(QString::number(x)))
class FileRefFactory {
public:
@ -95,18 +97,19 @@ TagLib::String StdStringToTaglibString(const std::string& s) {
TagLib::String QStringToTaglibString(const QString& s) {
return TagLib::String(s.toUtf8().constData(), TagLib::String::UTF8);
}
}
const char* TagReader::kMP4_FMPS_Rating_ID = "----:com.apple.iTunes:FMPS_Rating";
const char* TagReader::kMP4_FMPS_Playcount_ID = "----:com.apple.iTunes:FMPS_Playcount";
const char* TagReader::kMP4_FMPS_Score_ID = "----:com.apple.iTunes:FMPS_Rating_Amarok_Score";
const char* TagReader::kMP4_FMPS_Rating_ID =
"----:com.apple.iTunes:FMPS_Rating";
const char* TagReader::kMP4_FMPS_Playcount_ID =
"----:com.apple.iTunes:FMPS_Playcount";
const char* TagReader::kMP4_FMPS_Score_ID =
"----:com.apple.iTunes:FMPS_Rating_Amarok_Score";
TagReader::TagReader()
: factory_(new TagLibFileRefFactory),
network_(new QNetworkAccessManager),
kEmbeddedCover("(embedded)")
{}
kEmbeddedCover("(embedded)") {}
void TagReader::ReadFile(const QString& filename,
pb::tagreader::SongMetadata* song) const {
@ -141,14 +144,17 @@ void TagReader::ReadFile(const QString& filename,
QString disc;
QString compilation;
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same
// way;
// apart, so we keep specific behavior for some formats by adding another
// "else if" block below.
if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
if (TagLib::Ogg::XiphComment* tag =
dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
ParseOggTag(tag->fieldListMap(), nullptr, &disc, &compilation, song);
}
if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (TagLib::MPEG::File* file =
dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (file->ID3v2Tag()) {
const TagLib::ID3v2::FrameListMap& map = file->ID3v2Tag()->frameListMap();
@ -156,24 +162,29 @@ void TagReader::ReadFile(const QString& filename,
disc = TStringToQString(map["TPOS"].front()->toString()).trimmed();
if (!map["TBPM"].isEmpty())
song->set_bpm(TStringToQString(map["TBPM"].front()->toString()).trimmed().toFloat());
song->set_bpm(TStringToQString(map["TBPM"].front()->toString())
.trimmed()
.toFloat());
if (!map["TCOM"].isEmpty())
Decode(map["TCOM"].front()->toString(), nullptr, song->mutable_composer());
Decode(map["TCOM"].front()->toString(), nullptr,
song->mutable_composer());
if (!map["TIT1"].isEmpty()) // content group
Decode(map["TIT1"].front()->toString(), nullptr, song->mutable_grouping());
Decode(map["TIT1"].front()->toString(), nullptr,
song->mutable_grouping());
// Skip TPE1 (which is the artist) here because we already fetched it
if (!map["TPE2"].isEmpty()) // non-standard: Apple, Microsoft
Decode(map["TPE2"].front()->toString(), nullptr, song->mutable_albumartist());
Decode(map["TPE2"].front()->toString(), nullptr,
song->mutable_albumartist());
if (!map["TCMP"].isEmpty())
compilation = TStringToQString(map["TCMP"].front()->toString()).trimmed();
compilation =
TStringToQString(map["TCMP"].front()->toString()).trimmed();
if (!map["APIC"].isEmpty())
song->set_art_automatic(kEmbeddedCover);
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
// Find a suitable comment tag. For now we ignore iTunNORM comments.
for (int i = 0; i < map["COMM"].size(); ++i) {
@ -189,12 +200,12 @@ void TagReader::ReadFile(const QString& filename,
// Parse FMPS frames
for (int i = 0; i < map["TXXX"].size(); ++i) {
const TagLib::ID3v2::UserTextIdentificationFrame* frame =
dynamic_cast<const TagLib::ID3v2::UserTextIdentificationFrame*>(map["TXXX"][i]);
dynamic_cast<const TagLib::ID3v2::UserTextIdentificationFrame*>(
map["TXXX"][i]);
if (frame && frame->description().startsWith("FMPS_")) {
ParseFMPSFrame(TStringToQString(frame->description()),
TStringToQString(frame->fieldList()[1]),
song);
TStringToQString(frame->fieldList()[1]), song);
}
}
@ -203,7 +214,8 @@ void TagReader::ReadFile(const QString& filename,
// will consider POPM tags iff song has no rating/playcount already set.
if (!map["POPM"].isEmpty()) {
const TagLib::ID3v2::PopularimeterFrame* frame =
dynamic_cast<const TagLib::ID3v2::PopularimeterFrame*>(map["POPM"].front());
dynamic_cast<const TagLib::ID3v2::PopularimeterFrame*>(
map["POPM"].front());
if (frame) {
// Take a user rating only if there's no rating already set
if (song->rating() <= 0 && frame->rating() > 0) {
@ -214,11 +226,12 @@ void TagReader::ReadFile(const QString& filename,
}
}
}
}
} else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
} else if (TagLib::FLAC::File* file =
dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
if (file->xiphComment()) {
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song);
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc,
&compilation, song);
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
if (!file->pictureList().isEmpty()) {
song->set_art_automatic(kEmbeddedCover);
@ -226,7 +239,8 @@ void TagReader::ReadFile(const QString& filename,
#endif
}
Decode(tag->comment(), nullptr, song->mutable_comment());
} else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
} else if (TagLib::MP4::File* file =
dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
if (file->tag()) {
TagLib::MP4::Tag* mp4_tag = file->tag();
const TagLib::MP4::ItemListMap& items = mp4_tag->itemListMap();
@ -246,51 +260,67 @@ void TagReader::ReadFile(const QString& filename,
}
if (items.contains("disk")) {
disc = TStringToQString(TagLib::String::number(items["disk"].toIntPair().first));
disc = TStringToQString(
TagLib::String::number(items["disk"].toIntPair().first));
}
if (items.contains(kMP4_FMPS_Rating_ID)) {
float rating = TStringToQString(items[kMP4_FMPS_Rating_ID].toStringList().toString('\n')).toFloat();
float rating =
TStringToQString(items[kMP4_FMPS_Rating_ID].toStringList().toString(
'\n')).toFloat();
if (song->rating() <= 0 && rating > 0) {
song->set_rating(rating);
}
}
if (items.contains(kMP4_FMPS_Playcount_ID)) {
int playcount = TStringToQString(items[kMP4_FMPS_Playcount_ID].toStringList().toString('\n')).toFloat();
int playcount =
TStringToQString(
items[kMP4_FMPS_Playcount_ID].toStringList().toString('\n'))
.toFloat();
if (song->playcount() <= 0 && playcount > 0) {
song->set_playcount(playcount);
}
}
if (items.contains(kMP4_FMPS_Playcount_ID)) {
int score = TStringToQString(items[kMP4_FMPS_Score_ID].toStringList().toString('\n')).toFloat() * 100;
int score = TStringToQString(
items[kMP4_FMPS_Score_ID].toStringList().toString('\n'))
.toFloat() *
100;
if (song->score() <= 0 && score > 0) {
song->set_score(score);
}
}
if (items.contains("\251wrt")) {
Decode(items["\251wrt"].toStringList().toString(", "), nullptr, song->mutable_composer());
Decode(items["\251wrt"].toStringList().toString(", "), nullptr,
song->mutable_composer());
}
if (items.contains("\251grp")) {
Decode(items["\251grp"].toStringList().toString(" "), nullptr, song->mutable_grouping());
Decode(items["\251grp"].toStringList().toString(" "), nullptr,
song->mutable_grouping());
}
Decode(mp4_tag->comment(), nullptr, song->mutable_comment());
}
}
#ifdef TAGLIB_WITH_ASF
else if (TagLib::ASF::File* file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
const TagLib::ASF::AttributeListMap& attributes_map = file->tag()->attributeListMap();
else if (TagLib::ASF::File* file =
dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
const TagLib::ASF::AttributeListMap& attributes_map =
file->tag()->attributeListMap();
if (attributes_map.contains("FMPS/Rating")) {
const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating"];
const TagLib::ASF::AttributeList& attributes =
attributes_map["FMPS/Rating"];
if (!attributes.isEmpty()) {
float rating = TStringToQString(attributes.front().toString()).toFloat();
float rating =
TStringToQString(attributes.front().toString()).toFloat();
if (song->rating() <= 0 && rating > 0) {
song->set_rating(rating);
}
}
}
if (attributes_map.contains("FMPS/Playcount")) {
const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Playcount"];
const TagLib::ASF::AttributeList& attributes =
attributes_map["FMPS/Playcount"];
if (!attributes.isEmpty()) {
int playcount = TStringToQString(attributes.front().toString()).toInt();
if (song->playcount() <= 0 && playcount > 0) {
@ -299,9 +329,11 @@ void TagReader::ReadFile(const QString& filename,
}
}
if (attributes_map.contains("FMPS/Rating_Amarok_Score")) {
const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating_Amarok_Score"];
const TagLib::ASF::AttributeList& attributes =
attributes_map["FMPS/Rating_Amarok_Score"];
if (!attributes.isEmpty()) {
int score = TStringToQString(attributes.front().toString()).toFloat() * 100;
int score =
TStringToQString(attributes.front().toString()).toFloat() * 100;
if (song->score() <= 0 && score > 0) {
song->set_score(score);
}
@ -316,7 +348,8 @@ void TagReader::ReadFile(const QString& filename,
if (!disc.isEmpty()) {
const int i = disc.indexOf('/');
if (i != -1) {
// disc.right( i ).toInt() is total number of discs, we don't use this at the moment
// disc.right( i ).toInt() is total number of discs, we don't use this at
// the moment
song->set_disc(disc.left(i).toInt());
} else {
song->set_disc(disc.toInt());
@ -335,14 +368,18 @@ void TagReader::ReadFile(const QString& filename,
if (fileref->audioProperties()) {
song->set_bitrate(fileref->audioProperties()->bitrate());
song->set_samplerate(fileref->audioProperties()->sampleRate());
song->set_length_nanosec(fileref->audioProperties()->length() * kNsecPerSec);
song->set_length_nanosec(fileref->audioProperties()->length() *
kNsecPerSec);
}
// Get the filetype if we can
song->set_type(GuessFileType(fileref.get()));
// Set integer fields to -1 if they're not valid
#define SetDefault(field) if (song->field() <= 0) { song->set_##field(-1); }
#define SetDefault(field) \
if (song->field() <= 0) { \
song->set_##field(-1); \
}
SetDefault(track);
SetDefault(disc);
SetDefault(bpm);
@ -353,13 +390,13 @@ void TagReader::ReadFile(const QString& filename,
#undef SetDefault
}
void TagReader::Decode(const TagLib::String& tag, const QTextCodec* codec,
std::string* output) {
QString tmp;
if (codec && tag.isLatin1()) { // Never override UTF-8.
const std::string fixed = QString::fromUtf8(tag.toCString(true)).toStdString();
const std::string fixed =
QString::fromUtf8(tag.toCString(true)).toStdString();
tmp = codec->toUnicode(fixed.c_str()).trimmed();
} else {
tmp = TStringToQString(tag).trimmed();
@ -382,8 +419,7 @@ void TagReader::ParseFMPSFrame(const QString& name, const QString& value,
pb::tagreader::SongMetadata* song) const {
qLog(Debug) << "Parsing FMPSFrame" << name << ", " << value;
FMPSParser parser;
if (!parser.Parse(value) || parser.is_empty())
return;
if (!parser.Parse(value) || parser.is_empty()) return;
QVariant var;
if (name == "FMPS_Rating") {
@ -421,8 +457,8 @@ void TagReader::ParseFMPSFrame(const QString& name, const QString& value,
}
void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map,
const QTextCodec* codec,
QString* disc, QString* compilation,
const QTextCodec* codec, QString* disc,
QString* compilation,
pb::tagreader::SongMetadata* song) const {
if (!map["COMPOSER"].isEmpty())
Decode(map["COMPOSER"].front(), codec, song->mutable_composer());
@ -446,43 +482,67 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map,
if (!map["COMPILATION"].isEmpty())
*compilation = TStringToQString(map["COMPILATION"].front()).trimmed();
if (!map["COVERART"].isEmpty())
song->set_art_automatic(kEmbeddedCover);
if (!map["COVERART"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
if (!map["METADATA_BLOCK_PICTURE"].isEmpty())
song->set_art_automatic(kEmbeddedCover);
if (!map["FMPS_RATING"].isEmpty() && song->rating() <= 0)
song->set_rating(TStringToQString( map["FMPS_RATING"].front() ).trimmed().toFloat());
song->set_rating(
TStringToQString(map["FMPS_RATING"].front()).trimmed().toFloat());
if (!map["FMPS_PLAYCOUNT"].isEmpty() && song->playcount() <= 0)
song->set_playcount(TStringToQString( map["FMPS_PLAYCOUNT"].front() ).trimmed().toFloat());
song->set_playcount(
TStringToQString(map["FMPS_PLAYCOUNT"].front()).trimmed().toFloat());
if (!map["FMPS_RATING_AMAROK_SCORE"].isEmpty() && song->score() <= 0)
song->set_score(TStringToQString( map["FMPS_RATING_AMAROK_SCORE"].front() ).trimmed().toFloat() * 100);
song->set_score(TStringToQString(map["FMPS_RATING_AMAROK_SCORE"].front())
.trimmed()
.toFloat() *
100);
}
void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const {
const pb::tagreader::SongMetadata& song)
const {
vorbis_comments->addField("COMPOSER", StdStringToTaglibString(song.composer()), true);
vorbis_comments->addField("PERFORMER", StdStringToTaglibString(song.performer()), true);
vorbis_comments->addField("CONTENT GROUP", StdStringToTaglibString(song.grouping()), true);
vorbis_comments->addField("BPM", QStringToTaglibString(song.bpm() <= 0 -1 ? QString() : QString::number(song.bpm())), true);
vorbis_comments->addField("DISCNUMBER", QStringToTaglibString(song.disc() <= 0 -1 ? QString() : QString::number(song.disc())), true);
vorbis_comments->addField("COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"), true);
vorbis_comments->addField("COMPOSER",
StdStringToTaglibString(song.composer()), true);
vorbis_comments->addField("PERFORMER",
StdStringToTaglibString(song.performer()), true);
vorbis_comments->addField("CONTENT GROUP",
StdStringToTaglibString(song.grouping()), true);
vorbis_comments->addField(
"BPM", QStringToTaglibString(
song.bpm() <= 0 - 1 ? QString() : QString::number(song.bpm())),
true);
vorbis_comments->addField(
"DISCNUMBER",
QStringToTaglibString(
song.disc() <= 0 - 1 ? QString() : QString::number(song.disc())),
true);
vorbis_comments->addField(
"COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"),
true);
}
void TagReader::SetFMPSStatisticsVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
void TagReader::SetFMPSStatisticsVorbisComments(
TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const {
vorbis_comments->addField("FMPS_PLAYCOUNT", QStringToTaglibString(QString::number(song.playcount())));
vorbis_comments->addField("FMPS_RATING_AMAROK_SCORE", QStringToTaglibString(QString::number(song.score() / 100.0)));
vorbis_comments->addField(
"FMPS_PLAYCOUNT",
QStringToTaglibString(QString::number(song.playcount())));
vorbis_comments->addField(
"FMPS_RATING_AMAROK_SCORE",
QStringToTaglibString(QString::number(song.score() / 100.0)));
}
void TagReader::SetFMPSRatingVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
void TagReader::SetFMPSRatingVorbisComments(
TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const {
vorbis_comments->addField("FMPS_RATING", QStringToTaglibString(QString::number(song.rating())));
vorbis_comments->addField(
"FMPS_RATING", QStringToTaglibString(QString::number(song.rating())));
}
pb::tagreader::SongMetadata_Type TagReader::GuessFileType(
@ -523,8 +583,7 @@ pb::tagreader::SongMetadata_Type TagReader::GuessFileType(
bool TagReader::SaveFile(const QString& filename,
const pb::tagreader::SongMetadata& song) const {
if (filename.isNull())
return false;
if (filename.isNull()) return false;
qLog(Debug) << "Saving tags to" << filename;
@ -541,32 +600,44 @@ bool TagReader::SaveFile(const QString& filename,
fileref->tag()->setYear(song.year());
fileref->tag()->setTrack(song.track());
if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (TagLib::MPEG::File* file =
dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true);
SetTextFrame("TPOS", song.disc() <= 0 -1 ? QString() : QString::number(song.disc()), tag);
SetTextFrame("TBPM", song.bpm() <= 0 -1 ? QString() : QString::number(song.bpm()), tag);
SetTextFrame(
"TPOS", song.disc() <= 0 - 1 ? QString() : QString::number(song.disc()),
tag);
SetTextFrame("TBPM",
song.bpm() <= 0 - 1 ? QString() : QString::number(song.bpm()),
tag);
SetTextFrame("TCOM", song.composer(), tag);
SetTextFrame("TIT1", song.grouping(), tag);
// Skip TPE1 (which is the artist) here because we already set it
SetTextFrame("TPE2", song.albumartist(), tag);
SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag);
} else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
} else if (TagLib::FLAC::File* file =
dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
TagLib::Ogg::XiphComment* tag = file->xiphComment();
SetVorbisComments(tag, song);
} else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
} else if (TagLib::MP4::File* file =
dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
TagLib::MP4::Tag* tag = file->tag();
tag->itemListMap()["disk"] = TagLib::MP4::Item(song.disc() <= 0 -1 ? 0 : song.disc(), 0);
tag->itemListMap()["tmpo"] = TagLib::StringList(song.bpm() <= 0 -1 ? "0" : TagLib::String::number(song.bpm()));
tag->itemListMap()["disk"] =
TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0);
tag->itemListMap()["tmpo"] = TagLib::StringList(
song.bpm() <= 0 - 1 ? "0" : TagLib::String::number(song.bpm()));
tag->itemListMap()["\251wrt"] = TagLib::StringList(song.composer());
tag->itemListMap()["\251grp"] = TagLib::StringList(song.grouping());
tag->itemListMap()["aART"] = TagLib::StringList(song.albumartist());
tag->itemListMap()["cpil"] = TagLib::StringList(song.compilation() ? "1" : "0");
tag->itemListMap()["cpil"] =
TagLib::StringList(song.compilation() ? "1" : "0");
}
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same
// way;
// apart, so we keep specific behavior for some formats by adding another
// "else if" block above.
if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
if (TagLib::Ogg::XiphComment* tag =
dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
SetVorbisComments(tag, song);
}
@ -582,10 +653,9 @@ bool TagReader::SaveFile(const QString& filename,
return ret;
}
bool TagReader::SaveSongStatisticsToFile(const QString& filename,
const pb::tagreader::SongMetadata& song) const {
if (filename.isNull())
return false;
bool TagReader::SaveSongStatisticsToFile(
const QString& filename, const pb::tagreader::SongMetadata& song) const {
if (filename.isNull()) return false;
qLog(Debug) << "Saving song statistics tags to" << filename;
@ -594,34 +664,44 @@ bool TagReader::SaveSongStatisticsToFile(const QString& filename,
if (!fileref || fileref->isNull()) // The file probably doesn't exist
return false;
if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (TagLib::MPEG::File* file =
dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true);
// Save as FMPS
SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag);
SetUserTextFrame("FMPS_Rating_Amarok_Score", QString::number(song.score() / 100.0), tag);
SetUserTextFrame("FMPS_Rating_Amarok_Score",
QString::number(song.score() / 100.0), tag);
// Also save as POPM
TagLib::ID3v2::PopularimeterFrame* frame = GetPOPMFrameFromTag(tag);
frame->setCounter(song.playcount());
} else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
} else if (TagLib::FLAC::File* file =
dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
TagLib::Ogg::XiphComment* vorbis_comments = file->xiphComment(true);
SetFMPSStatisticsVorbisComments(vorbis_comments, song);
} else if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
} else if (TagLib::Ogg::XiphComment* tag =
dynamic_cast<TagLib::Ogg::XiphComment*>(
fileref->file()->tag())) {
SetFMPSStatisticsVorbisComments(tag, song);
}
#ifdef TAGLIB_WITH_ASF
else if (TagLib::ASF::File* file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
else if (TagLib::ASF::File* file =
dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
TagLib::ASF::Tag* tag = file->tag();
tag->addAttribute("FMPS/Playcount", NumberToASFAttribute(song.playcount()));
tag->addAttribute("FMPS/Rating_Amarok_Score", NumberToASFAttribute(song.score() / 100.0));
tag->addAttribute("FMPS/Rating_Amarok_Score",
NumberToASFAttribute(song.score() / 100.0));
}
#endif
else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
else if (TagLib::MP4::File* file =
dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
TagLib::MP4::Tag* tag = file->tag();
tag->itemListMap()[kMP4_FMPS_Score_ID] = TagLib::StringList(QStringToTaglibString(QString::number(song.score() / 100.0)));
tag->itemListMap()[kMP4_FMPS_Playcount_ID] = TagLib::StringList(TagLib::String::number(song.playcount()));
tag->itemListMap()[kMP4_FMPS_Score_ID] = TagLib::StringList(
QStringToTaglibString(QString::number(song.score() / 100.0)));
tag->itemListMap()[kMP4_FMPS_Playcount_ID] =
TagLib::StringList(TagLib::String::number(song.playcount()));
} else {
// Nothing to save: stop now
return true;
@ -638,10 +718,9 @@ bool TagReader::SaveSongStatisticsToFile(const QString& filename,
return ret;
}
bool TagReader::SaveSongRatingToFile(const QString& filename,
const pb::tagreader::SongMetadata& song) const {
if (filename.isNull())
return false;
bool TagReader::SaveSongRatingToFile(
const QString& filename, const pb::tagreader::SongMetadata& song) const {
if (filename.isNull()) return false;
qLog(Debug) << "Saving song rating tags to" << filename;
@ -650,7 +729,8 @@ bool TagReader::SaveSongRatingToFile(const QString& filename,
if (!fileref || fileref->isNull()) // The file probably doesn't exist
return false;
if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (TagLib::MPEG::File* file =
dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true);
// Save as FMPS
@ -660,21 +740,27 @@ bool TagReader::SaveSongRatingToFile(const QString& filename,
TagLib::ID3v2::PopularimeterFrame* frame = GetPOPMFrameFromTag(tag);
frame->setRating(ConvertToPOPMRating(song.rating()));
} else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
} else if (TagLib::FLAC::File* file =
dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
TagLib::Ogg::XiphComment* vorbis_comments = file->xiphComment(true);
SetFMPSRatingVorbisComments(vorbis_comments, song);
} else if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
} else if (TagLib::Ogg::XiphComment* tag =
dynamic_cast<TagLib::Ogg::XiphComment*>(
fileref->file()->tag())) {
SetFMPSRatingVorbisComments(tag, song);
}
#ifdef TAGLIB_WITH_ASF
else if (TagLib::ASF::File* file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
else if (TagLib::ASF::File* file =
dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
TagLib::ASF::Tag* tag = file->tag();
tag->addAttribute("FMPS/Rating", NumberToASFAttribute(song.rating()));
}
#endif
else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
else if (TagLib::MP4::File* file =
dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
TagLib::MP4::Tag* tag = file->tag();
tag->itemListMap()[kMP4_FMPS_Rating_ID] = TagLib::StringList(QStringToTaglibString(QString::number(song.rating())));
tag->itemListMap()[kMP4_FMPS_Rating_ID] = TagLib::StringList(
QStringToTaglibString(QString::number(song.rating())));
} else {
// Nothing to save: stop now
return true;
@ -691,7 +777,8 @@ bool TagReader::SaveSongRatingToFile(const QString& filename,
return ret;
}
void TagReader::SetUserTextFrame(const QString& description, const QString& value,
void TagReader::SetUserTextFrame(const QString& description,
const QString& value,
TagLib::ID3v2::Tag* tag) const {
const QByteArray descr_utf8(description.toUtf8());
const QByteArray value_utf8(value.toUtf8());
@ -752,8 +839,7 @@ bool TagReader::IsMediaFile(const QString& filename) const {
}
QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const {
if (filename.isEmpty())
return QByteArray();
if (filename.isEmpty()) return QByteArray();
qLog(Debug) << "Loading art from" << filename;
@ -763,20 +849,20 @@ QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const {
TagLib::FileRef ref(QFile::encodeName(filename).constData());
#endif
if (ref.isNull() || !ref.file())
return QByteArray();
if (ref.isNull() || !ref.file()) return QByteArray();
// MP3
TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(ref.file());
if (file && file->ID3v2Tag()) {
TagLib::ID3v2::FrameList apic_frames = file->ID3v2Tag()->frameListMap()["APIC"];
if (apic_frames.isEmpty())
return QByteArray();
TagLib::ID3v2::FrameList apic_frames =
file->ID3v2Tag()->frameListMap()["APIC"];
if (apic_frames.isEmpty()) return QByteArray();
TagLib::ID3v2::AttachedPictureFrame* pic =
static_cast<TagLib::ID3v2::AttachedPictureFrame*>(apic_frames.front());
return QByteArray((const char*) pic->picture().data(), pic->picture().size());
return QByteArray((const char*)pic->picture().data(),
pic->picture().size());
}
// Ogg vorbis/speex
@ -786,12 +872,14 @@ QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const {
if (xiph_comment) {
TagLib::Ogg::FieldListMap map = xiph_comment->fieldListMap();
// Other than the below mentioned non-standard COVERART, METADATA_BLOCK_PICTURE
// Other than the below mentioned non-standard COVERART,
// METADATA_BLOCK_PICTURE
// is the proposed tag for cover pictures.
// (see http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE)
if (map.contains("METADATA_BLOCK_PICTURE")) {
TagLib::StringList pict_list = map["METADATA_BLOCK_PICTURE"];
for(std::list<TagLib::String>::iterator it = pict_list.begin(); it != pict_list.end(); ++it) {
for (std::list<TagLib::String>::iterator it = pict_list.begin();
it != pict_list.end(); ++it) {
QByteArray data(QByteArray::fromBase64(it->toCString()));
TagLib::ByteVector tdata(data.data(), data.size());
TagLib::FLAC::Picture p(tdata);
@ -799,7 +887,8 @@ QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const {
return QByteArray(p.data().data(), p.data().size());
}
// If there was no specific front cover, just take the first picture
QByteArray data(QByteArray::fromBase64(map["METADATA_BLOCK_PICTURE"].front().toCString()));
QByteArray data(QByteArray::fromBase64(
map["METADATA_BLOCK_PICTURE"].front().toCString()));
TagLib::ByteVector tdata(data.data(), data.size());
TagLib::FLAC::Picture p(tdata);
return QByteArray(p.data().data(), p.data().size());
@ -807,8 +896,7 @@ QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const {
// Ogg lacks a definitive standard for embedding cover art, but it seems
// b64 encoding a field called COVERART is the general convention
if (!map.contains("COVERART"))
return QByteArray();
if (!map.contains("COVERART")) return QByteArray();
return QByteArray::fromBase64(map["COVERART"].toString().toCString());
}
@ -850,62 +938,45 @@ QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const {
return QByteArray();
}
#ifdef HAVE_GOOGLE_DRIVE
bool TagReader::ReadCloudFile(const QUrl& download_url,
const QString& title,
int size,
const QString& mime_type,
bool TagReader::ReadCloudFile(const QUrl& download_url, const QString& title,
int size, const QString& mime_type,
const QString& authorisation_header,
pb::tagreader::SongMetadata* song) const {
qLog(Debug) << "Loading tags from" << title;
CloudStream* stream = new CloudStream(
download_url, title, size, authorisation_header, network_);
CloudStream* stream = new CloudStream(download_url, title, size,
authorisation_header, network_);
stream->Precache();
std::unique_ptr<TagLib::File> tag;
if (mime_type == "audio/mpeg" && title.endsWith(".mp3")) {
tag.reset(new TagLib::MPEG::File(
stream, // Takes ownership.
tag.reset(new TagLib::MPEG::File(stream, // Takes ownership.
TagLib::ID3v2::FrameFactory::instance(),
TagLib::AudioProperties::Accurate));
} else if (mime_type == "audio/mp4" ||
(mime_type == "audio/mpeg" && title.endsWith(".m4a"))) {
tag.reset(new TagLib::MP4::File(
stream,
true,
TagLib::AudioProperties::Accurate));
tag.reset(
new TagLib::MP4::File(stream, true, TagLib::AudioProperties::Accurate));
}
#ifdef TAGLIB_HAS_OPUS
else if ((mime_type == "application/opus" ||
mime_type == "audio/opus" ||
mime_type == "application/ogg" ||
mime_type == "audio/ogg") && title.endsWith(".opus")) {
tag.reset(new TagLib::Ogg::Opus::File(
stream,
true,
else if ((mime_type == "application/opus" || mime_type == "audio/opus" ||
mime_type == "application/ogg" || mime_type == "audio/ogg") &&
title.endsWith(".opus")) {
tag.reset(new TagLib::Ogg::Opus::File(stream, true,
TagLib::AudioProperties::Accurate));
}
#endif
else if (mime_type == "application/ogg" ||
mime_type == "audio/ogg") {
tag.reset(new TagLib::Ogg::Vorbis::File(
stream,
true,
else if (mime_type == "application/ogg" || mime_type == "audio/ogg") {
tag.reset(new TagLib::Ogg::Vorbis::File(stream, true,
TagLib::AudioProperties::Accurate));
} else if (mime_type == "application/x-flac" ||
mime_type == "audio/flac" ||
} else if (mime_type == "application/x-flac" || mime_type == "audio/flac" ||
mime_type == "audio/x-flac") {
tag.reset(new TagLib::FLAC::File(
stream,
tag.reset(new TagLib::FLAC::File(stream,
TagLib::ID3v2::FrameFactory::instance(),
true,
TagLib::AudioProperties::Accurate));
true, TagLib::AudioProperties::Accurate));
} else if (mime_type == "audio/x-ms-wma") {
tag.reset(new TagLib::ASF::File(
stream,
true,
TagLib::AudioProperties::Accurate));
tag.reset(
new TagLib::ASF::File(stream, true, TagLib::AudioProperties::Accurate));
} else {
qLog(Debug) << "Unknown mime type for tagging:" << mime_type;
return false;
@ -914,8 +985,7 @@ bool TagReader::ReadCloudFile(const QUrl& download_url,
if (stream->num_requests() > 2) {
// Warn if pre-caching failed.
qLog(Warning) << "Total requests for file:" << title
<< stream->num_requests()
<< stream->cached_bytes();
<< stream->num_requests() << stream->cached_bytes();
}
if (tag->tag() && !tag->tag()->isEmpty()) {
@ -943,12 +1013,14 @@ bool TagReader::ReadCloudFile(const QUrl& download_url,
}
#endif // HAVE_GOOGLE_DRIVE
TagLib::ID3v2::PopularimeterFrame* TagReader::GetPOPMFrameFromTag(TagLib::ID3v2::Tag* tag) {
TagLib::ID3v2::PopularimeterFrame* TagReader::GetPOPMFrameFromTag(
TagLib::ID3v2::Tag* tag) {
TagLib::ID3v2::PopularimeterFrame* frame = nullptr;
const TagLib::ID3v2::FrameListMap& map = tag->frameListMap();
if (!map["POPM"].isEmpty()) {
frame = dynamic_cast<TagLib::ID3v2::PopularimeterFrame*>(map["POPM"].front());
frame =
dynamic_cast<TagLib::ID3v2::PopularimeterFrame*>(map["POPM"].front());
}
if (!frame) {

View File

@ -30,7 +30,6 @@ class QString;
class QTextCodec;
class QUrl;
namespace TagLib {
class FileRef;
class String;
@ -52,23 +51,24 @@ class TagReader {
public:
TagReader();
void ReadFile(const QString& filename, pb::tagreader::SongMetadata* song) const;
bool SaveFile(const QString& filename, const pb::tagreader::SongMetadata& song) const;
void ReadFile(const QString& filename,
pb::tagreader::SongMetadata* song) const;
bool SaveFile(const QString& filename,
const pb::tagreader::SongMetadata& song) const;
// Returns false if something went wrong; returns true otherwise (might
// returns true if the file exists but nothing has been written inside because
// statistics tag format is not supported for this kind of file)
bool SaveSongStatisticsToFile(const QString& filename, const pb::tagreader::SongMetadata& song) const;
bool SaveSongRatingToFile(const QString& filename, const pb::tagreader::SongMetadata& song) const;
bool SaveSongStatisticsToFile(const QString& filename,
const pb::tagreader::SongMetadata& song) const;
bool SaveSongRatingToFile(const QString& filename,
const pb::tagreader::SongMetadata& song) const;
bool IsMediaFile(const QString& filename) const;
QByteArray LoadEmbeddedArt(const QString& filename) const;
#ifdef HAVE_GOOGLE_DRIVE
bool ReadCloudFile(const QUrl& download_url,
const QString& title,
int size,
const QString& mime_type,
const QString& access_token,
bool ReadCloudFile(const QUrl& download_url, const QString& title, int size,
const QString& mime_type, const QString& access_token,
pb::tagreader::SongMetadata* song) const;
#endif // HAVE_GOOGLE_DRIVE
@ -80,21 +80,24 @@ class TagReader {
void ParseFMPSFrame(const QString& name, const QString& value,
pb::tagreader::SongMetadata* song) const;
void ParseOggTag(const TagLib::Ogg::FieldListMap& map,
const QTextCodec* codec,
QString* disc, QString* compilation,
const QTextCodec* codec, QString* disc, QString* compilation,
pb::tagreader::SongMetadata* song) const;
void SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const;
void SetFMPSStatisticsVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
void SetFMPSStatisticsVorbisComments(
TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const;
void SetFMPSRatingVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const;
const pb::tagreader::SongMetadata& song)
const;
pb::tagreader::SongMetadata_Type GuessFileType(TagLib::FileRef* fileref) const;
pb::tagreader::SongMetadata_Type GuessFileType(TagLib::FileRef* fileref)
const;
void SetUserTextFrame(const QString& description, const QString& value,
TagLib::ID3v2::Tag* tag) const;
void SetUserTextFrame(const std::string& description, const std::string& value,
void SetUserTextFrame(const std::string& description,
const std::string& value,
TagLib::ID3v2::Tag* tag) const;
void SetTextFrame(const char* id, const QString& value,
@ -106,11 +109,13 @@ private:
static const char* kMP4_FMPS_Rating_ID;
static const char* kMP4_FMPS_Playcount_ID;
static const char* kMP4_FMPS_Score_ID;
// Returns a float in [0.0..1.0] corresponding to the rating range we use in Clementine
// Returns a float in [0.0..1.0] corresponding to the rating range we use in
// Clementine
static float ConvertPOPMRating(const int POPM_rating);
// Reciprocal
static int ConvertToPOPMRating(const float rating);
static TagLib::ID3v2::PopularimeterFrame* GetPOPMFrameFromTag(TagLib::ID3v2::Tag* tag);
static TagLib::ID3v2::PopularimeterFrame* GetPOPMFrameFromTag(
TagLib::ID3v2::Tag* tag);
FileRefFactory* factory_;
QNetworkAccessManager* network_;

View File

@ -3,9 +3,7 @@
#include "engines/enginebase.h"
AnalyzerBase::AnalyzerBase(QWidget* parent)
: QGLWidget(parent),
engine_(nullptr) {
}
: QGLWidget(parent), engine_(nullptr) {}
void AnalyzerBase::set_engine(Engine::Base* engine) {
disconnect(engine_);

View File

@ -27,48 +27,45 @@
#include "engines/enginebase.h"
// INSTRUCTIONS Base2D
// 1. do anything that depends on height() in init(), Base2D will call it before you are shown
// 1. do anything that depends on height() in init(), Base2D will call it before
// you are shown
// 2. otherwise you can use the constructor to initialise things
// 3. reimplement analyze(), and paint to canvas(), Base2D will update the widget when you return control to it
// 3. reimplement analyze(), and paint to canvas(), Base2D will update the
// widget when you return control to it
// 4. if you want to manipulate the scope, reimplement transform()
// 5. for convenience <vector> <qpixmap.h> <qwdiget.h> are pre-included
// TODO make an INSTRUCTIONS file
// can't mod scope in analyze you have to use transform
// TODO for 2D use setErasePixmap Qt function insetead of m_background
// make the linker happy only for gcc < 4.0
#if !( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 0 ) ) && !defined(Q_OS_WIN32)
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \
!defined(Q_OS_WIN32)
template class Analyzer::Base<QWidget>;
#endif
Analyzer::Base::Base(QWidget* parent, uint scopeSize)
: QWidget( parent )
, m_timeout( 40 ) // msec
, m_fht( new FHT(scopeSize) )
, m_engine(nullptr)
, m_lastScope(512)
, new_frame_(false)
, is_playing_(false)
{
}
: QWidget(parent),
m_timeout(40) // msec
,
m_fht(new FHT(scopeSize)),
m_engine(nullptr),
m_lastScope(512),
new_frame_(false),
is_playing_(false) {}
void Analyzer::Base::hideEvent(QHideEvent *) {
m_timer.stop();
}
void Analyzer::Base::hideEvent(QHideEvent*) { m_timer.stop(); }
void Analyzer::Base::showEvent(QShowEvent *) {
m_timer.start(timeout(), this);
}
void Analyzer::Base::showEvent(QShowEvent*) { m_timer.start(timeout(), this); }
void Analyzer::Base::transform(Scope& scope) // virtual
{
// this is a standard transformation that should give
// an FFT scope that has bands for pretty analyzers
//NOTE resizing here is redundant as FHT routines only calculate FHT::size() values
// NOTE resizing here is redundant as FHT routines only calculate FHT::size()
// values
// scope.resize( m_fht->size() );
float* front = static_cast<float*>(&scope.front());
@ -82,22 +79,20 @@ void Analyzer::Base::transform( Scope &scope ) //virtual
delete[] f;
}
void Analyzer::Base::paintEvent(QPaintEvent * e)
{
void Analyzer::Base::paintEvent(QPaintEvent* e) {
QPainter p(this);
p.fillRect(e->rect(), palette().color(QPalette::Window));
switch( m_engine->state() )
{
case Engine::Playing:
{
switch (m_engine->state()) {
case Engine::Playing: {
const Engine::Scope& thescope = m_engine->scope();
int i = 0;
// convert to mono here - our built in analyzers need mono, but we the engines provide interleaved pcm
for( uint x = 0; (int)x < m_fht->size(); ++x )
{
m_lastScope[x] = double(thescope[i] + thescope[i+1]) / (2*(1<<15));
// convert to mono here - our built in analyzers need mono, but we the
// engines provide interleaved pcm
for (uint x = 0; (int)x < m_fht->size(); ++x) {
m_lastScope[x] =
double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
i += 2;
}
@ -119,12 +114,10 @@ void Analyzer::Base::paintEvent(QPaintEvent * e)
demo(p);
}
new_frame_ = false;
}
int Analyzer::Base::resizeExponent( int exp )
{
int Analyzer::Base::resizeExponent(int exp) {
if (exp < 3)
exp = 3;
else if (exp > 9)
@ -137,8 +130,7 @@ int Analyzer::Base::resizeExponent( int exp )
return exp;
}
int Analyzer::Base::resizeForBands( int bands )
{
int Analyzer::Base::resizeForBands(int bands) {
int exp;
if (bands <= 8)
exp = 4;
@ -162,8 +154,7 @@ void Analyzer::Base::demo(QPainter& p) //virtual
static int t = 201; // FIXME make static to namespace perhaps
if (t > 999) t = 1; // 0 = wasted calculations
if( t < 201 )
{
if (t < 201) {
Scope s(32);
const double dt = double(t) / 200;
@ -171,52 +162,43 @@ void Analyzer::Base::demo(QPainter& p) //virtual
s[i] = dt * (sin(M_PI + (i * M_PI) / s.size()) + 1.0);
analyze(p, s, new_frame_);
}
else analyze( p, Scope( 32, 0 ), new_frame_ );
} else
analyze(p, Scope(32, 0), new_frame_);
++t;
}
void Analyzer::Base::polishEvent()
{
void Analyzer::Base::polishEvent() {
init(); // virtual
}
void
Analyzer::interpolate( const Scope &inVec, Scope &outVec ) //static
void Analyzer::interpolate(const Scope& inVec, Scope& outVec) // static
{
double pos = 0.0;
const double step = (double)inVec.size() / outVec.size();
for ( uint i = 0; i < outVec.size(); ++i, pos += step )
{
for (uint i = 0; i < outVec.size(); ++i, pos += step) {
const double error = pos - std::floor(pos);
const unsigned long offset = (unsigned long)pos;
unsigned long indexLeft = offset + 0;
if ( indexLeft >= inVec.size() )
indexLeft = inVec.size() - 1;
if (indexLeft >= inVec.size()) indexLeft = inVec.size() - 1;
unsigned long indexRight = offset + 1;
if ( indexRight >= inVec.size() )
indexRight = inVec.size() - 1;
if (indexRight >= inVec.size()) indexRight = inVec.size() - 1;
outVec[i] = inVec[indexLeft ] * ( 1.0 - error ) +
inVec[indexRight] * error;
outVec[i] = inVec[indexLeft] * (1.0 - error) + inVec[indexRight] * error;
}
}
void
Analyzer::initSin( Scope &v, const uint size ) //static
void Analyzer::initSin(Scope& v, const uint size) // static
{
double step = (M_PI * 2) / size;
double radian = 0;
for ( uint i = 0; i < size; i++ )
{
for (uint i = 0; i < size; i++) {
v.push_back(sin(radian));
radian += step;
}
@ -224,8 +206,7 @@ Analyzer::initSin( Scope &v, const uint size ) //static
void Analyzer::Base::timerEvent(QTimerEvent* e) {
QWidget::timerEvent(e);
if (e->timerId() != m_timer.timerId())
return;
if (e->timerId() != m_timer.timerId()) return;
new_frame_ = true;
update();

View File

@ -4,7 +4,6 @@
#ifndef ANALYZERBASE_H
#define ANALYZERBASE_H
#ifdef __FreeBSD__
#include <sys/types.h>
#endif
@ -29,13 +28,11 @@ class QEvent;
class QPaintEvent;
class QResizeEvent;
namespace Analyzer {
typedef std::vector<float> Scope;
class Base : public QWidget
{
class Base : public QWidget {
Q_OBJECT
public:
@ -81,7 +78,6 @@ protected:
bool is_playing_;
};
void interpolate(const Scope&, Scope&);
void initSin(Scope&, const uint = 6000);

View File

@ -52,8 +52,7 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
double_click_timer_(new QTimer(this)),
ignore_next_click_(false),
current_analyzer_(nullptr),
engine_(nullptr)
{
engine_(nullptr) {
QHBoxLayout* layout = new QHBoxLayout(this);
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
@ -62,7 +61,8 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
AddFramerate(tr("Low (%1 fps)").arg(kLowFramerate), kLowFramerate);
AddFramerate(tr("Medium (%1 fps)").arg(kMediumFramerate), kMediumFramerate);
AddFramerate(tr("High (%1 fps)").arg(kHighFramerate), kHighFramerate);
AddFramerate(tr("Super high (%1 fps)").arg(kSuperHighFramerate), kSuperHighFramerate);
AddFramerate(tr("Super high (%1 fps)").arg(kSuperHighFramerate),
kSuperHighFramerate);
connect(mapper_framerate_, SIGNAL(mapped(int)), SLOT(ChangeFramerate(int)));
context_menu_->addMenu(context_menu_framerate_);
@ -76,8 +76,8 @@ AnalyzerContainer::AnalyzerContainer(QWidget *parent)
AddAnalyzerType<NyanCatAnalyzer>();
connect(mapper_, SIGNAL(mapped(int)), SLOT(ChangeAnalyzer(int)));
disable_action_ =
context_menu_->addAction(tr("No analyzer"), this, SLOT(DisableAnalyzer()));
disable_action_ = context_menu_->addAction(tr("No analyzer"), this,
SLOT(DisableAnalyzer()));
disable_action_->setCheckable(true);
group_->addAction(disable_action_);
@ -119,8 +119,7 @@ void AnalyzerContainer::mouseDoubleClickEvent(QMouseEvent *) {
double_click_timer_->stop();
ignore_next_click_ = true;
if (visualisation_action_)
visualisation_action_->trigger();
if (visualisation_action_) visualisation_action_->trigger();
}
void AnalyzerContainer::wheelEvent(QWheelEvent* e) {
@ -128,8 +127,7 @@ void AnalyzerContainer::wheelEvent(QWheelEvent* e) {
}
void AnalyzerContainer::SetEngine(EngineBase* engine) {
if (current_analyzer_)
current_analyzer_->set_engine(engine);
if (current_analyzer_) current_analyzer_->set_engine(engine);
engine_ = engine;
}
@ -144,7 +142,8 @@ void AnalyzerContainer::ChangeAnalyzer(int id) {
QObject* instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this));
if (!instance) {
qLog(Warning) << "Couldn't intialise a new" << analyzer_types_[id]->className();
qLog(Warning) << "Couldn't intialise a new"
<< analyzer_types_[id]->className();
return;
}
@ -152,7 +151,8 @@ void AnalyzerContainer::ChangeAnalyzer(int id) {
current_analyzer_ = qobject_cast<Analyzer::Base*>(instance);
current_analyzer_->set_engine(engine_);
// Even if it is not supposed to happen, I don't want to get a dbz error
current_framerate_ = current_framerate_ == 0 ? kMediumFramerate : current_framerate_;
current_framerate_ =
current_framerate_ == 0 ? kMediumFramerate : current_framerate_;
current_analyzer_->changeTimeout(1000 / current_framerate_);
layout()->addWidget(current_analyzer_);
@ -212,13 +212,14 @@ void AnalyzerContainer::Save() {
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("type", current_analyzer_ ?
current_analyzer_->metaObject()->className() :
QVariant());
s.setValue("type", current_analyzer_
? current_analyzer_->metaObject()->className()
: QVariant());
}
void AnalyzerContainer::AddFramerate(const QString& name, int framerate) {
QAction *action = context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map()));
QAction* action =
context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map()));
mapper_framerate_->setMapping(action, framerate);
group_framerate_->addAction(action);
framerate_list_ << framerate;

View File

@ -92,7 +92,8 @@ template <typename T>
int id = analyzer_types_.count();
analyzer_types_ << &T::staticMetaObject;
QAction* action = context_menu_->addAction(tr(T::kName), mapper_, SLOT(map()));
QAction* action =
context_menu_->addAction(tr(T::kName), mapper_, SLOT(map()));
group_->addAction(action);
mapper_->setMapping(action, id);
action->setCheckable(true);
@ -100,4 +101,3 @@ template <typename T>
}
#endif

View File

@ -16,8 +16,8 @@
#include <QtDebug>
#include <QPainter>
const char* BarAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Bar analyzer");
const char* BarAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Bar analyzer");
BarAnalyzer::BarAnalyzer(QWidget* parent)
: Analyzer::Base(parent, 8)
@ -31,31 +31,26 @@ BarAnalyzer::BarAnalyzer( QWidget *parent )
QColor fg(0xff, 0x50, 0x70);
double dr = double(m_bg.red() - fg.red()) / (NUM_ROOFS-1); //-1 because we start loop below at 0
double dr = double(m_bg.red() - fg.red()) /
(NUM_ROOFS - 1); //-1 because we start loop below at 0
double dg = double(m_bg.green() - fg.green()) / (NUM_ROOFS - 1);
double db = double(m_bg.blue() - fg.blue()) / (NUM_ROOFS - 1);
for ( uint i = 0; i < NUM_ROOFS; ++i )
{
for (uint i = 0; i < NUM_ROOFS; ++i) {
m_pixRoof[i] = QPixmap(COLUMN_WIDTH, 1);
m_pixRoof[i].fill( QColor( fg.red()+int(dr*i), fg.green()+int(dg*i), fg.blue()+int(db*i) ) );
m_pixRoof[i].fill(QColor(fg.red() + int(dr * i), fg.green() + int(dg * i),
fg.blue() + int(db * i)));
}
}
}
void BarAnalyzer::resizeEvent( QResizeEvent * e )
{
init();
}
void BarAnalyzer::resizeEvent(QResizeEvent* e) { init(); }
// METHODS =====================================================
void BarAnalyzer::init()
{
void BarAnalyzer::init() {
const double MAX_AMPLITUDE = 1.0;
const double F = double(height() - 2) / (log10(255) * MAX_AMPLITUDE);
BAND_COUNT = width() / 5;
MAX_DOWN = int(0 - (qMax(1, height() / 50)));
MAX_UP = int(qMax(1, height() / 25));
@ -66,9 +61,9 @@ void BarAnalyzer::init()
m_roofMem.resize(BAND_COUNT);
m_scope.resize(BAND_COUNT);
//generate a list of values that express amplitudes in range 0-MAX_AMP as ints from 0-height() on log scale
for ( uint x = 0; x < 256; ++x )
{
// generate a list of values that express amplitudes in range 0-MAX_AMP as
// ints from 0-height() on log scale
for (uint x = 0; x < 256; ++x) {
m_lvlMapper[x] = uint(F * log10(x + 1));
}
@ -76,40 +71,39 @@ void BarAnalyzer::init()
m_pixCompose = QPixmap(size());
QPainter p(&m_pixBarGradient);
for ( int x=0, r=0x40, g=0x30, b=0xff, r2=255-r;
x < height(); ++x )
{
for ( int y = x; y > 0; --y )
{
for (int x = 0, r = 0x40, g = 0x30, b = 0xff, r2 = 255 - r; x < height();
++x) {
for (int y = x; y > 0; --y) {
const double fraction = (double)y / height();
// p.setPen( QColor( r + (int)(r2 * fraction), g, b - (int)(255 * fraction) ) );
// p.setPen( QColor( r + (int)(r2 * fraction), g, b - (int)(255 *
// fraction) ) );
p.setPen(QColor(r + (int)(r2 * fraction), g, b));
p.drawLine( x*COLUMN_WIDTH, height() - y, (x+1)*COLUMN_WIDTH, height() - y );
p.drawLine(x * COLUMN_WIDTH, height() - y, (x + 1) * COLUMN_WIDTH,
height() - y);
}
}
setMinimumSize(QSize(BAND_COUNT * COLUMN_WIDTH, 10));
}
void BarAnalyzer::analyze( QPainter& p, const Scope &s, bool new_frame)
{
void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) {
// Analyzer::interpolate( s, m_bands );
Scope& v = m_scope;
Analyzer::interpolate(s, v);
for ( uint i = 0, x = 0, y2; i < v.size(); ++i, x+=COLUMN_WIDTH+1 )
{
for (uint i = 0, x = 0, y2; i < v.size(); ++i, x += COLUMN_WIDTH + 1) {
// assign pre[log10]'d value
y2 = uint(v[i] * 256); //256 will be optimised to a bitshift //no, it's a float
y2 = m_lvlMapper[ (y2 > 255) ? 255 : y2 ]; //lvlMapper is array of ints with values 0 to height()
y2 = uint(v[i] *
256); // 256 will be optimised to a bitshift //no, it's a float
y2 = m_lvlMapper[(y2 > 255) ? 255 : y2]; // lvlMapper is array of ints with
// values 0 to height()
int change = y2 - barVector[i];
//using the best of Markey's, piggz and Max's ideas on the way to shift the bars
// using the best of Markey's, piggz and Max's ideas on the way to shift the
// bars
// we have the following:
// 1. don't adjust shift when doing small up movements
// 2. shift large upwards with a bias towards last value
@ -119,12 +113,11 @@ void BarAnalyzer::analyze( QPainter& p, const Scope &s, bool new_frame)
//add some dynamics - makes the value slightly closer to what it was last time
y2 = ( barVector[i] + MAX_UP );
//y2 = ( barVector[i] * 2 + y2 ) / 3;
else*/ if ( change < MAX_DOWN )
else*/ if (change <
MAX_DOWN)
y2 = barVector[i] + MAX_DOWN;
if ( (int)y2 > roofVector[i] )
{
if ((int)y2 > roofVector[i]) {
roofVector[i] = (int)y2;
roofVelocityVector[i] = 1;
}
@ -137,30 +130,32 @@ void BarAnalyzer::analyze( QPainter& p, const Scope &s, bool new_frame)
// blt last n roofs, a.k.a motion blur
for (uint c = 0; c < m_roofMem[i].size(); ++c)
//bitBlt( m_pComposePixmap, x, m_roofMem[i]->at( c ), m_roofPixmaps[ c ] );
//bitBlt( canvas(), x, m_roofMem[i][c], &m_pixRoof[ NUM_ROOFS - 1 - c ] );
// bitBlt( m_pComposePixmap, x, m_roofMem[i]->at( c ), m_roofPixmaps[ c ]
// );
// bitBlt( canvas(), x, m_roofMem[i][c], &m_pixRoof[ NUM_ROOFS - 1 - c ]
// );
p.drawPixmap(x, m_roofMem[i][c], m_pixRoof[NUM_ROOFS - 1 - c]);
// blt the bar
p.drawPixmap(x, height() - y2,
*gradient(), y2 * COLUMN_WIDTH, height() - y2, COLUMN_WIDTH, y2);
p.drawPixmap(x, height() - y2, *gradient(), y2 * COLUMN_WIDTH,
height() - y2, COLUMN_WIDTH, y2);
/*bitBlt( canvas(), x, height() - y2,
gradient(), y2 * COLUMN_WIDTH, height() - y2, COLUMN_WIDTH, y2, Qt::CopyROP );*/
gradient(), y2 * COLUMN_WIDTH, height() - y2, COLUMN_WIDTH, y2,
Qt::CopyROP );*/
m_roofMem[i].push_back(height() - roofVector[i] - 2);
// set roof parameters for the NEXT draw
if ( roofVelocityVector[i] != 0 )
{
if (roofVelocityVector[i] != 0) {
if (roofVelocityVector[i] > 32) // no reason to do == 32
roofVector[i] -= (roofVelocityVector[i] - 32) / 20; //trivial calculation
roofVector[i] -=
(roofVelocityVector[i] - 32) / 20; // trivial calculation
if ( roofVector[i] < 0 )
{
if (roofVector[i] < 0) {
roofVector[i] = 0; // not strictly necessary
roofVelocityVector[i] = 0;
}
else ++roofVelocityVector[i];
} else
++roofVelocityVector[i];
}
}
}

View File

@ -10,9 +10,7 @@
typedef std::vector<uint> aroofMemVec;
class BarAnalyzer : public Analyzer::Base
{
class BarAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BarAnalyzer(QWidget*);
@ -41,7 +39,8 @@ class BarAnalyzer : public Analyzer::Base
QPixmap m_pixRoof[NUM_ROOFS];
// vector<uint> m_roofMem[BAND_COUNT];
//Scope m_bands; //copy of the Scope to prevent creating/destroying a Scope every iteration
// Scope m_bands; //copy of the Scope to prevent creating/destroying a Scope
// every iteration
uint m_lvlMapper[256];
std::vector<aroofMemVec> m_roofMem;
std::vector<uint> barVector; // positions of bars

View File

@ -19,36 +19,42 @@ const uint BlockAnalyzer::MIN_COLUMNS = 32; //arbituary
const uint BlockAnalyzer::MAX_COLUMNS = 256; // must be 2**n
const uint BlockAnalyzer::FADE_SIZE = 90;
const char* BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
const char* BlockAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
BlockAnalyzer::BlockAnalyzer(QWidget* parent)
: Analyzer::Base( parent, 9 )
, m_columns( 0 ) //uint
, m_rows( 0 ) //uint
, m_y( 0 ) //uint
, m_barPixmap( 1, 1 ) //null qpixmaps cause crashes
, m_topBarPixmap( WIDTH, HEIGHT )
, m_scope( MIN_COLUMNS ) //Scope
, m_store( 1 << 8, 0 ) //vector<uint>
, m_fade_bars( FADE_SIZE ) //vector<QPixmap>
, m_fade_pos( 1 << 8, 50 ) //vector<uint>
, m_fade_intensity( 1 << 8, 32 ) //vector<uint>
: Analyzer::Base(parent, 9),
m_columns(0) // uint
,
m_rows(0) // uint
,
m_y(0) // uint
,
m_barPixmap(1, 1) // null qpixmaps cause crashes
,
m_topBarPixmap(WIDTH, HEIGHT),
m_scope(MIN_COLUMNS) // Scope
,
m_store(1 << 8, 0) // vector<uint>
,
m_fade_bars(FADE_SIZE) // vector<QPixmap>
,
m_fade_pos(1 << 8, 50) // vector<uint>
,
m_fade_intensity(1 << 8, 32) // vector<uint>
{
setMinimumSize( MIN_COLUMNS*(WIDTH+1) -1, MIN_ROWS*(HEIGHT+1) -1 ); //-1 is padding, no drawing takes place there
setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1,
MIN_ROWS * (HEIGHT + 1) -
1); //-1 is padding, no drawing takes place there
setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1);
// mxcl says null pixmaps cause crashes, so let's play it safe
for ( uint i = 0; i < FADE_SIZE; ++i )
m_fade_bars[i] = QPixmap( 1, 1 );
for (uint i = 0; i < FADE_SIZE; ++i) m_fade_bars[i] = QPixmap(1, 1);
}
BlockAnalyzer::~BlockAnalyzer()
{
}
BlockAnalyzer::~BlockAnalyzer() {}
void
BlockAnalyzer::resizeEvent( QResizeEvent *e )
{
void BlockAnalyzer::resizeEvent(QResizeEvent* e) {
QWidget::resizeEvent(e);
m_background = QPixmap(size());
@ -73,7 +79,8 @@ BlockAnalyzer::resizeEvent( QResizeEvent *e )
m_yscale.resize(m_rows + 1);
const uint PRE = 1, PRO = 1; //PRE and PRO allow us to restrict the range somewhat
const uint PRE = 1,
PRO = 1; // PRE and PRO allow us to restrict the range somewhat
for (uint z = 0; z < m_rows; ++z)
m_yscale[z] = 1 - (log10(PRE + z) / log10(PRE + m_rows + PRO));
@ -84,39 +91,37 @@ BlockAnalyzer::resizeEvent( QResizeEvent *e )
paletteChange(palette());
}
drawBackground();
}
void
BlockAnalyzer::determineStep()
{
// falltime is dependent on rowcount due to our digital resolution (ie we have boxes/blocks of pixels)
void BlockAnalyzer::determineStep() {
// falltime is dependent on rowcount due to our digital resolution (ie we have
// boxes/blocks of pixels)
// I calculated the value 30 based on some trial and error
const double fallTime = 30 * m_rows;
m_step = double(m_rows * timeout()) / fallTime;
}
void
BlockAnalyzer::transform( Analyzer::Scope &s ) //pure virtual
void BlockAnalyzer::transform(Analyzer::Scope& s) // pure virtual
{
for( uint x = 0; x < s.size(); ++x )
s[x] *= 2;
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
float* front = static_cast<float*>(&s.front());
m_fht->spectrum(front);
m_fht->scale(front, 1.0 / 20);
//the second half is pretty dull, so only show it if the user has a large analyzer
//by setting to m_scope.size() if large we prevent interpolation of large analyzers, this is good!
s.resize( m_scope.size() <= MAX_COLUMNS/2 ? MAX_COLUMNS/2 : m_scope.size() );
// the second half is pretty dull, so only show it if the user has a large
// analyzer
// by setting to m_scope.size() if large we prevent interpolation of large
// analyzers, this is good!
s.resize(m_scope.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2
: m_scope.size());
}
void
BlockAnalyzer::analyze( QPainter& p, const Analyzer::Scope &s, bool new_frame)
{
void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
bool new_frame) {
// y = 2 3 2 1 0 2
// . . . . # .
// . . . # # .
@ -135,8 +140,7 @@ BlockAnalyzer::analyze( QPainter& p, const Analyzer::Scope &s, bool new_frame)
// Paint the background
p.drawPixmap(0, 0, m_background);
for( uint y, x = 0; x < m_scope.size(); ++x )
{
for (uint y, x = 0; x < m_scope.size(); ++x) {
// determine y
for (y = 0; m_scope[x] < m_yscale[y]; ++y)
;
@ -148,7 +152,8 @@ BlockAnalyzer::analyze( QPainter& p, const Analyzer::Scope &s, bool new_frame)
else
m_store[x] = y;
// if y is lower than m_fade_pos, then the bar has exceeded the height of the fadeout
// if y is lower than m_fade_pos, then the bar has exceeded the height of
// the fadeout
// if the fadeout is quite faded now, then display the new one
if (y <= m_fade_pos[x] /*|| m_fade_intensity[x] < FADE_SIZE / 3*/) {
m_fade_pos[x] = y;
@ -158,27 +163,24 @@ BlockAnalyzer::analyze( QPainter& p, const Analyzer::Scope &s, bool new_frame)
if (m_fade_intensity[x] > 0) {
const uint offset = --m_fade_intensity[x];
const uint y = m_y + (m_fade_pos[x] * (HEIGHT + 1));
p.drawPixmap(x*(WIDTH+1), y, m_fade_bars[offset], 0, 0, WIDTH, height() - y);
p.drawPixmap(x * (WIDTH + 1), y, m_fade_bars[offset], 0, 0, WIDTH,
height() - y);
}
if( m_fade_intensity[x] == 0 )
m_fade_pos[x] = m_rows;
if (m_fade_intensity[x] == 0) m_fade_pos[x] = m_rows;
//REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing, m_rows means none are
p.drawPixmap( x*(WIDTH+1), y*(HEIGHT+1) + m_y, *bar(), 0, y*(HEIGHT+1), bar()->width(), bar()->height() );
// REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing,
// m_rows means none are
p.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, *bar(), 0,
y * (HEIGHT + 1), bar()->width(), bar()->height());
}
for (uint x = 0; x < m_store.size(); ++x)
p.drawPixmap(x*(WIDTH+1), int(m_store[x])*(HEIGHT+1) + m_y, m_topBarPixmap );
p.drawPixmap(x * (WIDTH + 1), int(m_store[x]) * (HEIGHT + 1) + m_y,
m_topBarPixmap);
}
static inline void
adjustToLimits( int &b, int &f, uint &amount )
{
static inline void adjustToLimits(int& b, int& f, uint& amount) {
// with a range of 0-255 and maximum adjustment of amount,
// maximise the difference between f and b
@ -190,8 +192,7 @@ adjustToLimits( int &b, int &f, uint &amount )
amount -= (255 - f);
f = 255;
}
}
else {
} else {
if (f > 255 - b) {
amount -= f;
f = 0;
@ -205,17 +206,20 @@ adjustToLimits( int &b, int &f, uint &amount )
/**
* Clever contrast function
*
* It will try to adjust the foreground color such that it contrasts well with the background
* It will try to adjust the foreground color such that it contrasts well with
*the background
* It won't modify the hue of fg unless absolutely necessary
* @return the adjusted form of fg
*/
QColor
ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
{
QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
class OutputOnExit {
public:
OutputOnExit(const QColor& color) : c(color) {}
~OutputOnExit() { int h,s,v; c.getHsv( &h, &s, &v ); }
~OutputOnExit() {
int h, s, v;
c.getHsv(&h, &s, &v);
}
private:
const QColor& c;
};
@ -223,8 +227,10 @@ ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
// hack so I don't have to cast everywhere
#define amount static_cast<int>(_amount)
// #define STAMP debug() << (QValueList<int>() << fh << fs << fv) << endl;
// #define STAMP1( string ) debug() << string << ": " << (QValueList<int>() << fh << fs << fv) << endl;
// #define STAMP2( string, value ) debug() << string << "=" << value << ": " << (QValueList<int>() << fh << fs << fv) << endl;
// #define STAMP1( string ) debug() << string << ": " <<
// (QValueList<int>() << fh << fs << fv) << endl;
// #define STAMP2( string, value ) debug() << string << "=" << value << ":
// " << (QValueList<int>() << fh << fs << fv) << endl;
OutputOnExit allocateOnTheStack(fg);
@ -240,16 +246,14 @@ ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
// value is the best measure of contrast
// if there is enough difference in value already, return fg unchanged
if( dv > amount )
return fg;
if (dv > amount) return fg;
int ds = abs(bs - fs);
// STAMP2( "DS", ds );
// saturation is good enough too. But not as good. TODO adapt this a little
if( ds > amount )
return fg;
if (ds > amount) return fg;
int dh = abs(bh - fh);
@ -263,13 +267,16 @@ ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
// check the saturation for the two colours is sufficient that hue alone can
// provide sufficient contrast
if (ds > amount / 2 && (bs > 125 && fs > 125))
// STAMP1( "Sufficient saturation difference, and hues are compliemtary" );
// STAMP1( "Sufficient saturation difference, and hues are
// compliemtary" );
return fg;
else if (dv > amount / 2 && (bv > 125 && fv > 125))
// STAMP1( "Sufficient value difference, and hues are compliemtary" );
// STAMP1( "Sufficient value difference, and hues are
// compliemtary" );
return fg;
// STAMP1( "Hues are complimentary but we must modify the value or saturation of the contrasting colour" );
// STAMP1( "Hues are complimentary but we must modify the value or
// saturation of the contrasting colour" );
// but either the colours are two desaturated, or too dark
// so we need to adjust the system, although not as much
@ -287,22 +294,19 @@ ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
}
// test that there is available value to honor our contrast requirement
if( 255 - dv < amount )
{
if (255 - dv < amount) {
// we have to modify the value and saturation of fg
// adjustToLimits( bv, fv, amount );
// STAMP
// see if we need to adjust the saturation
if( amount > 0 )
adjustToLimits( bs, fs, _amount );
if (amount > 0) adjustToLimits(bs, fs, _amount);
// STAMP
// see if we need to adjust the hue
if( amount > 0 )
fh += amount; // cycles around;
if (amount > 0) fh += amount; // cycles around;
// STAMP
@ -311,13 +315,11 @@ ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
// STAMP
if( fv > bv && bv > amount )
return QColor::fromHsv( fh, fs, bv - amount);
if (fv > bv && bv > amount) return QColor::fromHsv(fh, fs, bv - amount);
// STAMP
if( fv < bv && fv > amount )
return QColor::fromHsv( fh, fs, fv - amount);
if (fv < bv && fv > amount) return QColor::fromHsv(fh, fs, fv - amount);
// STAMP
@ -338,8 +340,7 @@ ensureContrast( const QColor &bg, const QColor &fg, uint _amount = 150 )
// #undef STAMP
}
void
BlockAnalyzer::paletteChange( const QPalette& ) //virtual
void BlockAnalyzer::paletteChange(const QPalette&) // virtual
{
const QColor bg = palette().color(QPalette::Background);
const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight));
@ -356,14 +357,16 @@ BlockAnalyzer::paletteChange( const QPalette& ) //virtual
QPainter p(bar());
for (int y = 0; (uint)y < m_rows; ++y)
// graduate the fg color
p.fillRect( 0, y*(HEIGHT+1), WIDTH, HEIGHT, QColor( r+int(dr*y), g+int(dg*y), b+int(db*y) ) );
p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT,
QColor(r + int(dr * y), g + int(dg * y), b + int(db * y)));
{
const QColor bg = palette().color(QPalette::Background).dark(112);
// make a complimentary fadebar colour
// TODO dark is not always correct, dumbo!
int h,s,v; palette().color(QPalette::Background).dark( 150 ).getHsv( &h, &s, &v );
int h, s, v;
palette().color(QPalette::Background).dark(150).getHsv(&h, &s, &v);
const QColor fg(QColor::fromHsv(h + 120, s, v));
const double dr = fg.red() - bg.red();
@ -377,7 +380,8 @@ BlockAnalyzer::paletteChange( const QPalette& ) //virtual
QPainter f(&m_fade_bars[y]);
for (int z = 0; (uint)z < m_rows; ++z) {
const double Y = 1.0 - (log10(FADE_SIZE - y) / log10(FADE_SIZE));
f.fillRect( 0, z*(HEIGHT+1), WIDTH, HEIGHT, QColor( r+int(dr*Y), g+int(dg*Y), b+int(db*Y) ) );
f.fillRect(0, z * (HEIGHT + 1), WIDTH, HEIGHT,
QColor(r + int(dr * Y), g + int(dg * Y), b + int(db * Y)));
}
}
}
@ -385,9 +389,7 @@ BlockAnalyzer::paletteChange( const QPalette& ) //virtual
drawBackground();
}
void
BlockAnalyzer::drawBackground()
{
void BlockAnalyzer::drawBackground() {
const QColor bg = palette().color(QPalette::Background);
const QColor bgdark = bg.dark(112);
@ -396,5 +398,6 @@ BlockAnalyzer::drawBackground()
QPainter p(&m_background);
for (int x = 0; (uint)x < m_columns; ++x)
for (int y = 0; (uint)y < m_rows; ++y)
p.fillRect( x*(WIDTH+1), y*(HEIGHT+1) + m_y, WIDTH, HEIGHT, bgdark );
p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, WIDTH, HEIGHT,
bgdark);
}

View File

@ -12,13 +12,11 @@ class QResizeEvent;
class QMouseEvent;
class QPalette;
/**
* @author Max Howell
*/
class BlockAnalyzer : public Analyzer::Base
{
class BlockAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BlockAnalyzer(QWidget*);

View File

@ -5,39 +5,32 @@
#include <cmath>
#include <QPainter>
const char* BoomAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Boom analyzer");
const char* BoomAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Boom analyzer");
BoomAnalyzer::BoomAnalyzer(QWidget* parent)
: Analyzer::Base( parent, 9 )
, K_barHeight( 1.271 )//1.471
, F_peakSpeed( 1.103 )//1.122
, F( 1.0 )
, bar_height( BAND_COUNT, 0 )
, peak_height( BAND_COUNT, 0 )
, peak_speed( BAND_COUNT, 0.01 )
, barPixmap( COLUMN_WIDTH, 50 )
{
}
: Analyzer::Base(parent, 9),
K_barHeight(1.271) // 1.471
,
F_peakSpeed(1.103) // 1.122
,
F(1.0),
bar_height(BAND_COUNT, 0),
peak_height(BAND_COUNT, 0),
peak_speed(BAND_COUNT, 0.01),
barPixmap(COLUMN_WIDTH, 50) {}
void
BoomAnalyzer::changeK_barHeight( int newValue )
{
void BoomAnalyzer::changeK_barHeight(int newValue) {
K_barHeight = (double)newValue / 1000;
}
void
BoomAnalyzer::changeF_peakSpeed( int newValue )
{
void BoomAnalyzer::changeF_peakSpeed(int newValue) {
F_peakSpeed = (double)newValue / 1000;
}
void BoomAnalyzer::resizeEvent(QResizeEvent *) {
init();
}
void BoomAnalyzer::resizeEvent(QResizeEvent*) { init(); }
void
BoomAnalyzer::init()
{
void BoomAnalyzer::init() {
const uint HEIGHT = height() - 2;
const double h = 1.2 / HEIGHT;
@ -46,21 +39,17 @@ BoomAnalyzer::init()
barPixmap = QPixmap(COLUMN_WIDTH - 2, HEIGHT);
QPainter p(&barPixmap);
for( uint y = 0; y < HEIGHT; ++y )
{
for (uint y = 0; y < HEIGHT; ++y) {
const double F = (double)y * h;
p.setPen(QColor(
qMax(0, 255 - int(229.0 * F)),
p.setPen(QColor(qMax(0, 255 - int(229.0 * F)),
qMax(0, 255 - int(229.0 * F)),
qMax(0, 255 - int(191.0 * F))));
p.drawLine(0, y, COLUMN_WIDTH - 2, y);
}
}
void
BoomAnalyzer::transform( Scope &s )
{
void BoomAnalyzer::transform(Scope& s) {
float* front = static_cast<float*>(&s.front());
m_fht->spectrum(front);
@ -68,52 +57,43 @@ BoomAnalyzer::transform( Scope &s )
Scope scope(32, 0);
const uint xscale[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,24,29,36,43,52,63,76,91,108,129,153,182,216,255 };
const uint xscale[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 19, 24, 29, 36,
43, 52, 63, 76, 91, 108, 129, 153, 182, 216, 255};
for (uint j, i = 0; i < 32; i++)
for (j = xscale[i]; j < xscale[i + 1]; j++)
if ( s[j] > scope[i] )
scope[i] = s[j];
if (s[j] > scope[i]) scope[i] = s[j];
s = scope;
}
void
BoomAnalyzer::analyze( QPainter& p, const Scope& scope, bool new_frame)
{
void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
float h;
const uint MAX_HEIGHT = height() - 1;
for( uint i = 0, x = 0, y; i < BAND_COUNT; ++i, x += COLUMN_WIDTH+1 )
{
for (uint i = 0, x = 0, y; i < BAND_COUNT; ++i, x += COLUMN_WIDTH + 1) {
h = log10(scope[i] * 256.0) * F;
if( h > MAX_HEIGHT )
h = MAX_HEIGHT;
if (h > MAX_HEIGHT) h = MAX_HEIGHT;
if( h > bar_height[i] )
{
if (h > bar_height[i]) {
bar_height[i] = h;
if( h > peak_height[i] )
{
if (h > peak_height[i]) {
peak_height[i] = h;
peak_speed[i] = 0.01;
}
else goto peak_handling;
}
else
{
if( bar_height[i] > 0.0 )
{
} else
goto peak_handling;
} else {
if (bar_height[i] > 0.0) {
bar_height[i] -= K_barHeight; // 1.4
if (bar_height[i] < 0.0) bar_height[i] = 0.0;
}
peak_handling:
if( peak_height[i] > 0.0 )
{
if (peak_height[i] > 0.0) {
peak_height[i] -= peak_speed[i];
peak_speed[i] *= F_peakSpeed; // 1.12
@ -125,8 +105,7 @@ BoomAnalyzer::analyze( QPainter& p, const Scope& scope, bool new_frame)
y = height() - uint(bar_height[i]);
p.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1);
p.setPen(palette().color(QPalette::Highlight));
if (bar_height[i] > 0)
p.drawRect( x, y, COLUMN_WIDTH - 1, height() - y - 1 );
if (bar_height[i] > 0) p.drawRect(x, y, COLUMN_WIDTH - 1, height() - y - 1);
y = height() - uint(peak_height[i]);
p.setPen(palette().color(QPalette::Base));

View File

@ -11,8 +11,7 @@
@author Max Howell
*/
class BoomAnalyzer : public Analyzer::Base
{
class BoomAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BoomAnalyzer(QWidget*);

View File

@ -23,20 +23,14 @@
#include "glanalyzer.h"
#include <kdebug.h>
GLAnalyzer::GLAnalyzer(QWidget* parent)
: Analyzer::Base3D(parent, 15)
, m_oldy(32, -10.0f)
, m_peaks(32)
{}
: Analyzer::Base3D(parent, 15), m_oldy(32, -10.0f), m_peaks(32) {}
GLAnalyzer::~GLAnalyzer()
{}
GLAnalyzer::~GLAnalyzer() {}
// METHODS =====================================================
void GLAnalyzer::analyze( const Scope &s )
{
void GLAnalyzer::analyze(const Scope& s) {
// kdDebug() << "Scope Size: " << s.size() << endl;
/* Scope t(32);
if (s.size() != 32)
@ -52,39 +46,36 @@ void GLAnalyzer::analyze( const Scope &s )
float mfactor = 0.0;
static int drawcount;
if (s.size() == 64)
{
if (s.size() == 64) {
offset = 8;
}
glRotatef(0.25f, 0.0f, 1.0f, 0.5f); // Rotate the scene
drawFloor();
drawcount++;
if (drawcount > 25)
{
if (drawcount > 25) {
drawcount = 0;
peak = 0.0;
}
for ( uint i = 0; i < 32; i++ )
{
if (s[i] > peak)
{
for (uint i = 0; i < 32; i++) {
if (s[i] > peak) {
peak = s[i];
}
}
mfactor = 20 / peak;
for ( uint i = 0; i < 32; i++ )
{
for (uint i = 0; i < 32; i++) {
// kdDebug() << "Scope item " << i << " value: " << s[i] << endl;
// Calculate new horizontal position (x) depending on number of samples
x = -16.0f + i;
// Calculating new vertical position (y) depending on the data passed by amarok
y = float(s[i+offset] * mfactor); //This make it kinda dynamically resize depending on the data
// Calculating new vertical position (y) depending on the data passed by
// amarok
y = float(s[i + offset] * mfactor); // This make it kinda dynamically
// resize depending on the data
// Some basic bounds checking
if (y > 30)
@ -96,43 +87,36 @@ void GLAnalyzer::analyze( const Scope &s )
{
y = m_oldy[i] - 0.7f;
}
if (y < 0.0f)
{
if (y < 0.0f) {
y = 0.0f;
}
m_oldy[i] = y; // Save value as last value
// Peak Code
if (m_oldy[i] > m_peaks[i].level)
{
if (m_oldy[i] > m_peaks[i].level) {
m_peaks[i].level = m_oldy[i];
m_peaks[i].delay = 30;
}
if (m_peaks[i].delay > 0)
{
if (m_peaks[i].delay > 0) {
m_peaks[i].delay--;
}
if (m_peaks[i].level > 1.0f)
{
if (m_peaks[i].delay <= 0)
{
if (m_peaks[i].level > 1.0f) {
if (m_peaks[i].delay <= 0) {
m_peaks[i].level -= 0.4f;
}
}
// Draw the bar
drawBar(x, y);
drawPeak(x, m_peaks[i].level);
}
updateGL();
}
void GLAnalyzer::initializeGL()
{
void GLAnalyzer::initializeGL() {
// Clear frame (next fading will be preferred to clearing)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color to black
glClear(GL_COLOR_BUFFER_BIT);
@ -150,8 +134,7 @@ void GLAnalyzer::initializeGL()
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void GLAnalyzer::resizeGL( int w, int h )
{
void GLAnalyzer::resizeGL(int w, int h) {
glViewport(0, 0, (GLint)w, (GLint)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@ -160,8 +143,7 @@ void GLAnalyzer::resizeGL( int w, int h )
glLoadIdentity();
}
void GLAnalyzer::paintGL()
{
void GLAnalyzer::paintGL() {
glMatrixMode(GL_MODELVIEW);
#if 0
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
@ -185,11 +167,9 @@ void GLAnalyzer::paintGL()
// swapBuffers();
glFlush();
}
void GLAnalyzer::drawBar(float xPos, float height)
{
void GLAnalyzer::drawBar(float xPos, float height) {
glPushMatrix();
// Sets color to blue
@ -206,8 +186,7 @@ void GLAnalyzer::drawBar(float xPos, float height)
glPopMatrix();
}
void GLAnalyzer::drawFloor()
{
void GLAnalyzer::drawFloor() {
glPushMatrix();
// Sets color to amarok blue
@ -223,8 +202,7 @@ void GLAnalyzer::drawFloor()
glPopMatrix();
}
void GLAnalyzer::drawPeak(float xPos, float ypos)
{
void GLAnalyzer::drawPeak(float xPos, float ypos) {
glPushMatrix();
// Set the colour to red
@ -237,8 +215,7 @@ void GLAnalyzer::drawPeak(float xPos, float ypos)
glPopMatrix();
}
void GLAnalyzer::drawCube()
{
void GLAnalyzer::drawCube() {
glPushMatrix();
glBegin(GL_POLYGON);
@ -287,12 +264,10 @@ void GLAnalyzer::drawCube()
glEnd();
glPopMatrix();
}
void GLAnalyzer::drawFrame()
{
void GLAnalyzer::drawFrame() {
glPushMatrix();
glBegin(GL_LINES);
// This is the top face
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);

View File

@ -27,15 +27,12 @@
*@author piggz
*/
typedef struct
{
typedef struct {
float level;
uint delay;
}
peak_tx;
} peak_tx;
class GLAnalyzer : public Analyzer::Base3D
{
class GLAnalyzer : public Analyzer::Base3D {
private:
std::vector<float> m_oldy;
std::vector<peak_tx> m_peaks;
@ -47,6 +44,7 @@ private:
void drawFloor();
GLfloat x, y;
public:
GLAnalyzer(QWidget*);
~GLAnalyzer();

View File

@ -27,10 +27,7 @@
#include <qimage.h>
#include <sys/time.h>
GLAnalyzer2::GLAnalyzer2( QWidget *parent ):
Analyzer::Base3D(parent, 15)
{
GLAnalyzer2::GLAnalyzer2(QWidget* parent) : Analyzer::Base3D(parent, 15) {
// initialize openGL context before managing GL calls
makeCurrent();
loadTexture(locate("data", "amarok/data/dot.png"), dotTexture);
@ -43,15 +40,13 @@ Analyzer::Base3D(parent, 15)
frame.rotDegrees = 0.0;
}
GLAnalyzer2::~GLAnalyzer2()
{
GLAnalyzer2::~GLAnalyzer2() {
freeTexture(dotTexture);
freeTexture(w1Texture);
freeTexture(w2Texture);
}
void GLAnalyzer2::initializeGL()
{
void GLAnalyzer2::initializeGL() {
// Set a smooth shade model
glShadeModel(GL_SMOOTH);
@ -68,8 +63,7 @@ void GLAnalyzer2::initializeGL()
glClear(GL_COLOR_BUFFER_BIT);
}
void GLAnalyzer2::resizeGL( int w, int h )
{
void GLAnalyzer2::resizeGL(int w, int h) {
// Setup screen. We're going to manually do the perspective projection
glViewport(0, 0, (GLint)w, (GLint)h);
glMatrixMode(GL_PROJECTION);
@ -77,9 +71,7 @@ void GLAnalyzer2::resizeGL( int w, int h )
glOrtho(-10.0f, 10.0f, -10.0f, 10.0f, -5.0f, 5.0f);
// Get the aspect ratio of the screen to draw 'cicular' particles
float ratio = (float)w / (float)h,
eqPixH = 60,
eqPixW = 80;
float ratio = (float)w / (float)h, eqPixH = 60, eqPixW = 80;
if (ratio >= (4.0 / 3.0)) {
unitX = 10.0 / (eqPixH * ratio);
unitY = 10.0 / eqPixH;
@ -94,45 +86,34 @@ void GLAnalyzer2::resizeGL( int w, int h )
show.timeStamp = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
void GLAnalyzer2::paused()
{
analyze( Scope() );
}
void GLAnalyzer2::paused() { analyze(Scope()); }
void GLAnalyzer2::analyze( const Scope &s )
{
void GLAnalyzer2::analyze(const Scope& s) {
bool haveNoData = s.empty();
// if we're going into pause mode, clear timers.
if ( !show.paused && haveNoData )
show.pauseTimer = 0.0;
if (!show.paused && haveNoData) show.pauseTimer = 0.0;
// if we have got data, interpolate it (asking myself why I'm doing it here..)
if ( !(show.paused = haveNoData) )
{
int bands = s.size(),
lowbands = bands / 4,
hibands = bands / 3,
midbands = bands - lowbands - hibands; Q_UNUSED( midbands );
float currentEnergy = 0,
currentMeanBand = 0,
maxValue = 0;
for ( int i = 0; i < bands; i++ )
{
if (!(show.paused = haveNoData)) {
int bands = s.size(), lowbands = bands / 4, hibands = bands / 3,
midbands = bands - lowbands - hibands;
Q_UNUSED(midbands);
float currentEnergy = 0, currentMeanBand = 0, maxValue = 0;
for (int i = 0; i < bands; i++) {
float value = s[i];
currentEnergy += value;
currentMeanBand += (float)i * value;
if ( value > maxValue )
maxValue = value;
if (value > maxValue) maxValue = value;
}
frame.silence = currentEnergy < 0.001;
if ( !frame.silence )
{
if (!frame.silence) {
frame.meanBand = 100.0 * currentMeanBand / (currentEnergy * bands);
currentEnergy = 100.0 * currentEnergy / (float)bands;
frame.dEnergy = currentEnergy - frame.energy;
frame.energy = currentEnergy;
// printf( "%d [%f :: %f ]\t%f \n", bands, frame.energy, frame.meanBand, maxValue );
// printf( "%d [%f :: %f ]\t%f \n", bands, frame.energy,
// frame.meanBand, maxValue );
} else
frame.energy = 0.0;
}
@ -141,8 +122,7 @@ void GLAnalyzer2::analyze( const Scope &s )
updateGL();
}
void GLAnalyzer2::paintGL()
{
void GLAnalyzer2::paintGL() {
// Compute the dT since the last call to paintGL and update timings
timeval tv;
gettimeofday(&tv, nullptr);
@ -171,10 +151,8 @@ void GLAnalyzer2::paintGL()
glEnable(GL_TEXTURE_2D);
float alphaN = show.paused ? 0.2 : (frame.energy / 10.0),
alphaP = show.paused ? 1.0 : (1 - frame.energy / 20.0);
if ( alphaN > 1.0 )
alphaN = 1.0;
if ( alphaP < 0.1 )
alphaP = 0.1;
if (alphaN > 1.0) alphaN = 1.0;
if (alphaP < 0.1) alphaP = 0.1;
glBindTexture(GL_TEXTURE_2D, w2Texture);
setTextureMatrix(show.rotDegrees, 0.707 * alphaP);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
@ -211,12 +189,9 @@ void GLAnalyzer2::paintGL()
frame.rotDegrees += 80.0 * show.dT;
// handle the 'pause' status
if ( show.paused )
{
if ( show.pauseTimer > 0.5 )
{
if ( show.pauseTimer > 0.6 )
show.pauseTimer -= 0.6;
if (show.paused) {
if (show.pauseTimer > 0.5) {
if (show.pauseTimer > 0.6) show.pauseTimer -= 0.6;
drawFullDot(0.0f, 0.4f, 0.8f, 1.0f);
drawFullDot(0.0f, 0.4f, 0.8f, 1.0f);
}
@ -246,14 +221,9 @@ void GLAnalyzer2::paintGL()
glEnd();
}
void GLAnalyzer2::drawDot( float x, float y, float size )
{
float sizeX = size * unitX,
sizeY = size * unitY,
pLeft = x - sizeX,
pTop = y + sizeY,
pRight = x + sizeX,
pBottom = y - sizeY;
void GLAnalyzer2::drawDot(float x, float y, float size) {
float sizeX = size * unitX, sizeY = size * unitY, pLeft = x - sizeX,
pTop = y + sizeY, pRight = x + sizeX, pBottom = y - sizeY;
glTexCoord2f(0, 0); // Bottom Left
glVertex2f(pLeft, pBottom);
glTexCoord2f(0, 1); // Top Left
@ -264,8 +234,7 @@ void GLAnalyzer2::drawDot( float x, float y, float size )
glVertex2f(pRight, pBottom);
}
void GLAnalyzer2::drawFullDot( float r, float g, float b, float a )
{
void GLAnalyzer2::drawFullDot(float r, float g, float b, float a) {
glBindTexture(GL_TEXTURE_2D, dotTexture);
glEnable(GL_TEXTURE_2D);
glColor4f(r, g, b, a);
@ -282,13 +251,10 @@ void GLAnalyzer2::drawFullDot( float r, float g, float b, float a )
glDisable(GL_TEXTURE_2D);
}
void GLAnalyzer2::setTextureMatrix( float rot, float scale )
{
void GLAnalyzer2::setTextureMatrix(float rot, float scale) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
if ( rot != 0.0 || scale != 0.0 )
{
if (rot != 0.0 || scale != 0.0) {
glTranslatef(0.5f, 0.5f, 0.0f);
glRotatef(rot, 0.0f, 0.0f, 1.0f);
glScalef(scale, scale, 1.0f);
@ -297,36 +263,30 @@ void GLAnalyzer2::setTextureMatrix( float rot, float scale )
glMatrixMode(GL_MODELVIEW);
}
bool GLAnalyzer2::loadTexture( QString fileName, GLuint& textureID )
{
bool GLAnalyzer2::loadTexture(QString fileName, GLuint& textureID) {
// reset texture ID to the default EMPTY value
textureID = 0;
// load image
QImage tmp;
if ( !tmp.load( fileName ) )
return false;
if (!tmp.load(fileName)) return false;
// convert it to suitable format (flipped RGBA)
QImage texture = QGLWidget::convertToGLFormat(tmp);
if ( texture.isNull() )
return false;
if (texture.isNull()) return false;
// get texture number and bind loaded image to that texture
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, 4, texture.width(), texture.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits() );
glTexImage2D(GL_TEXTURE_2D, 0, 4, texture.width(), texture.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
return true;
}
void GLAnalyzer2::freeTexture( GLuint & textureID )
{
if ( textureID > 0 )
glDeleteTextures( 1, &textureID );
void GLAnalyzer2::freeTexture(GLuint& textureID) {
if (textureID > 0) glDeleteTextures(1, &textureID);
textureID = 0;
}

View File

@ -25,9 +25,7 @@
#include <qstring.h>
#include <qptrlist.h>
class GLAnalyzer2 : public Analyzer::Base3D
{
class GLAnalyzer2 : public Analyzer::Base3D {
public:
GLAnalyzer2(QWidget*);
~GLAnalyzer2();

View File

@ -28,30 +28,32 @@
#include <sys/time.h>
#ifndef HAVE_FABSF
inline float fabsf(float f)
{
return f < 0.f ? -f : f;
}
inline float fabsf(float f) { return f < 0.f ? -f : f; }
#endif
class Ball
{
class Ball {
public:
Ball() : x( drand48() - drand48() ), y( 1 - 2.0 * drand48() ),
z( drand48() ), vx( 0.0 ), vy( 0.0 ), vz( 0.0 ),
Ball()
: x(drand48() - drand48()),
y(1 - 2.0 * drand48()),
z(drand48()),
vx(0.0),
vy(0.0),
vz(0.0),
mass(0.01 + drand48() / 10.0)
//,color( (float[3]) { 0.0, drand48()*0.5, 0.7 + drand48() * 0.3 } )
{
//this is because GCC < 3.3 can't compile the above line, we aren't sure why though
color[0] = 0.0; color[1] = drand48()*0.5; color[2] = 0.7 + drand48() * 0.3;
// this is because GCC < 3.3 can't compile the above line, we aren't sure
// why though
color[0] = 0.0;
color[1] = drand48() * 0.5;
color[2] = 0.7 + drand48() * 0.3;
};
float x, y, z, vx, vy, vz, mass;
float color[3];
void updatePhysics( float dT )
{
void updatePhysics(float dT) {
x += vx * dT; // position
y += vy * dT; // position
z += vz * dT; // position
@ -66,21 +68,18 @@ class Ball
}
};
class Paddle
{
class Paddle {
public:
Paddle( float xPos ) : onLeft( xPos < 0 ), mass( 1.0 ),
X( xPos ), x( xPos ), vx( 0.0 ) {};
Paddle(float xPos)
: onLeft(xPos < 0), mass(1.0), X(xPos), x(xPos), vx(0.0) {};
void updatePhysics( float dT )
{
void updatePhysics(float dT) {
x += vx * dT; // posision
vx += (1300 * (X - x) / mass) * dT; // elasticity
vx *= (1 - 4.0 * dT); // air friction
}
void renderGL()
{
void renderGL() {
glBegin(GL_TRIANGLE_STRIP);
glColor3f(0.0f, 0.1f, 0.3f);
glVertex3f(x, -1.0f, 0.0);
@ -91,17 +90,13 @@ class Paddle
glEnd();
}
void bounce( Ball * ball )
{
if ( onLeft && ball->x < x )
{
void bounce(Ball* ball) {
if (onLeft && ball->x < x) {
ball->vx = vx * mass / (mass + ball->mass) + fabsf(ball->vx);
ball->vy = (drand48() - drand48()) * 1.8;
ball->vz = (drand48() - drand48()) * 0.9;
ball->x = x;
}
else if ( !onLeft && ball->x > x )
{
} else if (!onLeft && ball->x > x) {
ball->vx = vx * mass / (mass + ball->mass) - fabsf(ball->vx);
ball->vy = (drand48() - drand48()) * 1.8;
ball->vz = (drand48() - drand48()) * 0.9;
@ -109,10 +104,8 @@ class Paddle
}
}
void impulse( float strength )
{
if ( (onLeft && strength > vx) || (!onLeft && strength < vx) )
vx += strength;
void impulse(float strength) {
if ((onLeft && strength > vx) || (!onLeft && strength < vx)) vx += strength;
}
private:
@ -120,10 +113,7 @@ class Paddle
float mass, X, x, vx;
};
GLAnalyzer3::GLAnalyzer3( QWidget *parent ):
Analyzer::Base3D(parent, 15)
{
GLAnalyzer3::GLAnalyzer3(QWidget* parent) : Analyzer::Base3D(parent, 15) {
// initialize openGL context before managing GL calls
makeCurrent();
loadTexture(locate("data", "amarok/data/ball.png"), ballTexture);
@ -132,8 +122,7 @@ Analyzer::Base3D(parent, 15)
balls.setAutoDelete(true);
leftPaddle = new Paddle(-1.0);
rightPaddle = new Paddle(1.0);
for ( int i = 0; i < NUMBER_OF_BALLS; i++ )
balls.append( new Ball() );
for (int i = 0; i < NUMBER_OF_BALLS; i++) balls.append(new Ball());
show.colorK = 0.0;
show.gridScrollK = 0.0;
@ -146,8 +135,7 @@ Analyzer::Base3D(parent, 15)
frame.dEnergy = 0.0;
}
GLAnalyzer3::~GLAnalyzer3()
{
GLAnalyzer3::~GLAnalyzer3() {
freeTexture(ballTexture);
freeTexture(gridTexture);
delete leftPaddle;
@ -155,8 +143,7 @@ GLAnalyzer3::~GLAnalyzer3()
balls.clear();
}
void GLAnalyzer3::initializeGL()
{
void GLAnalyzer3::initializeGL() {
// Set a smooth shade model
glShadeModel(GL_SMOOTH);
@ -170,8 +157,7 @@ void GLAnalyzer3::initializeGL()
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
void GLAnalyzer3::resizeGL( int w, int h )
{
void GLAnalyzer3::resizeGL(int w, int h) {
// Setup screen. We're going to manually do the perspective projection
glViewport(0, 0, (GLint)w, (GLint)h);
glMatrixMode(GL_PROJECTION);
@ -194,13 +180,9 @@ void GLAnalyzer3::resizeGL( int w, int h )
show.timeStamp = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
void GLAnalyzer3::paused()
{
analyze( Scope() );
}
void GLAnalyzer3::paused() { analyze(Scope()); }
void GLAnalyzer3::analyze( const Scope &s )
{
void GLAnalyzer3::analyze(const Scope& s) {
// compute the dTime since the last call
timeval tv;
gettimeofday(&tv, nullptr);
@ -209,24 +191,19 @@ void GLAnalyzer3::analyze( const Scope &s )
show.timeStamp = currentTime;
// compute energy integrating frame's spectrum
if ( !s.empty() )
{
if (!s.empty()) {
int bands = s.size();
float currentEnergy = 0,
maxValue = 0;
float currentEnergy = 0, maxValue = 0;
// integrate spectrum -> energy
for ( int i = 0; i < bands; i++ )
{
for (int i = 0; i < bands; i++) {
float value = s[i];
currentEnergy += value;
if ( value > maxValue )
maxValue = value;
if (value > maxValue) maxValue = value;
}
currentEnergy *= 100.0 / (float)bands;
// emulate a peak detector: currentEnergy -> peakEnergy (3tau = 30 seconds)
show.peakEnergy = 1.0 + (show.peakEnergy - 1.0) * exp(-show.dT / 10.0);
if ( currentEnergy > show.peakEnergy )
show.peakEnergy = currentEnergy;
if (currentEnergy > show.peakEnergy) show.peakEnergy = currentEnergy;
// check for silence
frame.silence = currentEnergy < 0.001;
// normalize frame energy against peak energy and compute frame stats
@ -240,14 +217,11 @@ void GLAnalyzer3::analyze( const Scope &s )
updateGL();
}
void GLAnalyzer3::paintGL()
{
void GLAnalyzer3::paintGL() {
// limit max dT to 0.05 and update color and scroll constants
if ( show.dT > 0.05 )
show.dT = 0.05;
if (show.dT > 0.05) show.dT = 0.05;
show.colorK += show.dT * 0.4;
if ( show.colorK > 3.0 )
show.colorK -= 3.0;
if (show.colorK > 3.0) show.colorK -= 3.0;
show.gridScrollK += 0.2 * show.peakEnergy * show.dT;
// Switch to MODEL matrix and clear screen
@ -256,8 +230,7 @@ void GLAnalyzer3::paintGL()
glClear(GL_COLOR_BUFFER_BIT);
// Draw scrolling grid
if ( (show.gridEnergyK > 0.05) || (!frame.silence && frame.dEnergy < -0.3) )
{
if ((show.gridEnergyK > 0.05) || (!frame.silence && frame.dEnergy < -0.3)) {
show.gridEnergyK *= exp(-show.dT / 0.1);
if (-frame.dEnergy > show.gridEnergyK)
show.gridEnergyK = -frame.dEnergy * 2.0;
@ -290,26 +263,19 @@ void GLAnalyzer3::paintGL()
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
Ball* ball = balls.first();
for ( ; ball; ball = balls.next() )
{
float color[3],
angle = show.colorK;
for (; ball; ball = balls.next()) {
float color[3], angle = show.colorK;
// Rotate the color based on 'angle' value [0,3)
if ( angle < 1.0 )
{
if (angle < 1.0) {
color[0] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
color[1] = ball->color[1] * (1 - angle) + ball->color[2] * angle;
color[2] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
}
else if ( angle < 2.0 )
{
} else if (angle < 2.0) {
angle -= 1.0;
color[0] = ball->color[1] * (1 - angle) + ball->color[2] * angle;
color[1] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
color[2] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
}
else
{
} else {
angle -= 2.0;
color[0] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
color[1] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
@ -330,22 +296,16 @@ void GLAnalyzer3::paintGL()
// Update physics of paddles
leftPaddle->updatePhysics(show.dT);
rightPaddle->updatePhysics(show.dT);
if ( !frame.silence )
{
if (!frame.silence) {
leftPaddle->impulse(frame.energy * 3.0 + frame.dEnergy * 6.0);
rightPaddle->impulse(-frame.energy * 3.0 - frame.dEnergy * 6.0);
}
}
void GLAnalyzer3::drawDot3s( float x, float y, float z, float size )
{
void GLAnalyzer3::drawDot3s(float x, float y, float z, float size) {
// Circular XY dot drawing functions
float sizeX = size * unitX,
sizeY = size * unitY,
pXm = x - sizeX,
pXM = x + sizeX,
pYm = y - sizeY,
pYM = y + sizeY;
float sizeX = size * unitX, sizeY = size * unitY, pXm = x - sizeX,
pXM = x + sizeX, pYm = y - sizeY, pYM = y + sizeY;
// Draw the Dot
glBegin(GL_QUADS);
glTexCoord2f(0, 0); // Bottom Left
@ -359,13 +319,9 @@ void GLAnalyzer3::drawDot3s( float x, float y, float z, float size )
glEnd();
// Shadow XZ drawing functions
float sizeZ = size / 10.0,
pZm = z - sizeZ,
pZM = z + sizeZ,
currentColor[4];
float sizeZ = size / 10.0, pZm = z - sizeZ, pZM = z + sizeZ, currentColor[4];
glGetFloatv(GL_CURRENT_COLOR, currentColor);
float alpha = currentColor[3],
topSide = (y + 1) / 4,
float alpha = currentColor[3], topSide = (y + 1) / 4,
bottomSide = (1 - y) / 4;
// Draw the top shadow
currentColor[3] = topSide * topSide * alpha;
@ -395,8 +351,7 @@ void GLAnalyzer3::drawDot3s( float x, float y, float z, float size )
glEnd();
}
void GLAnalyzer3::drawHFace( float y )
{
void GLAnalyzer3::drawHFace(float y) {
glBegin(GL_TRIANGLE_STRIP);
glColor3f(0.0f, 0.1f, 0.2f);
glVertex3f(-1.0f, y, 0.0);
@ -407,17 +362,14 @@ void GLAnalyzer3::drawHFace( float y )
glEnd();
}
void GLAnalyzer3::drawScrollGrid( float scroll, float color[4] )
{
if ( !gridTexture )
return;
void GLAnalyzer3::drawScrollGrid(float scroll, float color[4]) {
if (!gridTexture) return;
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.0, -scroll, 0.0);
glMatrixMode(GL_MODELVIEW);
float backColor[4] = {1.0, 1.0, 1.0, 0.0};
for ( int i = 0; i < 3; i++ )
backColor[ i ] = color[ i ];
for (int i = 0; i < 3; i++) backColor[i] = color[i];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glEnable(GL_BLEND);
@ -445,35 +397,30 @@ void GLAnalyzer3::drawScrollGrid( float scroll, float color[4] )
glMatrixMode(GL_MODELVIEW);
}
bool GLAnalyzer3::loadTexture( QString fileName, GLuint& textureID )
{
bool GLAnalyzer3::loadTexture(QString fileName, GLuint& textureID) {
// reset texture ID to the default EMPTY value
textureID = 0;
// load image
QImage tmp;
if ( !tmp.load( fileName ) )
return false;
if (!tmp.load(fileName)) return false;
// convert it to suitable format (flipped RGBA)
QImage texture = QGLWidget::convertToGLFormat(tmp);
if ( texture.isNull() )
return false;
if (texture.isNull()) return false;
// get texture number and bind loaded image to that texture
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, 4, texture.width(), texture.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits() );
glTexImage2D(GL_TEXTURE_2D, 0, 4, texture.width(), texture.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
return true;
}
void GLAnalyzer3::freeTexture( GLuint& textureID )
{
if ( textureID > 0 )
glDeleteTextures( 1, &textureID );
void GLAnalyzer3::freeTexture(GLuint& textureID) {
if (textureID > 0) glDeleteTextures(1, &textureID);
textureID = 0;
}

View File

@ -29,8 +29,7 @@ class QWidget;
class Ball;
class Paddle;
class GLAnalyzer3 : public Analyzer::Base3D
{
class GLAnalyzer3 : public Analyzer::Base3D {
public:
GLAnalyzer3(QWidget*);
~GLAnalyzer3();

View File

@ -26,7 +26,6 @@
const char* NyanCatAnalyzer::kName = "Nyanalyzer cat";
const float NyanCatAnalyzer::kPixelScale = 0.02f;
NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent)
: Analyzer::Base(parent, 9),
cat_(":/nyancat.png"),
@ -36,24 +35,22 @@ NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent)
available_rainbow_width_(0),
px_per_frame_(0),
x_offset_(0),
background_brush_(QColor(0x0f, 0x43, 0x73))
{
background_brush_(QColor(0x0f, 0x43, 0x73)) {
memset(history_, 0, sizeof(history_));
for (int i = 0; i < kRainbowBands; ++i) {
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255),
kCatHeight/kRainbowBands,
Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin);
kCatHeight / kRainbowBands, Qt::SolidLine, Qt::FlatCap,
Qt::RoundJoin);
// pow constants computed so that
// | band_scale(0) | ~= .5 and | band_scale(5) | ~= 32
band_scale_[i] = -std::cos(M_PI * i / (kRainbowBands-1)) * 0.5 * std::pow(2.3, i);
band_scale_[i] =
-std::cos(M_PI * i / (kRainbowBands - 1)) * 0.5 * std::pow(2.3, i);
}
}
void NyanCatAnalyzer::transform(Scope& s) {
m_fht->spectrum(&s.front());
}
void NyanCatAnalyzer::transform(Scope& s) { m_fht->spectrum(&s.front()); }
void NyanCatAnalyzer::timerEvent(QTimerEvent* e) {
if (e->timerId() == timer_id_) {
@ -74,7 +71,8 @@ void NyanCatAnalyzer::resizeEvent(QResizeEvent* e) {
x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_;
}
void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_frame) {
void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
bool new_frame) {
// Discard the second half of the transform
const int scope_size = s.size() / 2;
@ -110,7 +108,8 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
const float top_of_cat = float(height()) / 2 - float(kCatHeight) / 2;
for (int band = 0; band < kRainbowBands; ++band) {
// Calculate the Y position of this band.
const float y = float(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat;
const float y =
float(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat;
// Add each point in the line.
for (int x = 0; x < kHistorySize; ++x) {
@ -132,27 +131,32 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
buffer_painter.setRenderHint(QPainter::Antialiasing);
for (int band = kRainbowBands - 1; band >= 0; --band) {
buffer_painter.setPen(colors_[band]);
buffer_painter.drawPolyline(&polyline[band*kHistorySize], kHistorySize);
buffer_painter.drawPolyline(&polyline[band*kHistorySize], kHistorySize);
buffer_painter.drawPolyline(&polyline[band * kHistorySize],
kHistorySize);
buffer_painter.drawPolyline(&polyline[band * kHistorySize],
kHistorySize);
}
} else {
const int last_buffer = current_buffer_;
current_buffer_ = (current_buffer_ + 1) % 2;
// We can just shuffle the buffer along a bit and draw the new frame's data.
// We can just shuffle the buffer along a bit and draw the new frame's
// data.
QPainter buffer_painter(&buffer_[current_buffer_]);
buffer_painter.setRenderHint(QPainter::Antialiasing);
buffer_painter.drawPixmap(0, 0, buffer_[last_buffer],
px_per_frame_, 0,
buffer_painter.drawPixmap(
0, 0, buffer_[last_buffer], px_per_frame_, 0,
x_offset_ + available_rainbow_width_ - px_per_frame_, 0);
buffer_painter.fillRect(x_offset_ + available_rainbow_width_ - px_per_frame_, 0,
buffer_painter.fillRect(
x_offset_ + available_rainbow_width_ - px_per_frame_, 0,
kCatWidth - kRainbowOverlap + px_per_frame_, height(),
background_brush_);
for (int band = kRainbowBands - 1; band >= 0; --band) {
buffer_painter.setPen(colors_[band]);
buffer_painter.drawPolyline(&polyline[(band+1)*kHistorySize - 3], 3);
buffer_painter.drawPolyline(&polyline[(band + 1) * kHistorySize - 3],
3);
}
}
}

View File

@ -60,8 +60,8 @@ private:
}
inline QRect CatDestRect() const {
return QRect(width() - kCatWidth, (height() - kCatHeight) / 2,
kCatWidth, kCatHeight);
return QRect(width() - kCatWidth, (height() - kCatHeight) / 2, kCatWidth,
kCatHeight);
}
inline QRect SleepingCatDestRect() const {

View File

@ -15,21 +15,14 @@
#include <QPainter>
const char* Sonogram::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Sonogram");
const char* Sonogram::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Sonogram");
Sonogram::Sonogram(QWidget *parent) :
Analyzer::Base(parent, 9)
{
}
Sonogram::Sonogram(QWidget* parent) : Analyzer::Base(parent, 9) {}
Sonogram::~Sonogram() {}
Sonogram::~Sonogram()
{
}
void Sonogram::resizeEvent(QResizeEvent *e)
{
void Sonogram::resizeEvent(QResizeEvent* e) {
QWidget::resizeEvent(e);
// only for gcc < 4.0
@ -41,9 +34,7 @@ void Sonogram::resizeEvent(QResizeEvent *e)
canvas_.fill(palette().color(QPalette::Background));
}
void Sonogram::analyze(QPainter& p, const Scope &s, bool new_frame)
{
void Sonogram::analyze(QPainter& p, const Scope& s, bool new_frame) {
int x = width() - 1;
QColor c;
@ -64,8 +55,7 @@ void Sonogram::analyze(QPainter& p, const Scope &s, bool new_frame)
canvas_painter.setPen(c);
canvas_painter.drawPoint(x, y--);
if (it < end)
++it;
if (it < end) ++it;
}
canvas_painter.end();
@ -73,18 +63,13 @@ void Sonogram::analyze(QPainter& p, const Scope &s, bool new_frame)
p.drawPixmap(0, 0, canvas_);
}
void Sonogram::transform(Scope &scope)
{
void Sonogram::transform(Scope& scope) {
float* front = static_cast<float*>(&scope.front());
m_fht->power2(front);
m_fht->scale(front, 1.0 / 256);
scope.resize(m_fht->size() / 2);
}
void Sonogram::demo(QPainter& p)
{
void Sonogram::demo(QPainter& p) {
analyze(p, Scope(m_fht->size(), 0), new_frame_);
}

View File

@ -20,8 +20,7 @@
@author Melchior FRANZ
*/
class Sonogram : public Analyzer::Base
{
class Sonogram : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE Sonogram(QWidget*);

View File

@ -12,44 +12,36 @@
#include "turbine.h"
const char* TurbineAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Turbine");
const char* TurbineAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Turbine");
void TurbineAnalyzer::analyze( QPainter& p, const Scope &scope, bool new_frame)
{
void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
float h;
const uint hd2 = height() / 2;
const uint MAX_HEIGHT = hd2 - 1;
for( uint i = 0, x = 0, y; i < BAND_COUNT; ++i, x += COLUMN_WIDTH+1 )
{
for (uint i = 0, x = 0, y; i < BAND_COUNT; ++i, x += COLUMN_WIDTH + 1) {
h = log10(scope[i] * 256.0) * F * 0.5;
if( h > MAX_HEIGHT )
h = MAX_HEIGHT;
if (h > MAX_HEIGHT) h = MAX_HEIGHT;
if( h > bar_height[i] )
{
if (h > bar_height[i]) {
bar_height[i] = h;
if( h > peak_height[i] )
{
if (h > peak_height[i]) {
peak_height[i] = h;
peak_speed[i] = 0.01;
}
else goto peak_handling;
}
else
{
if( bar_height[i] > 0.0 )
{
} else
goto peak_handling;
} else {
if (bar_height[i] > 0.0) {
bar_height[i] -= K_barHeight; // 1.4
if (bar_height[i] < 0.0) bar_height[i] = 0.0;
}
peak_handling:
if( peak_height[i] > 0.0 )
{
if (peak_height[i] > 0.0) {
peak_height[i] -= peak_speed[i];
peak_speed[i] *= F_peakSpeed; // 1.12
@ -58,7 +50,6 @@ void TurbineAnalyzer::analyze( QPainter& p, const Scope &scope, bool new_frame)
}
}
y = hd2 - uint(bar_height[i]);
p.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1);
p.drawPixmap(x + 1, hd2, barPixmap, 0, int(bar_height[i]), -1, -1);

View File

@ -11,8 +11,7 @@
#include "boomanalyzer.h"
class TurbineAnalyzer : public BoomAnalyzer
{
class TurbineAnalyzer : public BoomAnalyzer {
Q_OBJECT
public:
Q_INVOKABLE TurbineAnalyzer(QWidget* parent) : BoomAnalyzer(parent) {}

View File

@ -27,24 +27,21 @@ const char* Appearance::kBackgroundColor = "background-color";
const QPalette Appearance::kDefaultPalette = QPalette();
Appearance::Appearance(QObject* parent)
: QObject(parent)
{
Appearance::Appearance(QObject* parent) : QObject(parent) {
QSettings s;
s.beginGroup(kSettingsGroup);
QPalette p = QApplication::palette();
background_color_ = s.value(kBackgroundColor,
p.color(QPalette::WindowText)).value<QColor>();
foreground_color_ = s.value(kForegroundColor,
p.color(QPalette::Window)).value<QColor>();
background_color_ =
s.value(kBackgroundColor, p.color(QPalette::WindowText)).value<QColor>();
foreground_color_ =
s.value(kForegroundColor, p.color(QPalette::Window)).value<QColor>();
}
void Appearance::LoadUserTheme() {
QSettings s;
s.beginGroup(kSettingsGroup);
bool use_a_custom_color_set = s.value(kUseCustomColorSet).toBool();
if (!use_a_custom_color_set)
return;
if (!use_a_custom_color_set) return;
ChangeForegroundColor(foreground_color_);
ChangeBackgroundColor(background_color_);

View File

@ -69,8 +69,7 @@ Application::Application(QObject* parent)
moodbar_loader_(nullptr),
moodbar_controller_(nullptr),
network_remote_(nullptr),
network_remote_helper_(nullptr)
{
network_remote_helper_(nullptr) {
tag_reader_client_ = new TagReaderClient(this);
MoveToNewThread(tag_reader_client_);
tag_reader_client_->Start();
@ -111,7 +110,8 @@ Application::Application(QObject* parent)
MoveToNewThread(network_remote_);
// This must be before libraray_->Init();
// In the constructor the helper waits for the signal PlaylistManagerInitialized
// In the constructor the helper waits for the signal
// PlaylistManagerInitialized
// to start the remote. Without the playlist manager clementine can
// crash when a client connects before the manager is initialized!
network_remote_helper_ = new NetworkRemoteHelper(this);
@ -125,19 +125,14 @@ Application::~Application() {
// It's important that the device manager is deleted before the database.
// Deleting the database deletes all objects that have been created in its
// thread, including some device library backends.
delete device_manager_; device_manager_ = nullptr;
delete device_manager_;
device_manager_ = nullptr;
foreach (QObject* object, objects_in_threads_) {
object->deleteLater();
}
foreach(QObject * object, objects_in_threads_) { object->deleteLater(); }
foreach (QThread* thread, threads_) {
thread->quit();
}
foreach(QThread * thread, threads_) { thread->quit(); }
foreach (QThread* thread, threads_) {
thread->wait();
}
foreach(QThread * thread, threads_) { thread->wait(); }
}
void Application::MoveToNewThread(QObject* object) {
@ -155,9 +150,7 @@ void Application::MoveToThread(QObject* object, QThread* thread) {
objects_in_threads_ << object;
}
void Application::AddError(const QString& message) {
emit ErrorAdded(message);
}
void Application::AddError(const QString& message) { emit ErrorAdded(message); }
QString Application::language_without_region() const {
const int underscore = language_name_.indexOf('_');
@ -171,13 +164,9 @@ LibraryBackend* Application::library_backend() const {
return library()->backend();
}
LibraryModel* Application::library_model() const {
return library()->model();
}
LibraryModel* Application::library_model() const { return library()->model(); }
void Application::ReloadSettings() {
emit SettingsChanged();
}
void Application::ReloadSettings() { emit SettingsChanged(); }
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) {
emit SettingsDialogRequested(page);

View File

@ -47,7 +47,6 @@ class PodcastUpdater;
class TagReaderClient;
class TaskManager;
class Application : public QObject {
Q_OBJECT
@ -58,7 +57,8 @@ public:
~Application();
const QString& language_name() const { return language_name_; }
// Same as language_name, but remove the region code at the end if there is one
// Same as language_name, but remove the region code at the end if there is
// one
QString language_without_region() const;
void set_language_name(const QString& name) { language_name_ = name; }
@ -83,7 +83,9 @@ public:
MoodbarLoader* moodbar_loader() const { return moodbar_loader_; }
MoodbarController* moodbar_controller() const { return moodbar_controller_; }
NetworkRemote* network_remote() const { return network_remote_; }
NetworkRemoteHelper* network_remote_helper() const { return network_remote_helper_; }
NetworkRemoteHelper* network_remote_helper() const {
return network_remote_helper_;
}
LibraryBackend* library_backend() const;
LibraryModel* library_model() const;

View File

@ -9,17 +9,14 @@
const char* BackgroundStreams::kSettingsGroup = "BackgroundStreams";
const char* BackgroundStreams::kHypnotoadUrl = "hypnotoad:///";
const char* BackgroundStreams::kRainUrl = "http://data.clementine-player.org/rainymood";
const char* BackgroundStreams::kRainUrl =
"http://data.clementine-player.org/rainymood";
const char* BackgroundStreams::kEnterpriseUrl = "enterprise:///";
BackgroundStreams::BackgroundStreams(EngineBase* engine, QObject* parent)
: QObject(parent),
engine_(engine) {
}
: QObject(parent), engine_(engine) {}
BackgroundStreams::~BackgroundStreams() {
SaveStreams();
}
BackgroundStreams::~BackgroundStreams() { SaveStreams(); }
void BackgroundStreams::LoadStreams() {
QSettings s;
@ -39,8 +36,7 @@ void BackgroundStreams::LoadStreams() {
int size = s.beginReadArray("streams");
for (int i = 0; i < size; ++i) {
s.setArrayIndex(i);
AddStream(s.value("name").toString(),
s.value("url").toUrl(),
AddStream(s.value("name").toString(), s.value("url").toUrl(),
s.value("volume").toInt());
}
@ -63,8 +59,7 @@ void BackgroundStreams::SaveStreams() {
s.endArray();
}
void BackgroundStreams::AddStream(const QString& name,
const QUrl& url,
void BackgroundStreams::AddStream(const QString& name, const QUrl& url,
int volume) {
if (streams_.contains(name)) {
return;
@ -134,7 +129,8 @@ bool BackgroundStreams::IsPlaying(const QString& name) const {
void BackgroundStreams::AddAction(const QString& name, QAction* action) {
if (!streams_.contains(name)) {
qLog(Error) << "Tried to add action for stream" << name << "which doesn't exist";
qLog(Error) << "Tried to add action for stream" << name
<< "which doesn't exist";
return;
}

View File

@ -9,12 +9,9 @@ template <typename T, typename D>
class BoundFutureWatcher : public QFutureWatcher<T>, boost::noncopyable {
public:
BoundFutureWatcher(const D& data, QObject* parent = 0)
: QFutureWatcher<T>(parent),
data_(data) {
}
: QFutureWatcher<T>(parent), data_(data) {}
~BoundFutureWatcher() {
}
~BoundFutureWatcher() {}
const D& data() const { return data_; }

View File

@ -36,8 +36,7 @@ public:
int cache_duration_secs)
: settings_group_(settings_group),
name_(name),
cache_duration_secs_(cache_duration_secs) {
}
cache_duration_secs_(cache_duration_secs) {}
void Load() {
QSettings s;
@ -76,12 +75,11 @@ public:
bool IsStale() const {
return last_updated_.isNull() ||
last_updated_.secsTo(QDateTime::currentDateTime()) > cache_duration_secs_;
last_updated_.secsTo(QDateTime::currentDateTime()) >
cache_duration_secs_;
}
void Sort() {
qSort(data_);
}
void Sort() { qSort(data_); }
const ListType& Data() const { return data_; }
operator ListType() const { return data_; }

View File

@ -28,7 +28,6 @@
#include <QCoreApplication>
#include <QFileInfo>
const char* CommandlineOptions::kHelpText =
"%1: clementine [%2] [%3]\n"
"\n"
@ -62,8 +61,7 @@ const char* CommandlineOptions::kHelpText =
" --log-levels <levels> %29\n"
" --version %30\n";
const char* CommandlineOptions::kVersionText =
"Clementine %1";
const char* CommandlineOptions::kVersionText = "Clementine %1";
CommandlineOptions::CommandlineOptions(int argc, char** argv)
: argc_(argc),
@ -77,8 +75,7 @@ CommandlineOptions::CommandlineOptions(int argc, char** argv)
play_track_at_(-1),
show_osd_(false),
toggle_pretty_osd_(false),
log_levels_(logging::kDefaultLogLevels)
{
log_levels_(logging::kDefaultLogLevels) {
#ifdef Q_OS_DARWIN
// Remove -psn_xxx option that Mac passes when opened from Finder.
RemoveArg("-psn", 1);
@ -104,7 +101,6 @@ void CommandlineOptions::RemoveArg(const QString& starts_with, int count) {
bool CommandlineOptions::Parse() {
static const struct option kOptions[] = {
{"help", no_argument, 0, 'h'},
{"play", no_argument, 0, 'p'},
{"play-pause", no_argument, 0, 't'},
{"pause", no_argument, 0, 'u'},
@ -113,14 +109,12 @@ bool CommandlineOptions::Parse() {
{"next", no_argument, 0, 'f'},
{"volume", required_argument, 0, 'v'},
{"volume-up", no_argument, 0, VolumeUp},
{"volume-down", no_argument, 0, VolumeDown},
{"volume-increase-by", required_argument, 0, VolumeIncreaseBy},
{"volume-decrease-by", required_argument, 0, VolumeDecreaseBy},
{"seek-to", required_argument, 0, SeekTo},
{"seek-by", required_argument, 0, SeekBy},
{"restart-or-previous", no_argument, 0, RestartOrPrevious},
{"append", no_argument, 0, 'a'},
{"load", no_argument, 0, 'l'},
{"play-track", required_argument, 0, 'k'},
@ -131,9 +125,7 @@ bool CommandlineOptions::Parse() {
{"verbose", no_argument, 0, Verbose},
{"log-levels", required_argument, 0, LogLevels},
{"version", no_argument, 0, Version},
{0, 0, 0, 0}
};
{0, 0, 0, 0}};
// Parse the arguments
bool ok = false;
@ -141,62 +133,97 @@ bool CommandlineOptions::Parse() {
int c = getopt_long(argc_, argv_, "hptusrfv:alk:oyg:", kOptions, nullptr);
// End of the options
if (c == -1)
break;
if (c == -1) break;
switch (c) {
case 'h': {
QString translated_help_text = QString(kHelpText).arg(
tr("Usage"), tr("options"), tr("URL(s)"), tr("Player options"),
QString translated_help_text =
QString(kHelpText)
.arg(tr("Usage"), tr("options"), tr("URL(s)"),
tr("Player options"),
tr("Start the playlist currently playing"),
tr("Play if stopped, pause if playing"),
tr("Pause playback"),
tr("Stop playback"),
tr("Skip backwards in playlist")).arg(
tr("Skip forwards in playlist"),
tr("Pause playback"), tr("Stop playback"),
tr("Skip backwards in playlist"))
.arg(tr("Skip forwards in playlist"),
tr("Set the volume to <value> percent"),
tr("Increase the volume by 4%"),
tr("Decrease the volume by 4%"),
tr("Increase the volume by <value> percent"),
tr("Decrease the volume by <value> percent")).arg(
tr("Seek the currently playing track to an absolute position"),
tr("Seek the currently playing track by a relative amount"),
tr("Restart the track, or play the previous track if within 8 seconds of start."),
tr("Decrease the volume by <value> percent"))
.arg(tr("Seek the currently playing track to an absolute "
"position"),
tr("Seek the currently playing track by a relative "
"amount"),
tr("Restart the track, or play the previous track if "
"within 8 seconds of start."),
tr("Playlist options"),
tr("Append files/URLs to the playlist"),
tr("Loads files/URLs, replacing current playlist"),
tr("Play the <n>th track in the playlist")).arg(
tr("Other options"),
tr("Display the on-screen-display"),
tr("Play the <n>th track in the playlist"))
.arg(tr("Other options"), tr("Display the on-screen-display"),
tr("Toggle visibility for the pretty on-screen-display"),
tr("Change the language"),
tr("Equivalent to --log-levels *:1"),
tr("Equivalent to --log-levels *:3"),
tr("Comma separated list of class:level, level is 0-3")).arg(
tr("Print out version information"));
tr("Comma separated list of class:level, level is 0-3"))
.arg(tr("Print out version information"));
std::cout << translated_help_text.toLocal8Bit().constData();
return false;
}
case 'p': player_action_ = Player_Play; break;
case 't': player_action_ = Player_PlayPause; break;
case 'u': player_action_ = Player_Pause; break;
case 's': player_action_ = Player_Stop; break;
case 'r': player_action_ = Player_Previous; break;
case 'f': player_action_ = Player_Next; break;
case 'a': url_list_action_ = UrlList_Append; break;
case 'l': url_list_action_ = UrlList_Load; break;
case 'o': show_osd_ = true; break;
case 'y': toggle_pretty_osd_ = true; break;
case 'g': language_ = QString(optarg); break;
case VolumeUp: volume_modifier_ = +4; break;
case VolumeDown: volume_modifier_ = -4; break;
case Quiet: log_levels_ = "1"; break;
case Verbose: log_levels_ = "3"; break;
case LogLevels: log_levels_ = QString(optarg); break;
case 'p':
player_action_ = Player_Play;
break;
case 't':
player_action_ = Player_PlayPause;
break;
case 'u':
player_action_ = Player_Pause;
break;
case 's':
player_action_ = Player_Stop;
break;
case 'r':
player_action_ = Player_Previous;
break;
case 'f':
player_action_ = Player_Next;
break;
case 'a':
url_list_action_ = UrlList_Append;
break;
case 'l':
url_list_action_ = UrlList_Load;
break;
case 'o':
show_osd_ = true;
break;
case 'y':
toggle_pretty_osd_ = true;
break;
case 'g':
language_ = QString(optarg);
break;
case VolumeUp:
volume_modifier_ = +4;
break;
case VolumeDown:
volume_modifier_ = -4;
break;
case Quiet:
log_levels_ = "1";
break;
case Verbose:
log_levels_ = "3";
break;
case LogLevels:
log_levels_ = QString(optarg);
break;
case Version: {
QString version_text = QString(kVersionText).arg(CLEMENTINE_VERSION_DISPLAY);
QString version_text =
QString(kVersionText).arg(CLEMENTINE_VERSION_DISPLAY);
std::cout << version_text.toLocal8Bit().constData() << std::endl;
std::exit(0);
}
@ -254,15 +281,10 @@ bool CommandlineOptions::Parse() {
}
bool CommandlineOptions::is_empty() const {
return player_action_ == Player_None &&
set_volume_ == -1 &&
volume_modifier_ == 0 &&
seek_to_ == -1 &&
seek_by_ == 0 &&
play_track_at_ == -1 &&
show_osd_ == false &&
toggle_pretty_osd_ == false &&
urls_.isEmpty();
return player_action_ == Player_None && set_volume_ == -1 &&
volume_modifier_ == 0 && seek_to_ == -1 && seek_by_ == 0 &&
play_track_at_ == -1 && show_osd_ == false &&
toggle_pretty_osd_ == false && urls_.isEmpty();
}
QByteArray CommandlineOptions::Serialize() const {
@ -290,17 +312,9 @@ QString CommandlineOptions::tr(const char *source_text) {
}
QDataStream& operator<<(QDataStream& s, const CommandlineOptions& a) {
s << qint32(a.player_action_)
<< qint32(a.url_list_action_)
<< a.set_volume_
<< a.volume_modifier_
<< a.seek_to_
<< a.seek_by_
<< a.play_track_at_
<< a.show_osd_
<< a.urls_
<< a.log_levels_
<< a.toggle_pretty_osd_;
s << qint32(a.player_action_) << qint32(a.url_list_action_) << a.set_volume_
<< a.volume_modifier_ << a.seek_to_ << a.seek_by_ << a.play_track_at_
<< a.show_osd_ << a.urls_ << a.log_levels_ << a.toggle_pretty_osd_;
return s;
}
@ -308,17 +322,9 @@ QDataStream& operator<<(QDataStream& s, const CommandlineOptions& a) {
QDataStream& operator>>(QDataStream& s, CommandlineOptions& a) {
quint32 player_action = 0;
quint32 url_list_action = 0;
s >> player_action
>> url_list_action
>> a.set_volume_
>> a.volume_modifier_
>> a.seek_to_
>> a.seek_by_
>> a.play_track_at_
>> a.show_osd_
>> a.urls_
>> a.log_levels_
>> a.toggle_pretty_osd_;
s >> player_action >> url_list_action >> a.set_volume_ >>
a.volume_modifier_ >> a.seek_to_ >> a.seek_by_ >> a.play_track_at_ >>
a.show_osd_ >> a.urls_ >> a.log_levels_ >> a.toggle_pretty_osd_;
a.player_action_ = CommandlineOptions::PlayerAction(player_action);
a.url_list_action_ = CommandlineOptions::UrlListAction(url_list_action);

View File

@ -34,10 +34,7 @@ class CommandlineOptions {
// Don't change the values or order, these get serialised and sent to
// possibly a different version of Clementine
enum UrlListAction {
UrlList_Append = 0,
UrlList_Load = 1,
};
enum UrlListAction { UrlList_Append = 0, UrlList_Load = 1, };
enum PlayerAction {
Player_None = 0,
Player_Play = 1,
@ -90,7 +87,6 @@ class CommandlineOptions {
void RemoveArg(const QString& starts_with, int count);
private:
int argc_;
char** argv_;

View File

@ -35,8 +35,8 @@
#include "third_party/lss/linux_syscall_support.h"
#endif
const char* CrashSender::kUploadURL = "http://crashes.clementine-player.org/getuploadurl";
const char* CrashSender::kUploadURL =
"http://crashes.clementine-player.org/getuploadurl";
const char* CrashReporting::kSendCrashReportOption = "--send-crash-report";
char* CrashReporting::sPath = nullptr;
@ -45,11 +45,9 @@ char* CrashReporting::sPath = nullptr;
CrashReporting::CrashReporting()
: handler_(new google_breakpad::ExceptionHandler(
QDir::tempPath().toLocal8Bit().constData(), nullptr,
CrashReporting::Handler, this, true)) {
}
CrashReporting::Handler, this, true)) {}
CrashReporting::~CrashReporting() {
}
CrashReporting::~CrashReporting() {}
bool CrashReporting::SendCrashReport(int argc, char** argv) {
if (argc != 4 || strcmp(argv[1], kSendCrashReportOption) != 0) {
@ -76,21 +74,21 @@ void CrashReporting::Print(const char* message) {
}
}
bool CrashReporting::Handler(const char* dump_path,
const char* minidump_id,
void* context,
bool succeeded) {
bool CrashReporting::Handler(const char* dump_path, const char* minidump_id,
void* context, bool succeeded) {
Print("Clementine has crashed! A crash report has been saved to:\n ");
Print(dump_path);
Print("/");
Print(minidump_id);
Print("\n\nPlease send this to the developers so they can fix the problem:\n"
Print(
"\n\nPlease send this to the developers so they can fix the problem:\n"
" http://code.google.com/p/clementine-player/issues/entry\n\n");
if (sPath) {
// We know the path to clementine, so exec it again to prompt the user to
// upload the report.
const char* argv[] = {sPath, kSendCrashReportOption, dump_path, minidump_id, nullptr};
const char* argv[] = {sPath, kSendCrashReportOption, dump_path, minidump_id,
nullptr};
sys_execv(sPath, argv);
}
@ -102,8 +100,7 @@ CrashSender::CrashSender(const QString& path)
: network_(new QNetworkAccessManager(this)),
path_(path),
file_(new QFile(path_, this)),
progress_(nullptr) {
}
progress_(nullptr) {}
bool CrashSender::Start() {
if (!file_->open(QIODevice::ReadOnly)) {
@ -112,9 +109,12 @@ bool CrashSender::Start() {
}
// No tr() here.
QMessageBox prompt(QMessageBox::Critical, "Clementine has crashed!", QString(
"A crash report has been created and saved to '%1'. With your permission "
"it can be automatically sent to our server so the developers can find "
QMessageBox prompt(QMessageBox::Critical, "Clementine has crashed!",
QString(
"A crash report has been created and saved to '%1'. "
"With your permission "
"it can be automatically sent to our server so the "
"developers can find "
"out what happened.").arg(path_));
prompt.addButton("Don't send", QMessageBox::RejectRole);
prompt.addButton("Send crash report", QMessageBox::AcceptRole);
@ -141,7 +141,8 @@ void CrashSender::RedirectFinished() {
reply->deleteLater();
QUrl url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QUrl url =
reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (!url.isValid()) {
progress_->close();
return;
@ -160,14 +161,17 @@ void CrashSender::RedirectFinished() {
}
QNetworkRequest req(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
req.setHeader(QNetworkRequest::ContentTypeHeader,
"multipart/form-data; boundary=" + boundary);
// Construct the multipart/form-data
QByteArray form_data;
form_data.reserve(file_data.size() + 1024);
form_data.append("--");
form_data.append(boundary);
form_data.append("\nContent-Disposition: form-data; name=\"data\"; filename=\"data.dmp\"\n");
form_data.append(
"\nContent-Disposition: form-data; name=\"data\"; "
"filename=\"data.dmp\"\n");
form_data.append("Content-Type: application/octet-stream\n\n");
form_data.append(file_data);
form_data.append("\n--");
@ -178,13 +182,12 @@ void CrashSender::RedirectFinished() {
// Upload the data
reply = network_->post(req, form_data);
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SLOT(UploadProgress(qint64)));
connect(reply, SIGNAL(uploadProgress(qint64, qint64)),
SLOT(UploadProgress(qint64)));
connect(reply, SIGNAL(finished()), progress_, SLOT(close()));
}
void CrashSender::UploadProgress(qint64 bytes) {
progress_->setValue(bytes);
}
void CrashSender::UploadProgress(qint64 bytes) { progress_->setValue(bytes); }
#else // HAVE_BREAKPAD
@ -192,17 +195,12 @@ namespace google_breakpad {
class ExceptionHandler {};
}
CrashReporting::CrashReporting() {
}
CrashReporting::CrashReporting() {}
CrashReporting::~CrashReporting() {
}
CrashReporting::~CrashReporting() {}
bool CrashReporting::SendCrashReport(int, char**) {
return false;
}
bool CrashReporting::SendCrashReport(int, char**) { return false; }
void CrashReporting::SetApplicationPath(const QString&) {
}
void CrashReporting::SetApplicationPath(const QString&) {}
#endif // HAVE_BREAKPAD

View File

@ -30,7 +30,6 @@ namespace google_breakpad {
class ExceptionHandler;
}
// Wraps google_breakpad::ExceptionHandler - while an instance of this class
// is alive crashes will be handled.
class CrashReporting {
@ -53,10 +52,8 @@ private:
static void Print(const char* message);
// Breakpad callback.
static bool Handler(const char* dump_path,
const char* minidump_id,
void* context,
bool succeeded);
static bool Handler(const char* dump_path, const char* minidump_id,
void* context, bool succeeded);
private:
Q_DISABLE_COPY(CrashReporting);
@ -67,7 +64,6 @@ private:
std::unique_ptr<google_breakpad::ExceptionHandler> handler_;
};
// Asks the user if he wants to send a crash report, and displays a progress
// dialog while uploading it if he does.
class CrashSender : public QObject {

View File

@ -46,15 +46,11 @@ int Database::sNextConnectionId = 1;
QMutex Database::sNextConnectionIdMutex;
Database::Token::Token(const QString& token, int start, int end)
: token(token),
start_offset(start),
end_offset(end) {
}
: token(token), start_offset(start), end_offset(end) {}
struct sqlite3_tokenizer_module {
int iVersion;
int (*xCreate)(
int argc, /* Size of argv array */
int (*xCreate)(int argc, /* Size of argv array */
const char* const* argv, /* Tokenizer argument strings */
sqlite3_tokenizer** ppTokenizer); /* OUT: Created tokenizer */
@ -87,24 +83,22 @@ struct sqlite3_tokenizer_cursor {
sqlite3_tokenizer_module* Database::sFTSTokenizer = nullptr;
int Database::FTSCreate(int argc, const char* const* argv, sqlite3_tokenizer** tokenizer) {
int Database::FTSCreate(int argc, const char* const* argv,
sqlite3_tokenizer** tokenizer) {
*tokenizer = reinterpret_cast<sqlite3_tokenizer*>(new UnicodeTokenizer);
return SQLITE_OK;
}
int Database::FTSDestroy(sqlite3_tokenizer* tokenizer) {
UnicodeTokenizer* real_tokenizer = reinterpret_cast<UnicodeTokenizer*>(tokenizer);
UnicodeTokenizer* real_tokenizer =
reinterpret_cast<UnicodeTokenizer*>(tokenizer);
delete real_tokenizer;
return SQLITE_OK;
}
int Database::FTSOpen(
sqlite3_tokenizer* pTokenizer,
const char* input,
int bytes,
sqlite3_tokenizer_cursor** cursor) {
int Database::FTSOpen(sqlite3_tokenizer* pTokenizer, const char* input,
int bytes, sqlite3_tokenizer_cursor** cursor) {
UnicodeTokenizerCursor* new_cursor = new UnicodeTokenizerCursor;
new_cursor->pTokenizer = pTokenizer;
new_cursor->position = 0;
@ -163,20 +157,18 @@ int Database::FTSOpen(
}
int Database::FTSClose(sqlite3_tokenizer_cursor* cursor) {
UnicodeTokenizerCursor* real_cursor = reinterpret_cast<UnicodeTokenizerCursor*>(cursor);
UnicodeTokenizerCursor* real_cursor =
reinterpret_cast<UnicodeTokenizerCursor*>(cursor);
delete real_cursor;
return SQLITE_OK;
}
int Database::FTSNext(
sqlite3_tokenizer_cursor* cursor,
const char** token,
int* bytes,
int* start_offset,
int* end_offset,
int Database::FTSNext(sqlite3_tokenizer_cursor* cursor, const char** token,
int* bytes, int* start_offset, int* end_offset,
int* position) {
UnicodeTokenizerCursor* real_cursor = reinterpret_cast<UnicodeTokenizerCursor*>(cursor);
UnicodeTokenizerCursor* real_cursor =
reinterpret_cast<UnicodeTokenizerCursor*>(cursor);
QList<Token> tokens = real_cursor->tokens;
if (real_cursor->position >= tokens.size()) {
@ -196,7 +188,6 @@ int Database::FTSNext(
return SQLITE_OK;
}
void Database::StaticInit() {
sFTSTokenizer = new sqlite3_tokenizer_module;
sFTSTokenizer->iVersion = 0;
@ -208,21 +199,21 @@ void Database::StaticInit() {
return;
}
Database::Database(Application* app, QObject* parent, const QString& database_name)
Database::Database(Application* app, QObject* parent,
const QString& database_name)
: QObject(parent),
app_(app),
mutex_(QMutex::Recursive),
injected_database_name_(database_name),
query_hash_(0),
startup_schema_version_(-1)
{
startup_schema_version_(-1) {
{
QMutexLocker l(&sNextConnectionIdMutex);
connection_id_ = sNextConnectionId++;
}
directory_ = QDir::toNativeSeparators(
Utilities::GetConfigPath(Utilities::Path_Root));
directory_ =
QDir::toNativeSeparators(Utilities::GetConfigPath(Utilities::Path_Root));
attached_databases_["jamendo"] = AttachedDatabase(
directory_ + "/jamendo.db", ":/schema/jamendo.sql", false);
@ -241,8 +232,7 @@ QSqlDatabase Database::Connect() {
}
}
const QString connection_id =
QString("%1_thread_%2").arg(connection_id_).arg(
const QString connection_id = QString("%1_thread_%2").arg(connection_id_).arg(
reinterpret_cast<quint64>(QThread::currentThread()));
// Try to find an existing connection for this thread
@ -269,8 +259,9 @@ QSqlDatabase Database::Connect() {
{
QSqlQuery set_fts_tokenizer("SELECT fts3_tokenizer(:name, :pointer)", db);
set_fts_tokenizer.bindValue(":name", "unicode");
set_fts_tokenizer.bindValue(":pointer", QByteArray(
reinterpret_cast<const char*>(&sFTSTokenizer), sizeof(&sFTSTokenizer)));
set_fts_tokenizer.bindValue(
":pointer", QByteArray(reinterpret_cast<const char*>(&sFTSTokenizer),
sizeof(&sFTSTokenizer)));
if (!set_fts_tokenizer.exec()) {
qLog(Warning) << "Couldn't register FTS3 tokenizer";
}
@ -288,15 +279,15 @@ QSqlDatabase Database::Connect() {
for (const QString& key : attached_databases_.keys()) {
QString filename = attached_databases_[key].filename_;
if (!injected_database_name_.isNull())
filename = injected_database_name_;
if (!injected_database_name_.isNull()) filename = injected_database_name_;
// Attach the db
QSqlQuery q("ATTACH DATABASE :filename AS :alias", db);
q.bindValue(":filename", filename);
q.bindValue(":alias", key);
if (!q.exec()) {
qFatal("Couldn't attach external database '%s'", key.toAscii().constData());
qFatal("Couldn't attach external database '%s'",
key.toAscii().constData());
}
}
@ -311,8 +302,10 @@ QSqlDatabase Database::Connect() {
attached_databases_[key].schema_.isEmpty())
continue;
// Find out if there are any tables in this database
QSqlQuery q(QString("SELECT ROWID FROM %1.sqlite_master"
" WHERE type='table'").arg(key), db);
QSqlQuery q(QString(
"SELECT ROWID FROM %1.sqlite_master"
" WHERE type='table'").arg(key),
db);
if (!q.exec() || !q.next()) {
q.finish();
ExecSchemaCommandsFromFile(db, attached_databases_[key].schema_, 0);
@ -327,8 +320,7 @@ void Database::UpdateMainSchema(QSqlDatabase* db) {
int schema_version = 0;
{
QSqlQuery q("SELECT version FROM schema_version", *db);
if (q.next())
schema_version = q.value(0).toInt();
if (q.next()) schema_version = q.value(0).toInt();
// Implicit invocation of ~QSqlQuery() when leaving the scope
// to release any remaining database locks!
}
@ -336,7 +328,8 @@ void Database::UpdateMainSchema(QSqlDatabase* db) {
startup_schema_version_ = schema_version;
if (schema_version > kSchemaVersion) {
qLog(Warning) << "The database schema (version" << schema_version << ") is newer than I was expecting";
qLog(Warning) << "The database schema (version" << schema_version
<< ") is newer than I was expecting";
return;
}
if (schema_version < kSchemaVersion) {
@ -394,7 +387,8 @@ void Database::AttachDatabaseOnDbConnection(const QString &database_name,
q.bindValue(":filename", database.filename_);
q.bindValue(":alias", database_name);
if (!q.exec()) {
qFatal("Couldn't attach external database '%s'", database_name.toAscii().constData());
qFatal("Couldn't attach external database '%s'",
database_name.toAscii().constData());
}
}
@ -434,20 +428,22 @@ void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
UrlEncodeFilenameColumn(table, db);
}
}
qLog(Debug) << "Applying database schema update" << version
<< "from" << filename;
qLog(Debug) << "Applying database schema update" << version << "from"
<< filename;
ExecSchemaCommandsFromFile(db, filename, version - 1, true);
t.Commit();
} else {
qLog(Debug) << "Applying database schema update" << version
<< "from" << filename;
qLog(Debug) << "Applying database schema update" << version << "from"
<< filename;
ExecSchemaCommandsFromFile(db, filename, version - 1);
}
}
void Database::UrlEncodeFilenameColumn(const QString& table, QSqlDatabase& db) {
QSqlQuery select(QString("SELECT ROWID, filename FROM %1").arg(table), db);
QSqlQuery update(QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table), db);
QSqlQuery update(
QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table),
db);
select.exec();
if (CheckErrors(select)) return;
while (select.next()) {
@ -475,16 +471,12 @@ void Database::ExecSchemaCommandsFromFile(QSqlDatabase& db,
QFile schema_file(filename);
if (!schema_file.open(QIODevice::ReadOnly))
qFatal("Couldn't open schema file %s", filename.toUtf8().constData());
ExecSchemaCommands(db,
QString::fromUtf8(schema_file.readAll()),
schema_version,
in_transaction);
ExecSchemaCommands(db, QString::fromUtf8(schema_file.readAll()),
schema_version, in_transaction);
}
void Database::ExecSchemaCommands(QSqlDatabase& db,
const QString& schema,
int schema_version,
bool in_transaction) {
void Database::ExecSchemaCommands(QSqlDatabase& db, const QString& schema,
int schema_version, bool in_transaction) {
// Run each command
const QStringList commands(schema.split(QRegExp("; *\n\n")));
@ -530,8 +522,7 @@ void Database::ExecSongTablesCommands(QSqlDatabase& db,
}
} else {
QSqlQuery query(db.exec(command));
if (CheckErrors(query))
qFatal("Unable to update music library database");
if (CheckErrors(query)) qFatal("Unable to update music library database");
}
}
}
@ -541,14 +532,17 @@ QStringList Database::SongsTables(QSqlDatabase& db, int schema_version) const {
// look for the tables in the main db
for (const QString& table : db.tables()) {
if (table == "songs" || table.endsWith("_songs"))
ret << table;
if (table == "songs" || table.endsWith("_songs")) ret << table;
}
// look for the tables in attached dbs
for (const QString& key : attached_databases_.keys()) {
QSqlQuery q(QString("SELECT NAME FROM %1.sqlite_master"
" WHERE type='table' AND name='songs' OR name LIKE '%songs'").arg(key), db);
QSqlQuery q(
QString(
"SELECT NAME FROM %1.sqlite_master"
" WHERE type='table' AND name='songs' OR name LIKE '%songs'")
.arg(key),
db);
if (q.exec()) {
while (q.next()) {
QString tab_name = key + "." + q.value(0).toString();
@ -595,8 +589,10 @@ bool Database::IntegrityCheck(QSqlDatabase db) {
break;
} else {
if (!error_reported) {
app_->AddError(tr("Database corruption detected. Please read "
"https://code.google.com/p/clementine-player/wiki/DatabaseCorruption "
app_->AddError(
tr("Database corruption detected. Please read "
"https://code.google.com/p/clementine-player/wiki/"
"DatabaseCorruption "
"for instructions on how to recover your database"));
}
app_->AddError("Database: " + message);
@ -621,17 +617,16 @@ void Database::DoBackup() {
}
}
bool Database::OpenDatabase(const QString& filename, sqlite3** connection) const {
bool Database::OpenDatabase(const QString& filename,
sqlite3** connection) const {
int ret = sqlite3_open(filename.toUtf8(), connection);
if (ret != 0) {
if (*connection) {
const char* error_message = sqlite3_errmsg(*connection);
qLog(Error) << "Failed to open database for backup:"
<< filename
qLog(Error) << "Failed to open database for backup:" << filename
<< error_message;
} else {
qLog(Error) << "Failed to open database for backup:"
<< filename;
qLog(Error) << "Failed to open database for backup:" << filename;
}
return false;
}
@ -641,7 +636,8 @@ bool Database::OpenDatabase(const QString& filename, sqlite3** connection) const
void Database::BackupFile(const QString& filename) {
qLog(Debug) << "Starting database backup";
QString dest_filename = QString("%1.bak").arg(filename);
const int task_id = app_->task_manager()->StartTask(tr("Backing up database"));
const int task_id =
app_->task_manager()->StartTask(tr("Backing up database"));
sqlite3* source_connection = nullptr;
sqlite3* dest_connection = nullptr;
@ -651,7 +647,8 @@ void Database::BackupFile(const QString& filename) {
sqlite3_close(source_connection);
sqlite3_close(dest_connection);
app_->task_manager()->SetTaskFinished(task_id);
} BOOST_SCOPE_EXIT_END
}
BOOST_SCOPE_EXIT_END
bool success = OpenDatabase(filename, &source_connection);
if (!success) {
@ -663,9 +660,8 @@ void Database::BackupFile(const QString& filename) {
return;
}
sqlite3_backup* backup = sqlite3_backup_init(
dest_connection, "main",
source_connection, "main");
sqlite3_backup* backup =
sqlite3_backup_init(dest_connection, "main", source_connection, "main");
if (!backup) {
const char* error_message = sqlite3_errmsg(dest_connection);
qLog(Error) << "Failed to start database backup:" << error_message;

View File

@ -34,7 +34,6 @@ extern "C" {
struct sqlite3_tokenizer;
struct sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module;
}
class Application;
@ -48,7 +47,8 @@ class Database : public QObject {
struct AttachedDatabase {
AttachedDatabase() {}
AttachedDatabase(const QString& filename, const QString& schema, bool is_temporary)
AttachedDatabase(const QString& filename, const QString& schema,
bool is_temporary)
: filename_(filename), schema_(schema), is_temporary_(is_temporary) {}
QString filename_;
@ -65,15 +65,14 @@ class Database : public QObject {
QMutex* Mutex() { return &mutex_; }
void RecreateAttachedDb(const QString& database_name);
void ExecSchemaCommands(QSqlDatabase& db,
const QString& schema,
int schema_version,
bool in_transaction = false);
void ExecSchemaCommands(QSqlDatabase& db, const QString& schema,
int schema_version, bool in_transaction = false);
int startup_schema_version() const { return startup_schema_version_; }
int current_schema_version() const { return kSchemaVersion; }
void AttachDatabase(const QString& database_name, const AttachedDatabase& database);
void AttachDatabase(const QString& database_name,
const AttachedDatabase& database);
void AttachDatabaseOnDbConnection(const QString& database_name,
const AttachedDatabase& database,
QSqlDatabase& db);
@ -88,12 +87,10 @@ class Database : public QObject {
private:
void UpdateMainSchema(QSqlDatabase* db);
void ExecSchemaCommandsFromFile(QSqlDatabase& db,
const QString& filename,
void ExecSchemaCommandsFromFile(QSqlDatabase& db, const QString& filename,
int schema_version,
bool in_transaction = false);
void ExecSongTablesCommands(QSqlDatabase& db,
const QStringList& song_tables,
void ExecSongTablesCommands(QSqlDatabase& db, const QStringList& song_tables,
const QStringList& commands);
void UpdateDatabaseSchema(int version, QSqlDatabase& db);
@ -137,26 +134,23 @@ class Database : public QObject {
// Do static initialisation like loading sqlite functions.
static void StaticInit();
typedef int (*Sqlite3CreateFunc) (
sqlite3*, const char*, int, int, void*,
void (*) (sqlite3_context*, int, sqlite3_value**),
void (*) (sqlite3_context*, int, sqlite3_value**),
typedef int (*Sqlite3CreateFunc)(sqlite3*, const char*, int, int, void*,
void (*)(sqlite3_context*, int,
sqlite3_value**),
void (*)(sqlite3_context*, int,
sqlite3_value**),
void (*)(sqlite3_context*));
static sqlite3_tokenizer_module* sFTSTokenizer;
static int FTSCreate(int argc, const char* const* argv, sqlite3_tokenizer** tokenizer);
static int FTSCreate(int argc, const char* const* argv,
sqlite3_tokenizer** tokenizer);
static int FTSDestroy(sqlite3_tokenizer* tokenizer);
static int FTSOpen(sqlite3_tokenizer* tokenizer,
const char* input,
int bytes,
static int FTSOpen(sqlite3_tokenizer* tokenizer, const char* input, int bytes,
sqlite3_tokenizer_cursor** cursor);
static int FTSClose(sqlite3_tokenizer_cursor* cursor);
static int FTSNext(sqlite3_tokenizer_cursor* cursor,
const char** token,
int* bytes,
int* start_offset,
int* end_offset,
static int FTSNext(sqlite3_tokenizer_cursor* cursor, const char** token,
int* bytes, int* start_offset, int* end_offset,
int* position);
struct Token {
Token(const QString& token, int start, int end);

View File

@ -34,17 +34,14 @@ DeleteFiles::DeleteFiles(TaskManager* task_manager,
storage_(storage),
started_(false),
task_id_(0),
progress_(0)
{
progress_(0) {
original_thread_ = thread();
}
DeleteFiles::~DeleteFiles() {
}
DeleteFiles::~DeleteFiles() {}
void DeleteFiles::Start(const SongList& songs) {
if (thread_)
return;
if (thread_) return;
songs_ = songs;

View File

@ -22,12 +22,7 @@
#include <string.h>
#include "fht.h"
FHT::FHT(int n) :
m_buf(0),
m_tab(0),
m_log(0)
{
FHT::FHT(int n) : m_buf(0), m_tab(0), m_log(0) {
if (n < 3) {
m_num = 0;
m_exp2 = -1;
@ -42,59 +37,43 @@ FHT::FHT(int n) :
}
}
FHT::~FHT()
{
FHT::~FHT() {
delete[] m_buf;
delete[] m_tab;
delete[] m_log;
}
void FHT::makeCasTable(void)
{
void FHT::makeCasTable(void) {
float d, *costab, *sintab;
int ul, ndiv2 = m_num / 2;
for (costab = m_tab, sintab = m_tab + m_num / 2 + 1, ul = 0; ul < m_num; ul++) {
for (costab = m_tab, sintab = m_tab + m_num / 2 + 1, ul = 0; ul < m_num;
ul++) {
d = M_PI * ul / ndiv2;
*costab = *sintab = cos(d);
costab += 2, sintab += 2;
if (sintab > m_tab + m_num * 2)
sintab = m_tab + 1;
if (sintab > m_tab + m_num * 2) sintab = m_tab + 1;
}
}
float* FHT::copy(float *d, float *s)
{
float* FHT::copy(float* d, float* s) {
return (float*)memcpy(d, s, m_num * sizeof(float));
}
float* FHT::clear(float *d)
{
float* FHT::clear(float* d) {
return (float*)memset(d, 0, m_num * sizeof(float));
}
void FHT::scale(float *p, float d)
{
for (int i = 0; i < (m_num / 2); i++)
*p++ *= d;
void FHT::scale(float* p, float d) {
for (int i = 0; i < (m_num / 2); i++) *p++ *= d;
}
void FHT::ewma(float *d, float *s, float w)
{
for (int i = 0; i < (m_num / 2); i++, d++, s++)
*d = *d * w + *s * (1 - w);
void FHT::ewma(float* d, float* s, float w) {
for (int i = 0; i < (m_num / 2); i++, d++, s++) *d = *d * w + *s * (1 - w);
}
void FHT::logSpectrum(float *out, float *p)
{
void FHT::logSpectrum(float* out, float* p) {
int n = m_num / 2, i, j, k, *r;
if (!m_log) {
m_log = new int[n];
@ -113,15 +92,12 @@ void FHT::logSpectrum(float *out, float *p)
else {
float base = p[k - 1];
float step = (p[j] - base) / (j - (k - 1));
for (float corr = 0; k <= j; k++, corr += step)
*out++ = base + corr;
for (float corr = 0; k <= j; k++, corr += step) *out++ = base + corr;
}
}
}
void FHT::semiLogSpectrum(float *p)
{
void FHT::semiLogSpectrum(float* p) {
float e;
power2(p);
for (int i = 0; i < (m_num / 2); i++, p++) {
@ -130,25 +106,17 @@ void FHT::semiLogSpectrum(float *p)
}
}
void FHT::spectrum(float *p)
{
void FHT::spectrum(float* p) {
power2(p);
for (int i = 0; i < (m_num / 2); i++, p++)
*p = (float)sqrt(*p * .5);
for (int i = 0; i < (m_num / 2); i++, p++) *p = (float)sqrt(*p * .5);
}
void FHT::power(float *p)
{
void FHT::power(float* p) {
power2(p);
for (int i = 0; i < (m_num / 2); i++)
*p++ *= .5;
for (int i = 0; i < (m_num / 2); i++) *p++ *= .5;
}
void FHT::power2(float *p)
{
void FHT::power2(float* p) {
int i;
float* q;
_transform(p, m_num, 0);
@ -159,18 +127,14 @@ void FHT::power2(float *p)
*p = (*p * *p) + (*q * *q), p++;
}
void FHT::transform(float *p)
{
void FHT::transform(float* p) {
if (m_num == 8)
transform8(p);
else
_transform(p, m_num, 0);
}
void FHT::transform8(float *p)
{
void FHT::transform8(float* p) {
float a, b, c, d, e, f, g, h, b_f2, d_h2;
float a_c_eg, a_ce_g, ac_e_g, aceg, b_df_h, bdfh;
@ -197,9 +161,7 @@ void FHT::transform8(float *p)
*--p = aceg + bdfh;
}
void FHT::_transform(float *p, int n, int k)
{
void FHT::_transform(float* p, int n, int k) {
if (n == 8) {
transform8(p + k);
return;
@ -239,4 +201,3 @@ void FHT::_transform(float *p, int n, int k)
}
memcpy(p + k, m_buf, sizeof(float) * n);
}

View File

@ -29,8 +29,7 @@
*
* [1] Computer in Physics, Vol. 9, No. 4, Jul/Aug 1995 pp 373-379
*/
class FHT
{
class FHT {
int m_exp2;
int m_num;
float* m_buf;

View File

@ -23,17 +23,14 @@
#include <QUrl>
FilesystemMusicStorage::FilesystemMusicStorage(const QString& root)
: root_(root)
{
}
: root_(root) {}
bool FilesystemMusicStorage::CopyToStorage(const CopyJob& job) {
const QFileInfo src = QFileInfo(job.source_);
const QFileInfo dest = QFileInfo(root_ + "/" + job.destination_);
// Don't do anything if the destination is the same as the source
if (src == dest)
return true;
if (src == dest) return true;
// Create directories as required
QDir dir;
@ -43,8 +40,7 @@ bool FilesystemMusicStorage::CopyToStorage(const CopyJob& job) {
}
// Remove the destination file if it exists and we want to overwrite
if (job.overwrite_ && dest.exists())
QFile::remove(dest.absoluteFilePath());
if (job.overwrite_ && dest.exists()) QFile::remove(dest.absoluteFilePath());
// Copy or move
if (job.remove_original_)

View File

@ -24,10 +24,10 @@
#endif
FileSystemWatcherInterface::FileSystemWatcherInterface(QObject* parent)
: QObject(parent) {
}
: QObject(parent) {}
FileSystemWatcherInterface* FileSystemWatcherInterface::Create(QObject* parent) {
FileSystemWatcherInterface* FileSystemWatcherInterface::Create(
QObject* parent) {
FileSystemWatcherInterface* ret;
#ifdef Q_OS_DARWIN
ret = new MacFSListener(parent);

View File

@ -20,16 +20,11 @@
#include "globalshortcuts.h"
GlobalShortcutBackend::GlobalShortcutBackend(GlobalShortcuts* parent)
: QObject(parent),
manager_(parent),
active_(false)
{
}
: QObject(parent), manager_(parent), active_(false) {}
bool GlobalShortcutBackend::Register() {
bool ret = DoRegister();
if (ret)
active_ = true;
if (ret) active_ = true;
return ret;
}

View File

@ -38,18 +38,22 @@ GlobalShortcuts::GlobalShortcuts(QWidget *parent)
gnome_backend_(nullptr),
system_backend_(nullptr),
use_gnome_(false),
rating_signals_mapper_(new QSignalMapper(this))
{
rating_signals_mapper_(new QSignalMapper(this)) {
settings_.beginGroup(kSettingsGroup);
// Create actions
AddShortcut("play", tr("Play"), SIGNAL(Play()));
AddShortcut("pause", tr("Pause"), SIGNAL(Pause()));
AddShortcut("play_pause", tr("Play/Pause"), SIGNAL(PlayPause()), QKeySequence(Qt::Key_MediaPlay));
AddShortcut("stop", tr("Stop"), SIGNAL(Stop()), QKeySequence(Qt::Key_MediaStop));
AddShortcut("stop_after", tr("Stop playing after current track"), SIGNAL(StopAfter()));
AddShortcut("next_track", tr("Next track"), SIGNAL(Next()), QKeySequence(Qt::Key_MediaNext));
AddShortcut("prev_track", tr("Previous track"), SIGNAL(Previous()), QKeySequence(Qt::Key_MediaPrevious));
AddShortcut("play_pause", tr("Play/Pause"), SIGNAL(PlayPause()),
QKeySequence(Qt::Key_MediaPlay));
AddShortcut("stop", tr("Stop"), SIGNAL(Stop()),
QKeySequence(Qt::Key_MediaStop));
AddShortcut("stop_after", tr("Stop playing after current track"),
SIGNAL(StopAfter()));
AddShortcut("next_track", tr("Next track"), SIGNAL(Next()),
QKeySequence(Qt::Key_MediaNext));
AddShortcut("prev_track", tr("Previous track"), SIGNAL(Previous()),
QKeySequence(Qt::Key_MediaPrevious));
AddShortcut("inc_volume", tr("Increase volume"), SIGNAL(IncVolume()));
AddShortcut("dec_volume", tr("Decrease volume"), SIGNAL(DecVolume()));
AddShortcut("mute", tr("Mute"), SIGNAL(Mute()));
@ -57,19 +61,32 @@ GlobalShortcuts::GlobalShortcuts(QWidget *parent)
AddShortcut("seek_backward", tr("Seek backward"), SIGNAL(SeekBackward()));
AddShortcut("show_hide", tr("Show/Hide"), SIGNAL(ShowHide()));
AddShortcut("show_osd", tr("Show OSD"), SIGNAL(ShowOSD()));
AddShortcut("toggle_pretty_osd", tr("Toggle Pretty OSD"), SIGNAL(TogglePrettyOSD())); // Toggling possible only for pretty OSD
AddShortcut("shuffle_mode", tr("Change shuffle mode"), SIGNAL(CycleShuffleMode()));
AddShortcut("repeat_mode", tr("Change repeat mode"), SIGNAL(CycleRepeatMode()));
AddShortcut("toggle_last_fm_scrobbling", tr("Enable/disable Last.fm scrobbling"), SIGNAL(ToggleScrobbling()));
AddShortcut(
"toggle_pretty_osd", tr("Toggle Pretty OSD"),
SIGNAL(TogglePrettyOSD())); // Toggling possible only for pretty OSD
AddShortcut("shuffle_mode", tr("Change shuffle mode"),
SIGNAL(CycleShuffleMode()));
AddShortcut("repeat_mode", tr("Change repeat mode"),
SIGNAL(CycleRepeatMode()));
AddShortcut("toggle_last_fm_scrobbling",
tr("Enable/disable Last.fm scrobbling"),
SIGNAL(ToggleScrobbling()));
AddRatingShortcut("rate_zero_star", tr("Rate the current song 0 stars"), rating_signals_mapper_, 0);
AddRatingShortcut("rate_one_star", tr("Rate the current song 1 star"), rating_signals_mapper_, 1);
AddRatingShortcut("rate_two_star", tr("Rate the current song 2 stars"), rating_signals_mapper_, 2);
AddRatingShortcut("rate_three_star", tr("Rate the current song 3 stars"), rating_signals_mapper_, 3);
AddRatingShortcut("rate_four_star", tr("Rate the current song 4 stars"), rating_signals_mapper_, 4);
AddRatingShortcut("rate_five_star", tr("Rate the current song 5 stars"), rating_signals_mapper_, 5);
AddRatingShortcut("rate_zero_star", tr("Rate the current song 0 stars"),
rating_signals_mapper_, 0);
AddRatingShortcut("rate_one_star", tr("Rate the current song 1 star"),
rating_signals_mapper_, 1);
AddRatingShortcut("rate_two_star", tr("Rate the current song 2 stars"),
rating_signals_mapper_, 2);
AddRatingShortcut("rate_three_star", tr("Rate the current song 3 stars"),
rating_signals_mapper_, 3);
AddRatingShortcut("rate_four_star", tr("Rate the current song 4 stars"),
rating_signals_mapper_, 4);
AddRatingShortcut("rate_five_star", tr("Rate the current song 5 stars"),
rating_signals_mapper_, 5);
connect(rating_signals_mapper_, SIGNAL(mapped(int)), SIGNAL(RateCurrentSong(int)));
connect(rating_signals_mapper_, SIGNAL(mapped(int)),
SIGNAL(RateCurrentSong(int)));
// Create backends - these do the actual shortcut registration
gnome_backend_ = new GnomeGlobalShortcutBackend(this);
@ -98,8 +115,8 @@ void GlobalShortcuts::AddRatingShortcut(const QString& id, const QString& name,
mapper->setMapping(shortcut.action, rating);
}
GlobalShortcuts::Shortcut GlobalShortcuts::AddShortcut(const QString& id, const QString& name,
const QKeySequence& default_key) {
GlobalShortcuts::Shortcut GlobalShortcuts::AddShortcut(
const QString& id, const QString& name, const QKeySequence& default_key) {
Shortcut shortcut;
shortcut.action = new QAction(name, this);
QKeySequence key_sequence = QKeySequence::fromString(
@ -137,21 +154,19 @@ void GlobalShortcuts::ReloadSettings() {
}
void GlobalShortcuts::Unregister() {
if (gnome_backend_->is_active())
gnome_backend_->Unregister();
if (system_backend_->is_active())
system_backend_->Unregister();
if (gnome_backend_->is_active()) gnome_backend_->Unregister();
if (system_backend_->is_active()) system_backend_->Unregister();
}
void GlobalShortcuts::Register() {
if (use_gnome_ && gnome_backend_->Register())
return;
if (use_gnome_ && gnome_backend_->Register()) return;
system_backend_->Register();
}
bool GlobalShortcuts::IsMacAccessibilityEnabled() const {
#ifdef Q_OS_MAC
return static_cast<MacGlobalShortcutBackend*>(system_backend_)->IsAccessibilityEnabled();
return static_cast<MacGlobalShortcutBackend*>(system_backend_)
->IsAccessibilityEnabled();
#else
return true;
#endif
@ -159,6 +174,7 @@ bool GlobalShortcuts::IsMacAccessibilityEnabled() const {
void GlobalShortcuts::ShowMacAccessibilityDialog() {
#ifdef Q_OS_MAC
static_cast<MacGlobalShortcutBackend*>(system_backend_)->ShowAccessibilityDialog();
static_cast<MacGlobalShortcutBackend*>(system_backend_)
->ShowAccessibilityDialog();
#endif
}

View File

@ -79,9 +79,11 @@ signals:
private:
void AddShortcut(const QString& id, const QString& name, const char* signal,
const QKeySequence& default_key = QKeySequence(0));
void AddRatingShortcut(const QString& id, const QString& name, QSignalMapper* mapper,
int rating, const QKeySequence& default_key = QKeySequence(0));
Shortcut AddShortcut(const QString& id, const QString& name, const QKeySequence& default_key);
void AddRatingShortcut(const QString& id, const QString& name,
QSignalMapper* mapper, int rating,
const QKeySequence& default_key = QKeySequence(0));
Shortcut AddShortcut(const QString& id, const QString& name,
const QKeySequence& default_key);
private:
GlobalShortcutBackend* gnome_backend_;

View File

@ -33,23 +33,24 @@
#include <QtDBus>
#endif
const char* GnomeGlobalShortcutBackend::kGsdService = "org.gnome.SettingsDaemon";
const char* GnomeGlobalShortcutBackend::kGsdPath = "/org/gnome/SettingsDaemon/MediaKeys";
const char* GnomeGlobalShortcutBackend::kGsdInterface = "org.gnome.SettingsDaemon.MediaKeys";
const char* GnomeGlobalShortcutBackend::kGsdService =
"org.gnome.SettingsDaemon";
const char* GnomeGlobalShortcutBackend::kGsdPath =
"/org/gnome/SettingsDaemon/MediaKeys";
const char* GnomeGlobalShortcutBackend::kGsdInterface =
"org.gnome.SettingsDaemon.MediaKeys";
GnomeGlobalShortcutBackend::GnomeGlobalShortcutBackend(GlobalShortcuts* parent)
: GlobalShortcutBackend(parent),
interface_(nullptr),
is_connected_(false)
{
}
is_connected_(false) {}
bool GnomeGlobalShortcutBackend::DoRegister() {
#ifdef QT_DBUS_LIB
qLog(Debug) << "registering";
// Check if the GSD service is available
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService)) {
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(
kGsdService)) {
qLog(Warning) << "gnome settings daemon not registered";
return false;
}
@ -64,9 +65,8 @@ bool GnomeGlobalShortcutBackend::DoRegister() {
QDateTime::currentDateTime().toTime_t());
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
NewClosure(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
this, SLOT(RegisterFinished(QDBusPendingCallWatcher*)),
watcher);
NewClosure(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this,
SLOT(RegisterFinished(QDBusPendingCallWatcher*)), watcher);
return true;
#else // QT_DBUS_LIB
@ -75,19 +75,20 @@ bool GnomeGlobalShortcutBackend::DoRegister() {
#endif
}
void GnomeGlobalShortcutBackend::RegisterFinished(QDBusPendingCallWatcher* watcher) {
void GnomeGlobalShortcutBackend::RegisterFinished(
QDBusPendingCallWatcher* watcher) {
#ifdef QT_DBUS_LIB
QDBusMessage reply = watcher->reply();
watcher->deleteLater();
if (reply.type() == QDBusMessage::ErrorMessage) {
qLog(Warning) << "Failed to grab media keys"
<< reply.errorName() <<reply.errorMessage();
qLog(Warning) << "Failed to grab media keys" << reply.errorName()
<< reply.errorMessage();
return;
}
connect(interface_, SIGNAL(MediaPlayerKeyPressed(QString,QString)),
this, SLOT(GnomeMediaKeyPressed(QString,QString)));
connect(interface_, SIGNAL(MediaPlayerKeyPressed(QString, QString)), this,
SLOT(GnomeMediaKeyPressed(QString, QString)));
is_connected_ = true;
qLog(Debug) << "registered";
@ -98,20 +99,21 @@ void GnomeGlobalShortcutBackend::DoUnregister() {
qLog(Debug) << "unregister";
#ifdef QT_DBUS_LIB
// Check if the GSD service is available
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService))
return;
if (!interface_ || !is_connected_)
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(
kGsdService))
return;
if (!interface_ || !is_connected_) return;
is_connected_ = false;
interface_->ReleaseMediaPlayerKeys(QCoreApplication::applicationName());
disconnect(interface_, SIGNAL(MediaPlayerKeyPressed(QString,QString)),
this, SLOT(GnomeMediaKeyPressed(QString,QString)));
disconnect(interface_, SIGNAL(MediaPlayerKeyPressed(QString, QString)), this,
SLOT(GnomeMediaKeyPressed(QString, QString)));
#endif
}
void GnomeGlobalShortcutBackend::GnomeMediaKeyPressed(const QString&, const QString& key) {
void GnomeGlobalShortcutBackend::GnomeMediaKeyPressed(const QString&,
const QString& key) {
if (key == "Play") manager_->shortcuts()["play_pause"].action->trigger();
if (key == "Stop") manager_->shortcuts()["stop"].action->trigger();
if (key == "Next") manager_->shortcuts()["next_track"].action->trigger();

View File

@ -7,7 +7,6 @@
#import <Breakpad/Breakpad.h>
#endif
class PlatformInterface;
@class SPMediaKeyTap;
@ -25,10 +24,12 @@ class PlatformInterface;
- (id)initWithHandler:(PlatformInterface*)handler;
// NSApplicationDelegate
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag;
- (BOOL)applicationShouldHandleReopen:(NSApplication*)app
hasVisibleWindows:(BOOL)flag;
- (NSMenu*)applicationDockMenu:(NSApplication*)sender;
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender;
- (NSApplicationTerminateReply)applicationShouldTerminate:
(NSApplication*)sender;
// NSUserNotificationCenterDelegate
- (BOOL)userNotificationCenter:(id)center
@ -37,6 +38,6 @@ class PlatformInterface;
- (void)setDockMenu:(NSMenu*)menu;
- (MacGlobalShortcutBackend*)shortcut_handler;
- (void)setShortcutHandler:(MacGlobalShortcutBackend*)backend;
- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
- (void)mediaKeyTap:(SPMediaKeyTap*)keyTap
receivedMediaKeyEvent:(NSEvent*)event;
@end

View File

@ -30,5 +30,4 @@ namespace mac {
QKeySequence KeySequenceFromNSEvent(NSEvent* event);
void DumpDictionary(CFDictionaryRef dict);
float GetDevicePixelRatio(QWidget* widget);
}

View File

@ -45,11 +45,8 @@ class MacFSListener : public FileSystemWatcherInterface {
private:
void UpdateStreamAsync();
static void EventStreamCallback(
ConstFSEventStreamRef stream,
void* user_data,
size_t num_events,
void* event_paths,
static void EventStreamCallback(ConstFSEventStreamRef stream, void* user_data,
size_t num_events, void* event_paths,
const FSEventStreamEventFlags event_flags[],
const FSEventStreamEventId event_ids[]);

View File

@ -39,15 +39,12 @@ using boost::multi_index::multi_index_container;
using boost::multi_index::ordered_unique;
using boost::multi_index::tag;
std::size_t hash_value(const QModelIndex& index) {
return qHash(index);
}
std::size_t hash_value(const QModelIndex& index) { return qHash(index); }
namespace {
struct Mapping {
Mapping(const QModelIndex& _source_index)
: source_index(_source_index) {}
Mapping(const QModelIndex& _source_index) : source_index(_source_index) {}
QModelIndex source_index;
};
@ -64,10 +61,8 @@ class MergedProxyModelPrivate {
indexed_by<
hashed_unique<tag<tag_by_source>,
member<Mapping, QModelIndex, &Mapping::source_index> >,
ordered_unique<tag<tag_by_pointer>,
identity<Mapping*> >
>
> MappingContainer;
ordered_unique<tag<tag_by_pointer>, identity<Mapping*> > > >
MappingContainer;
public:
MappingContainer mappings_;
@ -76,12 +71,9 @@ class MergedProxyModelPrivate {
MergedProxyModel::MergedProxyModel(QObject* parent)
: QAbstractProxyModel(parent),
resetting_model_(nullptr),
p_(new MergedProxyModelPrivate) {
}
p_(new MergedProxyModelPrivate) {}
MergedProxyModel::~MergedProxyModel() {
DeleteAllMappings();
}
MergedProxyModel::~MergedProxyModel() { DeleteAllMappings(); }
void MergedProxyModel::DeleteAllMappings() {
const auto& begin = p_->mappings_.get<tag_by_pointer>().begin();
@ -92,27 +84,25 @@ void MergedProxyModel::DeleteAllMappings() {
void MergedProxyModel::AddSubModel(const QModelIndex& source_parent,
QAbstractItemModel* submodel) {
connect(submodel, SIGNAL(modelReset()), this, SLOT(SubModelReset()));
connect(submodel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(RowsAboutToBeInserted(QModelIndex,int,int)));
connect(submodel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(RowsAboutToBeRemoved(QModelIndex,int,int)));
connect(submodel, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(RowsInserted(QModelIndex,int,int)));
connect(submodel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(RowsRemoved(QModelIndex,int,int)));
connect(submodel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(DataChanged(QModelIndex,QModelIndex)));
connect(submodel, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this,
SLOT(RowsAboutToBeInserted(QModelIndex, int, int)));
connect(submodel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this,
SLOT(RowsAboutToBeRemoved(QModelIndex, int, int)));
connect(submodel, SIGNAL(rowsInserted(QModelIndex, int, int)), this,
SLOT(RowsInserted(QModelIndex, int, int)));
connect(submodel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this,
SLOT(RowsRemoved(QModelIndex, int, int)));
connect(submodel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this,
SLOT(DataChanged(QModelIndex, QModelIndex)));
QModelIndex proxy_parent = mapFromSource(source_parent);
const int rows = submodel->rowCount();
if (rows)
beginInsertRows(proxy_parent, 0, rows-1);
if (rows) beginInsertRows(proxy_parent, 0, rows - 1);
merge_points_.insert(submodel, source_parent);
if (rows)
endInsertRows();
if (rows) endInsertRows();
}
void MergedProxyModel::RemoveSubModel(const QModelIndex& source_parent) {
@ -147,21 +137,24 @@ void MergedProxyModel::RemoveSubModel(const QModelIndex &source_parent) {
void MergedProxyModel::setSourceModel(QAbstractItemModel* source_model) {
if (sourceModel()) {
disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(SourceModelReset()));
disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(RowsAboutToBeInserted(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(RowsAboutToBeRemoved(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(RowsInserted(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(RowsRemoved(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(modelReset()), this,
SLOT(SourceModelReset()));
disconnect(sourceModel(),
SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this,
SLOT(RowsAboutToBeInserted(QModelIndex, int, int)));
disconnect(sourceModel(),
SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this,
SLOT(RowsAboutToBeRemoved(QModelIndex, int, int)));
disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), this,
SLOT(RowsInserted(QModelIndex, int, int)));
disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this,
SLOT(RowsRemoved(QModelIndex, int, int)));
disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex, QModelIndex)),
this, SLOT(DataChanged(QModelIndex, QModelIndex)));
disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
this, SLOT(LayoutAboutToBeChanged()));
disconnect(sourceModel(), SIGNAL(layoutChanged()),
this, SLOT(LayoutChanged()));
disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()), this,
SLOT(LayoutAboutToBeChanged()));
disconnect(sourceModel(), SIGNAL(layoutChanged()), this,
SLOT(LayoutChanged()));
}
QAbstractProxyModel::setSourceModel(source_model);
@ -171,16 +164,15 @@ void MergedProxyModel::setSourceModel(QAbstractItemModel* source_model) {
this, SLOT(RowsAboutToBeInserted(QModelIndex, int, int)));
connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
this, SLOT(RowsAboutToBeRemoved(QModelIndex, int, int)));
connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(RowsInserted(QModelIndex,int,int)));
connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(RowsRemoved(QModelIndex,int,int)));
connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(DataChanged(QModelIndex,QModelIndex)));
connect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
this, SLOT(LayoutAboutToBeChanged()));
connect(sourceModel(), SIGNAL(layoutChanged()),
this, SLOT(LayoutChanged()));
connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), this,
SLOT(RowsInserted(QModelIndex, int, int)));
connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this,
SLOT(RowsRemoved(QModelIndex, int, int)));
connect(sourceModel(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), this,
SLOT(DataChanged(QModelIndex, QModelIndex)));
connect(sourceModel(), SIGNAL(layoutAboutToBeChanged()), this,
SLOT(LayoutAboutToBeChanged()));
connect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(LayoutChanged()));
}
void MergedProxyModel::SourceModelReset() {
@ -234,8 +226,8 @@ void MergedProxyModel::SubModelReset() {
emit SubModelReset(proxy_parent, submodel);
}
QModelIndex MergedProxyModel::GetActualSourceParent(const QModelIndex& source_parent,
QAbstractItemModel* model) const {
QModelIndex MergedProxyModel::GetActualSourceParent(
const QModelIndex& source_parent, QAbstractItemModel* model) const {
if (!source_parent.isValid() && model != sourceModel())
return merge_points_.value(model);
return source_parent;
@ -243,7 +235,8 @@ QModelIndex MergedProxyModel::GetActualSourceParent(const QModelIndex& source_pa
void MergedProxyModel::RowsAboutToBeInserted(const QModelIndex& source_parent,
int start, int end) {
beginInsertRows(mapFromSource(GetActualSourceParent(
beginInsertRows(
mapFromSource(GetActualSourceParent(
source_parent, static_cast<QAbstractItemModel*>(sender()))),
start, end);
}
@ -254,7 +247,8 @@ void MergedProxyModel::RowsInserted(const QModelIndex&, int, int) {
void MergedProxyModel::RowsAboutToBeRemoved(const QModelIndex& source_parent,
int start, int end) {
beginRemoveRows(mapFromSource(GetActualSourceParent(
beginRemoveRows(
mapFromSource(GetActualSourceParent(
source_parent, static_cast<QAbstractItemModel*>(sender()))),
start, end);
}
@ -263,29 +257,26 @@ void MergedProxyModel::RowsRemoved(const QModelIndex&, int, int) {
endRemoveRows();
}
QModelIndex MergedProxyModel::mapToSource(const QModelIndex& proxy_index) const {
if (!proxy_index.isValid())
return QModelIndex();
QModelIndex MergedProxyModel::mapToSource(const QModelIndex& proxy_index)
const {
if (!proxy_index.isValid()) return QModelIndex();
Mapping* mapping = static_cast<Mapping*>(proxy_index.internalPointer());
if (p_->mappings_.get<tag_by_pointer>().find(mapping) ==
p_->mappings_.get<tag_by_pointer>().end())
return QModelIndex();
if (mapping->source_index.model() == resetting_model_)
return QModelIndex();
if (mapping->source_index.model() == resetting_model_) return QModelIndex();
return mapping->source_index;
}
QModelIndex MergedProxyModel::mapFromSource(const QModelIndex& source_index) const {
if (!source_index.isValid())
return QModelIndex();
if (source_index.model() == resetting_model_)
return QModelIndex();
QModelIndex MergedProxyModel::mapFromSource(const QModelIndex& source_index)
const {
if (!source_index.isValid()) return QModelIndex();
if (source_index.model() == resetting_model_) return QModelIndex();
// Add a mapping if we don't have one already
const auto& it =
p_->mappings_.get<tag_by_source>().find(source_index);
const auto& it = p_->mappings_.get<tag_by_source>().find(source_index);
Mapping* mapping;
if (it != p_->mappings_.get<tag_by_source>().end()) {
mapping = *it;
@ -297,7 +288,8 @@ QModelIndex MergedProxyModel::mapFromSource(const QModelIndex& source_index) con
return createIndex(source_index.row(), source_index.column(), mapping);
}
QModelIndex MergedProxyModel::index(int row, int column, const QModelIndex &parent) const {
QModelIndex MergedProxyModel::index(int row, int column,
const QModelIndex& parent) const {
QModelIndex source_index;
if (!parent.isValid()) {
@ -320,8 +312,7 @@ QModelIndex MergedProxyModel::parent(const QModelIndex &child) const {
if (source_child.model() == sourceModel())
return mapFromSource(source_child.parent());
if (!IsKnownModel(source_child.model()))
return QModelIndex();
if (!IsKnownModel(source_child.model())) return QModelIndex();
if (!source_child.parent().isValid())
return mapFromSource(merge_points_.value(GetModel(source_child)));
@ -329,12 +320,10 @@ QModelIndex MergedProxyModel::parent(const QModelIndex &child) const {
}
int MergedProxyModel::rowCount(const QModelIndex& parent) const {
if (!parent.isValid())
return sourceModel()->rowCount(QModelIndex());
if (!parent.isValid()) return sourceModel()->rowCount(QModelIndex());
QModelIndex source_parent = mapToSource(parent);
if (!IsKnownModel(source_parent.model()))
return 0;
if (!IsKnownModel(source_parent.model())) return 0;
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
if (child_model) {
@ -349,26 +338,21 @@ int MergedProxyModel::rowCount(const QModelIndex &parent) const {
}
int MergedProxyModel::columnCount(const QModelIndex& parent) const {
if (!parent.isValid())
return sourceModel()->columnCount(QModelIndex());
if (!parent.isValid()) return sourceModel()->columnCount(QModelIndex());
QModelIndex source_parent = mapToSource(parent);
if (!IsKnownModel(source_parent.model()))
return 0;
if (!IsKnownModel(source_parent.model())) return 0;
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
if (child_model)
return child_model->columnCount(QModelIndex());
if (child_model) return child_model->columnCount(QModelIndex());
return source_parent.model()->columnCount(source_parent);
}
bool MergedProxyModel::hasChildren(const QModelIndex& parent) const {
if (!parent.isValid())
return sourceModel()->hasChildren(QModelIndex());
if (!parent.isValid()) return sourceModel()->hasChildren(QModelIndex());
QModelIndex source_parent = mapToSource(parent);
if (!IsKnownModel(source_parent.model()))
return false;
if (!IsKnownModel(source_parent.model())) return false;
const QAbstractItemModel* child_model = merge_points_.key(source_parent);
@ -380,25 +364,23 @@ bool MergedProxyModel::hasChildren(const QModelIndex &parent) const {
QVariant MergedProxyModel::data(const QModelIndex& proxyIndex, int role) const {
QModelIndex source_index = mapToSource(proxyIndex);
if (!IsKnownModel(source_index.model()))
return QVariant();
if (!IsKnownModel(source_index.model())) return QVariant();
return source_index.model()->data(source_index, role);
}
QMap<int, QVariant> MergedProxyModel::itemData(const QModelIndex& proxy_index) const {
QMap<int, QVariant> MergedProxyModel::itemData(const QModelIndex& proxy_index)
const {
QModelIndex source_index = mapToSource(proxy_index);
if (!source_index.isValid())
return sourceModel()->itemData(QModelIndex());
if (!source_index.isValid()) return sourceModel()->itemData(QModelIndex());
return source_index.model()->itemData(source_index);
}
Qt::ItemFlags MergedProxyModel::flags(const QModelIndex& index) const {
QModelIndex source_index = mapToSource(index);
if (!source_index.isValid())
return sourceModel()->flags(QModelIndex());
if (!source_index.isValid()) return sourceModel()->flags(QModelIndex());
return source_index.model()->flags(source_index);
}
@ -423,8 +405,7 @@ QStringList MergedProxyModel::mimeTypes() const {
}
QMimeData* MergedProxyModel::mimeData(const QModelIndexList& indexes) const {
if (indexes.isEmpty())
return 0;
if (indexes.isEmpty()) return 0;
// Only ask the first index's model
const QAbstractItemModel* model = mapToSource(indexes[0]).model();
@ -437,15 +418,16 @@ QMimeData* MergedProxyModel::mimeData(const QModelIndexList &indexes) const {
foreach(const QModelIndex & proxy_index, indexes) {
QModelIndex source_index = mapToSource(proxy_index);
if (source_index.model() != model)
continue;
if (source_index.model() != model) continue;
indexes_in_model << source_index;
}
return model->mimeData(indexes_in_model);
}
bool MergedProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) {
bool MergedProxyModel::dropMimeData(const QMimeData* data,
Qt::DropAction action, int row, int column,
const QModelIndex& parent) {
if (!parent.isValid()) {
return false;
}
@ -453,13 +435,12 @@ bool MergedProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action
return sourceModel()->dropMimeData(data, action, row, column, parent);
}
QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex& proxy_index) const {
if (!proxy_index.isValid())
return QModelIndex();
QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex& proxy_index)
const {
if (!proxy_index.isValid()) return QModelIndex();
QModelIndex source_index = mapToSource(proxy_index);
if (source_index.model() == sourceModel())
return source_index;
if (source_index.model() == sourceModel()) return source_index;
return merge_points_.value(GetModel(source_index));
}
@ -480,20 +461,20 @@ void MergedProxyModel::fetchMore(const QModelIndex& parent) {
GetModel(source_index)->fetchMore(source_index);
}
QAbstractItemModel* MergedProxyModel::GetModel(const QModelIndex& source_index) const {
QAbstractItemModel* MergedProxyModel::GetModel(const QModelIndex& source_index)
const {
// This is essentially const_cast<QAbstractItemModel*>(source_index.model()),
// but without the const_cast
const QAbstractItemModel* const_model = source_index.model();
if (const_model == sourceModel())
return sourceModel();
if (const_model == sourceModel()) return sourceModel();
foreach(QAbstractItemModel * submodel, merge_points_.keys()) {
if (submodel == const_model)
return submodel;
if (submodel == const_model) return submodel;
}
return nullptr;
}
void MergedProxyModel::DataChanged(const QModelIndex& top_left, const QModelIndex& bottom_right) {
void MergedProxyModel::DataChanged(const QModelIndex& top_left,
const QModelIndex& bottom_right) {
emit dataChanged(mapFromSource(top_left), mapFromSource(bottom_right));
}
@ -506,8 +487,7 @@ void MergedProxyModel::LayoutAboutToBeChanged() {
void MergedProxyModel::LayoutChanged() {
foreach(QAbstractItemModel * key, merge_points_.keys()) {
if (!old_merge_points_.contains(key))
continue;
if (!old_merge_points_.contains(key)) continue;
const int old_row = old_merge_points_[key].row();
const int new_row = merge_points_[key].row();
@ -526,7 +506,8 @@ bool MergedProxyModel::IsKnownModel(const QAbstractItemModel* model) const {
return false;
}
QModelIndexList MergedProxyModel::mapFromSource(const QModelIndexList& source_indexes) const {
QModelIndexList MergedProxyModel::mapFromSource(
const QModelIndexList& source_indexes) const {
QModelIndexList ret;
foreach(const QModelIndex & index, source_indexes) {
ret << mapFromSource(index);
@ -534,7 +515,8 @@ QModelIndexList MergedProxyModel::mapFromSource(const QModelIndexList& source_in
return ret;
}
QModelIndexList MergedProxyModel::mapToSource(const QModelIndexList& proxy_indexes) const {
QModelIndexList MergedProxyModel::mapToSource(
const QModelIndexList& proxy_indexes) const {
QModelIndexList ret;
foreach(const QModelIndex & index, proxy_indexes) {
ret << mapToSource(index);

View File

@ -34,7 +34,8 @@ class MergedProxyModel : public QAbstractProxyModel {
~MergedProxyModel();
// Make another model appear as a child of the given item in the source model.
void AddSubModel(const QModelIndex& source_parent, QAbstractItemModel* submodel);
void AddSubModel(const QModelIndex& source_parent,
QAbstractItemModel* submodel);
void RemoveSubModel(const QModelIndex& source_parent);
// Find the item in the source model that is the parent of the model
@ -47,14 +48,16 @@ class MergedProxyModel : public QAbstractProxyModel {
QModelIndex parent(const QModelIndex& child) const;
int rowCount(const QModelIndex& parent) const;
int columnCount(const QModelIndex& parent) const;
QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const;
QVariant data(const QModelIndex& proxyIndex,
int role = Qt::DisplayRole) const;
bool hasChildren(const QModelIndex& parent) const;
QMap<int, QVariant> itemData(const QModelIndex& proxyIndex) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
bool setData(const QModelIndex& index, const QVariant& value, int role);
QStringList mimeTypes() const;
QMimeData* mimeData(const QModelIndexList& indexes) const;
bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row,
int column, const QModelIndex& parent);
bool canFetchMore(const QModelIndex& parent) const;
void fetchMore(const QModelIndex& parent);
@ -77,11 +80,14 @@ class MergedProxyModel : public QAbstractProxyModel {
void SourceModelReset();
void SubModelReset();
void RowsAboutToBeInserted(const QModelIndex& source_parent, int start, int end);
void RowsAboutToBeInserted(const QModelIndex& source_parent, int start,
int end);
void RowsInserted(const QModelIndex& source_parent, int start, int end);
void RowsAboutToBeRemoved(const QModelIndex& source_parent, int start, int end);
void RowsAboutToBeRemoved(const QModelIndex& source_parent, int start,
int end);
void RowsRemoved(const QModelIndex& source_parent, int start, int end);
void DataChanged(const QModelIndex& top_left, const QModelIndex& bottom_right);
void DataChanged(const QModelIndex& top_left,
const QModelIndex& bottom_right);
void LayoutAboutToBeChanged();
void LayoutChanged();
@ -93,7 +99,6 @@ class MergedProxyModel : public QAbstractProxyModel {
void DeleteAllMappings();
bool IsKnownModel(const QAbstractItemModel* model) const;
QMap<QAbstractItemModel*, QPersistentModelIndex> merge_points_;
QAbstractItemModel* resetting_model_;

View File

@ -32,7 +32,8 @@ void RegisterMetaTypes() {
qRegisterMetaType<const char*>("const char*");
qRegisterMetaType<CoverSearchResult>("CoverSearchResult");
qRegisterMetaType<CoverSearchResults>("CoverSearchResults");
qRegisterMetaType<DigitallyImportedClient::Channel>("DigitallyImportedClient::Channel");
qRegisterMetaType<DigitallyImportedClient::Channel>(
"DigitallyImportedClient::Channel");
qRegisterMetaType<Directory>("Directory");
qRegisterMetaType<DirectoryList>("DirectoryList");
qRegisterMetaType<Engine::SimpleMetaBundle>("Engine::SimpleMetaBundle");
@ -49,8 +50,10 @@ void RegisterMetaTypes() {
qRegisterMetaType<PodcastList>("PodcastList");
qRegisterMetaType<QList<CoverSearchResult> >("QList<CoverSearchResult>");
qRegisterMetaType<QList<PlaylistItemPtr> >("QList<PlaylistItemPtr>");
qRegisterMetaType<PlaylistSequence::RepeatMode>("PlaylistSequence::RepeatMode");
qRegisterMetaType<PlaylistSequence::ShuffleMode>("PlaylistSequence::ShuffleMode");
qRegisterMetaType<PlaylistSequence::RepeatMode>(
"PlaylistSequence::RepeatMode");
qRegisterMetaType<PlaylistSequence::ShuffleMode>(
"PlaylistSequence::ShuffleMode");
qRegisterMetaType<QList<PodcastEpisode> >("QList<PodcastEpisode>");
qRegisterMetaType<QList<Podcast> >("QList<Podcast>");
qRegisterMetaType<QList<QNetworkCookie> >("QList<QNetworkCookie>");
@ -60,14 +63,17 @@ void RegisterMetaTypes() {
qRegisterMetaType<QNetworkReply**>("QNetworkReply**");
qRegisterMetaType<SearchProvider::ResultList>("SearchProvider::ResultList");
qRegisterMetaType<SearchProvider::Result>("SearchProvider::Result");
qRegisterMetaType<smart_playlists::GeneratorPtr>("smart_playlists::GeneratorPtr");
qRegisterMetaType<smart_playlists::GeneratorPtr>(
"smart_playlists::GeneratorPtr");
qRegisterMetaType<SomaFMService::Stream>("SomaFMService::Stream");
qRegisterMetaType<SongList>("SongList");
qRegisterMetaType<Song>("Song");
qRegisterMetaTypeStreamOperators<DigitallyImportedClient::Channel>("DigitallyImportedClient::Channel");
qRegisterMetaTypeStreamOperators<DigitallyImportedClient::Channel>(
"DigitallyImportedClient::Channel");
qRegisterMetaTypeStreamOperators<Equalizer::Params>("Equalizer::Params");
qRegisterMetaTypeStreamOperators<QMap<int, int> >("ColumnAlignmentMap");
qRegisterMetaTypeStreamOperators<SomaFMService::Stream>("SomaFMService::Stream");
qRegisterMetaTypeStreamOperators<SomaFMService::Stream>(
"SomaFMService::Stream");
qRegisterMetaType<SubdirectoryList>("SubdirectoryList");
qRegisterMetaType<Subdirectory>("Subdirectory");
qRegisterMetaType<QList<QUrl> >("QList<QUrl>");

View File

@ -24,8 +24,8 @@ class MimeData : public QMimeData {
Q_OBJECT
public:
MimeData(bool clear = false, bool play_now = false,
bool enqueue = false, bool open_in_new_playlist = false)
MimeData(bool clear = false, bool play_now = false, bool enqueue = false,
bool open_in_new_playlist = false)
: override_user_settings_(false),
clear_first_(clear),
play_now_(play_now),
@ -43,7 +43,8 @@ public:
// If this is set then the first item that is inserted will start playing
// immediately. Note: this is always overridden with the user's preference
// if the MimeData goes via MainWindow, unless you set override_user_settings_.
// if the MimeData goes via MainWindow, unless you set
// override_user_settings_.
bool play_now_;
// If this is set then the items are added to the queue after being inserted.
@ -60,11 +61,14 @@ public:
// the defaults set by the user.
bool from_doubleclick_;
// Returns a pretty name for a playlist containing songs described by this MimeData
// object. By pretty name we mean the value of 'name_for_new_playlist_' or generic
// Returns a pretty name for a playlist containing songs described by this
// MimeData
// object. By pretty name we mean the value of 'name_for_new_playlist_' or
// generic
// "Playlist" string if the 'name_for_new_playlist_' attribute is empty.
QString get_name_for_new_playlist() {
return name_for_new_playlist_.isEmpty() ? tr("Playlist") : name_for_new_playlist_;
return name_for_new_playlist_.isEmpty() ? tr("Playlist")
: name_for_new_playlist_;
}
};

View File

@ -8,18 +8,14 @@ template <typename T>
class ModelFutureWatcher : public QFutureWatcher<T> {
public:
ModelFutureWatcher(const QModelIndex& index, QObject* parent = 0)
: QFutureWatcher<T>(parent),
index_(index) {
}
: QFutureWatcher<T>(parent), index_(index) {}
~ModelFutureWatcher() {
}
~ModelFutureWatcher() {}
const QPersistentModelIndex& index() const { return index_; }
private:
QPersistentModelIndex index_;
};
#endif

View File

@ -24,8 +24,7 @@ namespace mpris {
Mpris::Mpris(Application* app, QObject* parent)
: QObject(parent),
mpris1_(new mpris::Mpris1(app, this)),
mpris2_(new mpris::Mpris2(app, mpris1_, this))
{
mpris2_(new mpris::Mpris2(app, mpris1_, this)) {
connect(mpris2_, SIGNAL(RaiseMainWindow()), SIGNAL(RaiseMainWindow()));
}

View File

@ -43,8 +43,7 @@ Mpris1::Mpris1(Application* app, QObject* parent,
dbus_service_name_(dbus_service_name),
root_(nullptr),
player_(nullptr),
tracklist_(nullptr)
{
tracklist_(nullptr) {
qDBusRegisterMetaType<DBusStatus>();
qDBusRegisterMetaType<Version>();
@ -53,7 +52,8 @@ Mpris1::Mpris1(Application* app, QObject* parent,
}
if (!QDBusConnection::sessionBus().registerService(dbus_service_name_)) {
qLog(Warning) << "Failed to register" << dbus_service_name_ << "on the session bus";
qLog(Warning) << "Failed to register" << dbus_service_name_
<< "on the session bus";
return;
}
@ -61,8 +61,10 @@ Mpris1::Mpris1(Application* app, QObject* parent,
player_ = new Mpris1Player(app, this);
tracklist_ = new Mpris1TrackList(app, this);
connect(app->current_art_loader(), SIGNAL(ArtLoaded(const Song&, const QString&, const QImage&)),
player_, SLOT(CurrentSongChanged(const Song&, const QString&, const QImage&)));
connect(app->current_art_loader(),
SIGNAL(ArtLoaded(const Song&, const QString&, const QImage&)),
player_,
SLOT(CurrentSongChanged(const Song&, const QString&, const QImage&)));
}
Mpris1::~Mpris1() {
@ -70,27 +72,29 @@ Mpris1::~Mpris1() {
}
Mpris1Root::Mpris1Root(Application* app, QObject* parent)
: QObject(parent),
app_(app) {
: QObject(parent), app_(app) {
new MprisRoot(this);
QDBusConnection::sessionBus().registerObject("/", this);
}
Mpris1Player::Mpris1Player(Application* app, QObject* parent)
: QObject(parent),
app_(app) {
: QObject(parent), app_(app) {
new MprisPlayer(this);
QDBusConnection::sessionBus().registerObject("/Player", this);
connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()), SLOT(PlaylistManagerInitialized()));
connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)),
SLOT(EngineStateChanged(Engine::State)));
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()),
SLOT(PlaylistManagerInitialized()));
}
// when PlaylistManager gets it ready, we connect PlaylistSequence with this
void Mpris1Player::PlaylistManagerInitialized() {
connect(app_->playlist_manager()->sequence(), SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)),
connect(app_->playlist_manager()->sequence(),
SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)),
SLOT(ShuffleModeChanged()));
connect(app_->playlist_manager()->sequence(), SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)),
connect(app_->playlist_manager()->sequence(),
SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)),
SLOT(RepeatModeChanged()));
}
@ -99,7 +103,8 @@ Mpris1TrackList::Mpris1TrackList(Application* app, QObject* parent)
new MprisTrackList(this);
QDBusConnection::sessionBus().registerObject("/TrackList", this);
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)), SLOT(PlaylistChanged(Playlist*)));
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)),
SLOT(PlaylistChanged(Playlist*)));
}
void Mpris1TrackList::PlaylistChanged(Playlist* playlist) {
@ -113,8 +118,8 @@ void Mpris1Player::EngineStateChanged(Engine::State state) {
emit CapsChange(GetCaps(state));
}
void Mpris1Player::CurrentSongChanged(
const Song& song, const QString& art_uri, const QImage&) {
void Mpris1Player::CurrentSongChanged(const Song& song, const QString& art_uri,
const QImage&) {
last_metadata_ = Mpris1::GetMetadata(song);
if (!art_uri.isEmpty()) {
@ -126,10 +131,8 @@ void Mpris1Player::CurrentSongChanged(
emit CapsChange(GetCaps());
}
QString Mpris1Root::Identity() {
return QString("%1 %2").arg(
QCoreApplication::applicationName(),
return QString("%1 %2").arg(QCoreApplication::applicationName(),
QCoreApplication::applicationVersion());
}
@ -140,42 +143,26 @@ Version Mpris1Root::MprisVersion() {
return version;
}
void Mpris1Root::Quit() {
qApp->quit();
}
void Mpris1Root::Quit() { qApp->quit(); }
void Mpris1Player::Pause() {
app_->player()->PlayPause();
}
void Mpris1Player::Pause() { app_->player()->PlayPause(); }
void Mpris1Player::Stop() {
app_->player()->Stop();
}
void Mpris1Player::Stop() { app_->player()->Stop(); }
void Mpris1Player::Prev() {
app_->player()->Previous();
}
void Mpris1Player::Prev() { app_->player()->Previous(); }
void Mpris1Player::Play() {
app_->player()->Play();
}
void Mpris1Player::Play() { app_->player()->Play(); }
void Mpris1Player::Next() {
app_->player()->Next();
}
void Mpris1Player::Next() { app_->player()->Next(); }
void Mpris1Player::Repeat(bool repeat) {
app_->playlist_manager()->sequence()->SetRepeatMode(
repeat ? PlaylistSequence::Repeat_Track : PlaylistSequence::Repeat_Off);
}
void Mpris1Player::ShuffleModeChanged() {
emit StatusChange(GetStatus());
}
void Mpris1Player::ShuffleModeChanged() { emit StatusChange(GetStatus()); }
void Mpris1Player::RepeatModeChanged() {
emit StatusChange(GetStatus());
}
void Mpris1Player::RepeatModeChanged() { emit StatusChange(GetStatus()); }
DBusStatus Mpris1Player::GetStatus() const {
return GetStatus(app_->player()->GetState());
@ -199,25 +186,27 @@ DBusStatus Mpris1Player::GetStatus(Engine::State state) const {
if (app_->playlist_manager()->sequence()) {
PlaylistManagerInterface* playlists_ = app_->playlist_manager();
PlaylistSequence::RepeatMode repeat_mode = playlists_->sequence()->repeat_mode();
PlaylistSequence::RepeatMode repeat_mode =
playlists_->sequence()->repeat_mode();
status.random = playlists_->sequence()->shuffle_mode() == PlaylistSequence::Shuffle_Off ? 0 : 1;
status.random =
playlists_->sequence()->shuffle_mode() == PlaylistSequence::Shuffle_Off
? 0
: 1;
status.repeat = repeat_mode == PlaylistSequence::Repeat_Track ? 1 : 0;
status.repeat_playlist = (repeat_mode == PlaylistSequence::Repeat_Album ||
status.repeat_playlist =
(repeat_mode == PlaylistSequence::Repeat_Album ||
repeat_mode == PlaylistSequence::Repeat_Playlist ||
repeat_mode == PlaylistSequence::Repeat_Track) ? 1 : 0;
repeat_mode == PlaylistSequence::Repeat_Track)
? 1
: 0;
}
return status;
}
void Mpris1Player::VolumeSet(int volume) {
app_->player()->SetVolume(volume);
}
void Mpris1Player::VolumeSet(int volume) { app_->player()->SetVolume(volume); }
int Mpris1Player::VolumeGet() const {
return app_->player()->GetVolume();
}
int Mpris1Player::VolumeGet() const { return app_->player()->GetVolume(); }
void Mpris1Player::PositionSet(int pos_msec) {
app_->player()->SeekTo(pos_msec / kMsecPerSec);
@ -227,9 +216,7 @@ int Mpris1Player::PositionGet() const {
return app_->player()->engine()->position_nanosec() / kNsecPerMsec;
}
QVariantMap Mpris1Player::GetMetadata() const {
return last_metadata_;
}
QVariantMap Mpris1Player::GetMetadata() const { return last_metadata_; }
int Mpris1Player::GetCaps() const {
return GetCaps(app_->player()->GetState());
@ -241,9 +228,12 @@ int Mpris1Player::GetCaps(Engine::State state) const {
PlaylistManagerInterface* playlists = app_->playlist_manager();
if (playlists->active()) {
// play is disabled when playlist is empty or when last.fm stream is already playing
if (playlists->active() && playlists->active()->rowCount() != 0
&& !(state == Engine::Playing && (app_->player()->GetCurrentItem()->options() & PlaylistItem::LastFMControls))) {
// play is disabled when playlist is empty or when last.fm stream is already
// playing
if (playlists->active() && playlists->active()->rowCount() != 0 &&
!(state == Engine::Playing &&
(app_->player()->GetCurrentItem()->options() &
PlaylistItem::LastFMControls))) {
caps |= CAN_PLAY;
}
@ -257,7 +247,8 @@ int Mpris1Player::GetCaps(Engine::State state) const {
if (current_item) {
caps |= CAN_PROVIDE_METADATA;
if (state == Engine::Playing && !(current_item->options() & PlaylistItem::PauseDisabled)) {
if (state == Engine::Playing &&
!(current_item->options() & PlaylistItem::PauseDisabled)) {
caps |= CAN_PAUSE;
}
if (state != Engine::Empty && !current_item->Metadata().is_stream()) {
@ -268,25 +259,17 @@ int Mpris1Player::GetCaps(Engine::State state) const {
return caps;
}
void Mpris1Player::VolumeUp(int change) {
VolumeSet(VolumeGet() + change);
}
void Mpris1Player::VolumeUp(int change) { VolumeSet(VolumeGet() + change); }
void Mpris1Player::VolumeDown(int change) {
VolumeSet(VolumeGet() - change);
}
void Mpris1Player::VolumeDown(int change) { VolumeSet(VolumeGet() - change); }
void Mpris1Player::Mute() {
app_->player()->Mute();
}
void Mpris1Player::Mute() { app_->player()->Mute(); }
void Mpris1Player::ShowOSD() {
app_->player()->ShowOSD();
}
void Mpris1Player::ShowOSD() { app_->player()->ShowOSD(); }
int Mpris1TrackList::AddTrack(const QString& track, bool play) {
app_->playlist_manager()->active()->InsertUrls(
QList<QUrl>() << QUrl(track), -1, play);
app_->playlist_manager()->active()->InsertUrls(QList<QUrl>() << QUrl(track),
-1, play);
return 0;
}
@ -304,15 +287,15 @@ int Mpris1TrackList::GetLength() const {
QVariantMap Mpris1TrackList::GetMetadata(int pos) const {
PlaylistItemPtr item = app_->player()->GetItemAt(pos);
if (!item)
return QVariantMap();
if (!item) return QVariantMap();
return Mpris1::GetMetadata(item->Metadata());
}
void Mpris1TrackList::SetLoop(bool enable) {
app_->playlist_manager()->active()->sequence()->SetRepeatMode(
enable ? PlaylistSequence::Repeat_Playlist : PlaylistSequence::Repeat_Off);
enable ? PlaylistSequence::Repeat_Playlist
: PlaylistSequence::Repeat_Off);
}
void Mpris1TrackList::SetRandom(bool enable) {
@ -353,7 +336,6 @@ QVariantMap Mpris1::GetMetadata(const Song& song) {
} // namespace mpris
QDBusArgument& operator<<(QDBusArgument& arg, const Version& version) {
arg.beginStructure();
arg << version.major << version.minor;

View File

@ -29,16 +29,13 @@ class Playlist;
struct DBusStatus { // From Amarok.
DBusStatus()
: play(Mpris_Stopped),
random(0),
repeat(0),
repeat_playlist(0)
{}
: play(Mpris_Stopped), random(0), repeat(0), repeat_playlist(0) {}
int play; // Playing = 0, Paused = 1, Stopped = 2
int random; // Linearly = 0, Randomly = 1
int repeat; // Go_To_Next = 0, Repeat_Current = 1
int repeat_playlist; // Stop_When_Finished = 0, Never_Give_Up_Playing = 1, Never_Let_You_Down = 42
int repeat_playlist; // Stop_When_Finished = 0, Never_Give_Up_Playing = 1,
// Never_Let_You_Down = 42
enum MprisPlayState {
Mpris_Playing = 0,
@ -51,7 +48,6 @@ Q_DECLARE_METATYPE(DBusStatus);
QDBusArgument& operator<<(QDBusArgument& arg, const DBusStatus& status);
const QDBusArgument& operator>>(const QDBusArgument& arg, DBusStatus& status);
struct Version {
quint16 minor;
quint16 major;
@ -78,7 +74,6 @@ class Mpris1Root;
class Mpris1Player;
class Mpris1TrackList;
class Mpris1 : public QObject {
Q_OBJECT
@ -103,7 +98,6 @@ private:
Mpris1TrackList* tracklist_;
};
class Mpris1Root : public QObject {
Q_OBJECT
@ -118,7 +112,6 @@ private:
Application* app_;
};
class Mpris1Player : public QObject {
Q_OBJECT
@ -132,7 +125,8 @@ public:
void Next();
void Repeat(bool);
// those methods will use engine's state obtained with player->GetState() method
// those methods will use engine's state obtained with player->GetState()
// method
DBusStatus GetStatus() const;
int GetCaps() const;
// those methods will use engine's state provided as an argument
@ -152,8 +146,8 @@ public:
void ShowOSD();
public slots:
void CurrentSongChanged(
const Song& song, const QString& art_uri, const QImage&);
void CurrentSongChanged(const Song& song, const QString& art_uri,
const QImage&);
signals:
void CapsChange(int);
@ -173,7 +167,6 @@ private:
QVariantMap last_metadata_;
};
class Mpris1TrackList : public QObject {
Q_OBJECT

View File

@ -48,8 +48,8 @@ QDBusArgument& operator<< (QDBusArgument& arg, const MprisPlaylist& playlist) {
return arg;
}
const QDBusArgument& operator>> (
const QDBusArgument& arg, MprisPlaylist& playlist) {
const QDBusArgument& operator>>(const QDBusArgument& arg,
MprisPlaylist& playlist) {
arg.beginStructure();
arg >> playlist.id >> playlist.name >> playlist.icon;
arg.endStructure();
@ -64,8 +64,8 @@ QDBusArgument& operator<< (QDBusArgument& arg, const MaybePlaylist& playlist) {
return arg;
}
const QDBusArgument& operator>> (
const QDBusArgument& arg, MaybePlaylist& playlist) {
const QDBusArgument& operator>>(const QDBusArgument& arg,
MaybePlaylist& playlist) {
arg.beginStructure();
arg >> playlist.valid >> playlist.playlist;
arg.endStructure();
@ -79,39 +79,45 @@ const char* Mpris2::kServiceName = "org.mpris.MediaPlayer2.clementine";
const char* Mpris2::kFreedesktopPath = "org.freedesktop.DBus.Properties";
Mpris2::Mpris2(Application* app, Mpris1* mpris1, QObject* parent)
: QObject(parent),
app_(app),
mpris1_(mpris1)
{
: QObject(parent), app_(app), mpris1_(mpris1) {
new Mpris2Root(this);
new Mpris2TrackList(this);
new Mpris2Player(this);
new Mpris2Playlists(this);
if (!QDBusConnection::sessionBus().registerService(kServiceName)) {
qLog(Warning) << "Failed to register" << QString(kServiceName) << "on the session bus";
qLog(Warning) << "Failed to register" << QString(kServiceName)
<< "on the session bus";
return;
}
QDBusConnection::sessionBus().registerObject(kMprisObjectPath, this);
connect(app_->current_art_loader(), SIGNAL(ArtLoaded(Song,QString,QImage)), SLOT(ArtLoaded(Song,QString)));
connect(app_->current_art_loader(), SIGNAL(ArtLoaded(Song, QString, QImage)),
SLOT(ArtLoaded(Song, QString)));
connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)),
SLOT(EngineStateChanged(Engine::State)));
connect(app_->player(), SIGNAL(VolumeChanged(int)), SLOT(VolumeChanged()));
connect(app_->player(), SIGNAL(Seeked(qlonglong)), SIGNAL(Seeked(qlonglong)));
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()), SLOT(PlaylistManagerInitialized()));
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), SLOT(CurrentSongChanged(Song)));
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)), SLOT(PlaylistChanged(Playlist*)));
connect(app_->playlist_manager(), SIGNAL(CurrentChanged(Playlist*)), SLOT(PlaylistCollectionChanged(Playlist*)));
connect(app_->playlist_manager(), SIGNAL(PlaylistManagerInitialized()),
SLOT(PlaylistManagerInitialized()));
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)),
SLOT(CurrentSongChanged(Song)));
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)),
SLOT(PlaylistChanged(Playlist*)));
connect(app_->playlist_manager(), SIGNAL(CurrentChanged(Playlist*)),
SLOT(PlaylistCollectionChanged(Playlist*)));
}
// when PlaylistManager gets it ready, we connect PlaylistSequence with this
void Mpris2::PlaylistManagerInitialized() {
connect(app_->playlist_manager()->sequence(), SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)),
connect(app_->playlist_manager()->sequence(),
SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)),
SLOT(ShuffleModeChanged()));
connect(app_->playlist_manager()->sequence(), SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)),
connect(app_->playlist_manager()->sequence(),
SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)),
SLOT(RepeatModeChanged()));
}
@ -124,65 +130,54 @@ void Mpris2::EngineStateChanged(Engine::State newState) {
EmitNotification("PlaybackStatus", PlaybackStatus(newState));
}
void Mpris2::VolumeChanged() {
EmitNotification("Volume");
}
void Mpris2::VolumeChanged() { EmitNotification("Volume"); }
void Mpris2::ShuffleModeChanged() {
EmitNotification("Shuffle");
}
void Mpris2::ShuffleModeChanged() { EmitNotification("Shuffle"); }
void Mpris2::RepeatModeChanged() {
EmitNotification("LoopStatus");
}
void Mpris2::RepeatModeChanged() { EmitNotification("LoopStatus"); }
void Mpris2::EmitNotification(const QString& name, const QVariant& val) {
EmitNotification(name, val, "org.mpris.MediaPlayer2.Player");
}
void Mpris2::EmitNotification(const QString& name, const QVariant& val, const QString& mprisEntity) {
void Mpris2::EmitNotification(const QString& name, const QVariant& val,
const QString& mprisEntity) {
QDBusMessage msg = QDBusMessage::createSignal(
kMprisObjectPath, kFreedesktopPath, "PropertiesChanged");
QVariantMap map;
map.insert(name, val);
QVariantList args = QVariantList()
<< mprisEntity
<< map
<< QStringList();
QVariantList args = QVariantList() << mprisEntity << map << QStringList();
msg.setArguments(args);
QDBusConnection::sessionBus().send(msg);
}
void Mpris2::EmitNotification(const QString& name) {
QVariant value;
if (name == "PlaybackStatus") value = PlaybackStatus();
else if (name == "LoopStatus") value = LoopStatus();
else if (name == "Shuffle") value = Shuffle();
else if (name == "Metadata") value = Metadata();
else if (name == "Volume") value = Volume();
else if (name == "Position") value = Position();
if (name == "PlaybackStatus")
value = PlaybackStatus();
else if (name == "LoopStatus")
value = LoopStatus();
else if (name == "Shuffle")
value = Shuffle();
else if (name == "Metadata")
value = Metadata();
else if (name == "Volume")
value = Volume();
else if (name == "Position")
value = Position();
if (value.isValid())
EmitNotification(name, value);
if (value.isValid()) EmitNotification(name, value);
}
//------------------Root Interface--------------------------//
bool Mpris2::CanQuit() const {
return true;
}
bool Mpris2::CanQuit() const { return true; }
bool Mpris2::CanRaise() const {
return true;
}
bool Mpris2::CanRaise() const { return true; }
bool Mpris2::HasTrackList() const {
return true;
}
bool Mpris2::HasTrackList() const { return true; }
QString Mpris2::Identity() const {
return QCoreApplication::applicationName();
}
QString Mpris2::Identity() const { return QCoreApplication::applicationName(); }
QString Mpris2::DesktopEntryAbsolutePath() const {
QStringList xdg_data_dirs = QString(getenv("XDG_DATA_DIRS")).split(":");
@ -190,10 +185,9 @@ QString Mpris2::DesktopEntryAbsolutePath() const {
xdg_data_dirs.append("/usr/share/");
foreach(const QString & directory, xdg_data_dirs) {
QString path = QString("%1/applications/%2.desktop").
arg(directory, QApplication::applicationName().toLower());
if (QFile::exists(path))
return path;
QString path = QString("%1/applications/%2.desktop").arg(
directory, QApplication::applicationName().toLower());
if (QFile::exists(path)) return path;
}
return QString();
}
@ -203,8 +197,7 @@ QString Mpris2::DesktopEntry() const {
}
QStringList Mpris2::SupportedUriSchemes() const {
static QStringList res = QStringList()
<< "file"
static QStringList res = QStringList() << "file"
<< "http"
<< "cdda"
<< "smb"
@ -213,8 +206,7 @@ QStringList Mpris2::SupportedUriSchemes() const {
}
QStringList Mpris2::SupportedMimeTypes() const {
static QStringList res = QStringList()
<< "application/ogg"
static QStringList res = QStringList() << "application/ogg"
<< "application/x-ogg"
<< "application/x-ogm-audio"
<< "audio/aac"
@ -242,13 +234,9 @@ QStringList Mpris2::SupportedMimeTypes() const {
return res;
}
void Mpris2::Raise() {
emit RaiseMainWindow();
}
void Mpris2::Raise() { emit RaiseMainWindow(); }
void Mpris2::Quit() {
qApp->quit();
}
void Mpris2::Quit() { qApp->quit(); }
QString Mpris2::PlaybackStatus() const {
return PlaybackStatus(app_->player()->GetState());
@ -256,9 +244,12 @@ QString Mpris2::PlaybackStatus() const {
QString Mpris2::PlaybackStatus(Engine::State state) const {
switch (state) {
case Engine::Playing: return "Playing";
case Engine::Paused: return "Paused";
default: return "Stopped";
case Engine::Playing:
return "Playing";
case Engine::Paused:
return "Paused";
default:
return "Stopped";
}
}
@ -269,9 +260,12 @@ QString Mpris2::LoopStatus() const {
switch (app_->playlist_manager()->sequence()->repeat_mode()) {
case PlaylistSequence::Repeat_Album:
case PlaylistSequence::Repeat_Playlist: return "Playlist";
case PlaylistSequence::Repeat_Track: return "Track";
default: return "None";
case PlaylistSequence::Repeat_Playlist:
return "Playlist";
case PlaylistSequence::Repeat_Track:
return "Track";
default:
return "None";
}
}
@ -289,9 +283,7 @@ void Mpris2::SetLoopStatus(const QString& value) {
app_->playlist_manager()->active()->sequence()->SetRepeatMode(mode);
}
double Mpris2::Rate() const {
return 1.0;
}
double Mpris2::Rate() const { return 1.0; }
void Mpris2::SetRate(double rate) {
if (rate == 0) {
@ -315,24 +307,20 @@ void Mpris2::SetShuffle(bool value) {
}
}
QVariantMap Mpris2::Metadata() const {
return last_metadata_;
}
QVariantMap Mpris2::Metadata() const { return last_metadata_; }
QString Mpris2::current_track_id() const {
if (!mpris1_->tracklist()) {
return QString();
}
return QString("/org/mpris/MediaPlayer2/Track/%1").arg(
QString::number(mpris1_->tracklist()->GetCurrentTrack()));
return QString("/org/mpris/MediaPlayer2/Track/%1")
.arg(QString::number(mpris1_->tracklist()->GetCurrentTrack()));
}
// We send Metadata change notification as soon as the process of
// changing song starts...
void Mpris2::CurrentSongChanged(const Song& song) {
ArtLoaded(song, "");
}
void Mpris2::CurrentSongChanged(const Song& song) { ArtLoaded(song, ""); }
// ... and we add the cover information later, when it's available.
void Mpris2::ArtLoaded(const Song& song, const QString& art_uri) {
@ -363,21 +351,15 @@ double Mpris2::Volume() const {
}
}
void Mpris2::SetVolume(double value) {
app_->player()->SetVolume(value * 100);
}
void Mpris2::SetVolume(double value) { app_->player()->SetVolume(value * 100); }
qlonglong Mpris2::Position() const {
return app_->player()->engine()->position_nanosec() / kNsecPerUsec;
}
double Mpris2::MaximumRate() const {
return 1.0;
}
double Mpris2::MaximumRate() const { return 1.0; }
double Mpris2::MinimumRate() const {
return 1.0;
}
double Mpris2::MinimumRate() const { return 1.0; }
bool Mpris2::CanGoNext() const {
if (mpris1_->player()) {
@ -395,17 +377,14 @@ bool Mpris2::CanGoPrevious() const {
}
}
bool Mpris2::CanPlay() const {
return mpris1_->player()->GetCaps() & CAN_PLAY;
}
bool Mpris2::CanPlay() const { return mpris1_->player()->GetCaps() & CAN_PLAY; }
// This one's a bit different than MPRIS 1 - we want this to be true even when
// the song is already paused or stopped.
bool Mpris2::CanPause() const {
if (mpris1_->player()) {
return mpris1_->player()->GetCaps() & CAN_PAUSE
|| PlaybackStatus() == "Paused"
|| PlaybackStatus() == "Stopped";
return mpris1_->player()->GetCaps() & CAN_PAUSE ||
PlaybackStatus() == "Paused" || PlaybackStatus() == "Stopped";
} else {
return true;
}
@ -419,9 +398,7 @@ bool Mpris2::CanSeek() const {
}
}
bool Mpris2::CanControl() const {
return true;
}
bool Mpris2::CanControl() const { return true; }
void Mpris2::Next() {
if (CanGoNext()) {
@ -447,9 +424,7 @@ void Mpris2::PlayPause() {
}
}
void Mpris2::Stop() {
app_->player()->Stop();
}
void Mpris2::Stop() { app_->player()->Stop(); }
void Mpris2::Play() {
if (CanPlay()) {
@ -459,7 +434,8 @@ void Mpris2::Play() {
void Mpris2::Seek(qlonglong offset) {
if (CanSeek()) {
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() / kNsecPerSec +
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() /
kNsecPerSec +
offset / kUsecPerSec);
}
}
@ -468,7 +444,8 @@ void Mpris2::SetPosition(const QDBusObjectPath& trackId, qlonglong offset) {
if (CanSeek() && trackId.path() == current_track_id() && offset >= 0) {
offset *= kNsecPerUsec;
if(offset < app_->player()->GetCurrentItem()->Metadata().length_nanosec()) {
if (offset <
app_->player()->GetCurrentItem()->Metadata().length_nanosec()) {
app_->player()->SeekTo(offset / kNsecPerSec);
}
}
@ -485,16 +462,15 @@ TrackIds Mpris2::Tracks() const {
return TrackIds();
}
bool Mpris2::CanEditTracks() const {
return false;
}
bool Mpris2::CanEditTracks() const { return false; }
TrackMetadata Mpris2::GetTracksMetadata(const TrackIds& tracks) const {
// TODO
return TrackMetadata();
}
void Mpris2::AddTrack(const QString &uri, const QDBusObjectPath &afterTrack, bool setAsCurrent) {
void Mpris2::AddTrack(const QString& uri, const QDBusObjectPath& afterTrack,
bool setAsCurrent) {
// TODO
}
@ -510,17 +486,14 @@ quint32 Mpris2::PlaylistCount() const {
return app_->playlist_manager()->GetAllPlaylists().size();
}
QStringList Mpris2::Orderings() const {
return QStringList() << "User";
}
QStringList Mpris2::Orderings() const { return QStringList() << "User"; }
namespace {
QDBusObjectPath MakePlaylistPath(int id) {
return QDBusObjectPath(QString(
"/org/mpris/MediaPlayer2/Playlists/%1").arg(id));
return QDBusObjectPath(
QString("/org/mpris/MediaPlayer2/Playlists/%1").arg(id));
}
}
MaybePlaylist Mpris2::ActivePlaylist() const {
@ -557,8 +530,9 @@ void Mpris2::ActivatePlaylist(const QDBusObjectPath& playlist_id) {
}
// TODO: Support sort orders.
MprisPlaylistList Mpris2::GetPlaylists(
quint32 index, quint32 max_count, const QString& order, bool reverse_order) {
MprisPlaylistList Mpris2::GetPlaylists(quint32 index, quint32 max_count,
const QString& order,
bool reverse_order) {
MprisPlaylistList ret;
foreach(Playlist * p, app_->playlist_manager()->GetAllPlaylists()) {
MprisPlaylist mpris_playlist;
@ -577,7 +551,8 @@ MprisPlaylistList Mpris2::GetPlaylists(
void Mpris2::PlaylistChanged(Playlist* playlist) {
MprisPlaylist mpris_playlist;
mpris_playlist.id = MakePlaylistPath(playlist->id());
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(playlist->id());
mpris_playlist.name =
app_->playlist_manager()->GetPlaylistName(playlist->id());
emit PlaylistChanged(mpris_playlist);
}

View File

@ -48,13 +48,12 @@ struct MaybePlaylist {
Q_DECLARE_METATYPE(MaybePlaylist);
QDBusArgument& operator<<(QDBusArgument& arg, const MprisPlaylist& playlist);
const QDBusArgument& operator>> (
const QDBusArgument& arg, MprisPlaylist& playlist);
const QDBusArgument& operator>>(const QDBusArgument& arg,
MprisPlaylist& playlist);
QDBusArgument& operator<<(QDBusArgument& arg, const MaybePlaylist& playlist);
const QDBusArgument& operator>> (
const QDBusArgument& arg, MaybePlaylist& playlist);
const QDBusArgument& operator>>(const QDBusArgument& arg,
MaybePlaylist& playlist);
namespace mpris {
@ -161,7 +160,8 @@ class Mpris2 : public QObject {
// Methods
TrackMetadata GetTracksMetadata(const TrackIds& tracks) const;
void AddTrack(const QString& uri, const QDBusObjectPath& afterTrack, bool setAsCurrent);
void AddTrack(const QString& uri, const QDBusObjectPath& afterTrack,
bool setAsCurrent);
void RemoveTrack(const QDBusObjectPath& trackId);
void GoTo(const QDBusObjectPath& trackId);
@ -172,8 +172,8 @@ class Mpris2 : public QObject {
// Methods
void ActivatePlaylist(const QDBusObjectPath& playlist_id);
QList<MprisPlaylist> GetPlaylists(
quint32 index, quint32 max_count, const QString& order, bool reverse_order);
QList<MprisPlaylist> GetPlaylists(quint32 index, quint32 max_count,
const QString& order, bool reverse_order);
signals:
// Player
@ -183,7 +183,8 @@ signals:
void TrackListReplaced(const TrackIds& Tracks, QDBusObjectPath CurrentTrack);
void TrackAdded(const TrackMetadata& Metadata, QDBusObjectPath AfterTrack);
void TrackRemoved(const QDBusObjectPath& trackId);
void TrackMetadataChanged(const QDBusObjectPath& trackId, const TrackMetadata& metadata);
void TrackMetadataChanged(const QDBusObjectPath& trackId,
const TrackMetadata& metadata);
void RaiseMainWindow();
@ -205,7 +206,8 @@ private slots:
private:
void EmitNotification(const QString& name);
void EmitNotification(const QString& name, const QVariant& val);
void EmitNotification(const QString& name, const QVariant& val, const QString& mprisEntity);
void EmitNotification(const QString& name, const QVariant& val,
const QString& mprisEntity);
QString PlaybackStatus(Engine::State state) const;

View File

@ -25,11 +25,13 @@
namespace mpris {
inline void AddMetadata(const QString& key, const QString& metadata, QVariantMap* map) {
inline void AddMetadata(const QString& key, const QString& metadata,
QVariantMap* map) {
if (!metadata.isEmpty()) (*map)[key] = metadata;
}
inline void AddMetadataAsList(const QString& key, const QString& metadata, QVariantMap* map) {
inline void AddMetadataAsList(const QString& key, const QString& metadata,
QVariantMap* map) {
if (!metadata.isEmpty()) (*map)[key] = QStringList() << metadata;
}
@ -45,7 +47,8 @@ inline void AddMetadata(const QString& key, double metadata, QVariantMap* map) {
if (metadata != 0.0) (*map)[key] = metadata;
}
inline void AddMetadata(const QString& key, const QDateTime& metadata, QVariantMap* map) {
inline void AddMetadata(const QString& key, const QDateTime& metadata,
QVariantMap* map) {
if (metadata.isValid()) (*map)[key] = metadata;
}

View File

@ -6,9 +6,7 @@
#include <QTime>
MultiSortFilterProxy::MultiSortFilterProxy(QObject* parent)
: QSortFilterProxyModel(parent)
{
}
: QSortFilterProxyModel(parent) {}
void MultiSortFilterProxy::AddSortSpec(int role, Qt::SortOrder order) {
sorting_ << SortSpec(role, order);
@ -31,29 +29,38 @@ bool MultiSortFilterProxy::lessThan(const QModelIndex& left,
template <typename T>
static inline int DoCompare(T left, T right) {
if (left < right)
return -1;
if (left > right)
return 1;
if (left < right) return -1;
if (left > right) return 1;
return 0;
}
int MultiSortFilterProxy::Compare(const QVariant& left, const QVariant& right) const {
int MultiSortFilterProxy::Compare(const QVariant& left,
const QVariant& right) const {
// Copied from the QSortFilterProxyModel::lessThan implementation, but returns
// -1, 0 or 1 instead of true or false.
switch (left.userType()) {
case QVariant::Invalid:
return (right.type() != QVariant::Invalid) ? -1 : 0;
case QVariant::Int: return DoCompare(left.toInt(), right.toInt());
case QVariant::UInt: return DoCompare(left.toUInt(), right.toUInt());
case QVariant::LongLong: return DoCompare(left.toLongLong(), right.toLongLong());
case QVariant::ULongLong: return DoCompare(left.toULongLong(), right.toULongLong());
case QMetaType::Float: return DoCompare(left.toFloat(), right.toFloat());
case QVariant::Double: return DoCompare(left.toDouble(), right.toDouble());
case QVariant::Char: return DoCompare(left.toChar(), right.toChar());
case QVariant::Date: return DoCompare(left.toDate(), right.toDate());
case QVariant::Time: return DoCompare(left.toTime(), right.toTime());
case QVariant::DateTime: return DoCompare(left.toDateTime(), right.toDateTime());
case QVariant::Int:
return DoCompare(left.toInt(), right.toInt());
case QVariant::UInt:
return DoCompare(left.toUInt(), right.toUInt());
case QVariant::LongLong:
return DoCompare(left.toLongLong(), right.toLongLong());
case QVariant::ULongLong:
return DoCompare(left.toULongLong(), right.toULongLong());
case QMetaType::Float:
return DoCompare(left.toFloat(), right.toFloat());
case QVariant::Double:
return DoCompare(left.toDouble(), right.toDouble());
case QVariant::Char:
return DoCompare(left.toChar(), right.toChar());
case QVariant::Date:
return DoCompare(left.toDate(), right.toDate());
case QVariant::Time:
return DoCompare(left.toTime(), right.toTime());
case QVariant::DateTime:
return DoCompare(left.toDateTime(), right.toDateTime());
case QVariant::String:
default:
if (isSortLocaleAware())

View File

@ -17,6 +17,4 @@
#include "musicstorage.h"
MusicStorage::MusicStorage()
{
}
MusicStorage::MusicStorage() {}

View File

@ -62,10 +62,16 @@ public:
virtual QString LocalPath() const { return QString(); }
virtual TranscodeMode GetTranscodeMode() const { return Transcode_Never; }
virtual Song::FileType GetTranscodeFormat() const { return Song::Type_Unknown; }
virtual bool GetSupportedFiletypes(QList<Song::FileType>* ret) { return true; }
virtual Song::FileType GetTranscodeFormat() const {
return Song::Type_Unknown;
}
virtual bool GetSupportedFiletypes(QList<Song::FileType>* ret) {
return true;
}
virtual bool StartCopy(QList<Song::FileType>* supported_types) { return true;}
virtual bool StartCopy(QList<Song::FileType>* supported_types) {
return true;
}
virtual bool CopyToStorage(const CopyJob& job) = 0;
virtual void FinishCopy(bool success) {}

View File

@ -29,12 +29,12 @@
QMutex ThreadSafeNetworkDiskCache::sMutex;
QNetworkDiskCache* ThreadSafeNetworkDiskCache::sCache = nullptr;
ThreadSafeNetworkDiskCache::ThreadSafeNetworkDiskCache(QObject* parent) {
QMutexLocker l(&sMutex);
if (!sCache) {
sCache = new QNetworkDiskCache;
sCache->setCacheDirectory(Utilities::GetConfigPath(Utilities::Path_NetworkCache));
sCache->setCacheDirectory(
Utilities::GetConfigPath(Utilities::Path_NetworkCache));
}
}
@ -58,7 +58,8 @@ QNetworkCacheMetaData ThreadSafeNetworkDiskCache::metaData(const QUrl& url) {
return sCache->metaData(url);
}
QIODevice* ThreadSafeNetworkDiskCache::prepare(const QNetworkCacheMetaData& metaData) {
QIODevice* ThreadSafeNetworkDiskCache::prepare(
const QNetworkCacheMetaData& metaData) {
QMutexLocker l(&sMutex);
return sCache->prepare(metaData);
}
@ -68,7 +69,8 @@ bool ThreadSafeNetworkDiskCache::remove(const QUrl& url) {
return sCache->remove(url);
}
void ThreadSafeNetworkDiskCache::updateMetaData(const QNetworkCacheMetaData& metaData) {
void ThreadSafeNetworkDiskCache::updateMetaData(
const QNetworkCacheMetaData& metaData) {
QMutexLocker l(&sMutex);
sCache->updateMetaData(metaData);
}
@ -78,18 +80,17 @@ void ThreadSafeNetworkDiskCache::clear() {
sCache->clear();
}
NetworkAccessManager::NetworkAccessManager(QObject* parent)
: QNetworkAccessManager(parent)
{
: QNetworkAccessManager(parent) {
setCache(new ThreadSafeNetworkDiskCache(this));
}
QNetworkReply* NetworkAccessManager::createRequest(
Operation op, const QNetworkRequest& request, QIODevice* outgoingData) {
QByteArray user_agent = QString("%1 %2").arg(
QCoreApplication::applicationName(),
QCoreApplication::applicationVersion()).toUtf8();
QByteArray user_agent = QString("%1 %2")
.arg(QCoreApplication::applicationName(),
QCoreApplication::applicationVersion())
.toUtf8();
if (request.hasRawHeader("User-Agent")) {
// Append the existing user-agent set by a client library (such as
@ -107,8 +108,8 @@ QNetworkReply* NetworkAccessManager::createRequest(
}
// Prefer the cache unless the caller has changed the setting already
if (request.attribute(QNetworkRequest::CacheLoadControlAttribute).toInt()
== QNetworkRequest::PreferNetwork) {
if (request.attribute(QNetworkRequest::CacheLoadControlAttribute).toInt() ==
QNetworkRequest::PreferNetwork) {
new_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::PreferCache);
}
@ -116,14 +117,11 @@ QNetworkReply* NetworkAccessManager::createRequest(
return QNetworkAccessManager::createRequest(op, new_request, outgoingData);
}
NetworkTimeouts::NetworkTimeouts(int timeout_msec, QObject* parent)
: timeout_msec_(timeout_msec) {
}
: timeout_msec_(timeout_msec) {}
void NetworkTimeouts::AddReply(QNetworkReply* reply) {
if (timers_.contains(reply))
return;
if (timers_.contains(reply)) return;
connect(reply, SIGNAL(destroyed()), SLOT(ReplyFinished()));
connect(reply, SIGNAL(finished()), SLOT(ReplyFinished()));
@ -167,8 +165,8 @@ void NetworkTimeouts::timerEvent(QTimerEvent* e) {
}
}
RedirectFollower::RedirectFollower(QNetworkReply* first_reply, int max_redirects)
RedirectFollower::RedirectFollower(QNetworkReply* first_reply,
int max_redirects)
: QObject(nullptr),
current_reply_(first_reply),
redirects_remaining_(max_redirects) {
@ -177,15 +175,19 @@ RedirectFollower::RedirectFollower(QNetworkReply* first_reply, int max_redirects
void RedirectFollower::ConnectReply(QNetworkReply* reply) {
connect(reply, SIGNAL(readyRead()), SLOT(ReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SIGNAL(error(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(downloadProgress(qint64,qint64)));
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SIGNAL(uploadProgress(qint64,qint64)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
SIGNAL(error(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(downloadProgress(qint64, qint64)),
SIGNAL(downloadProgress(qint64, qint64)));
connect(reply, SIGNAL(uploadProgress(qint64, qint64)),
SIGNAL(uploadProgress(qint64, qint64)));
connect(reply, SIGNAL(finished()), SLOT(ReplyFinished()));
}
void RedirectFollower::ReadyRead() {
// Don't re-emit this signal for redirect replies.
if (current_reply_->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) {
if (current_reply_->attribute(QNetworkRequest::RedirectionTargetAttribute)
.isValid()) {
return;
}
@ -195,14 +197,16 @@ void RedirectFollower::ReadyRead() {
void RedirectFollower::ReplyFinished() {
current_reply_->deleteLater();
if (current_reply_->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) {
if (current_reply_->attribute(QNetworkRequest::RedirectionTargetAttribute)
.isValid()) {
if (redirects_remaining_-- == 0) {
emit finished();
return;
}
const QUrl next_url = current_reply_->url().resolved(
current_reply_->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
current_reply_->attribute(QNetworkRequest::RedirectionTargetAttribute)
.toUrl());
QNetworkRequest req(current_reply_->request());
req.setUrl(next_url);

View File

@ -44,7 +44,6 @@ private:
static QNetworkDiskCache* sCache;
};
class NetworkAccessManager : public QNetworkAccessManager {
Q_OBJECT
@ -56,7 +55,6 @@ protected:
QIODevice* outgoingData);
};
class RedirectFollower : public QObject {
Q_OBJECT
@ -69,8 +67,12 @@ public:
// These are all forwarded to the current reply.
QNetworkReply::NetworkError error() const { return current_reply_->error(); }
QString errorString() const { return current_reply_->errorString(); }
QVariant attribute(QNetworkRequest::Attribute code) const { return current_reply_->attribute(code); }
QVariant header(QNetworkRequest::KnownHeaders header) const { return current_reply_->header(header); }
QVariant attribute(QNetworkRequest::Attribute code) const {
return current_reply_->attribute(code);
}
QVariant header(QNetworkRequest::KnownHeaders header) const {
return current_reply_->header(header);
}
qint64 bytesAvailable() const { return current_reply_->bytesAvailable(); }
QUrl url() const { return current_reply_->url(); }
QByteArray readAll() { return current_reply_->readAll(); }
@ -98,7 +100,6 @@ private:
int redirects_remaining_;
};
class NetworkTimeouts : public QObject {
Q_OBJECT

View File

@ -15,8 +15,7 @@ NetworkProxyFactory::NetworkProxyFactory()
: mode_(Mode_System),
type_(QNetworkProxy::HttpProxy),
port_(8080),
use_authentication_(false)
{
use_authentication_(false) {
#ifdef Q_OS_LINUX
// Linux uses environment variables to pass proxy configuration information,
// which systemProxyForQuery doesn't support for some reason.
@ -30,8 +29,7 @@ NetworkProxyFactory::NetworkProxyFactory()
qLog(Debug) << "Detected system proxy URLs:" << urls;
foreach(const QString & url_str, urls) {
if (url_str.isEmpty())
continue;
if (url_str.isEmpty()) continue;
env_url_ = QUrl(url_str);
break;
@ -56,7 +54,8 @@ void NetworkProxyFactory::ReloadSettings() {
s.beginGroup(kSettingsGroup);
mode_ = Mode(s.value("mode", Mode_System).toInt());
type_ = QNetworkProxy::ProxyType(s.value("type", QNetworkProxy::HttpProxy).toInt());
type_ = QNetworkProxy::ProxyType(
s.value("type", QNetworkProxy::HttpProxy).toInt());
hostname_ = s.value("hostname").toString();
port_ = s.value("port", 8080).toInt();
use_authentication_ = s.value("use_authentication", false).toBool();

View File

@ -8,11 +8,7 @@
class NetworkProxyFactory : public QNetworkProxyFactory {
public:
// These values are persisted
enum Mode {
Mode_System = 0,
Mode_Direct = 1,
Mode_Manual = 2,
};
enum Mode { Mode_System = 0, Mode_Direct = 1, Mode_Manual = 2, };
static NetworkProxyFactory* Instance();
static const char* kSettingsGroup;

View File

@ -53,8 +53,7 @@ Organise::Organise(TaskManager* task_manager,
tasks_complete_(0),
started_(false),
task_id_(0),
current_copy_progress_(0)
{
current_copy_progress_(0) {
original_thread_ = thread();
for (const NewSongInfo& song_info : songs_info) {
@ -63,15 +62,15 @@ Organise::Organise(TaskManager* task_manager,
}
void Organise::Start() {
if (thread_)
return;
if (thread_) return;
task_id_ = task_manager_->StartTask(tr("Organising files"));
task_manager_->SetTaskBlocksLibraryScans(true);
thread_ = new QThread;
connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
connect(transcoder_, SIGNAL(JobComplete(QString, bool)), SLOT(FileTranscoded(QString, bool)));
connect(transcoder_, SIGNAL(JobComplete(QString, bool)),
SLOT(FileTranscoded(QString, bool)));
moveToThread(thread_);
thread_->start();
@ -102,8 +101,7 @@ void Organise::ProcessSomeFiles() {
UpdateProgress();
destination_->FinishCopy(files_with_errors_.isEmpty());
if (eject_after_)
destination_->Eject();
if (eject_after_) destination_->Eject();
task_manager_->SetTaskFinished(task_id_);
@ -123,16 +121,14 @@ void Organise::ProcessSomeFiles() {
for (int i = 0; i < kBatchSize; ++i) {
SetSongProgress(0);
if (tasks_pending_.isEmpty())
break;
if (tasks_pending_.isEmpty()) break;
Task task = tasks_pending_.takeFirst();
qLog(Info) << "Processing" << task.song_info_.song_.url().toLocalFile();
// Use a Song instead of a tag reader
Song song = task.song_info_.song_;
if (!song.is_valid())
continue;
if (!song.is_valid()) continue;
// Maybe this file is one that's been transcoded already?
if (!task.transcoded_filename_.isEmpty()) {
@ -142,10 +138,13 @@ void Organise::ProcessSomeFiles() {
song.set_filetype(task.new_filetype_);
// Fiddle the filename extension as well to match the new type
song.set_url(QUrl::fromLocalFile(Utilities::FiddleFileExtension(song.basefilename(), task.new_extension_)));
song.set_basefilename(Utilities::FiddleFileExtension(song.basefilename(), task.new_extension_));
song.set_url(QUrl::fromLocalFile(Utilities::FiddleFileExtension(
song.basefilename(), task.new_extension_)));
song.set_basefilename(Utilities::FiddleFileExtension(
song.basefilename(), task.new_extension_));
// Have to set this to the size of the new file or else funny stuff happens
// Have to set this to the size of the new file or else funny stuff
// happens
song.set_filesize(QFileInfo(task.transcoded_filename_).size());
} else {
// Figure out if we need to transcode it
@ -167,21 +166,23 @@ void Organise::ProcessSomeFiles() {
// Start the transcoding - this will happen in the background and
// FileTranscoded() will get called when it's done. At that point the
// task will get re-added to the pending queue with the new filename.
transcoder_->AddJob(task.song_info_.song_.url().toLocalFile(), preset, task.transcoded_filename_);
transcoder_->AddJob(task.song_info_.song_.url().toLocalFile(), preset,
task.transcoded_filename_);
transcoder_->Start();
continue;
}
}
MusicStorage::CopyJob job;
job.source_ = task.transcoded_filename_.isEmpty() ?
task.song_info_.song_.url().toLocalFile() : task.transcoded_filename_;
job.source_ = task.transcoded_filename_.isEmpty()
? task.song_info_.song_.url().toLocalFile()
: task.transcoded_filename_;
job.destination_ = task.song_info_.new_filename_;
job.metadata_ = song;
job.overwrite_ = overwrite_;
job.remove_original_ = !copy_;
job.progress_ = std::bind(&Organise::SetSongProgress,
this, _1, !task.transcoded_filename_.isEmpty());
job.progress_ = std::bind(&Organise::SetSongProgress, this, _1,
!task.transcoded_filename_.isEmpty());
if (!destination_->CopyToStorage(job)) {
files_with_errors_ << task.song_info_.song_.basefilename();
@ -199,8 +200,7 @@ void Organise::ProcessSomeFiles() {
}
Song::FileType Organise::CheckTranscode(Song::FileType original_type) const {
if (original_type == Song::Type_Stream)
return Song::Type_Unknown;
if (original_type == Song::Type_Stream) return Song::Type_Unknown;
const MusicStorage::TranscodeMode mode = destination_->GetTranscodeMode();
const Song::FileType format = destination_->GetTranscodeFormat();
@ -210,16 +210,15 @@ Song::FileType Organise::CheckTranscode(Song::FileType original_type) const {
return Song::Type_Unknown;
case MusicStorage::Transcode_Always:
if (original_type == format)
return Song::Type_Unknown;
if (original_type == format) return Song::Type_Unknown;
return format;
case MusicStorage::Transcode_Unsupported:
if (supported_filetypes_.isEmpty() || supported_filetypes_.contains(original_type))
if (supported_filetypes_.isEmpty() ||
supported_filetypes_.contains(original_type))
return Song::Type_Unknown;
if (format != Song::Type_Unknown)
return format;
if (format != Song::Type_Unknown) return format;
// The user hasn't visited the device properties page yet to set a
// preferred format for the device, so we have to pick the best
@ -242,9 +241,9 @@ void Organise::UpdateProgress() {
// Update transcoding progress
QMap<QString, float> transcode_progress = transcoder_->GetProgress();
for (const QString& filename : transcode_progress.keys()) {
if (!tasks_transcoding_.contains(filename))
continue;
tasks_transcoding_[filename].transcode_progress_ = transcode_progress[filename];
if (!tasks_transcoding_.contains(filename)) continue;
tasks_transcoding_[filename].transcode_progress_ =
transcode_progress[filename];
}
// Count the progress of all tasks that are in the queue. Files that need

View File

@ -34,17 +34,16 @@ class Organise : public QObject {
Q_OBJECT
public:
struct NewSongInfo {
NewSongInfo(const Song& song = Song(), const QString& new_filename = QString())
NewSongInfo(const Song& song = Song(),
const QString& new_filename = QString())
: song_(song), new_filename_(new_filename) {}
Song song_;
QString new_filename_;
};
typedef QList<NewSongInfo> NewSongInfoList;
Organise(TaskManager* task_manager,
std::shared_ptr<MusicStorage> destination,
Organise(TaskManager* task_manager, std::shared_ptr<MusicStorage> destination,
const OrganiseFormat& format, bool copy, bool overwrite,
const NewSongInfoList& songs, bool eject_after);

View File

@ -27,11 +27,24 @@
const char* OrganiseFormat::kTagPattern = "\\%([a-zA-Z]*)";
const char* OrganiseFormat::kBlockPattern = "\\{([^{}]+)\\}";
const QStringList OrganiseFormat::kKnownTags = QStringList()
<< "title" << "album" << "artist" << "artistinitial" << "albumartist"
<< "composer" << "track" << "disc" << "bpm" << "year" << "genre"
<< "comment" << "length" << "bitrate" << "samplerate" << "extension"
<< "performer" << "grouping";
const QStringList OrganiseFormat::kKnownTags = QStringList() << "title"
<< "album"
<< "artist"
<< "artistinitial"
<< "albumartist"
<< "composer"
<< "track"
<< "disc"
<< "bpm"
<< "year"
<< "genre"
<< "comment"
<< "length"
<< "bitrate"
<< "samplerate"
<< "extension"
<< "performer"
<< "grouping";
// From http://en.wikipedia.org/wiki/8.3_filename#Directory_table
const char* OrganiseFormat::kInvalidFatCharacters = "\"*/\\:<>?|";
@ -56,8 +69,7 @@ OrganiseFormat::OrganiseFormat(const QString &format)
: format_(format),
replace_non_ascii_(false),
replace_spaces_(false),
replace_the_(false) {
}
replace_the_(false) {}
void OrganiseFormat::set_format(const QString& v) {
format_ = v;
@ -78,13 +90,14 @@ QString OrganiseFormat::GetFilenameForSong(const Song &song) const {
if (QFileInfo(filename).completeBaseName().isEmpty()) {
// Avoid having empty filenames, or filenames with extension only: in this
// case, keep the original filename.
// We remove the extension from "filename" if it exists, as song.basefilename()
// We remove the extension from "filename" if it exists, as
// song.basefilename()
// also contains the extension.
filename = Utilities::PathWithoutFilenameExtension(filename) + song.basefilename();
filename =
Utilities::PathWithoutFilenameExtension(filename) + song.basefilename();
}
if (replace_spaces_)
filename.replace(QRegExp("\\s"), "_");
if (replace_spaces_) filename.replace(QRegExp("\\s"), "_");
if (replace_non_ascii_) {
QString stripped;
@ -117,8 +130,7 @@ QString OrganiseFormat::ParseBlock(QString block, const Song& song,
// Recursively parse the block
bool empty = false;
QString value = ParseBlock(block_regexp.cap(1), song, &empty);
if (empty)
value = "";
if (empty) value = "";
// Replace the block's value
block.replace(pos, block_regexp.matchedLength(), value);
@ -130,58 +142,68 @@ QString OrganiseFormat::ParseBlock(QString block, const Song& song,
pos = 0;
while ((pos = tag_regexp.indexIn(block, pos)) != -1) {
QString value = TagValue(tag_regexp.cap(1), song);
if (value.isEmpty())
empty = true;
if (value.isEmpty()) empty = true;
block.replace(pos, tag_regexp.matchedLength(), value);
pos += value.length();
}
if (any_empty)
*any_empty = empty;
if (any_empty) *any_empty = empty;
return block;
}
QString OrganiseFormat::TagValue(const QString& tag, const Song& song) const {
QString value;
if (tag == "title") value = song.title();
else if (tag == "album") value = song.album();
else if (tag == "artist") value = song.artist();
else if (tag == "composer") value = song.composer();
else if (tag == "performer") value = song.performer();
else if (tag == "grouping") value = song.grouping();
else if (tag == "genre") value = song.genre();
else if (tag == "comment") value = song.comment();
else if (tag == "year") value = QString::number(song.year());
else if (tag == "track") value = QString::number(song.track());
else if (tag == "disc") value = QString::number(song.disc());
else if (tag == "bpm") value = QString::number(song.bpm());
else if (tag == "length") value =
QString::number(song.length_nanosec() / kNsecPerSec);
else if (tag == "bitrate") value = QString::number(song.bitrate());
else if (tag == "samplerate") value = QString::number(song.samplerate());
else if (tag == "extension") value = QFileInfo(song.url().toLocalFile()).suffix();
if (tag == "title")
value = song.title();
else if (tag == "album")
value = song.album();
else if (tag == "artist")
value = song.artist();
else if (tag == "composer")
value = song.composer();
else if (tag == "performer")
value = song.performer();
else if (tag == "grouping")
value = song.grouping();
else if (tag == "genre")
value = song.genre();
else if (tag == "comment")
value = song.comment();
else if (tag == "year")
value = QString::number(song.year());
else if (tag == "track")
value = QString::number(song.track());
else if (tag == "disc")
value = QString::number(song.disc());
else if (tag == "bpm")
value = QString::number(song.bpm());
else if (tag == "length")
value = QString::number(song.length_nanosec() / kNsecPerSec);
else if (tag == "bitrate")
value = QString::number(song.bitrate());
else if (tag == "samplerate")
value = QString::number(song.samplerate());
else if (tag == "extension")
value = QFileInfo(song.url().toLocalFile()).suffix();
else if (tag == "artistinitial") {
value = song.effective_albumartist().trimmed();
if (replace_the_ && !value.isEmpty())
value.replace(QRegExp("^the\\s+", Qt::CaseInsensitive), "");
if (!value.isEmpty()) value = value[0].toUpper();
} else if (tag == "albumartist") {
value = song.is_compilation()
? "Various Artists"
value = song.is_compilation() ? "Various Artists"
: song.effective_albumartist();
}
if (replace_the_ && (tag == "artist" || tag == "albumartist"))
value.replace(QRegExp("^the\\s+", Qt::CaseInsensitive), "");
if (value == "0" || value == "-1")
value = "";
if (value == "0" || value == "-1") value = "";
// Prepend a 0 to single-digit track numbers
if (tag == "track" && value.length() == 1)
value.prepend('0');
if (tag == "track" && value.length() == 1) value.prepend('0');
// Replace characters that really shouldn't be in paths
for (int i = 0; i < kInvalidFatCharactersCount; ++i) {
@ -191,12 +213,10 @@ QString OrganiseFormat::TagValue(const QString &tag, const Song &song) const {
return value;
}
OrganiseFormat::Validator::Validator(QObject* parent) : QValidator(parent) {}
OrganiseFormat::Validator::Validator(QObject *parent)
: QValidator(parent) {}
QValidator::State OrganiseFormat::Validator::validate(
QString& input, int&) const {
QValidator::State OrganiseFormat::Validator::validate(QString& input,
int&) const {
QRegExp tag_regexp(kTagPattern);
// Make sure all the blocks match up
@ -207,12 +227,10 @@ QValidator::State OrganiseFormat::Validator::validate(
else if (input[i] == '}')
block_level--;
if (block_level < 0 || block_level > 1)
return QValidator::Invalid;
if (block_level < 0 || block_level > 1) return QValidator::Invalid;
}
if (block_level != 0)
return QValidator::Invalid;
if (block_level != 0) return QValidator::Invalid;
// Make sure the tags are valid
int pos = 0;
@ -226,7 +244,6 @@ QValidator::State OrganiseFormat::Validator::validate(
return QValidator::Acceptable;
}
OrganiseFormat::SyntaxHighlighter::SyntaxHighlighter(QObject* parent)
: QSyntaxHighlighter(parent) {}
@ -274,4 +291,3 @@ void OrganiseFormat::SyntaxHighlighter::highlightBlock(const QString& text) {
pos += tag_regexp.matchedLength();
}
}

View File

@ -46,7 +46,6 @@ class OrganiseFormat {
bool IsValid() const;
QString GetFilenameForSong(const Song& song) const;
class Validator : public QValidator {
public:
explicit Validator(QObject* parent = 0);
@ -69,8 +68,8 @@ class OrganiseFormat {
};
private:
QString ParseBlock(
QString block, const Song& song, bool* any_empty = NULL) const;
QString ParseBlock(QString block, const Song& song,
bool* any_empty = NULL) const;
QString TagValue(const QString& tag, const Song& song) const;
QString format_;

View File

@ -48,26 +48,26 @@ Player::Player(Application* app, QObject* parent)
stream_change_type_(Engine::First),
last_state_(Engine::Empty),
nb_errors_received_(0),
volume_before_mute_(50)
{
volume_before_mute_(50) {
settings_.beginGroup("Player");
SetVolume(settings_.value("volume", 50).toInt());
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)),
SLOT(ValidSongRequested(QUrl)));
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)),
SLOT(InvalidSongRequested(QUrl)));
}
Player::~Player() {
}
Player::~Player() {}
void Player::Init() {
if (!engine_->Init())
qFatal("Error initialising audio engine");
if (!engine_->Init()) qFatal("Error initialising audio engine");
connect(engine_.get(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
connect(engine_.get(), SIGNAL(StateChanged(Engine::State)),
SLOT(EngineStateChanged(Engine::State)));
connect(engine_.get(), SIGNAL(TrackAboutToEnd()), SLOT(TrackAboutToEnd()));
connect(engine_.get(), SIGNAL(TrackEnded()), SLOT(TrackEnded()));
connect(engine_.get(), SIGNAL(MetaData(Engine::SimpleMetaBundle)),
@ -80,9 +80,7 @@ void Player::Init() {
#endif
}
void Player::ReloadSettings() {
engine_->ReloadSettings();
}
void Player::ReloadSettings() { engine_->ReloadSettings(); }
void Player::HandleLoadResult(const UrlHandler::LoadResult& result) {
switch (result.type_) {
@ -97,28 +95,27 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult& result) {
case UrlHandler::LoadResult::TrackAvailable: {
// Might've been an async load, so check we're still on the same item
int current_index = app_->playlist_manager()->active()->current_row();
if (current_index == -1)
return;
if (current_index == -1) return;
shared_ptr<PlaylistItem> item = app_->playlist_manager()->active()->item_at(current_index);
if (!item || item->Url() != result.original_url_)
return;
shared_ptr<PlaylistItem> item =
app_->playlist_manager()->active()->item_at(current_index);
if (!item || item->Url() != result.original_url_) return;
qLog(Debug) << "URL handler for" << result.original_url_
<< "returned" << result.media_url_;
qLog(Debug) << "URL handler for" << result.original_url_ << "returned"
<< result.media_url_;
// If there was no length info in song's metadata, use the one provided by
// URL handler, if there is one
if (item->Metadata().length_nanosec() <= 0 && result.length_nanosec_ != -1) {
if (item->Metadata().length_nanosec() <= 0 &&
result.length_nanosec_ != -1) {
Song song = item->Metadata();
song.set_length_nanosec(result.length_nanosec_);
item->SetTemporaryMetadata(song);
app_->playlist_manager()->active()->InformOfCurrentSongChange();
}
engine_->Play(result.media_url_, stream_change_type_,
item->Metadata().has_cue(),
item->Metadata().beginning_nanosec(),
item->Metadata().end_nanosec());
engine_->Play(
result.media_url_, stream_change_type_, item->Metadata().has_cue(),
item->Metadata().beginning_nanosec(), item->Metadata().end_nanosec());
current_item_ = item;
loading_async_ = QUrl();
@ -135,21 +132,17 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult& result) {
}
}
void Player::Next() {
NextInternal(Engine::Manual);
}
void Player::Next() { NextInternal(Engine::Manual); }
void Player::NextInternal(Engine::TrackChangeFlags change) {
if (HandleStopAfter())
return;
if (HandleStopAfter()) return;
if (app_->playlist_manager()->active()->current_item()) {
const QUrl url = app_->playlist_manager()->active()->current_item()->Url();
if (url_handlers_.contains(url.scheme())) {
// The next track is already being loaded
if (url == loading_async_)
return;
if (url == loading_async_) return;
stream_change_type_ = change;
HandleLoadResult(url_handlers_[url.scheme()]->LoadNext(url));
@ -168,8 +161,10 @@ void Player::NextItem(Engine::TrackChangeFlags change) {
const PlaylistSequence::RepeatMode repeat_mode =
active_playlist->sequence()->repeat_mode();
if (repeat_mode != PlaylistSequence::Repeat_Off) {
if ((repeat_mode == PlaylistSequence::Repeat_Track && nb_errors_received_ >= 3) ||
(nb_errors_received_ >= app_->playlist_manager()->active()->proxy()->rowCount())) {
if ((repeat_mode == PlaylistSequence::Repeat_Track &&
nb_errors_received_ >= 3) ||
(nb_errors_received_ >=
app_->playlist_manager()->active()->proxy()->rowCount())) {
// We received too many "Error" state changes: probably looping over a
// playlist which contains only unavailable elements: stop now.
nb_errors_received_ = 0;
@ -211,13 +206,13 @@ bool Player::HandleStopAfter() {
}
void Player::TrackEnded() {
if (HandleStopAfter())
return;
if (HandleStopAfter()) return;
if (current_item_ && current_item_->IsLocalLibraryItem() &&
current_item_->Metadata().id() != -1 &&
!app_->playlist_manager()->active()->have_incremented_playcount() &&
app_->playlist_manager()->active()->get_lastfm_status() != Playlist::LastFM_Seeked) {
app_->playlist_manager()->active()->get_lastfm_status() !=
Playlist::LastFM_Seeked) {
// The track finished before its scrobble point (30 seconds), so increment
// the play count now.
app_->playlist_manager()->library_backend()->IncrementPlayCountAsync(
@ -235,7 +230,8 @@ void Player::PlayPause() {
case Engine::Playing: {
// We really shouldn't pause last.fm streams
// Stopping seems like a reasonable thing to do (especially on mac where there
// Stopping seems like a reasonable thing to do (especially on mac where
// there
// is no media key for stop).
if (current_item_->options() & PlaylistItem::PauseDisabled) {
Stop();
@ -248,9 +244,9 @@ void Player::PlayPause() {
case Engine::Empty:
case Engine::Error:
case Engine::Idle: {
app_->playlist_manager()->SetActivePlaylist(app_->playlist_manager()->current_id());
if (app_->playlist_manager()->active()->rowCount() == 0)
break;
app_->playlist_manager()->SetActivePlaylist(
app_->playlist_manager()->current_id());
if (app_->playlist_manager()->active()->rowCount() == 0) break;
int i = app_->playlist_manager()->active()->current_row();
if (i == -1) i = app_->playlist_manager()->active()->last_played_row();
@ -263,8 +259,7 @@ void Player::PlayPause() {
}
void Player::RestartOrPrevious() {
if (engine_->position_nanosec() < 8*kNsecPerSec)
return Previous();
if (engine_->position_nanosec() < 8 * kNsecPerSec) return Previous();
SeekTo(0);
}
@ -276,12 +271,11 @@ void Player::Stop() {
}
void Player::StopAfterCurrent() {
app_->playlist_manager()->active()->StopAfter(app_->playlist_manager()->active()->current_row());
app_->playlist_manager()->active()->StopAfter(
app_->playlist_manager()->active()->current_row());
}
void Player::Previous() {
PreviousItem(Engine::Manual);
}
void Player::Previous() { PreviousItem(Engine::Manual); }
void Player::PreviousItem(Engine::TrackChangeFlags change) {
const bool ignore_repeat_track = change & Engine::Manual;
@ -304,11 +298,17 @@ void Player::EngineStateChanged(Engine::State state) {
}
switch (state) {
case Engine::Paused: emit Paused(); break;
case Engine::Playing: emit Playing(); break;
case Engine::Paused:
emit Paused();
break;
case Engine::Playing:
emit Playing();
break;
case Engine::Error:
case Engine::Empty:
case Engine::Idle: emit Stopped(); break;
case Engine::Idle:
emit Stopped();
break;
}
last_state_ = state;
}
@ -323,15 +323,14 @@ void Player::SetVolume(int value) {
if (volume != old_volume) {
emit VolumeChanged(volume);
}
}
int Player::GetVolume() const {
return engine_->volume();
}
int Player::GetVolume() const { return engine_->volume(); }
void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle) {
if (change == Engine::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
void Player::PlayAt(int index, Engine::TrackChangeFlags change,
bool reshuffle) {
if (change == Engine::Manual &&
engine_->position_nanosec() != engine_->length_nanosec()) {
emit TrackSkipped(current_item_);
const QUrl& url = current_item_->Url();
if (url_handlers_.contains(url.scheme())) {
@ -339,15 +338,13 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
}
}
if (current_item_ &&
app_->playlist_manager()->active()->has_item_at(index) &&
if (current_item_ && app_->playlist_manager()->active()->has_item_at(index) &&
current_item_->Metadata().IsOnSameAlbum(
app_->playlist_manager()->active()->item_at(index)->Metadata())) {
change |= Engine::SameAlbum;
}
if (reshuffle)
app_->playlist_manager()->active()->ReshuffleIndices();
if (reshuffle) app_->playlist_manager()->active()->ReshuffleIndices();
app_->playlist_manager()->active()->set_current_row(index);
if (app_->playlist_manager()->active()->current_row() == -1) {
@ -360,8 +357,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
if (url_handlers_.contains(url.scheme())) {
// It's already loading
if (url == loading_async_)
return;
if (url == loading_async_) return;
stream_change_type_ = change;
HandleLoadResult(url_handlers_[url.scheme()]->StartLoading(url));
@ -398,14 +394,16 @@ void Player::SeekTo(int seconds) {
return;
}
const qint64 nanosec = qBound(0ll, qint64(seconds) * kNsecPerSec,
length_nanosec);
const qint64 nanosec =
qBound(0ll, qint64(seconds) * kNsecPerSec, length_nanosec);
engine_->Seek(nanosec);
// If we seek the track we don't want to submit it to last.fm
qLog(Info) << "Track seeked to" << nanosec << "ns - not scrobbling";
if (app_->playlist_manager()->active()->get_lastfm_status() == Playlist::LastFM_New) {
app_->playlist_manager()->active()->set_lastfm_status(Playlist::LastFM_Seeked);
if (app_->playlist_manager()->active()->get_lastfm_status() ==
Playlist::LastFM_New) {
app_->playlist_manager()->active()->set_lastfm_status(
Playlist::LastFM_Seeked);
}
emit Seeked(nanosec / 1000);
@ -421,8 +419,7 @@ void Player::SeekBackward() {
void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle& bundle) {
PlaylistItemPtr item = app_->playlist_manager()->active()->current_item();
if (!item)
return;
if (!item) return;
Engine::SimpleMetaBundle bundle_copy = bundle;
@ -445,8 +442,7 @@ void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle& bundle) {
song.MergeFromSimpleMetaBundle(bundle_copy);
// Ignore useless metadata
if (song.title().isEmpty() && song.artist().isEmpty())
return;
if (song.title().isEmpty() && song.artist().isEmpty()) return;
app_->playlist_manager()->active()->SetStreamMetadata(item->Url(), song);
}
@ -468,9 +464,7 @@ void Player::Mute() {
}
}
void Player::Pause() {
engine_->Pause();
}
void Player::Pause() { engine_->Pause(); }
void Player::Play() {
switch (GetState()) {
@ -487,13 +481,11 @@ void Player::Play() {
}
void Player::ShowOSD() {
if (current_item_)
emit ForceShowOSD(current_item_->Metadata(), false);
if (current_item_) emit ForceShowOSD(current_item_->Metadata(), false);
}
void Player::TogglePrettyOSD() {
if (current_item_)
emit ForceShowOSD(current_item_->Metadata(), true);
if (current_item_) emit ForceShowOSD(current_item_->Metadata(), true);
}
void Player::TrackAboutToEnd() {
@ -509,11 +501,13 @@ void Player::TrackAboutToEnd() {
}
}
const bool has_next_row = app_->playlist_manager()->active()->next_row() != -1;
const bool has_next_row =
app_->playlist_manager()->active()->next_row() != -1;
PlaylistItemPtr next_item;
if (has_next_row) {
next_item = app_->playlist_manager()->active()->item_at(app_->playlist_manager()->active()->next_row());
next_item = app_->playlist_manager()->active()->item_at(
app_->playlist_manager()->active()->next_row());
}
if (engine_->is_autocrossfade_enabled()) {
@ -522,15 +516,12 @@ void Player::TrackAboutToEnd() {
// But, if there's no next track and we don't want to fade out, then do
// nothing and just let the track finish to completion.
if (!engine_->is_fadeout_enabled() && !has_next_row)
return;
if (!engine_->is_fadeout_enabled() && !has_next_row) return;
// If the next track is on the same album (or same cue file), and the
// user doesn't want to crossfade between tracks on the same album, then
// don't do this automatic crossfading.
if (engine_->crossfade_same_album() ||
!has_next_row ||
!next_item ||
if (engine_->crossfade_same_album() || !has_next_row || !next_item ||
!current_item_->Metadata().IsOnSameAlbum(next_item->Metadata())) {
TrackEnded();
return;
@ -539,8 +530,7 @@ void Player::TrackAboutToEnd() {
// Crossfade is off, so start preloading the next track so we don't get a
// gap between songs.
if (!has_next_row || !next_item)
return;
if (!has_next_row || !next_item) return;
QUrl url = next_item->Url();
@ -588,7 +578,8 @@ void Player::RegisterUrlHandler(UrlHandler* handler) {
qLog(Info) << "Registered URL handler for" << scheme;
url_handlers_.insert(scheme, handler);
connect(handler, SIGNAL(destroyed(QObject*)), SLOT(UrlHandlerDestroyed(QObject*)));
connect(handler, SIGNAL(destroyed(QObject*)),
SLOT(UrlHandlerDestroyed(QObject*)));
connect(handler, SIGNAL(AsyncLoadComplete(UrlHandler::LoadResult)),
SLOT(HandleLoadResult(UrlHandler::LoadResult)));
}
@ -596,20 +587,22 @@ void Player::RegisterUrlHandler(UrlHandler* handler) {
void Player::UnregisterUrlHandler(UrlHandler* handler) {
const QString scheme = url_handlers_.key(handler);
if (scheme.isEmpty()) {
qLog(Warning) << "Tried to unregister a URL handler for" << handler->scheme()
<< "that wasn't registered";
qLog(Warning) << "Tried to unregister a URL handler for"
<< handler->scheme() << "that wasn't registered";
return;
}
qLog(Info) << "Unregistered URL handler for" << scheme;
url_handlers_.remove(scheme);
disconnect(handler, SIGNAL(destroyed(QObject*)), this, SLOT(UrlHandlerDestroyed(QObject*)));
disconnect(handler, SIGNAL(AsyncLoadComplete(UrlHandler::LoadResult)),
this, SLOT(HandleLoadResult(UrlHandler::LoadResult)));
disconnect(handler, SIGNAL(destroyed(QObject*)), this,
SLOT(UrlHandlerDestroyed(QObject*)));
disconnect(handler, SIGNAL(AsyncLoadComplete(UrlHandler::LoadResult)), this,
SLOT(HandleLoadResult(UrlHandler::LoadResult)));
}
const UrlHandler* Player::HandlerForUrl(const QUrl& url) const {
QMap<QString, UrlHandler*>::const_iterator it = url_handlers_.constFind(url.scheme());
QMap<QString, UrlHandler*>::const_iterator it =
url_handlers_.constFind(url.scheme());
if (it == url_handlers_.constEnd()) {
return nullptr;
}

View File

@ -33,7 +33,6 @@
class Application;
class LastFMService;
class PlayerInterface : public QObject {
Q_OBJECT
@ -54,7 +53,8 @@ public slots:
virtual void ReloadSettings() = 0;
// Manual track change to the specified track
virtual void PlayAt(int i, Engine::TrackChangeFlags change, bool reshuffle) = 0;
virtual void PlayAt(int i, Engine::TrackChangeFlags change,
bool reshuffle) = 0;
// If there's currently a song playing, pause it, otherwise play the track
// that was playing last, or the first one on the playlist
@ -93,11 +93,13 @@ signals:
// Emitted when there's a manual change to the current's track position.
void Seeked(qlonglong microseconds);
// Emitted when Player has processed a request to play another song. This contains
// Emitted when Player has processed a request to play another song. This
// contains
// the URL of the song and a flag saying whether it was able to play the song.
void SongChangeRequestProcessed(const QUrl& url, bool valid);
// The toggle parameter is true when user requests to toggle visibility for Pretty OSD
// The toggle parameter is true when user requests to toggle visibility for
// Pretty OSD
void ForceShowOSD(Song, bool toogle);
};

View File

@ -26,7 +26,8 @@
class PoTranslator : public QTranslator {
public:
QString translate(const char* context, const char* source_text, const char* disambiguation = 0) const {
QString translate(const char* context, const char* source_text,
const char* disambiguation = 0) const {
QString ret = QTranslator::translate(context, source_text, disambiguation);
if (!ret.isEmpty()) return ret;
return QTranslator::translate(NULL, source_text, disambiguation);

View File

@ -21,9 +21,7 @@
#include <QUrl>
#if QT_VERSION < 0x040700
inline uint qHash(const QUrl& url) {
return qHash(url.toEncoded());
}
inline uint qHash(const QUrl& url) { return qHash(url.toEncoded()); }
#endif
#endif // QHASH_QURL_H

Some files were not shown because too many files have changed in this diff Show More