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,8 +158,9 @@ void MediaPipeline::EnoughDataCallback(GstAppSrc* src, void* data) {
me->accepting_data_ = false;
}
gboolean MediaPipeline::SeekDataCallback(GstAppSrc* src, guint64 offset, void * data) {
//MediaPipeline* me = reinterpret_cast<MediaPipeline*>(data);
gboolean MediaPipeline::SeekDataCallback(GstAppSrc* src, guint64 offset,
void* data) {
// MediaPipeline* me = reinterpret_cast<MediaPipeline*>(data);
qLog(Debug) << "Gstreamer wants seek to" << offset;
return false;

View File

@ -27,7 +27,7 @@
#include <gst/app/gstappsrc.h>
class MediaPipeline {
public:
public:
MediaPipeline(int port, quint64 length_msec);
~MediaPipeline();
@ -38,12 +38,12 @@ public:
void WriteData(const char* data, qint64 length);
void EndStream();
private:
private:
static void NeedDataCallback(GstAppSrc* src, guint length, void* data);
static void EnoughDataCallback(GstAppSrc* src, void* data);
static gboolean SeekDataCallback(GstAppSrc* src, guint64 offset, void* data);
private:
private:
Q_DISABLE_COPY(MediaPipeline)
const int port_;

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);
@ -126,7 +130,7 @@ void SpotifyClient::LoggedInCallback(sp_session* session, sp_error error) {
case SP_ERROR_USER_BANNED:
error_code = pb::spotify::LoginResponse_Error_UserBanned;
break;
case SP_ERROR_USER_NEEDS_PREMIUM :
case SP_ERROR_USER_NEEDS_PREMIUM:
error_code = pb::spotify::LoginResponse_Error_UserNeedsPremium;
break;
default:
@ -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;
}
@ -184,10 +185,10 @@ void SpotifyClient::SearchCompleteCallback(sp_search* result, void* userdata) {
// we can send our response.
const int count = sp_search_num_albums(result);
if (count != 0) {
for (int i=0 ; i<count ; ++i) {
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);
}
}
@ -235,14 +238,14 @@ void SpotifyClient::SendSearchResponse(sp_search* result) {
// Get the list of tracks from the search
int count = sp_search_num_tracks(result);
for (int i=0 ; i<count ; ++i) {
for (int i = 0; i < count; ++i) {
sp_track* track = sp_search_track(result, i);
ConvertTrack(track, response->add_result());
}
// Get the albums from the search. All these should be resolved by now.
QList<sp_albumbrowse*> browses = pending_search_album_browses_.take(result);
foreach (sp_albumbrowse* browse, browses) {
foreach(sp_albumbrowse * browse, browses) {
sp_album* album = sp_albumbrowse_album(browse);
pb::spotify::Album* msg = response->add_album();
@ -251,7 +254,7 @@ void SpotifyClient::SendSearchResponse(sp_search* result) {
// Add all tracks
const int tracks = sp_albumbrowse_num_tracks(browse);
for (int i=0 ; i<tracks ; ++i) {
for (int i = 0; i < tracks; ++i) {
ConvertTrack(sp_albumbrowse_track(browse, i), msg->add_track());
}
@ -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,12 +357,13 @@ 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
const int count = sp_playlistcontainer_num_playlists(pc);
for (int i=0 ; i<count ; ++i) {
for (int i = 0; i < count; ++i) {
sp_playlist* playlist = sp_playlistcontainer_playlist(pc, i);
sp_playlist_add_callbacks(playlist, &me->get_playlists_callbacks_, me);
}
@ -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
@ -395,12 +412,13 @@ void SpotifyClient::SendPlaylistList() {
const int count = sp_playlistcontainer_num_playlists(container);
for (int i=0 ; i<count ; ++i) {
for (int i = 0; i < count; ++i) {
const int type = sp_playlistcontainer_playlist_type(container, i);
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
@ -500,7 +524,7 @@ void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* u
// Find this playlist's pending load object
int pending_load_index = -1;
PendingLoadPlaylist* pending_load = nullptr;
for (int i=0 ; i<me->pending_load_playlists_.count() ; ++i) {
for (int i = 0; i < me->pending_load_playlists_.count(); ++i) {
if (me->pending_load_playlists_[i].playlist_ == pl) {
pending_load_index = i;
pending_load = &me->pending_load_playlists_[i];
@ -516,7 +540,7 @@ void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* u
// If the playlist was just loaded then get all its tracks and ref them
if (pending_load->tracks_.isEmpty()) {
const int count = sp_playlist_num_tracks(pl);
for (int i=0 ; i<count ; ++i) {
for (int i = 0; i < count; ++i) {
sp_track* track = sp_playlist_track(pl, i);
sp_track_add_ref(track);
pending_load->tracks_ << track;
@ -524,7 +548,7 @@ void SpotifyClient::PlaylistStateChangedForLoadPlaylist(sp_playlist* pl, void* u
}
// If any of the tracks aren't loaded yet we have to wait
foreach (sp_track* track, pending_load->tracks_) {
foreach(sp_track * track, pending_load->tracks_) {
if (!sp_track_is_loaded(track)) {
qLog(Debug) << "One or more tracks aren't loaded yet, waiting";
return;
@ -533,17 +557,17 @@ 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_;
foreach (sp_track* track, pending_load->tracks_) {
foreach(sp_track * track, pending_load->tracks_) {
me->ConvertTrack(track, response->add_track());
sp_track_release(track);
}
@ -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,15 +601,14 @@ 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));
// Artists
for (int i=0 ; i<sp_track_num_artists(track) ; ++i) {
for (int i = 0; i < sp_track_num_artists(track); ++i) {
pb->add_artist(sp_artist_name(sp_track_artist(track, i)));
}
@ -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_) {
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";
@ -716,8 +749,9 @@ 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);
for (int i = 0; i < count; ++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,14 +899,14 @@ 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_]) {
sp_image_add_load_callback(pending_load.image_, &ImageLoaded, this);
}
image_callbacks_registered_[pending_load.image_] ++;
image_callbacks_registered_[pending_load.image_]++;
TryImageAgain(pending_load.image_);
}
@ -885,7 +920,7 @@ void SpotifyClient::TryImageAgain(sp_image* image) {
// Find the pending request for this image
int index = -1;
PendingImageRequest* req = nullptr;
for (int i=0 ; i<pending_image_requests_.count() ; ++i) {
for (int i = 0; i < pending_image_requests_.count(); ++i) {
if (pending_image_requests_[i].image_ == image) {
index = i;
req = &pending_image_requests_[i];
@ -912,7 +947,7 @@ void SpotifyClient::TryImageAgain(sp_image* image) {
SendMessage(message);
// Free stuff
image_callbacks_registered_[image] --;
image_callbacks_registered_[image]--;
// TODO: memory leak?
// sp_image_remove_load_callback(image, &ImageLoaded, this);
@ -948,21 +983,22 @@ 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));
const int count = sp_albumbrowse_num_tracks(result);
for (int i=0 ; i<count ; ++i) {
for (int i = 0; i < count; ++i) {
me->ConvertTrack(sp_albumbrowse_track(result, i), msg->add_track());
}
@ -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
@ -39,7 +38,7 @@ class ResponseMessage;
class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
Q_OBJECT
public:
public:
SpotifyClient(QObject* parent = 0);
~SpotifyClient();
@ -48,14 +47,14 @@ public:
void Init(quint16 port);
protected:
protected:
void MessageArrived(const pb::spotify::Message& message);
void DeviceClosed();
private slots:
private slots:
void ProcessEvents();
private:
private:
void SendLoginCompleted(bool success, const QString& error,
pb::spotify::LoginResponse_Error error_code);
void SendPlaybackError(const QString& error);
@ -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);
@ -129,7 +138,7 @@ private:
// Gets the appropriate sp_playlist* but does not load it.
sp_playlist* GetPlaylist(pb::spotify::PlaylistType type, int user_index);
private:
private:
struct PendingLoadPlaylist {
pb::spotify::LoadPlaylistRequest request_;
sp_playlist* playlist_;
@ -142,7 +151,7 @@ private:
sp_link* link_;
sp_track* track_;
bool operator ==(const PendingPlaybackRequest& other) const {
bool operator==(const PendingPlaybackRequest& other) const {
return request_.track_uri() == other.request_.track_uri() &&
request_.media_port() == other.request_.media_port();
}
@ -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,15 +31,17 @@ 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;
}
// Seed random number generator
timeval time;
gettimeofday(&time,nullptr);
gettimeofday(&time, nullptr);
qsrand((time.tv_sec * 1000) + (time.tv_usec / 1000));
logging::Init();

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

@ -24,14 +24,14 @@
#include "core/messagehandler.h"
class TagReaderWorker : public AbstractMessageHandler<pb::tagreader::Message> {
public:
public:
TagReaderWorker(QIODevice* socket, QObject* parent = NULL);
protected:
protected:
void MessageArrived(const pb::tagreader::Message& message);
void DeviceClosed();
private:
private:
TagReader tag_reader_;
};

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 {
template <typename ReturnType>
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_());
@ -84,12 +82,10 @@ class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
// Partial specialisation for void return type.
template <typename... Args>
class ThreadFunctor <void, Args...> : public ThreadFunctorBase<void> {
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,39 +96,33 @@ class ThreadFunctor <void, Args...> : public ThreadFunctorBase<void> {
std::function<void()> function_;
};
/*
Run functions
*/
namespace ConcurrentRun {
// Empty argument form.
template <typename ReturnType>
QFuture<ReturnType> Run(
QThreadPool* threadpool,
std::function<ReturnType ()> function) {
// Empty argument form.
template <typename ReturnType>
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,
std::function<ReturnType (Args...)> function,
// Function object with arguments form.
template <typename ReturnType, typename... Args>
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...);
}
// 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...);
}
}
#endif // CONCURRENTRUN_H

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,13 +76,19 @@ 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')) {
foreach(const QString & line, QString::fromLocal8Bit(message).split('\n')) {
CreateLogger(level, "unknown", -1) << line.toLocal8Bit().constData();
}
@ -85,7 +97,6 @@ static void MessageHandler(QtMsgType type, const char* message) {
}
}
void Init() {
delete sClassLevels;
delete sNullDevice;
@ -100,10 +111,9 @@ void Init() {
}
void SetLevels(const QString& levels) {
if (!sClassLevels)
return;
if (!sClassLevels) return;
foreach (const QString& item, levels.split(',')) {
foreach(const QString & item, levels.split(',')) {
const QStringList class_level = item.split(':');
QString class_name;
@ -122,14 +132,14 @@ void SetLevels(const QString& levels) {
}
if (class_name.isEmpty() || class_name == "*") {
sDefaultLevel = (Level) level;
sDefaultLevel = (Level)level;
} else {
sClassLevels->insert(class_name, (Level) level);
sClassLevels->insert(class_name, (Level)level);
}
}
}
QString ParsePrettyFunction(const char * pretty_function) {
QString ParsePrettyFunction(const char* pretty_function) {
// Get the class name out of the function name.
QString class_name = pretty_function;
const int paren = class_name.indexOf('(');
@ -144,7 +154,7 @@ QString ParsePrettyFunction(const char * pretty_function) {
const int space = class_name.lastIndexOf(' ');
if (space != -1) {
class_name = class_name.mid(space+1);
class_name = class_name.mid(space + 1);
}
return class_name;
@ -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,46 +18,47 @@
// 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) \
#define qLog(level) \
logging::CreateLogger(logging::Level_##level, \
logging::ParsePrettyFunction(__PRETTY_FUNCTION__), __LINE__)
logging::ParsePrettyFunction(__PRETTY_FUNCTION__), \
__LINE__)
#endif
namespace logging {
class NullDevice : public QIODevice {
class NullDevice : public QIODevice {
protected:
qint64 readData(char*, qint64) { return -1; }
qint64 writeData(const char*, qint64 len) { return len; }
};
};
enum Level {
enum Level {
Level_Fatal = -1,
Level_Error = 0,
Level_Warning,
Level_Info,
Level_Debug,
};
};
void Init();
void SetLevels(const QString& levels);
void Init();
void SetLevels(const QString& levels);
void DumpStackTrace();
void DumpStackTrace();
QString ParsePrettyFunction(const char* pretty_function);
QDebug CreateLogger(Level level, const QString& class_name, int line);
QString ParsePrettyFunction(const char* pretty_function);
QDebug CreateLogger(Level level, const QString& class_name, int line);
void GLog(const char* domain, int level, const char* message, void* user_data);
void GLog(const char* domain, int level, const char* message, void* user_data);
extern const char* kDefaultLogLevels;
extern const char* kDefaultLogLevels;
}
#endif // LOGGING_H

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
@ -49,7 +45,7 @@ class QLocalSocket;
class _MessageHandlerBase : public QObject {
Q_OBJECT
public:
public:
// device can be NULL, in which case you must call SetDevice before writing
// any messages.
_MessageHandlerBase(QIODevice* device, QObject* parent);
@ -59,16 +55,16 @@ public:
// After this is true, messages cannot be sent to the handler any more.
bool is_device_closed() const { return is_device_closed_; }
protected slots:
protected slots:
void WriteMessage(const QByteArray& data);
void DeviceReadyRead();
virtual void DeviceClosed();
protected:
protected:
virtual bool RawMessageArrived(const QByteArray& data) = 0;
virtual void AbortAll() = 0;
protected:
protected:
typedef bool (QAbstractSocket::*FlushAbstractSocket)();
typedef bool (QLocalSocket::*FlushLocalSocket)();
@ -83,13 +79,12 @@ 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.
template <typename MT>
class AbstractMessageHandler : public _MessageHandlerBase {
public:
public:
AbstractMessageHandler(QIODevice* device, QObject* parent);
~AbstractMessageHandler() { AbortAll(); }
@ -113,7 +108,7 @@ public:
// reply on the socket. Used on the worker side.
void SendReply(const MessageType& request, MessageType* reply);
protected:
protected:
// Called when a message is received from the socket.
virtual void MessageArrived(const MessageType& message) {}
@ -121,19 +116,16 @@ protected:
bool RawMessageArrived(const QByteArray& data);
void AbortAll();
private:
private:
QMap<int, ReplyType*> pending_replies_;
};
template <typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(QIODevice* device,
QObject* parent)
: _MessageHandlerBase(device, parent) {}
template<typename MT>
AbstractMessageHandler<MT>::AbstractMessageHandler(
QIODevice* device, QObject* parent)
: _MessageHandlerBase(device, parent)
{
}
template<typename MT>
template <typename MT>
void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
Q_ASSERT(QThread::currentThread() == thread());
@ -141,27 +133,28 @@ void AbstractMessageHandler<MT>::SendMessage(const MessageType& message) {
WriteMessage(QByteArray(data.data(), data.size()));
}
template<typename MT>
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())));
}
template<typename MT>
template <typename MT>
void AbstractMessageHandler<MT>::SendRequest(ReplyType* reply) {
pending_replies_[reply->id()] = reply;
SendMessage(reply->request_message());
}
template<typename MT>
template <typename MT>
void AbstractMessageHandler<MT>::SendReply(const MessageType& request,
MessageType* reply) {
reply->set_id(request.id());
SendMessage(*reply);
}
template<typename MT>
template <typename MT>
bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
MessageType message;
if (!message.ParseFromArray(data.constData(), data.size())) {
@ -180,14 +173,10 @@ bool AbstractMessageHandler<MT>::RawMessageArrived(const QByteArray& data) {
return true;
}
template<typename MT>
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

@ -29,7 +29,7 @@
class _MessageReplyBase : public QObject {
Q_OBJECT
public:
public:
_MessageReplyBase(QObject* parent = 0);
virtual int id() const = 0;
@ -46,19 +46,18 @@ public:
signals:
void Finished(bool success);
protected:
protected:
bool finished_;
bool success_;
QSemaphore semaphore_;
};
// A reply future class that is returned immediately for requests that will
// occur in the background. Similar to QNetworkReply.
template <typename MessageType>
class MessageReply : public _MessageReplyBase {
public:
public:
MessageReply(const MessageType& request_message, QObject* parent = 0);
int id() const { return request_message_.id(); }
@ -67,21 +66,19 @@ public:
void SetReply(const MessageType& message);
private:
private:
MessageType request_message_;
MessageType reply_message_;
};
template<typename MessageType>
template <typename MessageType>
MessageReply<MessageType>::MessageReply(const MessageType& request_message,
QObject* parent)
: _MessageReplyBase(parent)
{
: _MessageReplyBase(parent) {
request_message_.MergeFrom(request_message);
}
template<typename MessageType>
template <typename MessageType>
void MessageReply<MessageType>::SetReply(const MessageType& message) {
Q_ASSERT(!finished_);

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
@ -26,13 +25,13 @@
// it is available.
#ifndef __has_extension
#define __has_extension(x) 0
#define __has_extension(x) 0
#endif
#if __has_extension(cxx_override_control) // Clang feature checking macro.
# define OVERRIDE override
#define OVERRIDE override
#else
# define OVERRIDE
#define OVERRIDE
#endif
#endif // 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,13 +32,12 @@
#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 {
Q_OBJECT
public:
public:
_WorkerPoolBase(QObject* parent = 0);
signals:
@ -46,14 +45,13 @@ signals:
// worker wasn't found, or couldn't be executed.
void WorkerFailedToStart();
protected slots:
protected slots:
virtual void DoStart() {}
virtual void NewConnection() {}
virtual void ProcessError(QProcess::ProcessError) {}
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
@ -61,7 +59,7 @@ protected slots:
// Instances of HandlerType are created in the WorkerPool's thread.
template <typename HandlerType>
class WorkerPool : public _WorkerPoolBase {
public:
public:
WorkerPool(QObject* parent = 0);
~WorkerPool();
@ -90,7 +88,7 @@ public:
// worker. Can be called from any thread.
ReplyType* SendMessageWithReply(MessageType* message);
protected:
protected:
// These are all reimplemented slots, they are called on the WorkerPool's
// thread.
void DoStart();
@ -98,9 +96,12 @@ protected:
void ProcessError(QProcess::ProcessError error);
void SendQueuedMessages();
private:
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_;
@ -114,8 +115,8 @@ private:
template <typename T>
Worker* FindWorker(T Worker::*member, T value) {
for (typename QList<Worker>::iterator it = workers_.begin() ;
it != workers_.end() ; ++it) {
for (typename QList<Worker>::iterator it = workers_.begin();
it != workers_.end(); ++it) {
if ((*it).*member == value) {
return &(*it);
}
@ -140,7 +141,7 @@ private:
// my thread.
HandlerType* NextHandler() const;
private:
private:
QString local_server_name_;
QString executable_name_;
QString executable_path_;
@ -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_) {
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;
}
@ -235,7 +231,7 @@ void WorkerPool<HandlerType>::DoStart() {
search_path << qApp->applicationDirPath() + "/../PlugIns";
#endif
foreach (const QString& path_prefix, search_path) {
foreach(const QString & path_prefix, search_path) {
const QString executable_path = path_prefix + "/" + executable_name_;
if (QFile::exists(executable_path)) {
executable_path_ = executable_path;
@ -244,7 +240,7 @@ void WorkerPool<HandlerType>::DoStart() {
}
// Start all the workers
for (int i=0 ; i<worker_count_ ; ++i) {
for (int i = 0; i < worker_count_; ++i) {
Worker worker;
StartOneWorker(&worker);
@ -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);
@ -390,7 +389,7 @@ void WorkerPool<HandlerType>::SendQueuedMessages() {
template <typename HandlerType>
HandlerType* WorkerPool<HandlerType>::NextHandler() const {
for (int i=0 ; i<workers_.count() ; ++i) {
for (int i = 0; i < workers_.count(); ++i) {
const int worker_index = (next_worker_ + i) % workers_.count();
if (workers_[worker_index].handler_ &&

View File

@ -28,13 +28,13 @@
#include "core/logging.h"
namespace {
static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough.
static const int kTaglibSuffixCacheBytes = 8 * 1024;
static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough.
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,24 +180,18 @@ 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";
}
void CloudStream::SSLErrors(const QList<QSslError>& errors) {
foreach (const QSslError& error, errors) {
foreach(const QSslError & error, errors) {
qLog(Debug) << error.error() << error.errorString();
qLog(Debug) << error.certificate();
}

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

@ -22,7 +22,7 @@
#include <QVariantList>
class FMPSParser {
public:
public:
FMPSParser();
// A FMPS result is a list of lists of values (where a value is a string or
@ -48,7 +48,7 @@ public:
int ParseListList(const QString& data, Result* ret) const;
int ParseListListRef(const QStringRef& data, Result* ret) const;
private:
private:
QRegExp float_re_;
QRegExp string_re_;
QRegExp escape_re_;

View File

@ -59,15 +59,17 @@
#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)
# define TAGLIB_HAS_FLAC_PICTURELIST
#if (TAGLIB_MAJOR_VERSION > 1) || \
(TAGLIB_MAJOR_VERSION == 1 && TAGLIB_MINOR_VERSION >= 7)
#define TAGLIB_HAS_FLAC_PICTURELIST
#endif
#ifdef HAVE_GOOGLE_DRIVE
# include "cloudstream.h"
#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:
@ -78,11 +80,11 @@ class FileRefFactory {
class TagLibFileRefFactory : public FileRefFactory {
public:
virtual TagLib::FileRef* GetFileRef(const QString& filename) {
#ifdef Q_OS_WIN32
#ifdef Q_OS_WIN32
return new TagLib::FileRef(filename.toStdWString().c_str());
#else
#else
return new TagLib::FileRef(QFile::encodeName(filename).constData());
#endif
#endif
}
};
@ -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 {
@ -122,7 +125,7 @@ void TagReader::ReadFile(const QString& filename,
song->set_ctime(info.created().toTime_t());
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
if(fileref->isNull()) {
if (fileref->isNull()) {
qLog(Info) << "TagLib hasn't been able to read " << filename << " file";
return;
}
@ -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,27 +162,32 @@ 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) {
for (int i = 0; i < map["COMM"].size(); ++i) {
const TagLib::ID3v2::CommentsFrame* frame =
dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);
@ -187,14 +198,14 @@ void TagReader::ReadFile(const QString& filename,
}
// Parse FMPS frames
for (int i=0 ; i<map["TXXX"].size() ; ++i) {
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())) {
if ( file->xiphComment() ) {
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song);
} else if (TagLib::FLAC::File* file =
dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
if (file->xiphComment()) {
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());
if (items.contains("\251wrt")) {
Decode(items["\251wrt"].toStringList().toString(", "), nullptr,
song->mutable_composer());
}
if(items.contains("\251grp")) {
Decode(items["\251grp"].toStringList().toString(" "), nullptr, song->mutable_grouping());
if (items.contains("\251grp")) {
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); }
// Set integer fields to -1 if they're not valid
#define SetDefault(field) \
if (song->field() <= 0) { \
song->set_##field(-1); \
}
SetDefault(track);
SetDefault(disc);
SetDefault(bpm);
@ -350,16 +387,16 @@ void TagReader::ReadFile(const QString& filename,
SetDefault(bitrate);
SetDefault(samplerate);
SetDefault(lastplayed);
#undef SetDefault
#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());
@ -437,52 +473,76 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map,
Decode(map["ALBUM ARTIST"].front(), codec, song->mutable_albumartist());
}
if (!map["BPM"].isEmpty() )
song->set_bpm(TStringToQString( map["BPM"].front() ).trimmed().toFloat());
if (!map["BPM"].isEmpty())
song->set_bpm(TStringToQString(map["BPM"].front()).trimmed().toFloat());
if (!map["DISCNUMBER"].isEmpty() )
*disc = TStringToQString( map["DISCNUMBER"].front() ).trimmed();
if (!map["DISCNUMBER"].isEmpty())
*disc = TStringToQString(map["DISCNUMBER"].front()).trimmed();
if (!map["COMPILATION"].isEmpty() )
*compilation = TStringToQString( map["COMPILATION"].front() ).trimmed();
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,51 +600,62 @@ 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);
}
bool ret = fileref->save();
#ifdef Q_OS_LINUX
#ifdef Q_OS_LINUX
if (ret) {
// Linux: inotify doesn't seem to notice the change to the file unless we
// change the timestamps as well. (this is what touch does)
utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0);
}
#endif // Q_OS_LINUX
#endif // Q_OS_LINUX
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,54 +664,63 @@ 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;
}
bool ret = fileref->save();
#ifdef Q_OS_LINUX
#ifdef Q_OS_LINUX
if (ret) {
// Linux: inotify doesn't seem to notice the change to the file unless we
// change the timestamps as well. (this is what touch does)
utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0);
}
#endif // Q_OS_LINUX
#endif // Q_OS_LINUX
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,38 +740,45 @@ 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;
}
bool ret = fileref->save();
#ifdef Q_OS_LINUX
#ifdef Q_OS_LINUX
if (ret) {
// Linux: inotify doesn't seem to notice the change to the file unless we
// change the timestamps as well. (this is what touch does)
utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0);
}
#endif // Q_OS_LINUX
#endif // Q_OS_LINUX
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,15 +30,14 @@ class QString;
class QTextCodec;
class QUrl;
namespace TagLib {
class FileRef;
class String;
class FileRef;
class String;
namespace ID3v2 {
class Tag;
class PopularimeterFrame;
}
namespace ID3v2 {
class Tag;
class PopularimeterFrame;
}
}
class FileRefFactory;
@ -52,25 +51,26 @@ 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,
#ifdef HAVE_GOOGLE_DRIVE
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
#endif // HAVE_GOOGLE_DRIVE
static void Decode(const TagLib::String& tag, const QTextCodec* codec,
std::string* output);
@ -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,
@ -102,15 +105,17 @@ class TagReader {
void SetTextFrame(const char* id, const std::string& value,
TagLib::ID3v2::Tag* tag) const;
private:
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,85 +27,80 @@
#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
// can't mod scope in analyze you have to use transform
//TODO for 2D use setErasePixmap Qt function insetead of m_background
// 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) {}
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)
void Analyzer::Base::hideEvent(QHideEvent*) { m_timer.stop(); }
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
// scope.resize( m_fht->size() );
float* front = static_cast<float*>(&scope.front());
float* f = new float[m_fht->size()];
m_fht->copy(&f[0], front);
m_fht->logSpectrum(front, &f[0]);
m_fht->scale(front, 1.0 / 20);
scope.resize(m_fht->size() / 2); // second half of values are rubbish
delete[] f;
}
void Analyzer::Base::hideEvent(QHideEvent *) {
m_timer.stop();
}
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
//scope.resize( m_fht->size() );
float *front = static_cast<float*>( &scope.front() );
float* f = new float[ m_fht->size() ];
m_fht->copy( &f[0], front );
m_fht->logSpectrum( front, &f[0] );
m_fht->scale( front, 1.0 / 20 );
scope.resize( m_fht->size() / 2 ); //second half of values are rubbish
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:
{
const Engine::Scope &thescope = m_engine->scope();
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;
}
is_playing_ = true;
transform( m_lastScope );
analyze( p, m_lastScope, new_frame_ );
transform(m_lastScope);
analyze(p, m_lastScope, new_frame_);
//scope.resize( m_fht->size() );
// scope.resize( m_fht->size() );
break;
}
@ -119,113 +114,99 @@ void Analyzer::Base::paintEvent(QPaintEvent * e)
demo(p);
}
new_frame_ = false;
}
int Analyzer::Base::resizeExponent( int exp )
{
if ( exp < 3 )
int Analyzer::Base::resizeExponent(int exp) {
if (exp < 3)
exp = 3;
else if ( exp > 9 )
else if (exp > 9)
exp = 9;
if ( exp != m_fht->sizeExp() ) {
if (exp != m_fht->sizeExp()) {
delete m_fht;
m_fht = new FHT( exp );
m_fht = new FHT(exp);
}
return exp;
}
int Analyzer::Base::resizeForBands( int bands )
{
int Analyzer::Base::resizeForBands(int bands) {
int exp;
if ( bands <= 8 )
if (bands <= 8)
exp = 4;
else if ( bands <= 16 )
else if (bands <= 16)
exp = 5;
else if ( bands <= 32 )
else if (bands <= 32)
exp = 6;
else if ( bands <= 64 )
else if (bands <= 64)
exp = 7;
else if ( bands <= 128 )
else if (bands <= 128)
exp = 8;
else
exp = 9;
resizeExponent( exp );
resizeExponent(exp);
return m_fht->size() / 2;
}
void Analyzer::Base::demo(QPainter& p) //virtual
void Analyzer::Base::demo(QPainter& p) // virtual
{
static int t = 201; //FIXME make static to namespace perhaps
static int t = 201; // FIXME make static to namespace perhaps
if( t > 999 ) t = 1; //0 = wasted calculations
if( t < 201 )
{
Scope s( 32 );
if (t > 999) t = 1; // 0 = wasted calculations
if (t < 201) {
Scope s(32);
const double dt = double(t) / 200;
for( uint i = 0; i < s.size(); ++i )
s[i] = dt * (sin( M_PI + (i * M_PI) / s.size() ) + 1.0);
for (uint i = 0; i < s.size(); ++i)
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_ );
analyze(p, s, new_frame_);
} else
analyze(p, Scope(32, 0), new_frame_);
++t;
}
void Analyzer::Base::polishEvent()
{
init(); //virtual
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 )
{
const double error = pos - std::floor( pos );
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 step = (M_PI * 2) / size;
double radian = 0;
for ( uint i = 0; i < size; i++ )
{
v.push_back( sin( radian ) );
for (uint i = 0; i < size; i++) {
v.push_back(sin(radian));
radian += step;
}
}
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,23 +28,21 @@ class QEvent;
class QPaintEvent;
class QResizeEvent;
namespace Analyzer {
typedef std::vector<float> Scope;
class Base : public QWidget
{
class Base : public QWidget {
Q_OBJECT
public:
public:
~Base() { delete m_fht; }
uint timeout() const { return m_timeout; }
void set_engine(EngineBase* engine) { m_engine = engine; }
void changeTimeout( uint newTimeout ) {
void changeTimeout(uint newTimeout) {
m_timeout = newTimeout;
if (m_timer.isActive()) {
m_timer.stop();
@ -53,27 +50,27 @@ public:
}
}
protected:
Base( QWidget*, uint scopeSize = 7 );
protected:
Base(QWidget*, uint scopeSize = 7);
void hideEvent(QHideEvent *);
void showEvent(QShowEvent *);
void paintEvent( QPaintEvent* );
void timerEvent(QTimerEvent *);
void hideEvent(QHideEvent*);
void showEvent(QShowEvent*);
void paintEvent(QPaintEvent*);
void timerEvent(QTimerEvent*);
void polishEvent();
int resizeExponent( int );
int resizeForBands( int );
int resizeExponent(int);
int resizeForBands(int);
virtual void init() {}
virtual void transform( Scope& );
virtual void analyze( QPainter& p, const Scope&, bool new_frame) = 0;
virtual void transform(Scope&);
virtual void analyze(QPainter& p, const Scope&, bool new_frame) = 0;
virtual void demo(QPainter& p);
protected:
protected:
QBasicTimer m_timer;
uint m_timeout;
FHT *m_fht;
FHT* m_fht;
EngineBase* m_engine;
Scope m_lastScope;
@ -81,11 +78,10 @@ protected:
bool is_playing_;
};
void interpolate(const Scope&, Scope&);
void initSin(Scope&, const uint = 6000);
void interpolate( const Scope&, Scope& );
void initSin( Scope&, const uint = 6000 );
} //END namespace Analyzer
} // END namespace Analyzer
using Analyzer::Scope;

View File

@ -39,7 +39,7 @@ const int AnalyzerContainer::kMediumFramerate = 25;
const int AnalyzerContainer::kHighFramerate = 30;
const int AnalyzerContainer::kSuperHighFramerate = 60;
AnalyzerContainer::AnalyzerContainer(QWidget *parent)
AnalyzerContainer::AnalyzerContainer(QWidget* parent)
: QWidget(parent),
current_framerate_(kMediumFramerate),
context_menu_(new QMenu(this)),
@ -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_);
@ -115,12 +115,11 @@ void AnalyzerContainer::ShowPopupMenu() {
context_menu_->popup(last_click_pos_);
}
void AnalyzerContainer::mouseDoubleClickEvent(QMouseEvent *) {
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_);
@ -161,7 +161,7 @@ void AnalyzerContainer::ChangeAnalyzer(int id) {
}
void AnalyzerContainer::ChangeFramerate(int new_framerate) {
if(current_analyzer_) {
if (current_analyzer_) {
// Even if it is not supposed to happen, I don't want to get a dbz error
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
current_analyzer_->changeTimeout(1000 / new_framerate);
@ -179,7 +179,7 @@ void AnalyzerContainer::Load() {
DisableAnalyzer();
disable_action_->setChecked(true);
} else {
for (int i=0 ; i<analyzer_types_.count() ; ++i) {
for (int i = 0; i < analyzer_types_.count(); ++i) {
if (type == analyzer_types_[i]->className()) {
ChangeAnalyzer(i);
actions_[i]->setChecked(true);
@ -190,8 +190,8 @@ void AnalyzerContainer::Load() {
// Framerate
current_framerate_ = s.value(kSettingsFramerate, kMediumFramerate).toInt();
for (int i=0 ; i<framerate_list_.count() ; ++i) {
if(current_framerate_ == framerate_list_[i]) {
for (int i = 0; i < framerate_list_.count(); ++i) {
if (current_framerate_ == framerate_list_[i]) {
ChangeFramerate(current_framerate_);
group_framerate_->actions()[i]->setChecked(true);
break;
@ -200,8 +200,8 @@ void AnalyzerContainer::Load() {
}
void AnalyzerContainer::SaveFramerate(int framerate) {
// For now, framerate is common for all analyzers. Maybe each analyzer should
// have its own framerate?
// For now, framerate is common for all analyzers. Maybe each analyzer should
// have its own framerate?
current_framerate_ = framerate;
QSettings s;
s.beginGroup(kSettingsGroup);
@ -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

@ -28,7 +28,7 @@
class AnalyzerContainer : public QWidget {
Q_OBJECT
public:
public:
AnalyzerContainer(QWidget* parent);
void SetEngine(EngineBase* engine);
@ -40,18 +40,18 @@ public:
signals:
void WheelEvent(int delta);
protected:
void mouseReleaseEvent(QMouseEvent *);
void mouseDoubleClickEvent(QMouseEvent *);
protected:
void mouseReleaseEvent(QMouseEvent*);
void mouseDoubleClickEvent(QMouseEvent*);
void wheelEvent(QWheelEvent* e);
private slots:
private slots:
void ChangeAnalyzer(int id);
void ChangeFramerate(int new_framerate);
void DisableAnalyzer();
void ShowPopupMenu();
private:
private:
static const int kLowFramerate;
static const int kMediumFramerate;
static const int kHighFramerate;
@ -64,7 +64,7 @@ private:
void AddAnalyzerType();
void AddFramerate(const QString& name, int framerate);
private:
private:
int current_framerate_; // fps
QMenu* context_menu_;
QMenu* context_menu_framerate_;
@ -88,11 +88,12 @@ private:
};
template <typename T>
void AnalyzerContainer::AddAnalyzerType() {
void AnalyzerContainer::AddAnalyzerType() {
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,101 +16,95 @@
#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 )
BarAnalyzer::BarAnalyzer(QWidget* parent)
: Analyzer::Base(parent, 8)
//, m_bands( BAND_COUNT )
//, barVector( BAND_COUNT, 0 )
//, roofVector( BAND_COUNT, 50 )
//, roofVelocityVector( BAND_COUNT, ROOF_VELOCITY_REDUCTION_FACTOR )
{
//roof pixmaps don't depend on size() so we do in the ctor
// roof pixmaps don't depend on size() so we do in the ctor
m_bg = parent->palette().color(QPalette::Background);
QColor fg( 0xff, 0x50, 0x70 );
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 dg = double(m_bg.green() - fg.green()) / (NUM_ROOFS-1);
double db = double(m_bg.blue() - fg.blue()) / (NUM_ROOFS-1);
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 )
{
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) ) );
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)));
}
}
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 );
const double F = double(height() - 2) / (log10(255) * MAX_AMPLITUDE);
BAND_COUNT = width() / 5;
MAX_DOWN = int(0 -(qMax(1, height() / 50)));
MAX_DOWN = int(0 - (qMax(1, height() / 50)));
MAX_UP = int(qMax(1, height() / 25));
barVector.resize( BAND_COUNT, 0 );
roofVector.resize( BAND_COUNT, height() -5 );
roofVelocityVector.resize( BAND_COUNT, ROOF_VELOCITY_REDUCTION_FACTOR );
barVector.resize(BAND_COUNT, 0);
roofVector.resize(BAND_COUNT, height() - 5);
roofVelocityVector.resize(BAND_COUNT, ROOF_VELOCITY_REDUCTION_FACTOR);
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 )
{
m_lvlMapper[x] = uint( F * log10( x+1 ) );
// 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));
}
m_pixBarGradient = QPixmap( height()*COLUMN_WIDTH, height() );
m_pixCompose = QPixmap( size() );
m_pixBarGradient = QPixmap(height() * COLUMN_WIDTH, height());
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 )
{
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) {
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 ) );
p.drawLine( x*COLUMN_WIDTH, height() - y, (x+1)*COLUMN_WIDTH, height() - y );
// 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);
}
}
setMinimumSize( QSize( BAND_COUNT * COLUMN_WIDTH, 10 ) );
setMinimumSize(QSize(BAND_COUNT * COLUMN_WIDTH, 10));
}
void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) {
// Analyzer::interpolate( s, m_bands );
void BarAnalyzer::analyze( QPainter& p, const Scope &s, bool new_frame)
{
//Analyzer::interpolate( s, m_bands );
Scope& v = m_scope;
Analyzer::interpolate(s, v);
Scope &v = m_scope;
Analyzer::interpolate( s, v );
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()
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()
int change = y2 - barVector[i];
//using the best of Markey's, piggz and Max's ideas on the way to shift the bars
//we have the following:
// 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
// 3. fall downwards at a constant pace
@ -119,48 +113,49 @@ 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;
}
//remember where we are
// remember where we are
barVector[i] = y2;
if ( m_roofMem[i].size() > NUM_ROOFS )
m_roofMem[i].erase( m_roofMem[i].begin() );
if (m_roofMem[i].size() > NUM_ROOFS)
m_roofMem[i].erase(m_roofMem[i].begin());
//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 ] );
p.drawPixmap(x, m_roofMem[i][c], m_pixRoof[ NUM_ROOFS - 1 - c ]);
// 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 ]
// );
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);
// blt the bar
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 );
m_roofMem[i].push_back(height() - roofVector[i] - 2);
//set roof parameters for the NEXT draw
if ( roofVelocityVector[i] != 0 )
{
if ( roofVelocityVector[i] > 32 ) //no reason to do == 32
roofVector[i] -= (roofVelocityVector[i] - 32) / 20; //trivial calculation
// set roof parameters for the NEXT draw
if (roofVelocityVector[i] != 0) {
if (roofVelocityVector[i] > 32) // no reason to do == 32
roofVector[i] -=
(roofVelocityVector[i] - 32) / 20; // trivial calculation
if ( roofVector[i] < 0 )
{
roofVector[i] = 0; //not strictly necessary
if (roofVector[i] < 0) {
roofVector[i] = 0; // not strictly necessary
roofVelocityVector[i] = 0;
}
else ++roofVelocityVector[i];
} else
++roofVelocityVector[i];
}
}
}

View File

@ -10,22 +10,20 @@
typedef std::vector<uint> aroofMemVec;
class BarAnalyzer : public Analyzer::Base
{
class BarAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BarAnalyzer( QWidget* );
Q_INVOKABLE BarAnalyzer(QWidget*);
void init();
virtual void analyze( QPainter& p, const Scope&, bool new_frame);
//virtual void transform( Scope& );
virtual void analyze(QPainter& p, const Scope&, bool new_frame);
// virtual void transform( Scope& );
/**
* Resizes the widget to a new geometry according to @p e
* @param e The resize-event
*/
void resizeEvent( QResizeEvent * e);
void resizeEvent(QResizeEvent* e);
uint BAND_COUNT;
int MAX_DOWN;
@ -39,21 +37,22 @@ class BarAnalyzer : public Analyzer::Base
protected:
QPixmap m_pixRoof[NUM_ROOFS];
//vector<uint> m_roofMem[BAND_COUNT];
// 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
std::vector<int> roofVector; //positions of roofs
std::vector<uint> roofVelocityVector; //speed that roofs falls
std::vector<uint> barVector; // positions of bars
std::vector<int> roofVector; // positions of roofs
std::vector<uint> roofVelocityVector; // speed that roofs falls
const QPixmap *gradient() const { return &m_pixBarGradient; }
const QPixmap* gradient() const { return &m_pixBarGradient; }
private:
QPixmap m_pixBarGradient;
QPixmap m_pixCompose;
Scope m_scope; //so we don't create a vector every frame
Scope m_scope; // so we don't create a vector every frame
QColor m_bg;
};

View File

@ -14,109 +14,114 @@
const uint BlockAnalyzer::HEIGHT = 2;
const uint BlockAnalyzer::WIDTH = 4;
const uint BlockAnalyzer::MIN_ROWS = 3; //arbituary
const uint BlockAnalyzer::MIN_COLUMNS = 32; //arbituary
const uint BlockAnalyzer::MAX_COLUMNS = 256; //must be 2**n
const uint BlockAnalyzer::MIN_ROWS = 3; // arbituary
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>
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>
{
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 );
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 )
{
QWidget::resizeEvent( e );
void BlockAnalyzer::resizeEvent(QResizeEvent* e) {
QWidget::resizeEvent(e);
m_background = QPixmap(size());
const uint oldRows = m_rows;
//all is explained in analyze()..
// all is explained in analyze()..
//+1 to counter -1 in maxSizes, trust me we need this!
m_columns = qMax( uint(double(width()+1) / (WIDTH+1)), MAX_COLUMNS );
m_rows = uint(double(height()+1) / (HEIGHT+1));
m_columns = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS);
m_rows = uint(double(height() + 1) / (HEIGHT + 1));
//this is the y-offset for drawing from the top of the widget
m_y = (height() - (m_rows * (HEIGHT+1)) + 2) / 2;
// this is the y-offset for drawing from the top of the widget
m_y = (height() - (m_rows * (HEIGHT + 1)) + 2) / 2;
m_scope.resize( m_columns );
m_scope.resize(m_columns);
if( m_rows != oldRows ) {
m_barPixmap = QPixmap( WIDTH, m_rows*(HEIGHT+1) );
if (m_rows != oldRows) {
m_barPixmap = QPixmap(WIDTH, m_rows * (HEIGHT + 1));
for ( uint i = 0; i < FADE_SIZE; ++i )
m_fade_bars[i] = QPixmap( WIDTH, m_rows*(HEIGHT+1) );
for (uint i = 0; i < FADE_SIZE; ++i)
m_fade_bars[i] = QPixmap(WIDTH, m_rows * (HEIGHT + 1));
m_yscale.resize( m_rows + 1 );
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 ));
for (uint z = 0; z < m_rows; ++z)
m_yscale[z] = 1 - (log10(PRE + z) / log10(PRE + m_rows + PRO));
m_yscale[m_rows] = 0;
determineStep();
paletteChange( palette() );
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() );
float* front = static_cast<float*>(&s.front());
m_fht->spectrum( front );
m_fht->scale( front, 1.0 / 20 );
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
// . . . . # .
// . . . # # .
@ -130,69 +135,65 @@ BlockAnalyzer::analyze( QPainter& p, const Analyzer::Scope &s, bool new_frame)
// m_yscale looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 }
// if it contains 6 elements there are 5 rows in the analyzer
Analyzer::interpolate( s, m_scope );
Analyzer::interpolate(s, m_scope);
// 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 )
for (y = 0; m_scope[x] < m_yscale[y]; ++y)
;
// this is opposite to what you'd think, higher than y
// means the bar is lower than y (physically)
if( (float)y > m_store[x] )
if ((float)y > m_store[x])
y = int(m_store[x] += m_step);
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*/ ) {
if (y <= m_fade_pos[x] /*|| m_fade_intensity[x] < FADE_SIZE / 3*/) {
m_fade_pos[x] = y;
m_fade_intensity[x] = FADE_SIZE;
}
if( m_fade_intensity[x] > 0 ) {
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);
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);
}
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 );
for (uint x = 0; x < m_store.size(); ++x)
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
if( b < f ) {
if( b > 255 - f ) {
if (b < f) {
if (b > 255 - f) {
amount -= f;
f = 0;
} else {
amount -= (255 - f);
f = 255;
}
}
else {
if( f > 255 - b ) {
} else {
if (f > 255 - b) {
amount -= f;
f = 0;
} else {
@ -205,166 +206,168 @@ 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(const QColor& color) : c(color) {}
~OutputOnExit() {
int h, s, v;
c.getHsv(&h, &s, &v);
}
private:
const QColor &c;
const QColor& c;
};
// 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;
// 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;
OutputOnExit allocateOnTheStack( fg );
OutputOnExit allocateOnTheStack(fg);
int bh, bs, bv;
int fh, fs, fv;
bg.getHsv( &bh, &bs, &bv );
fg.getHsv( &fh, &fs, &fv );
bg.getHsv(&bh, &bs, &bv);
fg.getHsv(&fh, &fs, &fv);
int dv = abs( bv - fv );
int dv = abs(bv - fv);
// STAMP2( "DV", dv );
// STAMP2( "DV", dv );
// 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 );
int ds = abs(bs - fs);
// STAMP2( "DS", ds );
// 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 );
int dh = abs(bh - fh);
// STAMP2( "DH", dh );
// STAMP2( "DH", dh );
if( dh > 120 ) {
if (dh > 120) {
// a third of the colour wheel automatically guarentees contrast
// but only if the values are high enough and saturations significant enough
// to allow the colours to be visible and not be shades of grey or black
// 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" );
if (ds > amount / 2 && (bs > 125 && fs > 125))
// 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" );
else if (dv > amount / 2 && (bv > 125 && fv > 125))
// 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
// but either the colours are two desaturated, or too dark
// so we need to adjust the system, although not as much
///_amount /= 2;
}
if( fs < 50 && ds < 40 ) {
if (fs < 50 && ds < 40) {
// low saturation on a low saturation is sad
const int tmp = 50 - fs;
fs = 50;
if( amount > tmp )
if (amount > tmp)
_amount -= tmp;
else
_amount = 0;
}
// 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 );
// adjustToLimits( bv, fv, amount );
// STAMP
// STAMP
// see if we need to adjust the saturation
if( amount > 0 )
adjustToLimits( bs, fs, _amount );
if (amount > 0) adjustToLimits(bs, fs, _amount);
// STAMP
// STAMP
// see if we need to adjust the hue
if( amount > 0 )
fh += amount; // cycles around;
if (amount > 0) fh += amount; // cycles around;
// STAMP
// STAMP
return QColor::fromHsv(fh, fs, fv);
}
// STAMP
// 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
// 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
// STAMP
if( fv > bv && (255 - fv > amount) )
return QColor::fromHsv( fh, fs, fv + amount);
if (fv > bv && (255 - fv > amount))
return QColor::fromHsv(fh, fs, fv + amount);
// STAMP
// STAMP
if( fv < bv && (255 - bv > amount ) )
return QColor::fromHsv( fh, fs, bv + amount);
if (fv < bv && (255 - bv > amount))
return QColor::fromHsv(fh, fs, bv + amount);
// STAMP
// debug() << "Something went wrong!\n";
// STAMP
// debug() << "Something went wrong!\n";
return Qt::blue;
#undef amount
// #undef STAMP
#undef amount
// #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) );
const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight));
m_topBarPixmap.fill( fg );
m_topBarPixmap.fill(fg);
const double dr = 15*double(bg.red() - fg.red()) / (m_rows*16);
const double dg = 15*double(bg.green() - fg.green()) / (m_rows*16);
const double db = 15*double(bg.blue() - fg.blue()) / (m_rows*16);
const double dr = 15 * double(bg.red() - fg.red()) / (m_rows * 16);
const double dg = 15 * double(bg.green() - fg.green()) / (m_rows * 16);
const double db = 15 * double(bg.blue() - fg.blue()) / (m_rows * 16);
const int r = fg.red(), g = fg.green(), b = fg.blue();
bar()->fill( bg );
bar()->fill(bg);
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) ) );
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)));
{
const QColor bg = palette().color(QPalette::Background).dark( 112 );
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 );
const QColor fg( QColor::fromHsv(h + 120, s, v));
// 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);
const QColor fg(QColor::fromHsv(h + 120, s, v));
const double dr = fg.red() - bg.red();
const double dg = fg.green() - bg.green();
@ -372,12 +375,13 @@ BlockAnalyzer::paletteChange( const QPalette& ) //virtual
const int r = bg.red(), g = bg.green(), b = bg.blue();
// Precalculate all fade-bar pixmaps
for( uint y = 0; y < FADE_SIZE; ++y ) {
m_fade_bars[y].fill( palette().color(QPalette::Background) );
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) ) );
for (uint y = 0; y < FADE_SIZE; ++y) {
m_fade_bars[y].fill(palette().color(QPalette::Background));
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)));
}
}
}
@ -385,16 +389,15 @@ 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 );
const QColor bgdark = bg.dark(112);
m_background.fill( bg );
m_background.fill(bg);
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 );
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);
}

View File

@ -12,16 +12,14 @@ 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* );
public:
Q_INVOKABLE BlockAnalyzer(QWidget*);
~BlockAnalyzer();
static const uint HEIGHT;
@ -33,33 +31,33 @@ public:
static const char* kName;
protected:
virtual void transform( Scope& );
virtual void analyze( QPainter& p, const Scope&, bool new_frame);
virtual void resizeEvent( QResizeEvent* );
virtual void paletteChange( const QPalette& );
protected:
virtual void transform(Scope&);
virtual void analyze(QPainter& p, const Scope&, bool new_frame);
virtual void resizeEvent(QResizeEvent*);
virtual void paletteChange(const QPalette&);
void drawBackground();
void determineStep();
private:
private:
QPixmap* bar() { return &m_barPixmap; }
uint m_columns, m_rows; //number of rows and columns of blocks
uint m_y; //y-offset from top of widget
uint m_columns, m_rows; // number of rows and columns of blocks
uint m_y; // y-offset from top of widget
QPixmap m_barPixmap;
QPixmap m_topBarPixmap;
QPixmap m_background;
Scope m_scope; //so we don't create a vector every frame
std::vector<float> m_store; //current bar heights
Scope m_scope; // so we don't create a vector every frame
std::vector<float> m_store; // current bar heights
std::vector<float> m_yscale;
//FIXME why can't I namespace these? c++ issue?
// FIXME why can't I namespace these? c++ issue?
std::vector<QPixmap> m_fade_bars;
std::vector<uint> m_fade_pos;
std::vector<int> m_fade_intensity;
float m_step; //rows to fall per frame
float m_step; // rows to fall per frame
};
#endif

View File

@ -5,131 +5,110 @@
#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 )
{
}
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) {}
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;
F = double(HEIGHT) / (log10( 256 ) * 1.1 /*<- max. amplitude*/);
F = double(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/);
barPixmap = QPixmap( COLUMN_WIDTH-2, HEIGHT );
barPixmap = QPixmap(COLUMN_WIDTH - 2, HEIGHT);
QPainter p( &barPixmap );
for( uint y = 0; y < HEIGHT; ++y )
{
QPainter p(&barPixmap);
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 );
p.drawLine(0, y, COLUMN_WIDTH - 2, y);
}
}
void
BoomAnalyzer::transform( Scope &s )
{
float *front = static_cast<float*>( &s.front() );
void BoomAnalyzer::transform(Scope& s) {
float* front = static_cast<float*>(&s.front());
m_fht->spectrum( front );
m_fht->scale( front, 1.0 / 60 );
m_fht->spectrum(front);
m_fht->scale(front, 1.0 / 60);
Scope scope( 32, 0 );
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];
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];
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 )
{
h = log10( scope[i]*256.0 ) * F;
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 )
{
bar_height[i] -= K_barHeight; //1.4
if( bar_height[i] < 0.0 ) 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
peak_speed[i] *= F_peakSpeed; // 1.12
if( peak_height[i] < bar_height[i] ) peak_height[i] = bar_height[i];
if( peak_height[i] < 0.0 ) peak_height[i] = 0.0;
if (peak_height[i] < bar_height[i]) peak_height[i] = bar_height[i];
if (peak_height[i] < 0.0) peak_height[i] = 0.0;
}
}
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 );
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);
y = height() - uint(peak_height[i]);
p.setPen( palette().color(QPalette::Base) );
p.drawLine( x, y, x+COLUMN_WIDTH-1, y );
p.setPen(palette().color(QPalette::Base));
p.drawLine(x, y, x + COLUMN_WIDTH - 1, y);
}
}

View File

@ -11,24 +11,23 @@
@author Max Howell
*/
class BoomAnalyzer : public Analyzer::Base
{
Q_OBJECT
public:
Q_INVOKABLE BoomAnalyzer( QWidget* );
class BoomAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BoomAnalyzer(QWidget*);
static const char* kName;
virtual void init();
virtual void transform( Scope &s );
virtual void analyze( QPainter& p, const Scope&, bool new_frame);
virtual void transform(Scope& s);
virtual void analyze(QPainter& p, const Scope&, bool new_frame);
public slots:
void changeK_barHeight( int );
void changeF_peakSpeed( int );
public slots:
void changeK_barHeight(int);
void changeF_peakSpeed(int);
protected:
void resizeEvent( QResizeEvent * e);
protected:
void resizeEvent(QResizeEvent* e);
static const uint COLUMN_WIDTH = 4;
static const uint BAND_COUNT = 32;

View File

@ -23,21 +23,15 @@
#include "glanalyzer.h"
#include <kdebug.h>
GLAnalyzer::GLAnalyzer(QWidget* parent)
: Analyzer::Base3D(parent, 15), m_oldy(32, -10.0f), m_peaks(32) {}
GLAnalyzer::GLAnalyzer( QWidget *parent )
: Analyzer::Base3D(parent, 15)
, m_oldy(32, -10.0f)
, m_peaks(32)
{}
GLAnalyzer::~GLAnalyzer()
{}
GLAnalyzer::~GLAnalyzer() {}
// METHODS =====================================================
void GLAnalyzer::analyze( const Scope &s )
{
//kdDebug() << "Scope Size: " << s.size() << endl;
void GLAnalyzer::analyze(const Scope& s) {
// kdDebug() << "Scope Size: " << s.size() << endl;
/* Scope t(32);
if (s.size() != 32)
{
@ -52,90 +46,80 @@ void GLAnalyzer::analyze( const Scope &s )
float mfactor = 0.0;
static int drawcount;
if (s.size() == 64)
{
offset=8;
if (s.size() == 64) {
offset = 8;
}
glRotatef(0.25f, 0.0f, 1.0f, 0.5f); //Rotate the scene
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;
// 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
// Some basic bounds checking
if (y > 30)
y = 30;
else if (y < 0)
y = 0;
if((y - m_oldy[i]) < -0.6f) // Going Down Too Much
if ((y - m_oldy[i]) < -0.6f) // Going Down Too Much
{
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
m_oldy[i] = y; // Save value as last value
//Peak Code
if (m_oldy[i] > m_peaks[i].level)
{
// Peak Code
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)
{
m_peaks[i].level-=0.4f;
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);
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 );
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color to black
glClear(GL_COLOR_BUFFER_BIT);
// Set the shading model
glShadeModel(GL_SMOOTH);
@ -147,87 +131,81 @@ void GLAnalyzer::initializeGL()
glEnable(GL_DEPTH_TEST);
// Set blend parameters for 'composting alpha'
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void GLAnalyzer::resizeGL( int w, int h )
{
glViewport( 0, 0, (GLint)w, (GLint)h );
glMatrixMode( GL_PROJECTION );
void GLAnalyzer::resizeGL(int w, int h) {
glViewport(0, 0, (GLint)w, (GLint)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-16.0f, 16.0f, -10.0f, 10.0f, -50.0f, 100.0f);
glMatrixMode( GL_MODELVIEW );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void GLAnalyzer::paintGL()
{
glMatrixMode( GL_MODELVIEW );
void GLAnalyzer::paintGL() {
glMatrixMode(GL_MODELVIEW);
#if 0
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
#else
glEnable( GL_DEPTH_TEST );
glEnable( GL_BLEND );
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLE_STRIP );
glColor4f( 0.0f, 0.0f, 0.1f, 0.08f );
glVertex2f( 20.0f, 10.0f );
glVertex2f( -20.0f, 10.0f );
glVertex2f( 20.0f, -10.0f );
glVertex2f( -20.0f, -10.0f );
glBegin(GL_TRIANGLE_STRIP);
glColor4f(0.0f, 0.0f, 0.1f, 0.08f);
glVertex2f(20.0f, 10.0f);
glVertex2f(-20.0f, 10.0f);
glVertex2f(20.0f, -10.0f);
glVertex2f(-20.0f, -10.0f);
glEnd();
glPopMatrix();
glDisable( GL_BLEND );
glEnable( GL_DEPTH_TEST );
glClear( GL_DEPTH_BUFFER_BIT );
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
#endif
//swapBuffers();
// swapBuffers();
glFlush();
}
void GLAnalyzer::drawBar(float xPos, float height)
{
void GLAnalyzer::drawBar(float xPos, float height) {
glPushMatrix();
//Sets color to blue
//Set the colour depending on the height of the bar
glColor3f((height/40) + 0.5f, (height/40) + 0.625f, 1.0f);
// Sets color to blue
// Set the colour depending on the height of the bar
glColor3f((height / 40) + 0.5f, (height / 40) + 0.625f, 1.0f);
glTranslatef(xPos, -10.0f, 0.0f);
glScalef(1.0f, height, 3.0f);
drawCube();
//Set colour to full blue
//glColor3f(0.0f, 0.0f, 1.0f);
//drawFrame();
// Set colour to full blue
// glColor3f(0.0f, 0.0f, 1.0f);
// drawFrame();
glPopMatrix();
}
void GLAnalyzer::drawFloor()
{
void GLAnalyzer::drawFloor() {
glPushMatrix();
//Sets color to amarok blue
glColor3f( 0.5f, 0.625f, 1.0f);
glTranslatef(-16.0f,-11.0f, -4.0f);
// Sets color to amarok blue
glColor3f(0.5f, 0.625f, 1.0f);
glTranslatef(-16.0f, -11.0f, -4.0f);
glScalef(32.0f, 1.0f, 10.0f);
drawCube();
//Set colour to full blue
// Set colour to full blue
glColor3f(0.0f, 0.0f, 1.0f);
drawFrame();
glPopMatrix();
}
void GLAnalyzer::drawPeak(float xPos, float ypos)
{
void GLAnalyzer::drawPeak(float xPos, float ypos) {
glPushMatrix();
//Set the colour to red
// Set the colour to red
glColor3f(1.0f, 0.0f, 0.0f);
glTranslatef(xPos, ypos - 10.0f, 0.0f);
@ -237,47 +215,46 @@ void GLAnalyzer::drawPeak(float xPos, float ypos)
glPopMatrix();
}
void GLAnalyzer::drawCube()
{
void GLAnalyzer::drawCube() {
glPushMatrix();
glBegin(GL_POLYGON);
//This is the top face
// This is the top face
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
//This is the front face
// This is the front face
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
//This is the right face
// This is the right face
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
//This is the left face
// This is the left face
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
//This is the bottom face
// This is the bottom face
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
//This is the back face
// This is the back face
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
@ -287,48 +264,46 @@ void GLAnalyzer::drawCube()
glEnd();
glPopMatrix();
}
void GLAnalyzer::drawFrame()
{
void GLAnalyzer::drawFrame() {
glPushMatrix();
glBegin(GL_LINES);
//This is the top face
// This is the top face
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
//This is the front face
// This is the front face
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
//This is the right face
// This is the right face
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
//This is the left face
// This is the left face
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
//This is the bottom face
// This is the bottom face
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
//This is the back face
// This is the back face
glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);

View File

@ -27,16 +27,13 @@
*@author piggz
*/
typedef struct
{
typedef struct {
float level;
uint delay;
}
peak_tx;
} peak_tx;
class GLAnalyzer : public Analyzer::Base3D
{
private:
class GLAnalyzer : public Analyzer::Base3D {
private:
std::vector<float> m_oldy;
std::vector<peak_tx> m_peaks;
@ -47,14 +44,15 @@ private:
void drawFloor();
GLfloat x, y;
public:
GLAnalyzer(QWidget *);
~GLAnalyzer();
void analyze( const Scope & );
protected:
public:
GLAnalyzer(QWidget*);
~GLAnalyzer();
void analyze(const Scope&);
protected:
void initializeGL();
void resizeGL( int w, int h );
void resizeGL(int w, int h);
void paintGL();
};

View File

@ -27,15 +27,12 @@
#include <qimage.h>
#include <sys/time.h>
GLAnalyzer2::GLAnalyzer2( QWidget *parent ):
Analyzer::Base3D(parent, 15)
{
//initialize openGL context before managing GL calls
GLAnalyzer2::GLAnalyzer2(QWidget* parent) : Analyzer::Base3D(parent, 15) {
// initialize openGL context before managing GL calls
makeCurrent();
loadTexture( locate("data","amarok/data/dot.png"), dotTexture );
loadTexture( locate("data","amarok/data/wirl1.png"), w1Texture );
loadTexture( locate("data","amarok/data/wirl2.png"), w2Texture );
loadTexture(locate("data", "amarok/data/dot.png"), dotTexture);
loadTexture(locate("data", "amarok/data/wirl1.png"), w1Texture);
loadTexture(locate("data", "amarok/data/wirl2.png"), w2Texture);
show.paused = true;
show.pauseTimer = 0.0;
@ -43,15 +40,13 @@ Analyzer::Base3D(parent, 15)
frame.rotDegrees = 0.0;
}
GLAnalyzer2::~GLAnalyzer2()
{
freeTexture( dotTexture );
freeTexture( w1Texture );
freeTexture( w2Texture );
GLAnalyzer2::~GLAnalyzer2() {
freeTexture(dotTexture);
freeTexture(w1Texture);
freeTexture(w2Texture);
}
void GLAnalyzer2::initializeGL()
{
void GLAnalyzer2::initializeGL() {
// Set a smooth shade model
glShadeModel(GL_SMOOTH);
@ -59,28 +54,25 @@ void GLAnalyzer2::initializeGL()
glDisable(GL_DEPTH_TEST);
// Set blend parameters for 'composting alpha'
glBlendFunc( GL_SRC_ALPHA, GL_ONE ); //superpose
//glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); //fade
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // superpose
// glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); //fade
glEnable(GL_BLEND);
// Clear frame with a black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear( GL_COLOR_BUFFER_BIT );
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 );
glViewport(0, 0, (GLint)w, (GLint)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( -10.0f, 10.0f, -10.0f, 10.0f, -5.0f, 5.0f );
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;
if ( ratio >= (4.0/3.0) ) {
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;
} else {
@ -90,49 +82,38 @@ void GLAnalyzer2::resizeGL( int w, int h )
// Get current timestamp.
timeval tv;
gettimeofday( &tv, nullptr );
show.timeStamp = (double)tv.tv_sec + (double)tv.tv_usec/1000000.0;
gettimeofday(&tv, nullptr);
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,24 +122,23 @@ 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 );
double currentTime = (double)tv.tv_sec + (double)tv.tv_usec/1000000.0;
gettimeofday(&tv, nullptr);
double currentTime = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
show.dT = currentTime - show.timeStamp;
show.timeStamp = currentTime;
// Clear frame
glClear( GL_COLOR_BUFFER_BIT );
glClear(GL_COLOR_BUFFER_BIT);
// Shitch to MODEL matrix and reset it to default
glMatrixMode( GL_MODELVIEW );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Fade the previous drawings.
/* glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
/* glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glBegin( GL_TRIANGLE_STRIP );
glColor4f( 0.0f, 0.0f, 0.0f, 0.2f );
glVertex2f( 10.0f, 10.0f );
@ -167,43 +147,41 @@ void GLAnalyzer2::paintGL()
glVertex2f( -10.0f, -10.0f );
glEnd();*/
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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;
glBindTexture( GL_TEXTURE_2D, w2Texture );
setTextureMatrix( show.rotDegrees, 0.707*alphaP );
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( 1.0, 1.0 );
glVertex2f( 10.0f, 10.0f );
glTexCoord2f( 0.0, 1.0 );
glVertex2f( -10.0f, 10.0f );
glTexCoord2f( 1.0, 0.0 );
glVertex2f( 10.0f, -10.0f );
glTexCoord2f( 0.0 , 0.0 );
glVertex2f( -10.0f, -10.0f );
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);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(1.0, 1.0);
glVertex2f(10.0f, 10.0f);
glTexCoord2f(0.0, 1.0);
glVertex2f(-10.0f, 10.0f);
glTexCoord2f(1.0, 0.0);
glVertex2f(10.0f, -10.0f);
glTexCoord2f(0.0, 0.0);
glVertex2f(-10.0f, -10.0f);
glEnd();
glBindTexture( GL_TEXTURE_2D, w1Texture );
setTextureMatrix( -show.rotDegrees * 2, 0.707 );
glColor4f( 1.0f, 1.0f, 1.0f, alphaN );
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( 1.0, 1.0 );
glVertex2f( 10.0f, 10.0f );
glTexCoord2f( 0.0, 1.0 );
glVertex2f( -10.0f, 10.0f );
glTexCoord2f( 1.0, 0.0 );
glVertex2f( 10.0f, -10.0f );
glTexCoord2f( 0.0 , 0.0 );
glVertex2f( -10.0f, -10.0f );
glBindTexture(GL_TEXTURE_2D, w1Texture);
setTextureMatrix(-show.rotDegrees * 2, 0.707);
glColor4f(1.0f, 1.0f, 1.0f, alphaN);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(1.0, 1.0);
glVertex2f(10.0f, 10.0f);
glTexCoord2f(0.0, 1.0);
glVertex2f(-10.0f, 10.0f);
glTexCoord2f(1.0, 0.0);
glVertex2f(10.0f, -10.0f);
glTexCoord2f(0.0, 0.0);
glVertex2f(-10.0f, -10.0f);
glEnd();
setTextureMatrix( 0.0, 0.0 );
glDisable( GL_TEXTURE_2D );
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
setTextureMatrix(0.0, 0.0);
glDisable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
// Here begins the real draw loop
// some updates to the show
@ -211,122 +189,104 @@ 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;
drawFullDot( 0.0f, 0.4f, 0.8f, 1.0f );
drawFullDot( 0.0f, 0.4f, 0.8f, 1.0f );
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);
}
show.pauseTimer += show.dT;
return;
}
if ( dotTexture ) {
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, dotTexture );
if (dotTexture) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dotTexture);
} else
glDisable( GL_TEXTURE_2D );
glDisable(GL_TEXTURE_2D);
glLoadIdentity();
// glRotatef( -frame.rotDegrees, 0,0,1 );
glBegin( GL_QUADS );
// Particle * particle = particleList.first();
// for (; particle; particle = particleList.next())
// glRotatef( -frame.rotDegrees, 0,0,1 );
glBegin(GL_QUADS);
// Particle * particle = particleList.first();
// for (; particle; particle = particleList.next())
{
glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
drawDot( 0, 0, kMax(10.0,(10.0 * frame.energy)) );
glColor4f( 1.0f, 0.0f, 0.0f, 1.0f );
drawDot( 6, 0, kMax(10.0, (5.0 * frame.energy)) );
glColor4f( 0.0f, 0.4f, 1.0f, 1.0f );
drawDot( -6, 0, kMax(10.0, (5.0 * frame.energy)) );
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
drawDot(0, 0, kMax(10.0, (10.0 * frame.energy)));
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
drawDot(6, 0, kMax(10.0, (5.0 * frame.energy)));
glColor4f(0.0f, 0.4f, 1.0f, 1.0f);
drawDot(-6, 0, kMax(10.0, (5.0 * frame.energy)));
}
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;
glTexCoord2f( 0, 0 ); // Bottom Left
glVertex2f( pLeft, pBottom );
glTexCoord2f( 0, 1 ); // Top Left
glVertex2f( pLeft, pTop );
glTexCoord2f( 1, 1 ); // Top Right
glVertex2f( pRight, pTop );
glTexCoord2f( 1, 0 ); // Bottom Right
glVertex2f( pRight, pBottom );
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
glVertex2f(pLeft, pTop);
glTexCoord2f(1, 1); // Top Right
glVertex2f(pRight, pTop);
glTexCoord2f(1, 0); // Bottom Right
glVertex2f(pRight, pBottom);
}
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 );
glBegin( GL_TRIANGLE_STRIP );
glTexCoord2f( 1.0, 1.0 );
glVertex2f( 10.0f, 10.0f );
glTexCoord2f( 0.0, 1.0 );
glVertex2f( -10.0f, 10.0f );
glTexCoord2f( 1.0, 0.0 );
glVertex2f( 10.0f, -10.0f );
glTexCoord2f( 0.0 , 0.0 );
glVertex2f( -10.0f, -10.0f );
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);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(1.0, 1.0);
glVertex2f(10.0f, 10.0f);
glTexCoord2f(0.0, 1.0);
glVertex2f(-10.0f, 10.0f);
glTexCoord2f(1.0, 0.0);
glVertex2f(10.0f, -10.0f);
glTexCoord2f(0.0, 0.0);
glVertex2f(-10.0f, -10.0f);
glEnd();
glDisable( GL_TEXTURE_2D );
glDisable(GL_TEXTURE_2D);
}
void GLAnalyzer2::setTextureMatrix( float rot, float scale )
{
glMatrixMode( GL_TEXTURE);
void GLAnalyzer2::setTextureMatrix(float rot, float scale) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
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 );
glTranslatef( -0.5f, -0.5f, 0.0f );
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);
glTranslatef(-0.5f, -0.5f, 0.0f);
}
glMatrixMode( GL_MODELVIEW );
glMatrixMode(GL_MODELVIEW);
}
bool GLAnalyzer2::loadTexture( QString fileName, GLuint& textureID )
{
//reset texture ID to the default EMPTY value
bool GLAnalyzer2::loadTexture(QString fileName, GLuint& textureID) {
// reset texture ID to the default EMPTY value
textureID = 0;
//load image
// 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;
// convert it to suitable format (flipped RGBA)
QImage texture = QGLWidget::convertToGLFormat(tmp);
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() );
// 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());
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,21 +25,19 @@
#include <qstring.h>
#include <qptrlist.h>
class GLAnalyzer2 : public Analyzer::Base3D
{
public:
GLAnalyzer2(QWidget *);
class GLAnalyzer2 : public Analyzer::Base3D {
public:
GLAnalyzer2(QWidget*);
~GLAnalyzer2();
void analyze( const Scope & );
void analyze(const Scope&);
void paused();
protected:
protected:
void initializeGL();
void resizeGL( int w, int h );
void resizeGL(int w, int h);
void paintGL();
private:
private:
struct ShowProperties {
bool paused;
double timeStamp;
@ -61,9 +59,9 @@ private:
GLuint w2Texture;
float unitX, unitY;
void drawDot( float x, float y, float size );
void drawFullDot( float r, float g, float b, float a );
void setTextureMatrix( float rot, float scale );
void drawDot(float x, float y, float size);
void drawFullDot(float r, float g, float b, float a);
void setTextureMatrix(float rot, float scale);
bool loadTexture(QString file, GLuint& textureID);
void freeTexture(GLuint& textureID);

View File

@ -28,91 +28,84 @@
#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 ),
mass( 0.01 + drand48()/10.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
if ( y < -0.8 ) vy = fabsf( vy );
if ( y > 0.8 ) vy = -fabsf( vy );
if ( z < 0.1 ) vz = fabsf( vz );
if ( z > 0.9 ) vz = -fabsf( vz );
vx += (( x > 0 ) ? 4.94 : -4.94) * dT; // G-force
if (y < -0.8) vy = fabsf(vy);
if (y > 0.8) vy = -fabsf(vy);
if (z < 0.1) vz = fabsf(vz);
if (z > 0.9) vz = -fabsf(vz);
vx += ((x > 0) ? 4.94 : -4.94) * dT; // G-force
vx *= (1 - 2.9 * dT); // air friction
vy *= (1 - 2.9 * dT); // air friction
vz *= (1 - 2.9 * dT); // air friction
}
};
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()
{
glBegin( GL_TRIANGLE_STRIP );
glColor3f( 0.0f, 0.1f, 0.3f );
glVertex3f( x, -1.0f, 0.0 );
glVertex3f( x, 1.0f, 0.0 );
glColor3f( 0.1f, 0.2f, 0.6f );
glVertex3f( x, -1.0f, 1.0 );
glVertex3f( x, 1.0f, 1.0 );
void renderGL() {
glBegin(GL_TRIANGLE_STRIP);
glColor3f(0.0f, 0.1f, 0.3f);
glVertex3f(x, -1.0f, 0.0);
glVertex3f(x, 1.0f, 0.0);
glColor3f(0.1f, 0.2f, 0.6f);
glVertex3f(x, -1.0f, 1.0);
glVertex3f(x, 1.0f, 1.0);
glEnd();
}
void bounce( Ball * ball )
{
if ( onLeft && ball->x < x )
{
ball->vx = vx * mass / (mass + ball->mass) + fabsf( ball->vx );
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 )
{
ball->vx = vx * mass / (mass + ball->mass) - fabsf( ball->vx );
} 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;
ball->x = x;
}
}
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,20 +113,16 @@ class Paddle
float mass, X, x, vx;
};
GLAnalyzer3::GLAnalyzer3( QWidget *parent ):
Analyzer::Base3D(parent, 15)
{
//initialize openGL context before managing GL calls
GLAnalyzer3::GLAnalyzer3(QWidget* parent) : Analyzer::Base3D(parent, 15) {
// initialize openGL context before managing GL calls
makeCurrent();
loadTexture( locate("data","amarok/data/ball.png"), ballTexture );
loadTexture( locate("data","amarok/data/grid.png"), gridTexture );
loadTexture(locate("data", "amarok/data/ball.png"), ballTexture);
loadTexture(locate("data", "amarok/data/grid.png"), gridTexture);
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() );
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());
show.colorK = 0.0;
show.gridScrollK = 0.0;
@ -146,41 +135,38 @@ Analyzer::Base3D(parent, 15)
frame.dEnergy = 0.0;
}
GLAnalyzer3::~GLAnalyzer3()
{
freeTexture( ballTexture );
freeTexture( gridTexture );
GLAnalyzer3::~GLAnalyzer3() {
freeTexture(ballTexture);
freeTexture(gridTexture);
delete leftPaddle;
delete rightPaddle;
balls.clear();
}
void GLAnalyzer3::initializeGL()
{
void GLAnalyzer3::initializeGL() {
// Set a smooth shade model
glShadeModel(GL_SMOOTH);
// Disable depth test (all is drawn 'z-sorted')
glDisable( GL_DEPTH_TEST );
glDisable(GL_DEPTH_TEST);
// Set blending function (Alpha addition)
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
// Clear frame with a black background
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 );
glViewport(0, 0, (GLint)w, (GLint)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum( -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 4.5f );
glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 4.5f);
// Get the aspect ratio of the screen to draw 'circular' particles
float ratio = (float)w / (float)h;
if ( ratio >= 1.0 ) {
if (ratio >= 1.0) {
unitX = 0.34 / ratio;
unitY = 0.34;
} else {
@ -190,43 +176,34 @@ void GLAnalyzer3::resizeGL( int w, int h )
// Get current timestamp.
timeval tv;
gettimeofday( &tv, nullptr );
show.timeStamp = (double)tv.tv_sec + (double)tv.tv_usec/1000000.0;
gettimeofday(&tv, nullptr);
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 );
double currentTime = (double)tv.tv_sec + (double)tv.tv_usec/1000000.0;
gettimeofday(&tv, nullptr);
double currentTime = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
show.dT = currentTime - show.timeStamp;
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;
show.peakEnergy = 1.0 + (show.peakEnergy - 1.0) * exp(-show.dT / 10.0);
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,240 +217,210 @@ 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
glMatrixMode( GL_MODELVIEW );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear( GL_COLOR_BUFFER_BIT );
glClear(GL_COLOR_BUFFER_BIT);
// Draw scrolling grid
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;
float gridColor[4] = { 0.0, 1.0, 0.6, show.gridEnergyK };
drawScrollGrid( show.gridScrollK, gridColor );
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;
float gridColor[4] = {0.0, 1.0, 0.6, show.gridEnergyK};
drawScrollGrid(show.gridScrollK, gridColor);
}
// Roll camera up/down handling the beat
show.camRot += show.camRoll * show.dT; // posision
show.camRoll -= 400 * show.camRot * show.dT; // elasticity
show.camRoll *= (1 - 2.0 * show.dT); // friction
if ( !frame.silence && frame.dEnergy > 0.4 )
show.camRoll += show.peakEnergy*2.0;
glRotatef( show.camRoll / 2.0, 1,0,0 );
if (!frame.silence && frame.dEnergy > 0.4)
show.camRoll += show.peakEnergy * 2.0;
glRotatef(show.camRoll / 2.0, 1, 0, 0);
// Translate the drawing plane
glTranslatef( 0.0f, 0.0f, -1.8f );
glTranslatef(0.0f, 0.0f, -1.8f);
// Draw upper/lower planes and paddles
drawHFace( -1.0 );
drawHFace( 1.0 );
drawHFace(-1.0);
drawHFace(1.0);
leftPaddle->renderGL();
rightPaddle->renderGL();
// Draw Balls
if ( ballTexture ) {
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, ballTexture );
if (ballTexture) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, ballTexture);
} else
glDisable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
Ball * ball = balls.first();
for ( ; ball; ball = balls.next() )
{
float color[3],
angle = show.colorK;
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
Ball* ball = balls.first();
for (; ball; ball = balls.next()) {
float color[3], angle = show.colorK;
// Rotate the color based on 'angle' value [0,3)
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 )
{
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) {
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
{
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 {
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;
color[ 2 ] = ball->color[ 1 ] * (1 - angle) + ball->color[ 2 ] * angle;
color[0] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
color[1] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
color[2] = ball->color[1] * (1 - angle) + ball->color[2] * angle;
}
// Draw the dot and update its physics also checking at bounces
glColor3fv( color );
drawDot3s( ball->x, ball->y, ball->z, 1.0 );
ball->updatePhysics( show.dT );
if ( ball->x < 0 )
leftPaddle->bounce( ball );
glColor3fv(color);
drawDot3s(ball->x, ball->y, ball->z, 1.0);
ball->updatePhysics(show.dT);
if (ball->x < 0)
leftPaddle->bounce(ball);
else
rightPaddle->bounce( ball );
rightPaddle->bounce(ball);
}
glDisable( GL_BLEND );
glDisable( GL_TEXTURE_2D );
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
// Update physics of paddles
leftPaddle->updatePhysics( show.dT );
rightPaddle->updatePhysics( show.dT );
if ( !frame.silence )
{
leftPaddle->impulse( frame.energy*3.0 + frame.dEnergy*6.0 );
rightPaddle->impulse( -frame.energy*3.0 - frame.dEnergy*6.0 );
leftPaddle->updatePhysics(show.dT);
rightPaddle->updatePhysics(show.dT);
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
glVertex3f( pXm, pYm, z );
glTexCoord2f( 0, 1 ); // Top Left
glVertex3f( pXm, pYM, z );
glTexCoord2f( 1, 1 ); // Top Right
glVertex3f( pXM, pYM, z );
glTexCoord2f( 1, 0 ); // Bottom Right
glVertex3f( pXM, pYm, z );
glBegin(GL_QUADS);
glTexCoord2f(0, 0); // Bottom Left
glVertex3f(pXm, pYm, z);
glTexCoord2f(0, 1); // Top Left
glVertex3f(pXm, pYM, z);
glTexCoord2f(1, 1); // Top Right
glVertex3f(pXM, pYM, z);
glTexCoord2f(1, 0); // Bottom Right
glVertex3f(pXM, pYm, z);
glEnd();
// Shadow XZ drawing functions
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 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,
bottomSide = (1 - y) / 4;
// Draw the top shadow
currentColor[3] = topSide * topSide * alpha;
glColor4fv( currentColor );
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 ); // Bottom Left
glVertex3f( pXm, 1, pZm );
glTexCoord2f( 0, 1 ); // Top Left
glVertex3f( pXm, 1, pZM );
glTexCoord2f( 1, 1 ); // Top Right
glVertex3f( pXM, 1, pZM );
glTexCoord2f( 1, 0 ); // Bottom Right
glVertex3f( pXM, 1, pZm );
glColor4fv(currentColor);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); // Bottom Left
glVertex3f(pXm, 1, pZm);
glTexCoord2f(0, 1); // Top Left
glVertex3f(pXm, 1, pZM);
glTexCoord2f(1, 1); // Top Right
glVertex3f(pXM, 1, pZM);
glTexCoord2f(1, 0); // Bottom Right
glVertex3f(pXM, 1, pZm);
glEnd();
// Draw the bottom shadow
currentColor[3] = bottomSide * bottomSide * alpha;
glColor4fv( currentColor );
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 ); // Bottom Left
glVertex3f( pXm, -1, pZm );
glTexCoord2f( 0, 1 ); // Top Left
glVertex3f( pXm, -1, pZM );
glTexCoord2f( 1, 1 ); // Top Right
glVertex3f( pXM, -1, pZM );
glTexCoord2f( 1, 0 ); // Bottom Right
glVertex3f( pXM, -1, pZm );
glColor4fv(currentColor);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); // Bottom Left
glVertex3f(pXm, -1, pZm);
glTexCoord2f(0, 1); // Top Left
glVertex3f(pXm, -1, pZM);
glTexCoord2f(1, 1); // Top Right
glVertex3f(pXM, -1, pZM);
glTexCoord2f(1, 0); // Bottom Right
glVertex3f(pXM, -1, pZm);
glEnd();
}
void GLAnalyzer3::drawHFace( float y )
{
glBegin( GL_TRIANGLE_STRIP );
glColor3f( 0.0f, 0.1f, 0.2f );
glVertex3f( -1.0f, y, 0.0 );
glVertex3f( 1.0f, y, 0.0 );
glColor3f( 0.1f, 0.6f, 0.5f );
glVertex3f( -1.0f, y, 2.0 );
glVertex3f( 1.0f, y, 2.0 );
void GLAnalyzer3::drawHFace(float y) {
glBegin(GL_TRIANGLE_STRIP);
glColor3f(0.0f, 0.1f, 0.2f);
glVertex3f(-1.0f, y, 0.0);
glVertex3f(1.0f, y, 0.0);
glColor3f(0.1f, 0.6f, 0.5f);
glVertex3f(-1.0f, y, 2.0);
glVertex3f(1.0f, y, 2.0);
glEnd();
}
void GLAnalyzer3::drawScrollGrid( float scroll, float color[4] )
{
if ( !gridTexture )
return;
glMatrixMode( GL_TEXTURE );
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 ];
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, gridTexture );
glEnable( GL_BLEND );
glBegin( GL_TRIANGLE_STRIP );
glColor4fv( color ); // top face
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -1.0f, 1.0f, -1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, -1.0f );
glColor4fv( backColor ); // central points
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( -1.0f, 0.0f, -3.0f );
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( 1.0f, 0.0f, -3.0f );
glColor4fv( color ); // bottom face
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -1.0f, -1.0f, -1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( 1.0f, -1.0f, -1.0f );
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];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_STRIP);
glColor4fv(color); // top face
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glColor4fv(backColor); // central points
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, -3.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, -3.0f);
glColor4fv(color); // bottom face
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glEnd();
glDisable( GL_BLEND );
glDisable( GL_TEXTURE_2D );
glMatrixMode( GL_TEXTURE );
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode( GL_MODELVIEW );
glMatrixMode(GL_MODELVIEW);
}
bool GLAnalyzer3::loadTexture( QString fileName, GLuint& textureID )
{
//reset texture ID to the default EMPTY value
bool GLAnalyzer3::loadTexture(QString fileName, GLuint& textureID) {
// reset texture ID to the default EMPTY value
textureID = 0;
//load image
// 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;
// convert it to suitable format (flipped RGBA)
QImage texture = QGLWidget::convertToGLFormat(tmp);
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() );
// 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());
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,20 +29,19 @@ class QWidget;
class Ball;
class Paddle;
class GLAnalyzer3 : public Analyzer::Base3D
{
public:
GLAnalyzer3(QWidget *);
class GLAnalyzer3 : public Analyzer::Base3D {
public:
GLAnalyzer3(QWidget*);
~GLAnalyzer3();
void analyze( const Scope & );
void analyze(const Scope&);
void paused();
protected:
protected:
void initializeGL();
void resizeGL( int w, int h );
void resizeGL(int w, int h);
void paintGL();
private:
private:
struct ShowProperties {
double timeStamp;
double dT;
@ -63,14 +62,14 @@ private:
static const int NUMBER_OF_BALLS = 16;
QPtrList<Ball> balls;
Paddle * leftPaddle, * rightPaddle;
Paddle* leftPaddle, *rightPaddle;
float unitX, unitY;
GLuint ballTexture;
GLuint gridTexture;
void drawDot3s( float x, float y, float z, float size );
void drawHFace( float y );
void drawScrollGrid( float scroll, float color[4] );
void drawDot3s(float x, float y, float z, float size);
void drawHFace(float y);
void drawScrollGrid(float scroll, float color[4]);
bool loadTexture(QString file, GLuint& textureID);
void freeTexture(GLuint& textureID);

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) {
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_) {
@ -70,18 +67,19 @@ void NyanCatAnalyzer::resizeEvent(QResizeEvent* e) {
buffer_[1] = QPixmap();
available_rainbow_width_ = width() - kCatWidth + kRainbowOverlap;
px_per_frame_ = float(available_rainbow_width_) / (kHistorySize-1) + 1;
x_offset_ = px_per_frame_ * (kHistorySize-1) - available_rainbow_width_;
px_per_frame_ = float(available_rainbow_width_) / (kHistorySize - 1) + 1;
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;
if ((new_frame && is_playing_) ||
(buffer_[0].isNull() && buffer_[1].isNull())) {
// Transform the music into rainbows!
for (int band=0 ; band<kRainbowBands ; ++band) {
for (int band = 0; band < kRainbowBands; ++band) {
float* band_start = history_ + band * kHistorySize;
// Move the history of each band across by 1 frame.
@ -93,13 +91,13 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
// but for now it's a series of separate square filters.
const int samples_per_band = scope_size / kRainbowBands;
int sample = 0;
for (int band=0 ; band<kRainbowBands ; ++band) {
for (int band = 0; band < kRainbowBands; ++band) {
float accumulator = 0.0;
for (int i=0 ; i<samples_per_band ; ++i) {
for (int i = 0; i < samples_per_band; ++i) {
accumulator += s[sample++];
}
history_[(band+1) * kHistorySize - 1] = accumulator * band_scale_[band];
history_[(band + 1) * kHistorySize - 1] = accumulator * band_scale_[band];
}
// Create polylines for the rainbows.
@ -107,22 +105,23 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
QPointF* dest = polyline;
float* source = history_;
const float top_of_cat = float(height())/2 - float(kCatHeight)/2;
for (int band=0 ; band<kRainbowBands ; ++band) {
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) {
for (int x = 0; x < kHistorySize; ++x) {
*dest = QPointF(px_per_frame_ * x, y + *source * kPixelScale);
++ dest;
++ source;
++dest;
++source;
}
}
// Do we have to draw the whole rainbow into the buffer?
if (buffer_[0].isNull()) {
for (int i=0 ; i<2 ; ++i) {
for (int i = 0; i < 2; ++i) {
buffer_[i] = QPixmap(QSize(width() + x_offset_, height()));
buffer_[i].fill(background_brush_.color());
}
@ -130,29 +129,34 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
QPainter buffer_painter(&buffer_[0]);
buffer_painter.setRenderHint(QPainter::Antialiasing);
for (int band=kRainbowBands-1 ; band>=0 ; --band) {
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) {
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

@ -25,19 +25,19 @@
class NyanCatAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
public:
Q_INVOKABLE NyanCatAnalyzer(QWidget* parent);
static const char* kName;
protected:
protected:
void transform(Scope&);
void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
void timerEvent(QTimerEvent* e);
void resizeEvent(QResizeEvent* e);
private:
private:
static const int kCatHeight = 21;
static const int kCatWidth = 34;
static const int kCatFrameCount = 6;
@ -50,7 +50,7 @@ private:
static const int kFrameIntervalMs = 150;
private:
private:
inline QRect CatSourceRect() const {
return QRect(0, kCatHeight * frame_, kCatWidth, kCatHeight);
}
@ -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 {
@ -69,7 +69,7 @@ private:
kCatWidth, kSleepingCatHeight);
}
private:
private:
// "constants" that get initialised in the constructor
float band_scale_[kRainbowBands];
QPen colors_[kRainbowBands];

View File

@ -15,25 +15,18 @@
#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
#if !( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 0 ) )
// only for gcc < 4.0
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0))
resizeForBands(height() < 128 ? 128 : height());
#endif
@ -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)
{
float *front = static_cast<float*>(&scope.front());
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 );
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,16 +20,15 @@
@author Melchior FRANZ
*/
class Sonogram : public Analyzer::Base
{
class Sonogram : public Analyzer::Base {
Q_OBJECT
public:
public:
Q_INVOKABLE Sonogram(QWidget*);
~Sonogram();
static const char* kName;
protected:
protected:
void analyze(QPainter& p, const Scope&, bool new_frame);
void transform(Scope&);
void demo(QPainter& p);

View File

@ -12,66 +12,57 @@
#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 )
{
h = log10( scope[i]*256.0 ) * F * 0.5;
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 )
{
bar_height[i] -= K_barHeight; //1.4
if( bar_height[i] < 0.0 ) 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
peak_speed[i] *= F_peakSpeed; // 1.12
if( peak_height[i] < bar_height[i] ) peak_height[i] = bar_height[i];
if( peak_height[i] < 0.0 ) peak_height[i] = 0.0;
if (peak_height[i] < bar_height[i]) peak_height[i] = bar_height[i];
if (peak_height[i] < 0.0) peak_height[i] = 0.0;
}
}
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);
p.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1);
p.drawPixmap(x + 1, hd2, barPixmap, 0, int(bar_height[i]), -1, -1);
p.setPen( palette().color(QPalette::Highlight) );
p.setPen(palette().color(QPalette::Highlight));
if (bar_height[i] > 0)
p.drawRect( x, y, COLUMN_WIDTH-1, (int)bar_height[i]*2 -1 );
p.drawRect(x, y, COLUMN_WIDTH - 1, (int)bar_height[i] * 2 - 1);
const uint x2 = x+COLUMN_WIDTH-1;
p.setPen( palette().color(QPalette::Base) );
const uint x2 = x + COLUMN_WIDTH - 1;
p.setPen(palette().color(QPalette::Base));
y = hd2 - uint(peak_height[i]);
p.drawLine( x, y, x2, y );
p.drawLine(x, y, x2, y);
y = hd2 + uint(peak_height[i]);
p.drawLine( x, y, x2, y );
p.drawLine(x, y, x2, y);
}
}

View File

@ -11,13 +11,12 @@
#include "boomanalyzer.h"
class TurbineAnalyzer : public BoomAnalyzer
{
class TurbineAnalyzer : public BoomAnalyzer {
Q_OBJECT
public:
Q_INVOKABLE TurbineAnalyzer( QWidget *parent ) : BoomAnalyzer( parent ) {}
Q_INVOKABLE TurbineAnalyzer(QWidget* parent) : BoomAnalyzer(parent) {}
void analyze( QPainter& p, const Scope&, bool new_frame);
void analyze(QPainter& p, const Scope&, bool new_frame);
static const char* kName;
};

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

@ -40,8 +40,8 @@
#include "podcasts/podcastupdater.h"
#ifdef HAVE_MOODBAR
# include "moodbar/moodbarcontroller.h"
# include "moodbar/moodbarloader.h"
#include "moodbar/moodbarcontroller.h"
#include "moodbar/moodbarloader.h"
#endif
bool Application::kIsPortable = false;
@ -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,18 +47,18 @@ class PodcastUpdater;
class TagReaderClient;
class TaskManager;
class Application : public QObject {
Q_OBJECT
public:
public:
static bool kIsPortable;
Application(QObject* parent = NULL);
~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;
@ -91,7 +93,7 @@ public:
void MoveToNewThread(QObject* object);
void MoveToThread(QObject* object, QThread* thread);
public slots:
public slots:
void AddError(const QString& message);
void ReloadSettings();
void OpenSettingsDialogAtPage(SettingsDialog::Page page);
@ -101,7 +103,7 @@ signals:
void SettingsChanged();
void SettingsDialogRequested(SettingsDialog::Page page);
private:
private:
QString language_name_;
TagReaderClient* tag_reader_client_;

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;
}
@ -156,7 +152,7 @@ void BackgroundStreams::StreamActionDestroyed() {
return;
}
foreach (Stream* stream, streams_.values()) {
foreach(Stream * stream, streams_.values()) {
if (stream->action == action) {
stream->action = nullptr;
}
@ -169,7 +165,7 @@ void BackgroundStreams::StreamActionToggled(bool checked) {
return;
}
foreach (Stream* stream, streams_.values()) {
foreach(Stream * stream, streams_.values()) {
if (stream->action == action) {
EnableStream(stream->name, checked);
}

View File

@ -29,7 +29,7 @@ class BackgroundStreams : public QObject {
void AddAction(const QString& name, QAction* action);
signals:
signals:
void StreamStarted(const QString& name);
void StreamStopped(const QString& name);

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

@ -23,7 +23,7 @@
template <typename T>
class CachedList {
public:
public:
// Use a CachedList when you want to download and save a list of things from a
// remote service, updating it only periodically.
// T must be a registered metatype and must support being stored in
@ -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;
@ -47,7 +46,7 @@ public:
data_.clear();
const int count = s.beginReadArray(name_ + "_data");
for (int i=0 ; i<count ; ++i) {
for (int i = 0; i < count; ++i) {
s.setArrayIndex(i);
data_ << s.value("value").value<T>();
}
@ -61,7 +60,7 @@ public:
s.setValue("last_refreshed_" + name_, last_updated_);
s.beginWriteArray(name_ + "_data", data_.size());
for (int i=0 ; i<data_.size() ; ++i) {
for (int i = 0; i < data_.size(); ++i) {
s.setArrayIndex(i);
s.setValue("value", QVariant::fromValue(data_[i]));
}
@ -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_; }
@ -91,7 +89,7 @@ public:
const_iterator begin() const { return data_.begin(); }
const_iterator end() const { return data_.end(); }
private:
private:
const QString settings_group_;
const QString name_;
const int cache_duration_secs_;

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);
@ -93,7 +90,7 @@ void CommandlineOptions::RemoveArg(const QString& starts_with, int count) {
QString opt(argv_[i]);
if (opt.startsWith(starts_with)) {
for (int j = i; j < argc_ - count + 1; ++j) {
argv_[j] = argv_[j+count];
argv_[j] = argv_[j + count];
}
argc_ -= count;
break;
@ -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);
}
@ -241,7 +268,7 @@ bool CommandlineOptions::Parse() {
}
// Get any filenames or URLs following the arguments
for (int i=optind ; i<argc_ ; ++i) {
for (int i = optind; i < argc_; ++i) {
QString value = QFile::decodeName(argv_[i]);
QFileInfo file_info(value);
if (file_info.exists())
@ -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 {
@ -276,7 +298,7 @@ QByteArray CommandlineOptions::Serialize() const {
return buf.data();
}
void CommandlineOptions::Load(const QByteArray &serialized) {
void CommandlineOptions::Load(const QByteArray& serialized) {
QByteArray copy(serialized);
QBuffer buf(&copy);
buf.open(QIODevice::ReadOnly);
@ -285,22 +307,14 @@ void CommandlineOptions::Load(const QByteArray &serialized) {
s >> *this;
}
QString CommandlineOptions::tr(const char *source_text) {
QString CommandlineOptions::tr(const char* source_text) {
return QObject::tr(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

@ -27,17 +27,14 @@ class CommandlineOptions {
friend QDataStream& operator>>(QDataStream& s, CommandlineOptions& a);
public:
CommandlineOptions(int argc = 0, char** argv = NULL);
CommandlineOptions(int argc = 0, char* *argv = NULL);
static const char* kHelpText;
static const char* kVersionText;
// 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

@ -31,12 +31,12 @@
#include <QtDebug>
#if defined(HAVE_BREAKPAD) and defined(Q_OS_LINUX)
# include "client/linux/handler/exception_handler.h"
# include "third_party/lss/linux_syscall_support.h"
#include "client/linux/handler/exception_handler.h"
#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,31 +182,25 @@ 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
namespace google_breakpad {
class ExceptionHandler {};
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

@ -27,14 +27,13 @@ class QNetworkAccessManager;
class QProgressDialog;
namespace google_breakpad {
class ExceptionHandler;
class ExceptionHandler;
}
// Wraps google_breakpad::ExceptionHandler - while an instance of this class
// is alive crashes will be handled.
class CrashReporting {
public:
public:
CrashReporting();
~CrashReporting();
@ -48,17 +47,15 @@ public:
// --send-crash-report when a crash happens.
static void SetApplicationPath(const QString& path);
private:
private:
// Prints the message to stdout without using libc.
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:
private:
Q_DISABLE_COPY(CrashReporting);
static const char* kSendCrashReportOption;
@ -67,24 +64,23 @@ 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 {
Q_OBJECT
public:
public:
CrashSender(const QString& path);
// Returns false if the user doesn't want to send the crash report (caller
// should exit), or true if he does (caller should start the Qt event loop).
bool Start();
private slots:
private slots:
void RedirectFinished();
void UploadProgress(qint64 bytes);
private:
private:
static const char* kUploadURL;
QNetworkAccessManager* network_;

View File

@ -46,65 +46,59 @@ 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 */
const char *const*argv, /* Tokenizer argument strings */
sqlite3_tokenizer **ppTokenizer); /* OUT: Created tokenizer */
int (*xCreate)(int argc, /* Size of argv array */
const char* const* argv, /* Tokenizer argument strings */
sqlite3_tokenizer** ppTokenizer); /* OUT: Created tokenizer */
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
int (*xDestroy)(sqlite3_tokenizer* pTokenizer);
int (*xOpen)(
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
const char *pInput, int nBytes, /* Input buffer */
sqlite3_tokenizer_cursor **ppCursor);/* OUT: Created tokenizer cursor */
sqlite3_tokenizer* pTokenizer, /* Tokenizer object */
const char* pInput, int nBytes, /* Input buffer */
sqlite3_tokenizer_cursor** ppCursor); /* OUT: Created tokenizer cursor */
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
int (*xClose)(sqlite3_tokenizer_cursor* pCursor);
int (*xNext)(
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition); /* OUT: Number of tokens returned before this one */
sqlite3_tokenizer_cursor* pCursor, /* Tokenizer cursor */
const char** ppToken, int* pnBytes, /* OUT: Normalized text for token */
int* piStartOffset, /* OUT: Byte offset of token in input buffer */
int* piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int* piPosition); /* OUT: Number of tokens returned before this one */
};
struct sqlite3_tokenizer {
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
const sqlite3_tokenizer_module* pModule; /* The module for this tokenizer */
/* Tokenizer implementations will typically add additional fields */
};
struct sqlite3_tokenizer_cursor {
sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
sqlite3_tokenizer* pTokenizer; /* Tokenizer for this cursor. */
/* Tokenizer implementations will typically add additional fields */
};
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,12 +328,13 @@ 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) {
// Update the schema
for (int v = schema_version+1; v <= kSchemaVersion; ++v) {
for (int v = schema_version + 1; v <= kSchemaVersion; ++v) {
UpdateDatabaseSchema(v, *db);
}
}
@ -384,8 +377,8 @@ void Database::AttachDatabase(const QString& database_name,
attached_databases_[database_name] = database;
}
void Database::AttachDatabaseOnDbConnection(const QString &database_name,
const AttachedDatabase &database,
void Database::AttachDatabaseOnDbConnection(const QString& database_name,
const AttachedDatabase& database,
QSqlDatabase& db) {
AttachDatabase(database_name, database);
@ -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());
}
}
@ -414,7 +408,7 @@ void Database::DetachDatabase(const QString& database_name) {
attached_databases_.remove(database_name);
}
void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
void Database::UpdateDatabaseSchema(int version, QSqlDatabase& db) {
QString filename;
if (version == 0)
filename = ":/schema/schema.sql";
@ -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,21 +65,20 @@ 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);
void DetachDatabase(const QString& database_name);
signals:
signals:
void Error(const QString& message);
public slots:
@ -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**),
void (*) (sqlite3_context*));
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;
@ -60,7 +57,7 @@ void DeleteFiles::Start(const SongList& songs) {
void DeleteFiles::Start(const QStringList& filenames) {
SongList songs;
foreach (const QString& filename, filenames) {
foreach(const QString & filename, filenames) {
Song song;
song.set_url(QUrl::fromLocalFile(filename));
songs << song;
@ -98,7 +95,7 @@ void DeleteFiles::ProcessSomeFiles() {
// We process files in batches so we can be cancelled part-way through.
const int n = qMin(songs_.count(), progress_ + kBatchSize);
for ( ; progress_<n ; ++progress_) {
for (; progress_ < n; ++progress_) {
task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
const Song& song = songs_[progress_];

View File

@ -30,7 +30,7 @@ class TaskManager;
class DeleteFiles : public QObject {
Q_OBJECT
public:
public:
DeleteFiles(TaskManager* task_manager, std::shared_ptr<MusicStorage> storage);
~DeleteFiles();
@ -42,10 +42,10 @@ public:
signals:
void Finished(const SongList& songs_with_errors);
private slots:
private slots:
void ProcessSomeFiles();
private:
private:
QThread* thread_;
QThread* original_thread_;
TaskManager* task_manager_;

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)
{
return (float *)memcpy(d, s, m_num * sizeof(float));
float* FHT::copy(float* d, float* s) {
return (float*)memcpy(d, s, m_num * sizeof(float));
}
float* FHT::clear(float *d)
{
return (float *)memset(d, 0, m_num * sizeof(float));
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,27 +106,19 @@ 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;
float* q;
_transform(p, m_num, 0);
*p = (*p * *p), *p += *p, p++;
@ -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,13 +29,12 @@
*
* [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;
float *m_tab;
int *m_log;
float* m_buf;
float* m_tab;
int* m_log;
/**
* Create a table of "cas" (cosine and sine) values.
@ -47,7 +46,7 @@ class FHT
/**
* Recursive in-place Hartley transform. For internal use only!
*/
void _transform(float *, int, int);
void _transform(float*, int, int);
public:
/**
@ -60,9 +59,9 @@ class FHT
~FHT();
inline int sizeExp() const { return m_exp2; }
inline int size() const { return m_num; }
float *copy(float *, float *);
float *clear(float *);
void scale(float *, float);
float* copy(float*, float*);
float* clear(float*);
void scale(float*, float);
/**
* Exponentially Weighted Moving Average (EWMA) filter.
@ -70,7 +69,7 @@ class FHT
* @param s is fresh input.
* @param w is the weighting factor.
*/
void ewma(float *d, float *s, float w);
void ewma(float* d, float* s, float w);
/**
* Logarithmic audio spectrum. Maps semi-logarithmic spectrum
@ -79,17 +78,17 @@ class FHT
* @param p is the input array.
* @param out is the spectrum.
*/
void logSpectrum(float *out, float *p);
void logSpectrum(float* out, float* p);
/**
* Semi-logarithmic audio spectrum.
*/
void semiLogSpectrum(float *);
void semiLogSpectrum(float*);
/**
* Fourier spectrum.
*/
void spectrum(float *);
void spectrum(float*);
/**
* Calculates a mathematically correct FFT power spectrum.
@ -97,7 +96,7 @@ class FHT
* and factor the 0.5 in the final scaling factor.
* @see FHT::power2()
*/
void power(float *);
void power(float*);
/**
* Calculates an FFT power spectrum with doubled values as a
@ -106,14 +105,14 @@ class FHT
* of @f$2^n@f$ input values. This is the fastest transform.
* @see FHT::power()
*/
void power2(float *);
void power2(float*);
/**
* Discrete Hartley transform of data sets with 8 values.
*/
void transform8(float *);
void transform8(float*);
void transform(float *);
void transform(float*);
};
#endif

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_ );
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

@ -21,7 +21,7 @@
#include "musicstorage.h"
class FilesystemMusicStorage : public virtual MusicStorage {
public:
public:
FilesystemMusicStorage(const QString& root);
~FilesystemMusicStorage() {}
@ -30,7 +30,7 @@ public:
bool CopyToStorage(const CopyJob& job);
bool DeleteFromStorage(const DeleteJob& job);
private:
private:
QString root_;
};

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

@ -31,7 +31,7 @@ class FileSystemWatcherInterface : public QObject {
static FileSystemWatcherInterface* Create(QObject* parent = 0);
signals:
signals:
void PathChanged(const QString& path);
};

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

@ -25,7 +25,7 @@ class GlobalShortcuts;
class GlobalShortcutBackend : public QObject {
Q_OBJECT
public:
public:
GlobalShortcutBackend(GlobalShortcuts* parent = 0);
virtual ~GlobalShortcutBackend() {}
@ -37,7 +37,7 @@ public:
signals:
void RegisterFinished(bool success);
protected:
protected:
virtual bool DoRegister() = 0;
virtual void DoUnregister() = 0;

View File

@ -28,28 +28,32 @@
#include <QtDebug>
#ifdef QT_DBUS_LIB
# include <QtDBus>
#include <QtDBus>
#endif
const char* GlobalShortcuts::kSettingsGroup = "Shortcuts";
GlobalShortcuts::GlobalShortcuts(QWidget *parent)
GlobalShortcuts::GlobalShortcuts(QWidget* parent)
: 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

@ -32,7 +32,7 @@ class QSignalMapper;
class GlobalShortcuts : public QWidget {
Q_OBJECT
public:
public:
GlobalShortcuts(QWidget* parent = 0);
static const char* kSettingsGroup;
@ -48,7 +48,7 @@ public:
bool IsGsdAvailable() const;
bool IsMacAccessibilityEnabled() const;
public slots:
public slots:
void ReloadSettings();
void ShowMacAccessibilityDialog();
@ -76,14 +76,16 @@ signals:
void CycleRepeatMode();
void ToggleScrobbling();
private:
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:
private:
GlobalShortcutBackend* gnome_backend_;
GlobalShortcutBackend* system_backend_;

View File

@ -21,7 +21,7 @@
#include "core/logging.h"
#ifdef QT_DBUS_LIB
# include "dbus/gnomesettingsdaemon.h"
#include "dbus/gnomesettingsdaemon.h"
#endif
#include <QAction>
@ -30,26 +30,27 @@
#include <QtDebug>
#ifdef QT_DBUS_LIB
# include <QtDBus>
#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

@ -27,24 +27,24 @@ class QDBusPendingCallWatcher;
class GnomeGlobalShortcutBackend : public GlobalShortcutBackend {
Q_OBJECT
public:
public:
GnomeGlobalShortcutBackend(GlobalShortcuts* parent);
static const char* kGsdService;
static const char* kGsdPath;
static const char* kGsdInterface;
protected:
protected:
bool RegisterInNewThread() const { return true; }
bool DoRegister();
void DoUnregister();
private slots:
private slots:
void RegisterFinished(QDBusPendingCallWatcher* watcher);
void GnomeMediaKeyPressed(const QString& application, const QString& key);
private:
private:
OrgGnomeSettingsDaemonMediaKeysInterface* interface_;
bool is_connected_;
};

View File

@ -7,11 +7,10 @@
#import <Breakpad/Breakpad.h>
#endif
class PlatformInterface;
@class SPMediaKeyTap;
@interface AppDelegate :NSObject <NSApplicationDelegate> {
@interface AppDelegate : NSObject<NSApplicationDelegate> {
PlatformInterface* application_handler_;
NSMenu* dock_menu_;
MacGlobalShortcutBackend* shortcut_handler_;
@ -22,21 +21,23 @@ class PlatformInterface;
#endif
}
- (id) initWithHandler: (PlatformInterface*)handler;
- (id)initWithHandler:(PlatformInterface*)handler;
// NSApplicationDelegate
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag;
- (NSMenu*) applicationDockMenu: (NSApplication*)sender;
- (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
shouldPresentNotification: (id)notification;
- (BOOL)userNotificationCenter:(id)center
shouldPresentNotification:(id)notification;
- (void) setDockMenu: (NSMenu*)menu;
- (MacGlobalShortcutBackend*) shortcut_handler;
- (void) setShortcutHandler: (MacGlobalShortcutBackend*)backend;
- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
- (void)setDockMenu:(NSMenu*)menu;
- (MacGlobalShortcutBackend*)shortcut_handler;
- (void)setShortcutHandler:(MacGlobalShortcutBackend*)backend;
- (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

@ -36,7 +36,7 @@ class MacFSListener : public FileSystemWatcherInterface {
void RemovePath(const QString& path);
void Clear();
signals:
signals:
void PathChanged(const QString& path);
private slots:
@ -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

@ -31,7 +31,7 @@ class QAction;
class MacGlobalShortcutBackend : public GlobalShortcutBackend {
Q_OBJECT
public:
public:
MacGlobalShortcutBackend(GlobalShortcuts* parent);
virtual ~MacGlobalShortcutBackend();
@ -40,11 +40,11 @@ public:
void MacMediaKeyPressed(int key);
protected:
protected:
bool DoRegister();
void DoUnregister();
private:
private:
bool KeyPressed(const QKeySequence& sequence);
QMap<QKeySequence, QAction*> shortcuts_;

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,30 +84,28 @@ 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) {
void MergedProxyModel::RemoveSubModel(const QModelIndex& source_parent) {
// Find the submodel that the parent corresponded to
QAbstractItemModel* submodel = merge_points_.key(source_parent);
merge_points_.remove(submodel);
@ -147,40 +137,42 @@ 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(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(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()));
}
QAbstractProxyModel::setSourceModel(source_model);
connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(SourceModelReset()));
connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
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(rowsAboutToBeInserted(QModelIndex, int, int)),
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()));
}
void MergedProxyModel::SourceModelReset() {
@ -227,15 +219,15 @@ void MergedProxyModel::SubModelReset() {
// "Insert" items from the newly reset submodel
int count = submodel->rowCount();
if (count) {
beginInsertRows(proxy_parent, 0, count-1);
beginInsertRows(proxy_parent, 0, count - 1);
endInsertRows();
}
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()) {
@ -315,26 +307,23 @@ QModelIndex MergedProxyModel::index(int row, int column, const QModelIndex &pare
return mapFromSource(source_index);
}
QModelIndex MergedProxyModel::parent(const QModelIndex &child) const {
QModelIndex MergedProxyModel::parent(const QModelIndex& child) const {
QModelIndex source_child = mapToSource(child);
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)));
return mapFromSource(source_child.parent());
}
int MergedProxyModel::rowCount(const QModelIndex &parent) const {
if (!parent.isValid())
return sourceModel()->rowCount(QModelIndex());
int MergedProxyModel::rowCount(const QModelIndex& parent) const {
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) {
@ -348,27 +337,22 @@ int MergedProxyModel::rowCount(const QModelIndex &parent) const {
return source_parent.model()->rowCount(source_parent);
}
int MergedProxyModel::columnCount(const QModelIndex &parent) const {
if (!parent.isValid())
return sourceModel()->columnCount(QModelIndex());
int MergedProxyModel::columnCount(const QModelIndex& parent) const {
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());
bool MergedProxyModel::hasChildren(const QModelIndex& parent) const {
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,29 +364,27 @@ 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 {
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);
}
bool MergedProxyModel::setData(const QModelIndex &index, const QVariant &value,
bool MergedProxyModel::setData(const QModelIndex& index, const QVariant& value,
int role) {
QModelIndex source_index = mapToSource(index);
@ -415,16 +397,15 @@ QStringList MergedProxyModel::mimeTypes() const {
QStringList ret;
ret << sourceModel()->mimeTypes();
foreach (const QAbstractItemModel* model, merge_points_.keys()) {
foreach(const QAbstractItemModel * model, merge_points_.keys()) {
ret << model->mimeTypes();
}
return ret;
}
QMimeData* MergedProxyModel::mimeData(const QModelIndexList &indexes) const {
if (indexes.isEmpty())
return 0;
QMimeData* MergedProxyModel::mimeData(const QModelIndexList& indexes) const {
if (indexes.isEmpty()) return 0;
// Only ask the first index's model
const QAbstractItemModel* model = mapToSource(indexes[0]).model();
@ -435,17 +416,18 @@ QMimeData* MergedProxyModel::mimeData(const QModelIndexList &indexes) const {
// Only ask about the indexes that are actually in that model
QModelIndexList indexes_in_model;
foreach (const QModelIndex& proxy_index, indexes) {
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,17 +435,16 @@ 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));
}
bool MergedProxyModel::canFetchMore(const QModelIndex &parent) const {
bool MergedProxyModel::canFetchMore(const QModelIndex& parent) const {
QModelIndex source_index = mapToSource(parent);
if (!source_index.isValid())
@ -480,34 +461,33 @@ 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();
foreach (QAbstractItemModel* submodel, merge_points_.keys()) {
if (submodel == const_model)
return submodel;
if (const_model == sourceModel()) return sourceModel();
foreach(QAbstractItemModel * submodel, merge_points_.keys()) {
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));
}
void MergedProxyModel::LayoutAboutToBeChanged() {
old_merge_points_.clear();
foreach (QAbstractItemModel* key, merge_points_.keys()) {
foreach(QAbstractItemModel * key, merge_points_.keys()) {
old_merge_points_[key] = merge_points_.value(key);
}
}
void MergedProxyModel::LayoutChanged() {
foreach (QAbstractItemModel* key, merge_points_.keys()) {
if (!old_merge_points_.contains(key))
continue;
foreach(QAbstractItemModel * key, merge_points_.keys()) {
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,17 +506,19 @@ 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) {
foreach(const QModelIndex & index, source_indexes) {
ret << mapFromSource(index);
}
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) {
foreach(const QModelIndex & index, proxy_indexes) {
ret << mapToSource(index);
}
return ret;

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
@ -43,45 +44,50 @@ class MergedProxyModel : public QAbstractProxyModel {
QModelIndex FindSourceParent(const QModelIndex& proxy_index) const;
// QAbstractItemModel
QModelIndex index(int row, int column, const QModelIndex &parent) const;
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;
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);
QModelIndex index(int row, int column, const QModelIndex& parent) const;
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;
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 canFetchMore(const QModelIndex &parent) const;
QMimeData* mimeData(const QModelIndexList& indexes) const;
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);
// QAbstractProxyModel
// Note that these implementations of map{To,From}Source will not always
// give you an index in sourceModel(), you might get an index in one of the
// child models instead.
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
void setSourceModel(QAbstractItemModel *sourceModel);
QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;
QModelIndex mapToSource(const QModelIndex& proxyIndex) const;
void setSourceModel(QAbstractItemModel* sourceModel);
// Convenience functions that call map{To,From}Source multiple times.
QModelIndexList mapFromSource(const QModelIndexList& source_indexes) const;
QModelIndexList mapToSource(const QModelIndexList& proxy_indexes) const;
signals:
signals:
void SubModelReset(const QModelIndex& root, QAbstractItemModel* model);
private slots:
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

@ -23,9 +23,9 @@
class MimeData : public QMimeData {
Q_OBJECT
public:
MimeData(bool clear = false, bool play_now = false,
bool enqueue = false, bool open_in_new_playlist = false)
public:
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

@ -30,13 +30,13 @@ class Mpris2;
class Mpris : public QObject {
Q_OBJECT
public:
public:
Mpris(Application* app, QObject* parent = 0);
signals:
void RaiseMainWindow();
private:
private:
Mpris1* mpris1_;
Mpris2* mpris2_;
};

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,22 +336,21 @@ QVariantMap Mpris1::GetMetadata(const Song& song) {
} // namespace mpris
QDBusArgument& operator<< (QDBusArgument& arg, const Version& version) {
QDBusArgument& operator<<(QDBusArgument& arg, const Version& version) {
arg.beginStructure();
arg << version.major << version.minor;
arg.endStructure();
return arg;
}
const QDBusArgument& operator>> (const QDBusArgument& arg, Version& version) {
const QDBusArgument& operator>>(const QDBusArgument& arg, Version& version) {
arg.beginStructure();
arg >> version.major >> version.minor;
arg.endStructure();
return arg;
}
QDBusArgument& operator<< (QDBusArgument& arg, const DBusStatus& status) {
QDBusArgument& operator<<(QDBusArgument& arg, const DBusStatus& status) {
arg.beginStructure();
arg << status.play;
arg << status.random;
@ -378,7 +360,7 @@ QDBusArgument& operator<< (QDBusArgument& arg, const DBusStatus& status) {
return arg;
}
const QDBusArgument& operator>> (const QDBusArgument& arg, DBusStatus& status) {
const QDBusArgument& operator>>(const QDBusArgument& arg, DBusStatus& status) {
arg.beginStructure();
arg >> status.play;
arg >> status.random;

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,
@ -48,9 +45,8 @@ struct DBusStatus { // From Amarok.
};
Q_DECLARE_METATYPE(DBusStatus);
QDBusArgument& operator <<(QDBusArgument& arg, const DBusStatus& status);
const QDBusArgument& operator >>(const QDBusArgument& arg, DBusStatus& status);
QDBusArgument& operator<<(QDBusArgument& arg, const DBusStatus& status);
const QDBusArgument& operator>>(const QDBusArgument& arg, DBusStatus& status);
struct Version {
quint16 minor;
@ -58,8 +54,8 @@ struct Version {
};
Q_DECLARE_METATYPE(Version);
QDBusArgument& operator <<(QDBusArgument& arg, const Version& version);
const QDBusArgument& operator >>(const QDBusArgument& arg, Version& version);
QDBusArgument& operator<<(QDBusArgument& arg, const Version& version);
const QDBusArgument& operator>>(const QDBusArgument& arg, Version& version);
namespace mpris {
@ -78,11 +74,10 @@ class Mpris1Root;
class Mpris1Player;
class Mpris1TrackList;
class Mpris1 : public QObject {
Q_OBJECT
public:
public:
Mpris1(Application* app, QObject* parent = 0,
const QString& dbus_service_name = QString());
~Mpris1();
@ -93,7 +88,7 @@ public:
Mpris1Player* player() const { return player_; }
Mpris1TrackList* tracklist() const { return tracklist_; }
private:
private:
static const char* kDefaultDbusServiceName;
QString dbus_service_name_;
@ -103,26 +98,24 @@ private:
Mpris1TrackList* tracklist_;
};
class Mpris1Root : public QObject {
Q_OBJECT
public:
public:
Mpris1Root(Application* app, QObject* parent = 0);
QString Identity();
void Quit();
Version MprisVersion();
private:
private:
Application* app_;
};
class Mpris1Player : public QObject {
Q_OBJECT
public:
public:
Mpris1Player(Application* app, QObject* parent = 0);
void Pause();
@ -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
@ -151,33 +145,32 @@ public:
void Mute();
void ShowOSD();
public slots:
void CurrentSongChanged(
const Song& song, const QString& art_uri, const QImage&);
public slots:
void CurrentSongChanged(const Song& song, const QString& art_uri,
const QImage&);
signals:
void CapsChange(int);
void TrackChange(const QVariantMap&);
void StatusChange(DBusStatus);
private slots:
private slots:
void PlaylistManagerInitialized();
void EngineStateChanged(Engine::State state);
void ShuffleModeChanged();
void RepeatModeChanged();
private:
private:
Application* app_;
QVariantMap last_metadata_;
};
class Mpris1TrackList : public QObject {
Q_OBJECT
public:
public:
Mpris1TrackList(Application* app, QObject* parent = 0);
int AddTrack(const QString&, bool);
@ -194,10 +187,10 @@ public:
signals:
void TrackListChange(int i);
private slots:
private slots:
void PlaylistChanged(Playlist* playlist);
private:
private:
Application* app_;
};

View File

@ -41,22 +41,22 @@
#include <QDBusConnection>
#include <QtConcurrentRun>
QDBusArgument& operator<< (QDBusArgument& arg, const MprisPlaylist& playlist) {
QDBusArgument& operator<<(QDBusArgument& arg, const MprisPlaylist& playlist) {
arg.beginStructure();
arg << playlist.id << playlist.name << playlist.icon;
arg.endStructure();
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();
return arg;
}
QDBusArgument& operator<< (QDBusArgument& arg, const MaybePlaylist& playlist) {
QDBusArgument& operator<<(QDBusArgument& arg, const MaybePlaylist& playlist) {
arg.beginStructure();
arg << playlist.valid;
arg << playlist.playlist;
@ -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,121 +79,115 @@ 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()));
}
void Mpris2::EngineStateChanged(Engine::State newState) {
if(newState != Engine::Playing && newState != Engine::Paused) {
last_metadata_= QVariantMap();
if (newState != Engine::Playing && newState != Engine::Paused) {
last_metadata_ = QVariantMap();
EmitNotification("Metadata");
}
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(":");
xdg_data_dirs.append("/usr/local/share/");
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;
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;
}
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,12 +283,10 @@ 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) {
if (rate == 0) {
if (mpris1_->player()) {
mpris1_->player()->Pause();
}
@ -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,24 +398,22 @@ bool Mpris2::CanSeek() const {
}
}
bool Mpris2::CanControl() const {
return true;
}
bool Mpris2::CanControl() const { return true; }
void Mpris2::Next() {
if(CanGoNext()) {
if (CanGoNext()) {
app_->player()->Next();
}
}
void Mpris2::Previous() {
if(CanGoPrevious()) {
if (CanGoPrevious()) {
app_->player()->Previous();
}
}
void Mpris2::Pause() {
if(CanPause() && app_->player()->GetState() != Engine::Paused) {
if (CanPause() && app_->player()->GetState() != Engine::Paused) {
app_->player()->Pause();
}
}
@ -447,19 +424,18 @@ void Mpris2::PlayPause() {
}
}
void Mpris2::Stop() {
app_->player()->Stop();
}
void Mpris2::Stop() { app_->player()->Stop(); }
void Mpris2::Play() {
if(CanPlay()) {
if (CanPlay()) {
app_->player()->Play();
}
}
void Mpris2::Seek(qlonglong offset) {
if(CanSeek()) {
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() / kNsecPerSec +
if (CanSeek()) {
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);
}
}
@ -481,46 +458,42 @@ void Mpris2::OpenUri(const QString& uri) {
}
TrackIds Mpris2::Tracks() const {
//TODO
// TODO
return TrackIds();
}
bool Mpris2::CanEditTracks() const {
return false;
}
bool Mpris2::CanEditTracks() const { return false; }
TrackMetadata Mpris2::GetTracksMetadata(const TrackIds &tracks) const {
//TODO
TrackMetadata Mpris2::GetTracksMetadata(const TrackIds& tracks) const {
// TODO
return TrackMetadata();
}
void Mpris2::AddTrack(const QString &uri, const QDBusObjectPath &afterTrack, bool setAsCurrent) {
//TODO
void Mpris2::AddTrack(const QString& uri, const QDBusObjectPath& afterTrack,
bool setAsCurrent) {
// TODO
}
void Mpris2::RemoveTrack(const QDBusObjectPath &trackId) {
//TODO
void Mpris2::RemoveTrack(const QDBusObjectPath& trackId) {
// TODO
}
void Mpris2::GoTo(const QDBusObjectPath &trackId) {
//TODO
void Mpris2::GoTo(const QDBusObjectPath& trackId) {
// TODO
}
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,10 +530,11 @@ 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()) {
foreach(Playlist * p, app_->playlist_manager()->GetAllPlaylists()) {
MprisPlaylist mpris_playlist;
mpris_playlist.id = MakePlaylistPath(p->id());
mpris_playlist.name = app_->playlist_manager()->GetPlaylistName(p->id());
@ -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

@ -47,14 +47,13 @@ struct MaybePlaylist {
};
Q_DECLARE_METATYPE(MaybePlaylist);
QDBusArgument& operator<< (QDBusArgument& arg, const 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);
QDBusArgument& operator<<(QDBusArgument& arg, const 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);
namespace mpris {
@ -64,44 +63,44 @@ class Mpris2 : public QObject {
Q_OBJECT
public:
//org.mpris.MediaPlayer2 MPRIS 2.0 Root interface
Q_PROPERTY( bool CanQuit READ CanQuit )
Q_PROPERTY( bool CanRaise READ CanRaise )
Q_PROPERTY( bool HasTrackList READ HasTrackList )
Q_PROPERTY( QString Identity READ Identity )
Q_PROPERTY( QString DesktopEntry READ DesktopEntry )
Q_PROPERTY( QStringList SupportedUriSchemes READ SupportedUriSchemes )
Q_PROPERTY( QStringList SupportedMimeTypes READ SupportedMimeTypes )
// org.mpris.MediaPlayer2 MPRIS 2.0 Root interface
Q_PROPERTY(bool CanQuit READ CanQuit)
Q_PROPERTY(bool CanRaise READ CanRaise)
Q_PROPERTY(bool HasTrackList READ HasTrackList)
Q_PROPERTY(QString Identity READ Identity)
Q_PROPERTY(QString DesktopEntry READ DesktopEntry)
Q_PROPERTY(QStringList SupportedUriSchemes READ SupportedUriSchemes)
Q_PROPERTY(QStringList SupportedMimeTypes READ SupportedMimeTypes)
//org.mpris.MediaPlayer2 MPRIS 2.2 Root interface
Q_PROPERTY( bool CanSetFullscreen READ CanSetFullscreen )
Q_PROPERTY( bool Fullscreen READ Fullscreen WRITE SetFullscreen )
// org.mpris.MediaPlayer2 MPRIS 2.2 Root interface
Q_PROPERTY(bool CanSetFullscreen READ CanSetFullscreen)
Q_PROPERTY(bool Fullscreen READ Fullscreen WRITE SetFullscreen)
//org.mpris.MediaPlayer2.Player MPRIS 2.0 Player interface
Q_PROPERTY( QString PlaybackStatus READ PlaybackStatus )
Q_PROPERTY( QString LoopStatus READ LoopStatus WRITE SetLoopStatus )
Q_PROPERTY( double Rate READ Rate WRITE SetRate )
Q_PROPERTY( bool Shuffle READ Shuffle WRITE SetShuffle )
Q_PROPERTY( QVariantMap Metadata READ Metadata )
Q_PROPERTY( double Volume READ Volume WRITE SetVolume )
Q_PROPERTY( qlonglong Position READ Position )
Q_PROPERTY( double MinimumRate READ MinimumRate )
Q_PROPERTY( double MaximumRate READ MaximumRate )
Q_PROPERTY( bool CanGoNext READ CanGoNext )
Q_PROPERTY( bool CanGoPrevious READ CanGoPrevious )
Q_PROPERTY( bool CanPlay READ CanPlay )
Q_PROPERTY( bool CanPause READ CanPause )
Q_PROPERTY( bool CanSeek READ CanSeek )
Q_PROPERTY( bool CanControl READ CanControl )
// org.mpris.MediaPlayer2.Player MPRIS 2.0 Player interface
Q_PROPERTY(QString PlaybackStatus READ PlaybackStatus)
Q_PROPERTY(QString LoopStatus READ LoopStatus WRITE SetLoopStatus)
Q_PROPERTY(double Rate READ Rate WRITE SetRate)
Q_PROPERTY(bool Shuffle READ Shuffle WRITE SetShuffle)
Q_PROPERTY(QVariantMap Metadata READ Metadata)
Q_PROPERTY(double Volume READ Volume WRITE SetVolume)
Q_PROPERTY(qlonglong Position READ Position)
Q_PROPERTY(double MinimumRate READ MinimumRate)
Q_PROPERTY(double MaximumRate READ MaximumRate)
Q_PROPERTY(bool CanGoNext READ CanGoNext)
Q_PROPERTY(bool CanGoPrevious READ CanGoPrevious)
Q_PROPERTY(bool CanPlay READ CanPlay)
Q_PROPERTY(bool CanPause READ CanPause)
Q_PROPERTY(bool CanSeek READ CanSeek)
Q_PROPERTY(bool CanControl READ CanControl)
//org.mpris.MediaPlayer2.TrackList MPRIS 2.0 Player interface
Q_PROPERTY( TrackIds Tracks READ Tracks )
Q_PROPERTY( bool CanEditTracks READ CanEditTracks )
// org.mpris.MediaPlayer2.TrackList MPRIS 2.0 Player interface
Q_PROPERTY(TrackIds Tracks READ Tracks)
Q_PROPERTY(bool CanEditTracks READ CanEditTracks)
//org.mpris.MediaPlayer2.Playlists MPRIS 2.1 Playlists interface
Q_PROPERTY( quint32 PlaylistCount READ PlaylistCount )
Q_PROPERTY( QStringList Orderings READ Orderings )
Q_PROPERTY( MaybePlaylist ActivePlaylist READ ActivePlaylist )
// org.mpris.MediaPlayer2.Playlists MPRIS 2.1 Playlists interface
Q_PROPERTY(quint32 PlaylistCount READ PlaylistCount)
Q_PROPERTY(QStringList Orderings READ Orderings)
Q_PROPERTY(MaybePlaylist ActivePlaylist READ ActivePlaylist)
Mpris2(Application* app, Mpris1* mpris1, QObject* parent = 0);
@ -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,14 +183,15 @@ 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();
// Playlist
void PlaylistChanged(const MprisPlaylist& playlist);
private slots:
private slots:
void ArtLoaded(const Song& song, const QString& art_uri);
void EngineStateChanged(Engine::State newState);
void VolumeChanged();
@ -202,10 +203,11 @@ private slots:
void PlaylistChanged(Playlist* playlist);
void PlaylistCollectionChanged(Playlist* playlist);
private:
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;
@ -213,7 +215,7 @@ private:
QString DesktopEntryAbsolutePath() const;
private:
private:
static const char* kMprisObjectPath;
static const char* kServiceName;
static const char* kFreedesktopPath;

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);
@ -16,7 +14,7 @@ void MultiSortFilterProxy::AddSortSpec(int role, Qt::SortOrder order) {
bool MultiSortFilterProxy::lessThan(const QModelIndex& left,
const QModelIndex& right) const {
foreach (const SortSpec& spec, sorting_) {
foreach(const SortSpec & spec, sorting_) {
const int ret = Compare(left.data(spec.first), right.data(spec.first));
if (ret < 0) {
@ -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

@ -4,15 +4,15 @@
#include <QSortFilterProxyModel>
class MultiSortFilterProxy : public QSortFilterProxyModel {
public:
public:
MultiSortFilterProxy(QObject* parent = NULL);
void AddSortSpec(int role, Qt::SortOrder order = Qt::AscendingOrder);
protected:
protected:
bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
private:
private:
int Compare(const QVariant& left, const QVariant& right) const;
typedef QPair<int, Qt::SortOrder> SortSpec;

View File

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

View File

@ -26,7 +26,7 @@
#include <QMetaType>
class MusicStorage {
public:
public:
MusicStorage();
virtual ~MusicStorage() {}
@ -44,7 +44,7 @@ public:
Transcode_Unsupported = 3,
};
typedef std::function<void (float progress)> ProgressFunction;
typedef std::function<void(float progress)> ProgressFunction;
struct CopyJob {
QString source_;
@ -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) {}

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