cog/Plugins/Hively/Hively/HVLDecoder.m

201 lines
4.0 KiB
Objective-C

//
// HVLDecoder.m
// Hively
//
// Created by Christopher Snowhill on 10/29/13.
// Copyright 2013 __NoWork, Inc__. All rights reserved.
//
#import "HVLDecoder.h"
#import "PlaylistController.h"
static void oneTimeInit(void) {
static BOOL initialized = NO;
if(!initialized) {
hvl_InitReplayer();
initialized = YES;
}
}
@implementation HVLDecoder
+ (void)initialize {
if([self class] == [HVLDecoder class])
oneTimeInit();
}
- (BOOL)open:(id<CogSource>)s {
[s seek:0 whence:SEEK_END];
long size = [s tell];
[s seek:0 whence:SEEK_SET];
if(size > UINT_MAX)
return NO;
void *data = malloc(size);
[s read:data amount:size];
tune = hvl_LoadTune(data, (uint32_t)size, 44100, 2);
free(data);
if(!tune)
return NO;
unsigned long safety = 2 * 60 * 60 * 50 * tune->ht_SpeedMultiplier;
NSURL *url = [s url];
if([[url fragment] length] == 0)
trackNumber = 0;
else
trackNumber = [[url fragment] intValue];
hvl_InitSubsong(tune, trackNumber);
unsigned long loops = 0;
while(loops < 2 && safety) {
while(!tune->ht_SongEndReached && safety) {
hvl_play_irq(tune);
--safety;
}
tune->ht_SongEndReached = 0;
++loops;
}
framesLength = tune->ht_PlayingTime * 44100 / (tune->ht_SpeedMultiplier * 50);
framesFade = 44100 * 8;
totalFrames = framesLength + framesFade;
framesRead = 0;
framesInBuffer = 0;
buffer = malloc(sizeof(int32_t) * (44100 / 50) * 2);
hvl_InitSubsong(tune, trackNumber);
[self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"];
return YES;
}
- (NSDictionary *)properties {
return @{ @"bitrate": @(0),
@"sampleRate": @(44100),
@"totalFrames": @(totalFrames),
@"bitsPerSample": @(32),
@"floatingPoint": @(YES),
@"channels": @(2),
@"seekable": @(YES),
@"endian": @"host",
@"encoding": @"synthesized" };
}
- (NSDictionary *)metadata {
return @{};
}
- (int)readAudio:(void *)buf frames:(UInt32)frames {
BOOL repeatone = IsRepeatOneSet();
if(!repeatone && framesRead >= totalFrames)
return 0;
int total = 0;
while(total < frames) {
if(framesInBuffer) {
float *outbuffer = ((float *)buf) + total * 2;
int framesToCopy = frames - total;
if(framesToCopy > framesInBuffer)
framesToCopy = (int)framesInBuffer;
for(int i = 0; i < framesToCopy; ++i) {
outbuffer[0] = buffer[i * 2 + 0] * (1.0f / 16777216.0f);
outbuffer[1] = buffer[i * 2 + 1] * (1.0f / 16777216.0f);
outbuffer += 2;
}
framesInBuffer -= framesToCopy;
total += framesToCopy;
if(framesInBuffer) {
memcpy(buffer, buffer + framesToCopy * 2, sizeof(int32_t) * framesInBuffer * 2);
break;
}
}
hvl_DecodeFrame(tune, (int8_t *)buffer, ((int8_t *)buffer) + 4, 8);
framesInBuffer = 44100 / 50;
}
if(!repeatone && framesRead + total > framesLength) {
long fadeStart = (framesLength > framesRead) ? framesLength : framesRead;
long fadeEnd = (framesRead + total) > totalFrames ? totalFrames : (framesRead + total);
long fadePos;
float *buff = (float *)buf;
float fadeScale = (float)(totalFrames - fadeStart) / (float)framesFade;
float fadeStep = 1.0 / (float)framesFade;
for(fadePos = fadeStart; fadePos < fadeEnd; ++fadePos) {
buff[0] *= fadeScale;
buff[1] *= fadeScale;
buff += 2;
fadeScale -= fadeStep;
if(fadeScale <= 0.0) break;
}
total = (int)(fadePos - fadeStart);
}
framesRead += total;
return total;
}
- (long)seek:(long)frame {
if(frame < framesRead) {
hvl_InitSubsong(tune, trackNumber);
framesRead = 0;
}
while(framesRead < frame) {
hvl_play_irq(tune);
framesRead += 44100 / 50;
}
return framesRead;
}
- (void)close {
if(tune) {
hvl_FreeTune(tune);
tune = NULL;
}
if(buffer) {
free(buffer);
buffer = NULL;
}
}
- (void)dealloc {
[self close];
}
+ (NSArray *)fileTypes {
return @[@"hvl", @"ahx"];
}
+ (NSArray *)fileTypeAssociations {
return @[
@[@"Hively Tracker File", @"song.icns", @"hvl"],
@[@"Abyss&apos; Highest eXperience File", @"song.icns", @"ahx"]
];
}
+ (NSArray *)mimeTypes {
return nil;
}
+ (float)priority {
return 1.0;
}
@end