More ReplayGain support, now with metadata handling, but only if the metadata is already loaded
parent
6ea103b1c3
commit
4c0cf34250
|
@ -14,6 +14,7 @@ extern NSString *CogPlaybackDidPauseNotficiation;
|
|||
extern NSString *CogPlaybackDidResumeNotficiation;
|
||||
extern NSString *CogPlaybackDidStopNotficiation;
|
||||
|
||||
extern NSDictionary * makeRGInfo(PlaylistEntry *pe);
|
||||
|
||||
@class PlaylistController;
|
||||
@class PlaylistView;
|
||||
|
|
|
@ -117,6 +117,22 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
|
|||
[self playEntryAtIndex:[playlistView selectedRow]];
|
||||
}
|
||||
|
||||
NSDictionary * makeRGInfo(PlaylistEntry *pe)
|
||||
{
|
||||
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
|
||||
if ([pe replayGainAlbumGain] != 0)
|
||||
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainAlbumGain]] forKey:@"replayGainAlbumGain"];
|
||||
if ([pe replayGainAlbumPeak] != 0)
|
||||
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainAlbumPeak]] forKey:@"replayGainAlbumPeak"];
|
||||
if ([pe replayGainTrackGain] != 0)
|
||||
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainTrackGain]] forKey:@"replayGainTrackGain"];
|
||||
if ([pe replayGainTrackPeak] != 0)
|
||||
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainTrackPeak]] forKey:@"replayGainTrackPeak"];
|
||||
if ([pe volume] != 1)
|
||||
[dictionary setObject:[NSNumber numberWithFloat:[pe volume]] forKey:@"volume"];
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
- (void)playEntry:(PlaylistEntry *)pe
|
||||
{
|
||||
if (playbackStatus != kCogStatusStopped)
|
||||
|
@ -130,7 +146,7 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
|
|||
if (pe == nil)
|
||||
return;
|
||||
|
||||
[audioPlayer play:[pe URL] withUserInfo:pe];
|
||||
[audioPlayer play:[pe URL] withUserInfo:pe withRGInfo:makeRGInfo(pe)];
|
||||
}
|
||||
|
||||
- (IBAction)next:(id)sender
|
||||
|
@ -430,7 +446,7 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
|
|||
else
|
||||
pe = [playlistController getNextEntry:curEntry];
|
||||
|
||||
[player setNextStream:[pe URL] withUserInfo:pe];
|
||||
[player setNextStream:[pe URL] withUserInfo:pe withRGInfo:makeRGInfo(pe)];
|
||||
}
|
||||
|
||||
- (void)audioPlayer:(AudioPlayer *)player didBeginStream:(id)userInfo
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
NSURL *nextStream;
|
||||
id nextStreamUserInfo;
|
||||
NSDictionary *nextStreamRGInfo;
|
||||
|
||||
id delegate;
|
||||
|
||||
|
@ -35,7 +36,7 @@
|
|||
- (id)delegate;
|
||||
|
||||
- (void)play:(NSURL *)url;
|
||||
- (void)play:(NSURL *)url withUserInfo:(id)userInfo;
|
||||
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary*)rgi;
|
||||
|
||||
- (void)stop;
|
||||
- (void)pause;
|
||||
|
@ -50,9 +51,11 @@
|
|||
- (double)amountPlayed;
|
||||
|
||||
- (void)setNextStream:(NSURL *)url;
|
||||
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo;
|
||||
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary*)rgi;
|
||||
- (void)resetNextStreams;
|
||||
|
||||
- (void)setRGInfo:(NSDictionary *)rgi;
|
||||
|
||||
+ (NSArray *)fileTypes;
|
||||
+ (NSArray *)schemes;
|
||||
+ (NSArray *)containerTypes;
|
||||
|
|
|
@ -43,10 +43,10 @@
|
|||
|
||||
- (void)play:(NSURL *)url
|
||||
{
|
||||
[self play:url withUserInfo:nil];
|
||||
[self play:url withUserInfo:nil withRGInfo:nil];
|
||||
}
|
||||
|
||||
- (void)play:(NSURL *)url withUserInfo:(id)userInfo
|
||||
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi
|
||||
{
|
||||
if (output)
|
||||
{
|
||||
|
@ -91,6 +91,7 @@
|
|||
}
|
||||
|
||||
userInfo = nextStreamUserInfo;
|
||||
rgi = nextStreamRGInfo;
|
||||
|
||||
[self notifyStreamChanged:userInfo];
|
||||
|
||||
|
@ -98,6 +99,7 @@
|
|||
}
|
||||
|
||||
[bufferChain setUserInfo:userInfo];
|
||||
[bufferChain setRGInfo:rgi];
|
||||
|
||||
[self setShouldContinue:YES];
|
||||
|
||||
|
@ -152,10 +154,10 @@
|
|||
//This is called by the delegate DURING a requestNextStream request.
|
||||
- (void)setNextStream:(NSURL *)url
|
||||
{
|
||||
[self setNextStream:url withUserInfo:nil];
|
||||
[self setNextStream:url withUserInfo:nil withRGInfo:nil];
|
||||
}
|
||||
|
||||
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo
|
||||
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi
|
||||
{
|
||||
[url retain];
|
||||
[nextStream release];
|
||||
|
@ -164,7 +166,10 @@
|
|||
[userInfo retain];
|
||||
[nextStreamUserInfo release];
|
||||
nextStreamUserInfo = userInfo;
|
||||
|
||||
|
||||
[rgi retain];
|
||||
[nextStreamRGInfo release];
|
||||
nextStreamRGInfo = rgi;
|
||||
}
|
||||
|
||||
// Called when the playlist changed before we actually started playing a requested stream. We will re-request.
|
||||
|
@ -212,7 +217,7 @@
|
|||
|
||||
- (void)notifyStreamChanged:(id)userInfo
|
||||
{
|
||||
[self sendDelegateMethod:@selector(audioPlayer:didBeginStream:) withObject:userInfo waitUntilDone:NO];
|
||||
[self sendDelegateMethod:@selector(audioPlayer:didBeginStream:) withObject:userInfo waitUntilDone:YES];
|
||||
}
|
||||
|
||||
- (void)addChainToQueue:(BufferChain *)newChain
|
||||
|
@ -233,6 +238,9 @@
|
|||
nextStreamUserInfo = [sender userInfo];
|
||||
[nextStreamUserInfo retain]; //Retained because when setNextStream is called, it will be released!!!
|
||||
|
||||
nextStreamRGInfo = [sender rgInfo];
|
||||
[nextStreamRGInfo retain];
|
||||
|
||||
[self requestNextStream: nextStreamUserInfo];
|
||||
newChain = [[BufferChain alloc] initWithController:self];
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
NSURL *streamURL;
|
||||
id userInfo;
|
||||
NSDictionary *rgInfo;
|
||||
|
||||
id finalNode; //Final buffer in the chain.
|
||||
|
||||
|
@ -43,6 +44,9 @@
|
|||
- (id)userInfo;
|
||||
- (void)setUserInfo:(id)i;
|
||||
|
||||
- (NSDictionary*)rgInfo;
|
||||
- (void)setRGInfo:(NSDictionary *)rgi;
|
||||
|
||||
- (NSURL *)streamURL;
|
||||
- (void)setStreamURL:(NSURL *)url;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
controller = c;
|
||||
streamURL = nil;
|
||||
userInfo = nil;
|
||||
rgInfo = nil;
|
||||
|
||||
inputNode = nil;
|
||||
converterNode = nil;
|
||||
|
@ -100,8 +101,22 @@
|
|||
return userInfo;
|
||||
}
|
||||
|
||||
- (void)setRGInfo:(NSDictionary *)rgi
|
||||
{
|
||||
[rgi retain];
|
||||
[rgInfo release];
|
||||
rgInfo = rgi;
|
||||
[inputNode setRGInfo:rgi];
|
||||
}
|
||||
|
||||
- (NSDictionary *)rgInfo
|
||||
{
|
||||
return rgInfo;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[rgInfo release];
|
||||
[userInfo release];
|
||||
[streamURL release];
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
@interface InputNode : Node {
|
||||
id<CogDecoder> decoder;
|
||||
NSDictionary * rgInfo;
|
||||
|
||||
int bytesPerSample;
|
||||
int bytesPerFrame;
|
||||
|
@ -39,6 +40,8 @@
|
|||
|
||||
- (BOOL)setTrack:(NSURL *)track;
|
||||
|
||||
- (void)setRGInfo:(NSDictionary *)rgi;
|
||||
|
||||
- (id<CogDecoder>) decoder;
|
||||
|
||||
- (void)refreshVolumeScaling;
|
||||
|
|
|
@ -133,11 +133,13 @@ static float db_to_scale(float db)
|
|||
- (void)refreshVolumeScaling
|
||||
{
|
||||
NSDictionary *properties = [decoder properties];
|
||||
if (rgInfo != nil)
|
||||
properties = rgInfo;
|
||||
NSString * scaling = [[NSUserDefaults standardUserDefaults] stringForKey:@"volumeScaling"];
|
||||
BOOL useAlbum = [scaling hasPrefix:@"albumGain"];
|
||||
BOOL useTrack = useAlbum || [scaling hasPrefix:@"trackGain"];
|
||||
BOOL useVolume = useAlbum || useTrack || [scaling isEqualToString:@"volumeScale"];
|
||||
bool usePeak = [scaling hasSuffix:@"WithPeak"];
|
||||
BOOL usePeak = [scaling hasSuffix:@"WithPeak"];
|
||||
float scale = 1.0;
|
||||
float peak = 0.0;
|
||||
if (useVolume) {
|
||||
|
@ -319,9 +321,19 @@ static int32_t swap_32(uint32_t input)
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (void)setRGInfo:(NSDictionary *)i
|
||||
{
|
||||
[i retain];
|
||||
[rgInfo release];
|
||||
rgInfo = i;
|
||||
[self refreshVolumeScaling];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NSLog(@"Input Node dealloc");
|
||||
|
||||
[rgInfo release];
|
||||
|
||||
[decoder removeObserver:self forKeyPath:@"properties"];
|
||||
[decoder removeObserver:self forKeyPath:@"metadata"];
|
||||
|
|
|
@ -133,6 +133,34 @@ TagLib::uint APE::Tag::track() const
|
|||
return d->itemListMap["TRACK"].toString().toInt();
|
||||
}
|
||||
|
||||
float APE::Tag::rgAlbumGain() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgAlbumPeak() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_ALBUM_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_ALBUM_PEAK"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgTrackGain() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_TRACK_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_TRACK_GAIN"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgTrackPeak() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_TRACK_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_TRACK_PEAK"].toString().toFloat();
|
||||
}
|
||||
|
||||
void APE::Tag::setTitle(const String &s)
|
||||
{
|
||||
addValue("TITLE", s, true);
|
||||
|
@ -174,6 +202,38 @@ void APE::Tag::setTrack(uint i)
|
|||
addValue("TRACK", String::number(i), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGAlbumGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_ALBUM_GAIN");
|
||||
else
|
||||
addValue("REPLAYGAIN_ALBUM_GAIN", String::number(f) + " dB", true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGAlbumPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_ALBUM_PEAK");
|
||||
else
|
||||
addValue("REPLAYGAIN_ALBUM_PEAK", String::number(f), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGTrackGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_TRACK_GAIN");
|
||||
else
|
||||
addValue("REPLAYGAIN_TRACK_GAIN", String::number(f) + " dB", true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGTrackPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_TRACK_PEAK");
|
||||
else
|
||||
addValue("REPLAYGAIN_TRACK_PEAK", String::number(f), true);
|
||||
}
|
||||
|
||||
APE::Footer *APE::Tag::footer() const
|
||||
{
|
||||
return &d->footer;
|
||||
|
|
|
@ -94,6 +94,10 @@ namespace TagLib {
|
|||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
|
@ -102,6 +106,10 @@ namespace TagLib {
|
|||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's footer.
|
||||
|
|
|
@ -19,6 +19,10 @@ public:
|
|||
TagLib::uint disk;
|
||||
TagLib::uint numDisks;
|
||||
TagLib::uint bpm;
|
||||
float rgAlbumGain;
|
||||
float rgAlbumPeak;
|
||||
float rgTrackGain;
|
||||
float rgTrackPeak;
|
||||
bool isEmpty;
|
||||
TagLib::ByteVector cover;
|
||||
};
|
||||
|
@ -76,6 +80,26 @@ TagLib::uint MP4::Tag::track() const
|
|||
return d->track;
|
||||
}
|
||||
|
||||
float MP4::Tag::rgAlbumGain() const
|
||||
{
|
||||
return d->rgAlbumGain;
|
||||
}
|
||||
|
||||
float MP4::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return d->rgAlbumPeak;
|
||||
}
|
||||
|
||||
float MP4::Tag::rgTrackGain() const
|
||||
{
|
||||
return d->rgTrackGain;
|
||||
}
|
||||
|
||||
float MP4::Tag::rgTrackPeak() const
|
||||
{
|
||||
return d->rgTrackPeak;
|
||||
}
|
||||
|
||||
TagLib::uint MP4::Tag::numTracks() const
|
||||
{
|
||||
return d->numTracks;
|
||||
|
@ -153,6 +177,30 @@ void MP4::Tag::setTrack(TagLib::uint i)
|
|||
d->isEmpty = false;
|
||||
}
|
||||
|
||||
void MP4::Tag::setRGAlbumGain(float f)
|
||||
{
|
||||
d->rgAlbumGain = f;
|
||||
d->isEmpty = false;
|
||||
}
|
||||
|
||||
void MP4::Tag::setRGAlbumPeak(float f)
|
||||
{
|
||||
d->rgAlbumPeak = f;
|
||||
d->isEmpty = false;
|
||||
}
|
||||
|
||||
void MP4::Tag::setRGTrackGain(float f)
|
||||
{
|
||||
d->rgTrackGain = f;
|
||||
d->isEmpty = false;
|
||||
}
|
||||
|
||||
void MP4::Tag::setRGTrackPeak(float f)
|
||||
{
|
||||
d->rgTrackPeak = f;
|
||||
d->isEmpty = false;
|
||||
}
|
||||
|
||||
void MP4::Tag::setNumTracks(TagLib::uint i)
|
||||
{
|
||||
d->numTracks = i;
|
||||
|
|
|
@ -33,6 +33,10 @@ namespace TagLib
|
|||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
|
@ -41,6 +45,10 @@ namespace TagLib
|
|||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
// MP4 specific fields
|
||||
|
||||
|
|
|
@ -152,6 +152,26 @@ TagLib::uint ID3v1::Tag::track() const
|
|||
return d->track;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgAlbumGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgTrackGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgTrackPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTitle(const String &s)
|
||||
{
|
||||
d->title = s;
|
||||
|
@ -187,6 +207,22 @@ void ID3v1::Tag::setTrack(uint i)
|
|||
d->track = i < 256 ? i : 0;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGAlbumGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGAlbumPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGTrackGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGTrackPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
|
||||
{
|
||||
delete TagPrivate::stringHandler;
|
||||
|
|
|
@ -140,6 +140,10 @@ namespace TagLib {
|
|||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
|
@ -148,6 +152,10 @@ namespace TagLib {
|
|||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
/*!
|
||||
* Sets the string handler that decides how the ID3v1 data will be
|
||||
|
|
|
@ -195,6 +195,39 @@ TagLib::uint ID3v2::Tag::track() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rg(const String &type) const
|
||||
{
|
||||
const FrameList &list = d->frameListMap["TXXX"];
|
||||
if (!list.isEmpty()) {
|
||||
for (FrameList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (static_cast<UserTextIdentificationFrame *>(*it)->description() == type) {
|
||||
return static_cast<UserTextIdentificationFrame *>(*it)->toString().toFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgAlbumGain() const
|
||||
{
|
||||
return rg("replaygain_album_gain");
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return rg("replaygain_album_peak");
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgTrackGain() const
|
||||
{
|
||||
return rg("replaygain_track_gain");
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgTrackPeak() const
|
||||
{
|
||||
return rg("replaygain_track_peak");
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setTitle(const String &s)
|
||||
{
|
||||
setTextFrame("TIT2", s);
|
||||
|
@ -270,6 +303,52 @@ void ID3v2::Tag::setTrack(uint i)
|
|||
setTextFrame("TRCK", String::number(i));
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRG(const String &type, float f, bool peak)
|
||||
{
|
||||
bool createdFrame = false;
|
||||
UserTextIdentificationFrame * frame = NULL;
|
||||
FrameList &list = d->frameListMap["TXXX"];
|
||||
for (FrameList::Iterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (static_cast<UserTextIdentificationFrame *>(*it)->description() == type) {
|
||||
frame = static_cast<UserTextIdentificationFrame*>(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f == 0) {
|
||||
if (frame)
|
||||
removeFrame(frame);
|
||||
return;
|
||||
}
|
||||
if (frame == NULL) {
|
||||
frame = new UserTextIdentificationFrame;
|
||||
frame->setDescription(type);
|
||||
createdFrame = true;
|
||||
}
|
||||
frame->setText(String::number(f) + (peak ? "" : " dB"));
|
||||
if (createdFrame)
|
||||
addFrame(frame);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGAlbumGain(float f)
|
||||
{
|
||||
setRG("replaygain_album_gain", f, false);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGAlbumPeak(float f)
|
||||
{
|
||||
setRG("replaygain_album_peak", f, true);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGTrackGain(float f)
|
||||
{
|
||||
setRG("replaygain_track_gain", f, false);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGTrackPeak(float f)
|
||||
{
|
||||
setRG("replaygain_track_peak", f, true);
|
||||
}
|
||||
|
||||
bool ID3v2::Tag::isEmpty() const
|
||||
{
|
||||
return d->frameList.isEmpty();
|
||||
|
|
|
@ -142,6 +142,12 @@ namespace TagLib {
|
|||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
|
||||
float rg(const String &type) const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
virtual void setAlbum(const String &s);
|
||||
|
@ -150,6 +156,12 @@ namespace TagLib {
|
|||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
|
||||
void setRG(const String &type, float f, bool peak);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
|
|
|
@ -115,6 +115,34 @@ TagLib::uint Ogg::XiphComment::track() const
|
|||
return d->fieldListMap["TRACKNUMBER"].front().toInt();
|
||||
}
|
||||
|
||||
float Ogg::XiphComment::rgAlbumGain() const
|
||||
{
|
||||
if(d->fieldListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->fieldListMap["REPLAYGAIN_ALBUM_GAIN"].front().toFloat();
|
||||
}
|
||||
|
||||
float Ogg::XiphComment::rgAlbumPeak() const
|
||||
{
|
||||
if(d->fieldListMap["REPLAYGAIN_ALBUM_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->fieldListMap["REPLAYGAIN_ALBUM_PEAK"].front().toFloat();
|
||||
}
|
||||
|
||||
float Ogg::XiphComment::rgTrackGain() const
|
||||
{
|
||||
if(d->fieldListMap["REPLAYGAIN_TRACK_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->fieldListMap["REPLAYGAIN_TRACK_GAIN"].front().toFloat();
|
||||
}
|
||||
|
||||
float Ogg::XiphComment::rgTrackPeak() const
|
||||
{
|
||||
if(d->fieldListMap["REPLAYGAIN_TRACK_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->fieldListMap["REPLAYGAIN_TRACK_PEAK"].front().toFloat();
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::setTitle(const String &s)
|
||||
{
|
||||
addField("TITLE", s);
|
||||
|
@ -156,6 +184,38 @@ void Ogg::XiphComment::setTrack(uint i)
|
|||
addField("TRACKNUMBER", String::number(i));
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::setRGAlbumGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeField("REPLAYGAIN_ALBUM_GAIN");
|
||||
else
|
||||
addField("REPLAYGAIN_ALBUM_GAIN", String::number(f) + " dB");
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::setRGAlbumPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeField("REPLAYGAIN_ALBUM_PEAK");
|
||||
else
|
||||
addField("REPLAYGAIN_ALBUM_PEAK", String::number(f));
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::setRGTrackGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeField("REPLAYGAIN_TRACK_GAIN");
|
||||
else
|
||||
addField("REPLAYGAIN_TRACK_GAIN", String::number(f) + " dB");
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::setRGTrackPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeField("REPLAYGAIN_TRACK_PEAK");
|
||||
else
|
||||
addField("REPLAYGAIN_TRACK_PEAK", String::number(f));
|
||||
}
|
||||
|
||||
bool Ogg::XiphComment::isEmpty() const
|
||||
{
|
||||
FieldListMap::ConstIterator it = d->fieldListMap.begin();
|
||||
|
|
|
@ -86,6 +86,10 @@ namespace TagLib {
|
|||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
|
@ -94,6 +98,10 @@ namespace TagLib {
|
|||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
|
|
|
@ -90,7 +90,31 @@ namespace TagLib {
|
|||
* return 0.
|
||||
*/
|
||||
virtual uint track() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the ReplayGain album gain; if there is no gain level set, this
|
||||
* will return 0.
|
||||
*/
|
||||
virtual float rgAlbumGain() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the ReplayGain album peak; if there is no gain level set, this
|
||||
* will return 0.
|
||||
*/
|
||||
virtual float rgAlbumPeak() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the ReplayGain track gain; if there is no gain level set, this
|
||||
* will return 0.
|
||||
*/
|
||||
virtual float rgTrackGain() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the ReplayGain track peak; if there is no gain level set, this
|
||||
* will return 0.
|
||||
*/
|
||||
virtual float rgTrackPeak() const = 0;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a s. If \a s is String::null then this value will be
|
||||
* cleared.
|
||||
|
@ -133,7 +157,31 @@ namespace TagLib {
|
|||
* Sets the track to \a i. If \a s is 0 then this value will be cleared.
|
||||
*/
|
||||
virtual void setTrack(uint i) = 0;
|
||||
|
||||
/*!
|
||||
* Sets the ReplayGain album gain to \a f. If \a f is 0 then this value will
|
||||
* be cleared.
|
||||
*/
|
||||
virtual void setRGAlbumGain(float i) = 0;
|
||||
|
||||
/*!
|
||||
* Sets the ReplayGain album peak to \a f. If \a f is 0 then this value will
|
||||
* be cleared.
|
||||
*/
|
||||
virtual void setRGAlbumPeak(float i) = 0;
|
||||
|
||||
/*!
|
||||
* Sets the ReplayGain track gain to \a f. If \a f is 0 then this value will
|
||||
* be cleared.
|
||||
*/
|
||||
virtual void setRGTrackGain(float i) = 0;
|
||||
|
||||
/*!
|
||||
* Sets the ReplayGain track peak to \a f. If \a f is 0 then this value will
|
||||
* be cleared.
|
||||
*/
|
||||
virtual void setRGTrackPeak(float i) = 0;
|
||||
|
||||
/*!
|
||||
* Returns true if the tag does not contain any data. This should be
|
||||
* reimplemented in subclasses that provide more than the basic tagging
|
||||
|
|
|
@ -45,6 +45,15 @@ using namespace TagLib;
|
|||
return tag(2)->method(); \
|
||||
return 0
|
||||
|
||||
#define floatUnion(method) \
|
||||
if(tag(0) && tag(0)->method() != 0) \
|
||||
return tag(0)->method(); \
|
||||
if(tag(1) && tag(1)->method() != 0) \
|
||||
return tag(1)->method(); \
|
||||
if(tag(2) && tag(2)->method() != 0) \
|
||||
return tag(2)->method(); \
|
||||
return 0
|
||||
|
||||
#define setUnion(method, value) \
|
||||
if(tag(0)) \
|
||||
tag(0)->set##method(value); \
|
||||
|
@ -136,6 +145,26 @@ TagLib::uint TagUnion::track() const
|
|||
numberUnion(track);
|
||||
}
|
||||
|
||||
float TagUnion::rgAlbumGain() const
|
||||
{
|
||||
floatUnion(rgAlbumGain);
|
||||
}
|
||||
|
||||
float TagUnion::rgAlbumPeak() const
|
||||
{
|
||||
floatUnion(rgAlbumPeak);
|
||||
}
|
||||
|
||||
float TagUnion::rgTrackGain() const
|
||||
{
|
||||
floatUnion(rgTrackGain);
|
||||
}
|
||||
|
||||
float TagUnion::rgTrackPeak() const
|
||||
{
|
||||
floatUnion(rgTrackPeak);
|
||||
}
|
||||
|
||||
void TagUnion::setTitle(const String &s)
|
||||
{
|
||||
setUnion(Title, s);
|
||||
|
@ -171,6 +200,26 @@ void TagUnion::setTrack(uint i)
|
|||
setUnion(Track, i);
|
||||
}
|
||||
|
||||
void TagUnion::setRGAlbumGain(float f)
|
||||
{
|
||||
setUnion(RGAlbumGain, f);
|
||||
}
|
||||
|
||||
void TagUnion::setRGAlbumPeak(float f)
|
||||
{
|
||||
setUnion(RGAlbumPeak, f);
|
||||
}
|
||||
|
||||
void TagUnion::setRGTrackGain(float f)
|
||||
{
|
||||
setUnion(RGTrackGain, f);
|
||||
}
|
||||
|
||||
void TagUnion::setRGTrackPeak(float f)
|
||||
{
|
||||
setUnion(RGTrackPeak, f);
|
||||
}
|
||||
|
||||
bool TagUnion::isEmpty() const
|
||||
{
|
||||
if(d->tags[0] && !d->tags[0]->isEmpty())
|
||||
|
|
|
@ -63,6 +63,10 @@ namespace TagLib {
|
|||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
|
@ -71,6 +75,10 @@ namespace TagLib {
|
|||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
template <class T> T *access(int index, bool create)
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
inline unsigned short byteSwap(unsigned short x)
|
||||
|
@ -435,6 +437,31 @@ int String::toInt() const
|
|||
return value;
|
||||
}
|
||||
|
||||
float String::toFloat() const
|
||||
{
|
||||
float value = 0;
|
||||
float decimal_value = 1;
|
||||
|
||||
bool negative = d->data[0] == '-';
|
||||
uint i = negative ? 1 : 0;
|
||||
|
||||
for(; i < d->data.size() && d->data[i] >= '0' && d->data[i] <= '9'; i++)
|
||||
value = value * 10 + (d->data[i] - '0');
|
||||
|
||||
if (i < d->data.size() && d->data[i] == '.')
|
||||
for(++i; i < d->data.size() && d->data[i] >= '0' && d->data[i] <= '9'; i++) {
|
||||
value = value * 10 + (d->data[i] - '0');
|
||||
decimal_value *= 0.1;
|
||||
}
|
||||
|
||||
if(negative)
|
||||
value = value * -1;
|
||||
|
||||
value *= decimal_value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
String String::stripWhiteSpace() const
|
||||
{
|
||||
wstring::const_iterator begin = d->data.begin();
|
||||
|
@ -479,6 +506,11 @@ bool String::isAscii() const
|
|||
return true;
|
||||
}
|
||||
|
||||
String String::number(uint n)
|
||||
{
|
||||
return number((int)n);
|
||||
}
|
||||
|
||||
String String::number(int n) // static
|
||||
{
|
||||
if(n == 0)
|
||||
|
@ -508,6 +540,48 @@ String String::number(int n) // static
|
|||
return s;
|
||||
}
|
||||
|
||||
String String::number(float n) // static
|
||||
{
|
||||
if(n == 0)
|
||||
return String("0");
|
||||
|
||||
float decimal = fmod(n, 1);
|
||||
n -= decimal;
|
||||
|
||||
String charStack;
|
||||
|
||||
bool negative = n < 0;
|
||||
|
||||
if(negative)
|
||||
n = n * -1;
|
||||
|
||||
while(n > 0) {
|
||||
float remainder = fmod(n, 10);
|
||||
charStack += char(remainder + '0');
|
||||
n = (n - remainder) / 10;
|
||||
}
|
||||
|
||||
String s;
|
||||
|
||||
if(negative)
|
||||
s += '-';
|
||||
|
||||
for(int i = charStack.d->data.size() - 1; i >= 0; i--)
|
||||
s += charStack.d->data[i];
|
||||
|
||||
if (decimal > 0) {
|
||||
s += '.';
|
||||
while (decimal > 0) {
|
||||
decimal *= 10;
|
||||
float remainder = fmod(decimal, 1);
|
||||
s += char(decimal + '0');
|
||||
decimal = remainder;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
TagLib::wchar &String::operator[](int i)
|
||||
{
|
||||
return d->data[i];
|
||||
|
|
|
@ -286,6 +286,11 @@ namespace TagLib {
|
|||
* Convert the string to an integer.
|
||||
*/
|
||||
int toInt() const;
|
||||
|
||||
/*!
|
||||
* Convert the string to a float.
|
||||
*/
|
||||
float toFloat() const;
|
||||
|
||||
/*!
|
||||
* Returns a string with the leading and trailing whitespace stripped.
|
||||
|
@ -305,7 +310,13 @@ namespace TagLib {
|
|||
/*!
|
||||
* Converts the base-10 integer \a n to a string.
|
||||
*/
|
||||
static String number(uint n);
|
||||
static String number(int n);
|
||||
|
||||
/*!
|
||||
* Converts the base-10 float \a n to a string.
|
||||
*/
|
||||
static String number(float n);
|
||||
|
||||
/*!
|
||||
* Returns a reference to the character at position \a i.
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
@synthesize bitsPerSample;
|
||||
@synthesize sampleRate;
|
||||
|
||||
@synthesize replayGainAlbumGain;
|
||||
@synthesize replayGainAlbumPeak;
|
||||
@synthesize replayGainTrackGain;
|
||||
@synthesize replayGainTrackPeak;
|
||||
@synthesize volume;
|
||||
|
||||
@synthesize endian;
|
||||
|
||||
@synthesize seekable;
|
||||
|
@ -82,6 +88,18 @@
|
|||
return [NSString stringWithFormat:@"PlaylistEntry %i:(%@)", self.index, self.URL];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.replayGainAlbumGain = 0;
|
||||
self.replayGainAlbumPeak = 0;
|
||||
self.replayGainTrackGain = 0;
|
||||
self.replayGainTrackPeak = 0;
|
||||
self.volume = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
self.errorMessage = nil;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
{
|
||||
TagLib::String artist, title, album, genre, comment;
|
||||
int year, track;
|
||||
float rgAlbumGain, rgAlbumPeak, rgTrackGain, rgTrackPeak;
|
||||
|
||||
artist = tag->artist();
|
||||
title = tag->title();;
|
||||
|
@ -44,6 +45,15 @@
|
|||
|
||||
track = tag->track();
|
||||
[dict setObject:[NSNumber numberWithInt:track] forKey:@"track"];
|
||||
|
||||
rgAlbumGain = tag->rgAlbumGain();
|
||||
rgAlbumPeak = tag->rgAlbumPeak();
|
||||
rgTrackGain = tag->rgTrackGain();
|
||||
rgTrackPeak = tag->rgTrackPeak();
|
||||
[dict setObject:[NSNumber numberWithFloat:rgAlbumGain] forKey:@"replayGainAlbumGain"];
|
||||
[dict setObject:[NSNumber numberWithFloat:rgAlbumPeak] forKey:@"replayGainAlbumPeak"];
|
||||
[dict setObject:[NSNumber numberWithFloat:rgTrackGain] forKey:@"replayGainTrackGain"];
|
||||
[dict setObject:[NSNumber numberWithFloat:rgTrackPeak] forKey:@"replayGainTrackPeak"];
|
||||
|
||||
if (!artist.isNull())
|
||||
[dict setObject:[NSString stringWithUTF8String:artist.toCString(true)] forKey:@"artist"];
|
||||
|
|
Loading…
Reference in New Issue