OTHER: implement volume/balance handling in own class
This commit is contained in:
parent
75bf5909ef
commit
19a877ddc6
7 changed files with 299 additions and 154 deletions
199
backend_xmmsclient++/volumehandler.cpp
Normal file
199
backend_xmmsclient++/volumehandler.cpp
Normal file
|
@ -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 <QStyle>
|
||||
#include <xplayback.h>
|
||||
|
||||
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<double>(right-left) / static_cast<double>(qMax(left, right));
|
||||
|
||||
tmp *= static_cast<double>(MAX_STEREO_BALANCE);
|
||||
tmp += 0.5;
|
||||
|
||||
return static_cast<int>(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<double>(volume) / static_cast<double>(MAX_STEREO_BALANCE) * static_cast<double>(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"
|
77
backend_xmmsclient++/volumehandler.h
Normal file
77
backend_xmmsclient++/volumehandler.h
Normal file
|
@ -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 <QObject>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class XClient;
|
||||
|
||||
typedef QMap<QString, int> 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
|
|
@ -41,6 +41,7 @@ lib_source = """
|
|||
xclientcache.cpp
|
||||
xcollection.cpp
|
||||
xmmsqt4.cpp
|
||||
volumehandler.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<QString, QVariant> 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"
|
||||
|
|
|
@ -21,8 +21,9 @@ class XClient;
|
|||
|
||||
#include <xmmsclient/xmmsclient++.h>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
static const int MAX_BALANCE = 20;
|
||||
typedef QMap<QString, int> 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
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue