]> granicus.if.org Git - taglib/commitdiff
Fix up the RVA2 handling. I'm still not thrilled with the API, but this
authorScott Wheeler <wheeler@kde.org>
Thu, 21 Jul 2005 00:10:57 +0000 (00:10 +0000)
committerScott Wheeler <wheeler@kde.org>
Thu, 21 Jul 2005 00:10:57 +0000 (00:10 +0000)
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

mpeg/id3v2/frames/relativevolumeframe.cpp
mpeg/id3v2/frames/relativevolumeframe.h

index 3042a2da79e70da3fd519fcf8c4df08d437afba8..3b8caea9418e6b42358ca39c12f38cf5d7f6d6e7 100644 (file)
  ***************************************************************************/
 
 #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;
 }
 
+List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
+{
+  List<ChannelType> l;
+
+  Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
+  for(; it != d->channels.end(); ++it)
+    l.append((*it).first);
+
+  return l;
+}
+
+// deprecated
+
 RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
 {
-  return d->channelType;
+  return MasterVolume;
 }
 
-void RelativeVolumeFrame::setChannelType(ChannelType t)
+// deprecated
+
+void RelativeVolumeFrame::setChannelType(ChannelType)
 {
-  d->channelType = t;
+
+}
+
+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.
+
+  while(pos <= data.size() - 4) {
+
+
+    ChannelType type = ChannelType(data[pos]);
+    pos += 1;
 
-  d->volumeAdjustment = data.mid(pos, 2).toShort();
-  pos += 2;
+    ChannelData &channel = d->channels[type];
 
-  d->peakVolume.bitsRepresentingPeak = data[pos];
-  pos += 1;
+    channel.volumeAdjustment = data.mid(pos, 2).toShort();
+    pos += 2;
 
-  d->peakVolume.peakVolume = data.mid(pos, d->peakVolume.bitsRepresentingPeak);
+    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;
 }
index f2d9a9dc3f49e09a279dd4869d249d0a3937084a..981ea2e8a3cdf7d413715842fca62ce03cf02a64 100644 (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;