From 19a877ddc6baf402f60518f835d81d9a7554c562 Mon Sep 17 00:00:00 2001 From: Thomas Frauendorfer Date: Fri, 22 Jan 2010 06:13:08 +0100 Subject: [PATCH] OTHER: implement volume/balance handling in own class --- backend_xmmsclient++/volumehandler.cpp | 199 +++++++++++++++++++++++++ backend_xmmsclient++/volumehandler.h | 77 ++++++++++ backend_xmmsclient++/wscript | 1 + backend_xmmsclient++/xplayback.cpp | 143 +----------------- backend_xmmsclient++/xplayback.h | 17 +-- src/mainwindow/maindisplay.cpp | 14 +- src/mainwindow/maindisplay.h | 2 + 7 files changed, 299 insertions(+), 154 deletions(-) create mode 100644 backend_xmmsclient++/volumehandler.cpp create mode 100644 backend_xmmsclient++/volumehandler.h diff --git a/backend_xmmsclient++/volumehandler.cpp b/backend_xmmsclient++/volumehandler.cpp new file mode 100644 index 0000000..e95cd31 --- /dev/null +++ b/backend_xmmsclient++/volumehandler.cpp @@ -0,0 +1,199 @@ +/** + * This file is a part of Promoe, an XMMS2 Client. + * + * Copyright (C) 2005-2010 XMMS2 Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include "volumehandler.h" + +#include "xclient.h" + +#include +#include + +struct volumes { + int left; + int right; +}; + +// The balance calculation still need some tweaking, as modifying volume +// also changes balance (towards 0). So changing volume multiple times causes +// balance to be reset to center + +static int +calcBalance (int left, int right) +{ + if (left == right) + return 0; + if (left == 0) + return MAX_STEREO_BALANCE; + if (right == 0) + return -MAX_STEREO_BALANCE; + + double tmp = static_cast(right-left) / static_cast(qMax(left, right)); + + tmp *= static_cast(MAX_STEREO_BALANCE); + tmp += 0.5; + + return static_cast(tmp); + +} + + +static struct volumes +calcVolumes (int volume, int balance) +{ + struct volumes vols = {volume, volume}; + + if (balance == 0) { + return vols; + } + + if (balance >= MAX_STEREO_BALANCE) { + vols.left = 0; + return vols; + } + + if (balance <= -MAX_STEREO_BALANCE) { + vols.right = 0; + return vols; + } + + int dec = (static_cast(volume) / static_cast(MAX_STEREO_BALANCE) * static_cast(qAbs(balance))) + 0.5; + + if (balance > 0) { + vols.left -= dec; + } else { + vols.right -= dec; + } + + return vols; +} + + +VolumeHandler::VolumeHandler(const XClient *client) : QObject(), + m_client (client) +{ + m_balance = 0; + m_volume = 0; + + keys_left << "left"; + keys_right << "right"; + + connect (m_client->xplayback (), SIGNAL(volumeChanged(VolumeMap)), + this, SLOT(serverVolumeChanged (VolumeMap))); +} + +void VolumeHandler::serverVolumeChanged (VolumeMap volumes) +{ + if (m_volumes.size () <= 1 && volumes.size () > 1) { + emit mono(false); + } + + if (m_volumes.size () > 1 && volumes.size () <= 1) { + emit mono(true); + } + + m_volumes = volumes; + int _balance = 0; + int _volume = 0; + + if (volumes.isEmpty()) { + channel_left_mono = QString (); + channel_right = QString (); + } else if (isMono ()) { + channel_left_mono = m_volumes.keys ().first (); + channel_right = QString (); + _volume = m_volumes.value (channel_left_mono); + } else { + channel_left_mono = channel_right = QString (); + QStringList keys = m_volumes.keys (); + foreach (QString lkey, keys) { + if (keys_left.contains (lkey)) { + channel_left_mono = lkey; + break; + } + } + foreach (QString rkey, keys) { + if (keys_right.contains (rkey)) { + channel_right = rkey; + break; + } + } + if (channel_left_mono.isEmpty () || channel_right.isEmpty ()) { + qWarning () << "Could not parse left and right volume from: " + << keys; + } else { + int lvalue = m_volumes.value(channel_left_mono); + int rvalue = m_volumes.value(channel_right); + _volume = qMax (lvalue, rvalue); + _balance = calcBalance (lvalue, rvalue); + } + } + + if (_volume != m_volume) { + m_volume = _volume; + emit volume(_volume); + } + if (_balance != m_balance) { + m_balance = _balance; + emit balance(m_balance); + } + +} + +void VolumeHandler::setVolume (QString key, int volume) +{ + if (key.isEmpty ()) + return; + + if (!m_volumes.contains (key)) + return; + + if (m_volumes.value (key) == volume) + return; + + m_client->xplayback ()->setVolume (key, volume); +} + + +void VolumeHandler::setVolume (int _volume, int _balance) +{ + if (m_volumes.isEmpty ()) + return; + + if (isMono ()) + _balance = 0; + + if (_volume == m_volume && _balance == m_balance) + return; + + const struct volumes vols = calcVolumes (_volume, _balance); + + setVolume (channel_left_mono, vols.left); + setVolume (channel_right, vols.right); +} + +// calculate volumes for left and right and set them in the server +void VolumeHandler::setVolume (int volume) +{ + setVolume (volume, m_balance); +} + +// calculate volumes for left and right and set them in the server +void VolumeHandler::setBalance (int balance) +{ + setVolume (m_volume, balance); +} + +#include "volumehandler.moc" diff --git a/backend_xmmsclient++/volumehandler.h b/backend_xmmsclient++/volumehandler.h new file mode 100644 index 0000000..d5e7984 --- /dev/null +++ b/backend_xmmsclient++/volumehandler.h @@ -0,0 +1,77 @@ +/** + * This file is a part of Promoe, an XMMS2 Client. + * + * Copyright (C) 2005-2010 XMMS2 Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#ifndef __VOLUMEHANDLER_H__ +#define __VOLUMEHANDLER_H__ + +#include +#include +#include +#include + +class XClient; + +typedef QMap VolumeMap; + +static const int MAX_STEREO_BALANCE = 20; + +class VolumeHandler : public QObject +{ + Q_OBJECT + + public: + VolumeHandler (const XClient *); + + VolumeMap getVolumes () const { + return m_volumes; + }; + + QStringList getVolumeKeys () const { + return m_volumes.keys(); + } + + bool isMono () const { + return (m_volumes.size() == 1); + } + + public slots: + void serverVolumeChanged (VolumeMap); + + void setVolume (QString, int); + + void setVolume (int volume, int balance); + void setVolume (int); + void setBalance (int); + + signals: + void volume (int volume); + void balance (int balance); + void mono (bool); + + protected: + const XClient *m_client; + + int m_volume; + int m_balance; + QString channel_left_mono; + QString channel_right; + VolumeMap m_volumes; + + QStringList keys_left; + QStringList keys_right; +}; + +#endif diff --git a/backend_xmmsclient++/wscript b/backend_xmmsclient++/wscript index 4da79fd..dcad64c 100644 --- a/backend_xmmsclient++/wscript +++ b/backend_xmmsclient++/wscript @@ -41,6 +41,7 @@ lib_source = """ xclientcache.cpp xcollection.cpp xmmsqt4.cpp + volumehandler.cpp """ diff --git a/backend_xmmsclient++/xplayback.cpp b/backend_xmmsclient++/xplayback.cpp index 19c507e..311fc35 100644 --- a/backend_xmmsclient++/xplayback.cpp +++ b/backend_xmmsclient++/xplayback.cpp @@ -30,9 +30,6 @@ XPlayback::XPlayback (XClient *client) { m_client = client; - m_volume = 0; - m_balance = 0; - connect (client, SIGNAL (gotConnection (XClient *)), this, SLOT (on_connect (XClient *))); @@ -151,149 +148,25 @@ XPlayback::playback_status (const Xmms::Playback::Status &status) /* * Volume */ -inline int -calcBalance (int left, int right) -{ - if (left == right) - return 0; - if (left == 0) - return MAX_BALANCE; - if (right == 0) - return -MAX_BALANCE; - - //FIXME: This somehow works, but I'm not happy with it as - // QStyle::sliderValueFromPosition is not intended for this - if (left > right) - return -QStyle::sliderValueFromPosition(0, MAX_BALANCE, right, left, true); - else - return QStyle::sliderValueFromPosition(0, MAX_BALANCE, left, right, true); -} bool XPlayback::volume_changed (const Xmms::Dict &volDict) { QHash levels = XClient::convert_dict (volDict); - if (levels.size () == 1) { - m_onechannel = true; - newVolume (levels.values ().first ().toInt ()); - newBalance (0); - } else { - /* - * I might add a configure option later, to map arbitrary keys to - * left and right - */ - if (!levels.contains ("left") || !levels.contains ("right")) { - qWarning () << "Could not get volume levels, dict contains keys: " - << levels.keys (); - // disable further updates. Otherwise we would spam the console - return false; - } - int left = levels["left"].toInt (); - int right = levels["right"].toInt (); - newVolume (qMax (right, left)); - newBalance (calcBalance (left, right)); + VolumeMap volumes; + QStringList keys = levels.keys(); + foreach (QString key, keys) { + volumes.insert (key, levels.value (key).toInt()); } - - - return true; + emit volumeChanged (volumes); } + void -XPlayback::newVolume (int new_volume) +XPlayback::setVolume (QString key, int volume) { - // only emit signal if the volume really changed - if (new_volume == m_volume) - return; - - m_volume = new_volume; - emit volumeChanged (new_volume); -} - -void -XPlayback::newBalance (int new_balance) -{ - // only emit signal if balance really changed - if (new_balance == m_balance) - return; - - m_balance = new_balance; - emit balanceChanged (new_balance); -} - - -int -calcVolume (int volume, int balance) -{ - balance = qAbs (balance); - if (balance > MAX_BALANCE) { - qWarning () << "Error in calculating balance, value " << balance - << "is outside valid range"; - return 0; - } - - if (balance == 0) - return volume; - if (balance == MAX_BALANCE) - return 0; - - //FIXME: this somehow works, but I'm not happy with it as - // QStyle::sliderPositionFromValue is not intended for this - return QStyle::sliderPositionFromValue(0, MAX_BALANCE, balance, volume, true); -} - -void -XPlayback::setVolume (int new_volume) -{ - if (!m_client->isConnected ()) return; - - // Don't echo values the server sent us back to it - if (m_volume == new_volume) - return; - - //TODO: some error checking - if (m_onechannel) { - m_client->playback ()->volumeSet ("master", new_volume); - } else { - int right, left; - if (m_balance < 0) { - left = new_volume; - right = calcVolume (new_volume, m_balance); - } else { - left = calcVolume (new_volume, m_balance); - right = new_volume; - } - m_client->playback ()->volumeSet ("left", left); - m_client->playback ()->volumeSet ("right", right); - } - - m_volume = new_volume; -} - -void -XPlayback::setBalance (int new_balance) -{ - if (!m_client->isConnected ()) return; - - // Don't echo values the server sent back to the server - if ((m_balance == new_balance) || m_onechannel) - return; - - if (new_balance < 0) { - if (m_balance > 0) { - m_client->playback ()->volumeSet ("left", m_volume); - } - m_client->playback ()->volumeSet ("right", - calcVolume (m_volume, new_balance)); - } else { - if (m_balance < 0) { - m_client->playback ()->volumeSet ("right", m_volume); - } - m_client->playback ()->volumeSet ("left", - calcVolume (m_volume, new_balance)); - } - - m_balance = new_balance; + m_client->playback ()->volumeSet (key.toStdString(), volume); } #include "xplayback.moc" diff --git a/backend_xmmsclient++/xplayback.h b/backend_xmmsclient++/xplayback.h index c2b40e2..d5169b4 100644 --- a/backend_xmmsclient++/xplayback.h +++ b/backend_xmmsclient++/xplayback.h @@ -21,8 +21,9 @@ class XClient; #include #include +#include -static const int MAX_BALANCE = 20; +typedef QMap VolumeMap; /** * @class XPlayback @@ -35,9 +36,6 @@ class XPlayback : public QObject { public: XPlayback (XClient *); - int getVolume () {return m_volume;} - int getBalance () {return m_balance;} - public slots: void play (); void pause (); @@ -52,8 +50,7 @@ class XPlayback : public QObject { // Helper to directly connect sliders to this class void seekMs (int milliseconds) {seekMs ((uint) milliseconds);}; - void setVolume (int new_volume); - void setBalance (int new_balance); + void setVolume (QString key, int volume); // callbacks for clientlib bool playback_status (const Xmms::Playback::Status &status); @@ -63,18 +60,12 @@ class XPlayback : public QObject { signals: void playbackStatusChanged (Xmms::Playback::Status status); - void volumeChanged (int volume); - void balanceChanged (int balance); + void volumeChanged (VolumeMap); private: XClient *m_client; Xmms::Playback::Status m_status; - void newVolume (int new_volume); - void newBalance (int new_balance); - int m_volume; - int m_balance; - bool m_onechannel; }; #endif diff --git a/src/mainwindow/maindisplay.cpp b/src/mainwindow/maindisplay.cpp index 209e26f..045b371 100644 --- a/src/mainwindow/maindisplay.cpp +++ b/src/mainwindow/maindisplay.cpp @@ -17,6 +17,7 @@ #include "xclientcache.h" #include "xplayback.h" #include "xconfig.h" +#include "volumehandler.h" #include "application.h" #include "maindisplay.h" @@ -44,6 +45,7 @@ MainDisplay::MainDisplay (MainWindow *parent) : SkinDisplay(parent) { const XClient *client = App->client (); m_xconfig = client->xconfig (); + m_volumehandler = new VolumeHandler (client); Skin* skin = Skin::getInstance (); connect (skin, SIGNAL (skinChanged (Skin *)), @@ -101,21 +103,21 @@ MainDisplay::MainDisplay (MainWindow *parent) : SkinDisplay(parent) m_vslider->setSliderOffset (QPoint (0, 1)); m_vslider->resize (skin->getSize (Skin::SLIDER_VOLUMEBAR_BGS)); m_vslider->move (skin->getPos (Skin::SLIDER_VOLUMEBAR_BGS)); - connect (client->xplayback (), SIGNAL (volumeChanged (int)), + connect (m_volumehandler, SIGNAL (volume (int)), m_vslider, SLOT (setValue (int))); connect (m_vslider, SIGNAL (sliderMoved (int)), - client->xplayback (), SLOT (setVolume (int))); + m_volumehandler, SLOT (setVolume (int))); m_bslider = new PixmapSlider (this); - m_bslider->setMinimum (-MAX_BALANCE); - m_bslider->setMaximum (MAX_BALANCE); + m_bslider->setMinimum (-MAX_STEREO_BALANCE); + m_bslider->setMaximum (MAX_STEREO_BALANCE); m_bslider->setSliderOffset (QPoint (0, 1)); m_bslider->resize (skin->getSize (Skin::SLIDER_BALANCEBAR_BGS)); m_bslider->move (skin->getPos (Skin::SLIDER_BALANCEBAR_BGS)); - connect (client->xplayback (), SIGNAL (balanceChanged (int)), + connect (m_volumehandler, SIGNAL (balance (int)), m_bslider, SLOT (setValue (int))); connect (m_bslider, SIGNAL (sliderMoved (int)), - client->xplayback (), SLOT (setBalance (int))); + m_volumehandler, SLOT (setBalance (int))); connect (client->cache (), SIGNAL (activeEntryChanged (QVariantHash)), this, SLOT (setMediainfo (const QVariantHash))); diff --git a/src/mainwindow/maindisplay.h b/src/mainwindow/maindisplay.h index 6f87ac0..244fe7c 100644 --- a/src/mainwindow/maindisplay.h +++ b/src/mainwindow/maindisplay.h @@ -47,6 +47,7 @@ class MainWindow; class ClutterBar; class XConfig; class XClient; +class VolumeHandler; class MainDisplay : public SkinDisplay { @@ -110,6 +111,7 @@ class MainDisplay : public SkinDisplay XConfig *m_xconfig; + VolumeHandler *m_volumehandler; }; #endif