Fix up the RVA2 handling. I'm still not thrilled with the API, but this

should be functional enough to hold over to the next binary
incompatible change and has a minimum of differences to the previous
API.

I did a slightly nasty hack so that the API docs will see just methods
with an optional argument, but those are actually two separate methods
(for BC).

Brian, please feel free to take a look at this prior to 1.4 going out.

BUG:107025



git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@437115 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
Scott Wheeler 2005-07-21 00:10:57 +00:00
parent e321ae7774
commit c756813a21
2 changed files with 162 additions and 43 deletions

View File

@ -20,21 +20,32 @@
***************************************************************************/
#include <tdebug.h>
#include <tmap.h>
#include "relativevolumeframe.h"
using namespace TagLib;
using namespace ID3v2;
static inline int bitsToBytes(int i)
{
return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1;
}
struct ChannelData
{
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
RelativeVolumeFrame::ChannelType channelType;
short volumeAdjustment;
RelativeVolumeFrame::PeakVolume peakVolume;
};
class RelativeVolumeFrame::RelativeVolumeFramePrivate
{
public:
RelativeVolumeFramePrivate() : channelType(Other), volumeAdjustment(0) {}
String identification;
ChannelType channelType;
short volumeAdjustment;
PeakVolume peakVolume;
Map<ChannelType, ChannelData> channels;
};
////////////////////////////////////////////////////////////////////////////////
@ -57,44 +68,89 @@ String RelativeVolumeFrame::toString() const
return d->identification;
}
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
{
return d->channelType;
List<ChannelType> l;
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
for(; it != d->channels.end(); ++it)
l.append((*it).first);
return l;
}
void RelativeVolumeFrame::setChannelType(ChannelType t)
// deprecated
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
{
d->channelType = t;
return MasterVolume;
}
// deprecated
void RelativeVolumeFrame::setChannelType(ChannelType)
{
}
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const
{
return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0;
}
short RelativeVolumeFrame::volumeAdjustmentIndex() const
{
return d->volumeAdjustment;
return volumeAdjustmentIndex(MasterVolume);
}
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type)
{
d->channels[type].volumeAdjustment = index;
}
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index)
{
d->volumeAdjustment = index;
setVolumeAdjustmentIndex(index, MasterVolume);
}
float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const
{
return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0;
}
float RelativeVolumeFrame::volumeAdjustment() const
{
return float(d->volumeAdjustment) / float(512);
return volumeAdjustment(MasterVolume);
}
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type)
{
d->channels[type].volumeAdjustment = short(adjustment / float(512));
}
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment)
{
d->volumeAdjustment = short(adjustment / float(512));
setVolumeAdjustment(adjustment, MasterVolume);
}
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const
{
return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume();
}
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const
{
return d->peakVolume;
return peakVolume(MasterVolume);
}
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type)
{
d->channels[type].peakVolume = peak;
}
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak)
{
d->peakVolume = peak;
setPeakVolume(peak, MasterVolume);
}
////////////////////////////////////////////////////////////////////////////////
@ -103,24 +159,29 @@ void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak)
void RelativeVolumeFrame::parseFields(const ByteVector &data)
{
if(data.size() < 6) {
debug("A relative volume frame must contain at least 6 bytes.");
return;
}
int pos = data.find(textDelimiter(String::Latin1));
uint pos = data.find(textDelimiter(String::Latin1));
d->identification = String(data.mid(0, pos), String::Latin1);
d->channelType = ChannelType(data[pos]);
pos += 1;
// Each channel is at least 4 bytes.
d->volumeAdjustment = data.mid(pos, 2).toShort();
pos += 2;
while(pos <= data.size() - 4) {
d->peakVolume.bitsRepresentingPeak = data[pos];
pos += 1;
d->peakVolume.peakVolume = data.mid(pos, d->peakVolume.bitsRepresentingPeak);
ChannelType type = ChannelType(data[pos]);
pos += 1;
ChannelData &channel = d->channels[type];
channel.volumeAdjustment = data.mid(pos, 2).toShort();
pos += 2;
channel.peakVolume.bitsRepresentingPeak = data[pos];
pos += 1;
int bytes = bitsToBytes(channel.peakVolume.bitsRepresentingPeak);
channel.peakVolume.peakVolume = data.mid(pos, bytes);
pos += bytes;
}
}
ByteVector RelativeVolumeFrame::renderFields() const
@ -129,10 +190,18 @@ ByteVector RelativeVolumeFrame::renderFields() const
data.append(d->identification.data(String::Latin1));
data.append(textDelimiter(String::Latin1));
data.append(char(d->channelType));
data.append(ByteVector::fromShort(d->volumeAdjustment));
data.append(char(d->peakVolume.bitsRepresentingPeak));
data.append(d->peakVolume.peakVolume);
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
for(; it != d->channels.end(); ++it) {
ChannelType type = (*it).first;
const ChannelData &channel = (*it).second;
data.append(char(type));
data.append(ByteVector::fromShort(channel.volumeAdjustment));
data.append(char(channel.peakVolume.bitsRepresentingPeak));
data.append(channel.peakVolume.peakVolume);
}
return data;
}

View File

@ -22,6 +22,7 @@
#ifndef TAGLIB_RELATIVEVOLUMEFRAME_H
#define TAGLIB_RELATIVEVOLUMEFRAME_H
#include <tlist.h>
#include <id3v2frame.h>
namespace TagLib {
@ -118,38 +119,52 @@ namespace TagLib {
virtual String toString() const;
/*!
* Returns the channel type that this frame refers to.
*
* \see setChannelType()
* Returns a list of channels with information currently in the frame.
*/
List<ChannelType> channels() const;
/*!
* \deprecated Always returns master volume.
*/
ChannelType channelType() const;
/*!
* Sets the channel type that this frame refers to.
*
* \see channelType()
* \deprecated This method no longer has any effect.
*/
void setChannelType(ChannelType t);
/*
* There was a terrible API goof here, and while this can't be changed to
* the way it appears below for binary compaibility reasons, let's at
* least pretend that it looks clean.
*/
#ifdef DOXYGEN
/*!
* Returns the relative volume adjustment "index". As indicated by the
* ID3v2 standard this is a 16-bit signed integer that reflects the
* decibils of adjustment when divided by 512.
*
* This defaults to returning the value for the master volume channel if
* available and returns 0 if the specified channel does not exist.
*
* \see setVolumeAdjustmentIndex()
* \see volumeAjustment()
*/
short volumeAdjustmentIndex() const;
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
/*!
* Set the volume adjustment to \a index. As indicated by the ID3v2
* standard this is a 16-bit signed integer that reflects the decibils of
* adjustment when divided by 512.
*
* By default this sets the value for the master volume.
*
* \see volumeAdjustmentIndex()
* \see setVolumeAjustment()
*/
void setVolumeAdjustmentIndex(short index);
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);
/*!
* Returns the relative volume adjustment in decibels.
@ -158,14 +173,19 @@ namespace TagLib {
* value the value returned by this method may not be identical to the
* value set using setVolumeAdjustment().
*
* This defaults to returning the value for the master volume channel if
* available and returns 0 if the specified channel does not exist.
*
* \see setVolumeAdjustment()
* \see volumeAdjustmentIndex()
*/
float volumeAdjustment() const;
float volumeAdjustment(ChannelType type = MasterVolume) const;
/*!
* Set the relative volume adjustment in decibels to \a adjustment.
*
* By default this sets the value for the master volume.
*
* \note Because this is actually stored internally as an "index" to this
* value the value set by this method may not be identical to the one
* returned by volumeAdjustment().
@ -173,22 +193,52 @@ namespace TagLib {
* \see setVolumeAdjustment()
* \see volumeAdjustmentIndex()
*/
void setVolumeAdjustment(float adjustment);
void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume);
/*!
* Returns the peak volume (represented as a length and a string of bits).
*
* This defaults to returning the value for the master volume channel if
* available and returns 0 if the specified channel does not exist.
*
* \see setPeakVolume()
*/
PeakVolume peakVolume() const;
PeakVolume peakVolume(ChannelType type = MasterVolume) const;
/*!
* Sets the peak volume to \a peak.
*
* By default this sets the value for the master volume.
*
* \see peakVolume()
*/
void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume);
#else
// BIC: Combine each of the following pairs of functions (or maybe just
// rework this junk altogether).
short volumeAdjustmentIndex(ChannelType type) const;
short volumeAdjustmentIndex() const;
void setVolumeAdjustmentIndex(short index, ChannelType type);
void setVolumeAdjustmentIndex(short index);
float volumeAdjustment(ChannelType type) const;
float volumeAdjustment() const;
void setVolumeAdjustment(float adjustment, ChannelType type);
void setVolumeAdjustment(float adjustment);
PeakVolume peakVolume(ChannelType type) const;
PeakVolume peakVolume() const;
void setPeakVolume(const PeakVolume &peak, ChannelType type);
void setPeakVolume(const PeakVolume &peak);
#endif
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;