libsidplayfp: Fix stereo playback, and implement support for multi-file songs, and fix stereo blending so it applies to the entire output
parent
f6f81c3083
commit
b32f9d4ac3
|
@ -18,4 +18,4 @@
|
||||||
url = https://github.com/shpakovski/MASShortcut.git
|
url = https://github.com/shpakovski/MASShortcut.git
|
||||||
[submodule "Frameworks/libsidplayfp/sidplayfp"]
|
[submodule "Frameworks/libsidplayfp/sidplayfp"]
|
||||||
path = Frameworks/libsidplayfp/sidplayfp
|
path = Frameworks/libsidplayfp/sidplayfp
|
||||||
url = https://github.com/libsidplayfp/libsidplayfp.git
|
url = https://github.com/kode54/libsidplayfp.git
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2dabc64539be158edcd913cdb4c5ef200c9c0fff
|
Subproject commit 80b72991b746bea85c992cc407e976a24fe76d64
|
|
@ -26,6 +26,9 @@
|
||||||
id<CogSource> source;
|
id<CogSource> source;
|
||||||
long length;
|
long length;
|
||||||
|
|
||||||
|
NSString *currentUrl;
|
||||||
|
BOOL hintAdded;
|
||||||
|
|
||||||
int n_channels;
|
int n_channels;
|
||||||
|
|
||||||
long renderedTotal;
|
long renderedTotal;
|
||||||
|
|
|
@ -16,20 +16,123 @@
|
||||||
|
|
||||||
#import "PlaylistController.h"
|
#import "PlaylistController.h"
|
||||||
|
|
||||||
@implementation SidDecoder
|
#include <vector>
|
||||||
|
|
||||||
- (BOOL)open:(id<CogSource>)s
|
static const char * extListEmpty[] = { NULL };
|
||||||
|
static const char * extListStr[] = { ".str", NULL };
|
||||||
|
|
||||||
|
@interface sid_file_container : NSObject {
|
||||||
|
NSLock * lock;
|
||||||
|
NSMutableDictionary * list;
|
||||||
|
}
|
||||||
|
+ (sid_file_container *)instance;
|
||||||
|
- (void)add_hint:(NSString *)path source:(id)source;
|
||||||
|
- (void)remove_hint:(NSString *)path;
|
||||||
|
- (BOOL)try_hint:(NSString *)path source:(id*)source;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation sid_file_container
|
||||||
|
+ (sid_file_container *)instance {
|
||||||
|
static sid_file_container * instance;
|
||||||
|
|
||||||
|
@synchronized(self) {
|
||||||
|
if (!instance) {
|
||||||
|
instance = [[self alloc] init];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
- (sid_file_container *)init
|
||||||
{
|
{
|
||||||
[self setSource:s];
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
lock = [[NSLock alloc] init];
|
||||||
|
list = [[NSMutableDictionary alloc] initWithCapacity:0];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)add_hint:(NSString *)path source:(id)source
|
||||||
|
{
|
||||||
|
[lock lock];
|
||||||
|
[list setObject:source forKey:path];
|
||||||
|
[lock unlock];
|
||||||
|
}
|
||||||
|
- (void)remove_hint:(NSString *)path
|
||||||
|
{
|
||||||
|
[lock lock];
|
||||||
|
[list removeObjectForKey:path];
|
||||||
|
[lock unlock];
|
||||||
|
}
|
||||||
|
- (BOOL)try_hint:(NSString *)path source:(id *)source
|
||||||
|
{
|
||||||
|
[lock lock];
|
||||||
|
*source = [list objectForKey:path];
|
||||||
|
[lock unlock];
|
||||||
|
if ( *source )
|
||||||
|
{
|
||||||
|
[ *source seek:0 whence:0 ];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static void sidTuneLoader(const char* fileName, std::vector<uint8_t>& bufferRef) {
|
||||||
|
id<CogSource> source;
|
||||||
|
if ( ![[sid_file_container instance] try_hint:[NSString stringWithUTF8String:fileName] source:&source] ) {
|
||||||
|
NSString * urlString = [NSString stringWithUTF8String:fileName];
|
||||||
|
NSURL * url = [NSURL URLWithDataRepresentation:[urlString dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil];
|
||||||
|
|
||||||
|
id audioSourceClass = NSClassFromString(@"AudioSource");
|
||||||
|
source = [audioSourceClass audioSourceForURL:url];
|
||||||
|
|
||||||
|
if (![source open:url])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (![source seekable])
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[source seek:0 whence:SEEK_END];
|
[source seek:0 whence:SEEK_END];
|
||||||
long size = [source tell];
|
long size = [source tell];
|
||||||
[source seek:0 whence:SEEK_SET];
|
[source seek:0 whence:SEEK_SET];
|
||||||
|
|
||||||
void * data = malloc(size);
|
bufferRef.resize( size );
|
||||||
[source read:data amount:size];
|
|
||||||
|
|
||||||
tune = new SidTune((const uint_least8_t *)data, (uint_least32_t)size);
|
[source read:&bufferRef[0] amount:size];
|
||||||
|
|
||||||
|
[source close];
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation SidDecoder
|
||||||
|
|
||||||
|
- (BOOL)open:(id<CogSource>)s
|
||||||
|
{
|
||||||
|
if (![s seekable])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[self setSource:s];
|
||||||
|
|
||||||
|
NSString * path = [[s url] absoluteString];
|
||||||
|
NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch];
|
||||||
|
if (fragmentRange.location != NSNotFound) {
|
||||||
|
path = [path substringToIndex:fragmentRange.location];
|
||||||
|
}
|
||||||
|
|
||||||
|
currentUrl = [path stringByRemovingPercentEncoding];
|
||||||
|
|
||||||
|
[[sid_file_container instance] add_hint:currentUrl source:s];
|
||||||
|
hintAdded = YES;
|
||||||
|
|
||||||
|
NSString * extension = [[s url] pathExtension];
|
||||||
|
|
||||||
|
const char ** extList = [extension isEqualToString:@"mus"] ? extListStr : extListEmpty;
|
||||||
|
|
||||||
|
tune = new SidTune([currentUrl UTF8String], extList, true, sidTuneLoader);
|
||||||
|
|
||||||
if (!tune->getStatus())
|
if (!tune->getStatus())
|
||||||
return NO;
|
return NO;
|
||||||
|
@ -41,7 +144,7 @@
|
||||||
else
|
else
|
||||||
track_num = [[url fragment] intValue];
|
track_num = [[url fragment] intValue];
|
||||||
|
|
||||||
n_channels = 2;
|
n_channels = 1;
|
||||||
|
|
||||||
length = 3 * 60 * 44100;
|
length = 3 * 60 * 44100;
|
||||||
|
|
||||||
|
@ -71,13 +174,21 @@
|
||||||
}
|
}
|
||||||
else return NO;
|
else return NO;
|
||||||
|
|
||||||
|
const SidTuneInfo *tuneInfo = tune->getInfo();
|
||||||
|
|
||||||
SidConfig conf = engine->config();
|
SidConfig conf = engine->config();
|
||||||
conf.frequency = 44100;
|
conf.frequency = 44100;
|
||||||
conf.playback = SidConfig::STEREO;
|
|
||||||
conf.sidEmulation = builder;
|
conf.sidEmulation = builder;
|
||||||
|
conf.playback = SidConfig::MONO;
|
||||||
|
if (tuneInfo && (tuneInfo->sidChips() > 1))
|
||||||
|
conf.playback = SidConfig::STEREO;
|
||||||
if (!engine->config(conf))
|
if (!engine->config(conf))
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
|
if (conf.playback == SidConfig::STEREO) {
|
||||||
|
n_channels = 2;
|
||||||
|
}
|
||||||
|
|
||||||
renderedTotal = 0;
|
renderedTotal = 0;
|
||||||
fadeTotal = fadeRemain = 44100 * 8;
|
fadeTotal = fadeRemain = 44100 * 8;
|
||||||
|
|
||||||
|
@ -114,12 +225,14 @@
|
||||||
if (rendered <= 0)
|
if (rendered <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (int i = 0; i < rendered; i += 2) {
|
if (n_channels == 2) {
|
||||||
int16_t * sample = sampleBuffer + total * 2 + i;
|
for (int i = 0, j = rendered * 2; i < j; i += 2) {
|
||||||
int mid = (sample[0] + sample[1]) / 2;
|
int16_t * sample = sampleBuffer + total * 2 + i;
|
||||||
int side = (sample[0] - sample[1]) / 4;
|
int mid = (int)(sample[0] + sample[1]) / 2;
|
||||||
sample[0] = mid + side;
|
int side = (int)(sample[0] - sample[1]) / 4;
|
||||||
sample[1] = mid - side;
|
sample[0] = mid + side;
|
||||||
|
sample[1] = mid - side;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderedTotal += rendered;
|
renderedTotal += rendered;
|
||||||
|
@ -217,6 +330,13 @@
|
||||||
delete tune;
|
delete tune;
|
||||||
tune = NULL;
|
tune = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source = nil;
|
||||||
|
if (hintAdded) {
|
||||||
|
[[sid_file_container instance] remove_hint:currentUrl];
|
||||||
|
hintAdded = NO;
|
||||||
|
}
|
||||||
|
currentUrl = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)close
|
- (void)close
|
||||||
|
|
Loading…
Reference in New Issue