Browse Source

Implemented support for VGMStream external !tags.m3u metadata playlists

master
Christopher Snowhill 4 months ago
parent
commit
86681e9726
3 changed files with 94 additions and 13 deletions
  1. +85
    -11
      Plugins/vgmstream/vgmstream/VGMDecoder.m
  2. +3
    -0
      Plugins/vgmstream/vgmstream/VGMInterface.h
  3. +6
    -2
      Plugins/vgmstream/vgmstream/VGMInterface.m

+ 85
- 11
Plugins/vgmstream/vgmstream/VGMDecoder.m View File

@@ -35,11 +35,73 @@
int sampleRate = stream->sample_rate;
int channels = stream->channels;
long totalFrames = get_vgmstream_play_samples( 2.0, 10.0, 10.0, stream );
long framesFade = stream->loop_flag ? sampleRate * 10 : 0;
long framesLength = totalFrames - framesFade;
int bitrate = get_vgmstream_average_bitrate(stream);
NSURL *folder = [url URLByDeletingLastPathComponent];
NSURL *tagurl = [folder URLByAppendingPathComponent:@"!tags.m3u" isDirectory:NO];
NSString *filename = [url lastPathComponent];

NSString *album = @"";
NSString *artist = @"";
NSNumber *year = [NSNumber numberWithInt:0];
NSNumber *track = [NSNumber numberWithInt:0];
NSString *title = @"";

NSNumber *rgTrackGain = [NSNumber numberWithInt:0];
NSNumber *rgTrackPeak = [NSNumber numberWithInt:0];
NSNumber *rgAlbumGain = [NSNumber numberWithInt:0];
NSNumber *rgAlbumPeak = [NSNumber numberWithInt:0];
STREAMFILE *tagFile = cogsf_create_from_url(tagurl);
if (tagFile) {
VGMSTREAM_TAGS *tags;
const char *tag_key, *tag_val;
tags = vgmstream_tags_init(&tag_key, &tag_val);
vgmstream_tags_reset(tags, [filename UTF8String]);
while (vgmstream_tags_next_tag(tags, tagFile)) {
NSString *value = [NSString stringWithUTF8String:tag_val];
if (!strncasecmp(tag_key, "REPLAYGAIN_", strlen("REPLAYGAIN_"))) {
if (!strncasecmp(tag_key+strlen("REPLAYGAIN_"), "TRACK_", strlen("TRACK_"))) {
if (!strcasecmp(tag_key+strlen("REPLAYGAIN_TRACK_"), "GAIN")) {
rgTrackGain = [NSNumber numberWithFloat:[value floatValue]];
}
else if (!strcasecmp(tag_key+strlen("REPLAYGAIN_TRACK_"), "PEAK")) {
rgTrackPeak = [NSNumber numberWithFloat:[value floatValue]];
}
}
else if (!strncasecmp(tag_key+strlen("REPLAYGAIN_"), "ALBUM_", strlen("ALBUM_"))) {
if (!strcasecmp(tag_key+strlen("REPLAYGAIN_ALBUM_"), "GAIN")) {
rgAlbumGain = [NSNumber numberWithFloat:[value floatValue]];
}
else if (!strcasecmp(tag_key+strlen("REPLAYGAIN_ALBUM_"), "PEAK")) {
rgAlbumPeak = [NSNumber numberWithFloat:[value floatValue]];
}
}
}
else if (!strcasecmp(tag_key, "ALBUM")) {
album = value;
}
else if (!strcasecmp(tag_key, "ARTIST")) {
artist = value;
}
else if (!strcasecmp(tag_key, "DATE")) {
year = [NSNumber numberWithInt:[value intValue]];
}
else if (!strcasecmp(tag_key, "TRACK") ||
!strcasecmp(tag_key, "TRACKNUMBER")) {
track = [NSNumber numberWithInt:[value intValue]];
}
else if (!strcasecmp(tag_key, "TITLE")) {
title = value;
}
}
vgmstream_tags_close(tags);
close_streamfile(tagFile);
}
NSDictionary * properties =
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:bitrate / 1000], @"bitrate",
@@ -52,19 +114,31 @@
@"host", @"endian",
nil];

NSString * title;
if ( stream->num_streams > 1 ) {
title = [NSString stringWithFormat:@"%@ - %s", [[url URLByDeletingPathExtension] lastPathComponent], stream->stream_name];
} else {
title = [[url URLByDeletingPathExtension] lastPathComponent];
if ( [title isEqualToString:@""] ) {
if ( stream->num_streams > 1 ) {
title = [NSString stringWithFormat:@"%@ - %s", [[url URLByDeletingPathExtension] lastPathComponent], stream->stream_name];
} else {
title = [[url URLByDeletingPathExtension] lastPathComponent];
}
}
if ( [track isEqualToNumber:[NSNumber numberWithInt:0]] )
track = [NSNumber numberWithInt:track_num];

NSDictionary * metadata =
[NSDictionary dictionaryWithObjectsAndKeys:
NSMutableDictionary * mutableMetadata =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
title, @"title",
[NSNumber numberWithInt:track_num], @"track",
track, @"track",
nil];
if ( ![album isEqualToString:@""] )
[mutableMetadata setValue:album forKey:@"album"];
if ( ![artist isEqualToString:@""] )
[mutableMetadata setValue:artist forKey:@"artist"];
if ( ![year isEqualToNumber:[NSNumber numberWithInt:0]] )
[mutableMetadata setValue:year forKey:@"year"];
NSDictionary * metadata = mutableMetadata;

NSDictionary * package =
[NSDictionary dictionaryWithObjectsAndKeys:


+ 3
- 0
Plugins/vgmstream/vgmstream/VGMInterface.h View File

@@ -7,6 +7,7 @@
//

#import <libvgmstream/vgmstream.h>
#import <libvgmstream/plugins.h>

typedef struct _COGSTREAMFILE {
STREAMFILE sf;
@@ -15,4 +16,6 @@ typedef struct _COGSTREAMFILE {
char name[PATH_LIMIT];
} COGSTREAMFILE;

STREAMFILE *cogsf_create_from_url(NSURL * url);

VGMSTREAM *init_vgmstream_from_cogfile(const char *path, int subsong);

+ 6
- 2
Plugins/vgmstream/vgmstream/VGMInterface.m View File

@@ -81,10 +81,14 @@ static STREAMFILE *cogsf_create(id file, const char *path) {
}

STREAMFILE *cogsf_create_from_path(const char *path) {
id<CogSource> source;
NSString * urlString = [NSString stringWithUTF8String:path];
NSURL * url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
return cogsf_create_from_url(url);
}

STREAMFILE *cogsf_create_from_url(NSURL * url) {
id<CogSource> source;
id audioSourceClass = NSClassFromString(@"AudioSource");
source = [audioSourceClass audioSourceForURL:url];
@@ -94,7 +98,7 @@ STREAMFILE *cogsf_create_from_path(const char *path) {
if (![source seekable])
return 0;
return cogsf_create(source, path);
return cogsf_create(source, [[[url absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] UTF8String]);
}

VGMSTREAM *init_vgmstream_from_cogfile(const char *path, int subsong) {


Loading…
Cancel
Save