From 3c351f6968dd440bc2102535f107e98a0e8e793b Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 10 Jul 2022 15:14:47 -0700 Subject: [PATCH] [Input API] Change input readAudio method readAudio now returns an AudioChunk object directly, and all inputs have been changed to accomodate this. Also, input and converter processing have been altered to better work with this. Signed-off-by: Christopher Snowhill --- Audio/Chain/AudioChunk.h | 2 + Audio/Chain/AudioChunk.m | 24 +++++ Audio/Chain/ConverterNode.m | 45 ++++----- Audio/Chain/InputNode.m | 74 +++++++-------- Audio/Chain/Node.h | 3 +- Audio/Chain/Node.m | 31 ++++++- Audio/CogPluginMulti.m | 6 +- Audio/Plugin.h | 4 +- Cog.xcodeproj/project.pbxproj | 2 + Plugins/APL/APL.xcodeproj/project.pbxproj | 2 + Plugins/APL/APLDecoder.m | 22 +++-- .../AdPlug/AdPlug.xcodeproj/project.pbxproj | 2 + Plugins/AdPlug/AdPlug/AdPlugDecoder.mm | 13 ++- .../ArchiveSource.xcodeproj/project.pbxproj | 2 + .../CoreAudio.xcodeproj/project.pbxproj | 2 + Plugins/CoreAudio/CoreAudioDecoder.m | 16 +++- .../CueSheet.xcodeproj/project.pbxproj | 2 + Plugins/CueSheet/CueSheetDecoder.m | 17 +++- .../FFMPEG/FFMPEG.xcodeproj/project.pbxproj | 2 + Plugins/FFMPEG/FFMPEGDecoder.h | 3 +- Plugins/FFMPEG/FFMPEGDecoder.m | 48 +++++----- .../FileSource.xcodeproj/project.pbxproj | 2 + Plugins/Flac/Flac.xcodeproj/project.pbxproj | 2 + Plugins/Flac/FlacDecoder.m | 44 +++------ Plugins/GME/GME.xcodeproj/project.pbxproj | 2 + Plugins/GME/GameDecoder.m | 17 +++- .../HTTPSource.xcodeproj/project.pbxproj | 2 + .../HighlyComplete.xcodeproj/project.pbxproj | 2 + .../HighlyComplete/HCDecoder.mm | 14 ++- .../Hively/Hively.xcodeproj/project.pbxproj | 2 + Plugins/Hively/Hively/HVLDecoder.m | 12 ++- Plugins/M3u/M3u.xcodeproj/project.pbxproj | 2 + Plugins/MAD/MAD.xcodeproj/project.pbxproj | 2 + Plugins/MAD/MADDecoder.m | 38 +++----- Plugins/MIDI/MIDI.xcodeproj/project.pbxproj | 2 + Plugins/MIDI/MIDI/MIDIDecoder.mm | 21 +++-- .../Musepack.xcodeproj/project.pbxproj | 2 + Plugins/Musepack/MusepackDecoder.m | 14 ++- .../OpenMPT/OpenMPT.xcodeproj/project.pbxproj | 2 + Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm | 12 ++- Plugins/Opus/Opus/OpusDecoder.m | 11 ++- .../Opus/OpusPlugin.xcodeproj/project.pbxproj | 2 + Plugins/Pls/Pls.xcodeproj/project.pbxproj | 2 + .../Shorten/Shorten.xcodeproj/project.pbxproj | 2 + Plugins/Shorten/ShortenDecoder.mm | 13 ++- .../SilenceDecoder.xcodeproj/project.pbxproj | 2 + .../SilenceDecoder/SilenceDecoder.m | 12 ++- .../TagLib/TagLib.xcodeproj/project.pbxproj | 4 + Plugins/Vorbis/VorbisDecoder.m | 13 ++- .../VorbisPlugin.xcodeproj/project.pbxproj | 2 + .../WavPack/WavPack.xcodeproj/project.pbxproj | 2 + Plugins/WavPack/WavPackDecoder.m | 15 ++- Plugins/libvgmPlayer/libvgmDecoder.mm | 17 +++- .../libvgmPlayer.xcodeproj/project.pbxproj | 2 + Plugins/sidplay/SidDecoder.mm | 91 +++++++++---------- .../sidplay/sidplay.xcodeproj/project.pbxproj | 2 + .../vgmstream.xcodeproj/project.pbxproj | 2 + Plugins/vgmstream/vgmstream/VGMDecoder.m | 13 ++- 58 files changed, 472 insertions(+), 251 deletions(-) diff --git a/Audio/Chain/AudioChunk.h b/Audio/Chain/AudioChunk.h index 29fce39e5..68942db0e 100644 --- a/Audio/Chain/AudioChunk.h +++ b/Audio/Chain/AudioChunk.h @@ -80,6 +80,7 @@ enum { + (uint32_t)findChannelIndex:(uint32_t)flag; - (id)init; +- (id)initWithProperties:(NSDictionary *)properties; - (void)assignSamples:(const void *)data frameCount:(size_t)count; @@ -88,6 +89,7 @@ enum { - (BOOL)isEmpty; - (size_t)frameCount; +- (void)setFrameCount:(size_t)count; // For truncation only - (double)duration; diff --git a/Audio/Chain/AudioChunk.m b/Audio/Chain/AudioChunk.m index 05130c506..adb72814f 100644 --- a/Audio/Chain/AudioChunk.m +++ b/Audio/Chain/AudioChunk.m @@ -7,6 +7,8 @@ #import "AudioChunk.h" +#import "CoreAudioUtils.h" + @implementation AudioChunk - (id)init { @@ -21,6 +23,18 @@ return self; } +- (id)initWithProperties:(NSDictionary *)properties { + self = [super init]; + + if(self) { + chunkData = [[NSMutableData alloc] init]; + [self setFormat:propertiesToASBD(properties)]; + lossless = [[properties objectForKey:@"encoding"] isEqualToString:@"lossless"]; + } + + return self; +} + static const uint32_t AudioChannelConfigTable[] = { 0, AudioConfigMono, @@ -156,6 +170,16 @@ static const uint32_t AudioChannelConfigTable[] = { return 0; } +- (void)setFrameCount:(size_t)count { + if(formatAssigned) { + count *= format.mBytesPerPacket; + size_t currentLength = [chunkData length]; + if(count < currentLength) { + [chunkData replaceBytesInRange:NSMakeRange(count, currentLength - count) withBytes:NULL length:0]; + } + } +} + - (double)duration { if(formatAssigned) { const size_t bytesPerPacket = format.mBytesPerPacket; diff --git a/Audio/Chain/ConverterNode.m b/Audio/Chain/ConverterNode.m index c0e427960..932fa0e73 100644 --- a/Audio/Chain/ConverterNode.m +++ b/Audio/Chain/ConverterNode.m @@ -432,34 +432,32 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes } - (void)process { - char writeBuf[CHUNK_SIZE]; - // Removed endOfStream check from here, since we want to be able to flush the converter // when the end of stream is reached. Convert function instead processes what it can, // and returns 0 samples when it has nothing more to process at the end of stream. while([self shouldContinue] == YES) { - int amountConverted; + AudioChunk *chunk = nil; while(paused) { usleep(500); } @autoreleasepool { - amountConverted = [self convert:writeBuf amount:CHUNK_SIZE]; + chunk = [self convert]; } - if(!amountConverted) { - if(paused) { - continue; - } else if(streamFormatChanged) { - [self cleanUp]; - [self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig isLossless:rememberedLossless]; - continue; - } else - break; + if(!chunk) { + continue; + } + @autoreleasepool { + [self writeChunk:chunk]; + chunk = nil; + } + if(streamFormatChanged) { + [self cleanUp]; + [self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig isLossless:rememberedLossless]; } - [self writeData:writeBuf amount:amountConverted]; } } -- (int)convert:(void *)dest amount:(int)amount { +- (AudioChunk *)convert { UInt32 ioNumberPackets; int amountReadFromFC; int amountRead = 0; @@ -472,7 +470,7 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes tryagain: if(stopping || [self shouldContinue] == NO) { convertEntered = NO; - return amountRead; + return nil; } amountReadFromFC = 0; @@ -543,7 +541,7 @@ tryagain: if(!bytesReadFromInput) { convertEntered = NO; - return amountRead; + return nil; } if(bytesReadFromInput && isBigEndian) { @@ -703,19 +701,22 @@ tryagain: if(floatOffset == floatSize) goto tryagain; - ioNumberPackets = (amount - amountRead); - if(ioNumberPackets > (floatSize - floatOffset)) - ioNumberPackets = (UInt32)(floatSize - floatOffset); + ioNumberPackets = (UInt32)(floatSize - floatOffset); ioNumberPackets -= ioNumberPackets % dmFloatFormat.mBytesPerPacket; - memcpy(((uint8_t *)dest) + amountRead, ((uint8_t *)floatBuffer) + floatOffset, ioNumberPackets); + AudioChunk *chunk = [[AudioChunk alloc] init]; + [chunk setFormat:nodeFormat]; + if(nodeChannelConfig) { + [chunk setChannelConfig:nodeChannelConfig]; + } + [chunk assignSamples:floatBuffer frameCount:ioNumberPackets / dmFloatFormat.mBytesPerPacket]; floatOffset += ioNumberPackets; amountRead += ioNumberPackets; convertEntered = NO; - return amountRead; + return chunk; } - (void)observeValueForKeyPath:(NSString *)keyPath diff --git a/Audio/Chain/InputNode.m b/Audio/Chain/InputNode.m index f5840a284..4a1fb9471 100644 --- a/Audio/Chain/InputNode.m +++ b/Audio/Chain/InputNode.m @@ -142,10 +142,6 @@ static void *kInputNodeContext = &kInputNodeContext; } - (void)process { - int amountInBuffer = 0; - int bytesInBuffer = 0; - void *inputBuffer = malloc(CHUNK_SIZE * 8 * 18); // Maximum 18 channels, dunno what we'll receive - BOOL shouldClose = YES; BOOL seekError = NO; @@ -165,7 +161,6 @@ static void *kInputNodeContext = &kInputNodeContext; ConverterNode *converter = [bufferChain converter]; DLog(@"SEEKING! Resetting Buffer"); - amountInBuffer = 0; // This resets the converter's buffer [self resetBuffer]; [converter resetBuffer]; @@ -174,7 +169,9 @@ static void *kInputNodeContext = &kInputNodeContext; DLog(@"Reset buffer!"); DLog(@"SEEKING!"); - seekError = [decoder seek:seekFrame] < 0; + @autoreleasepool { + seekError = [decoder seek:seekFrame] < 0; + } shouldSeek = NO; DLog(@"Seeked! Resetting Buffer"); @@ -185,44 +182,39 @@ static void *kInputNodeContext = &kInputNodeContext; } } - if(amountInBuffer < CHUNK_SIZE) { - int framesToRead = CHUNK_SIZE - amountInBuffer; - int framesRead; + AudioChunk *chunk; + @autoreleasepool { + chunk = [decoder readAudio]; + } + + if(chunk) { @autoreleasepool { - framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead]; + [self writeChunk:chunk]; + chunk = nil; + } + } else { + DLog(@"End of stream? %@", [self properties]); + + endOfStream = YES; + shouldClose = [controller endOfInputReached]; // Lets us know if we should keep going or not (occassionally, for track changes within a file) + DLog(@"closing? is %i", shouldClose); + + // Move this here, so that the above endOfInputReached has a chance to queue another track before starting output + // Technically, the output should still play out its buffer first before checking if it should stop + if(initialBufferFilled == NO) { + [controller initialBufferFilled:self]; } - if(framesRead > 0 && !seekError) { - amountInBuffer += framesRead; - bytesInBuffer += framesRead * bytesPerFrame; - [self writeData:inputBuffer amount:bytesInBuffer]; - amountInBuffer = 0; - bytesInBuffer = 0; + // wait before exiting, as we might still get seeking request + DLog("InputNode: Before wait") + [exitAtTheEndOfTheStream waitIndefinitely]; + DLog("InputNode: After wait, should seek = %d", shouldSeek); + if(shouldSeek) { + endOfStream = NO; + shouldClose = NO; + continue; } else { - DLog(@"End of stream? %@", [self properties]); - - endOfStream = YES; - shouldClose = [controller endOfInputReached]; // Lets us know if we should keep going or not (occassionally, for track changes within a file) - DLog(@"closing? is %i", shouldClose); - - // Move this here, so that the above endOfInputReached has a chance to queue another track before starting output - // Technically, the output should still play out its buffer first before checking if it should stop - if(initialBufferFilled == NO) { - [controller initialBufferFilled:self]; - } - - // wait before exiting, as we might still get seeking request - DLog("InputNode: Before wait") - [exitAtTheEndOfTheStream waitIndefinitely]; - DLog("InputNode: After wait, should seek = %d", shouldSeek); - if(shouldSeek) { - endOfStream = NO; - shouldClose = NO; - continue; - } - else { - break; - } + break; } } } @@ -230,8 +222,6 @@ static void *kInputNodeContext = &kInputNodeContext; if(shouldClose) [decoder close]; - free(inputBuffer); - [exitAtTheEndOfTheStream signal]; DLog("Input node thread stopping"); diff --git a/Audio/Chain/Node.h b/Audio/Chain/Node.h index 0e2feb2e2..12eca8726 100644 --- a/Audio/Chain/Node.h +++ b/Audio/Chain/Node.h @@ -19,7 +19,7 @@ ChunkList *buffer; Semaphore *semaphore; - NSRecursiveLock *accessLock; + NSLock *accessLock; id __weak previousNode; id __weak controller; @@ -37,6 +37,7 @@ - (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p; - (void)writeData:(const void *_Nonnull)ptr amount:(size_t)a; +- (void)writeChunk:(AudioChunk *_Nonnull)chunk; - (AudioChunk *_Nonnull)readChunk:(size_t)maxFrames; - (BOOL)peekFormat:(AudioStreamBasicDescription *_Nonnull)format channelConfig:(uint32_t *_Nonnull)config; diff --git a/Audio/Chain/Node.m b/Audio/Chain/Node.m index 3fc91b533..bef0b2b2a 100644 --- a/Audio/Chain/Node.m +++ b/Audio/Chain/Node.m @@ -25,7 +25,7 @@ buffer = [[ChunkList alloc] initWithMaximumDuration:3.0]; semaphore = [[Semaphore alloc] init]; - accessLock = [[NSRecursiveLock alloc] init]; + accessLock = [[NSLock alloc] init]; initialBufferFilled = NO; @@ -91,6 +91,35 @@ [accessLock unlock]; } +- (void)writeChunk:(AudioChunk *)chunk { + [accessLock lock]; + + const double chunkDuration = [chunk duration]; + double durationLeft = [buffer maxDuration] - [buffer listDuration]; + + while(shouldContinue == YES && chunkDuration > durationLeft) { + if(durationLeft < chunkDuration) { + if(initialBufferFilled == NO) { + initialBufferFilled = YES; + if([controller respondsToSelector:@selector(initialBufferFilled:)]) + [controller performSelector:@selector(initialBufferFilled:) withObject:self]; + } + } + + if(durationLeft < chunkDuration || shouldReset) { + [accessLock unlock]; + [semaphore wait]; + [accessLock lock]; + } + + durationLeft = [buffer maxDuration] - [buffer listDuration]; + } + + [buffer addChunk:chunk]; + + [accessLock unlock]; +} + // Should be overwriten by subclass. - (void)process { } diff --git a/Audio/CogPluginMulti.m b/Audio/CogPluginMulti.m index 66f2bdffb..6d4f88720 100644 --- a/Audio/CogPluginMulti.m +++ b/Audio/CogPluginMulti.m @@ -79,9 +79,9 @@ static void *kCogDecoderMultiContext = &kCogDecoderMultiContext; return @{}; } -- (int)readAudio:(void *)buffer frames:(UInt32)frames { - if(theDecoder != nil) return [theDecoder readAudio:buffer frames:frames]; - return 0; +- (AudioChunk *)readAudio { + if(theDecoder != nil) return [theDecoder readAudio]; + return nil; } - (BOOL)open:(id)source { diff --git a/Audio/Plugin.h b/Audio/Plugin.h index e3db69361..80e0748ed 100644 --- a/Audio/Plugin.h +++ b/Audio/Plugin.h @@ -1,5 +1,7 @@ // Plugins! HOORAY! +#import "AudioChunk.h" + @protocol CogSource + (NSArray *)schemes; // http, file, etc @@ -42,7 +44,7 @@ - (NSDictionary *)properties; - (NSDictionary *)metadata; // Only to be implemented for dynamic metadata, send events on change -- (int)readAudio:(void *)buffer frames:(UInt32)frames; +- (AudioChunk *)readAudio; - (BOOL)open:(id)source; - (long)seek:(long)frame; diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 686f1e86c..e277e4250 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -927,6 +927,7 @@ 83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libvgmPlayer.xcodeproj; path = Plugins/libvgmPlayer/libvgmPlayer.xcodeproj; sourceTree = ""; }; 8349270127B4EFFC0009AB2B /* duplicateItemsTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = duplicateItemsTemplate.pdf; path = Images/duplicateItemsTemplate.pdf; sourceTree = ""; }; 8349270B27B4EFFC0009AB2B /* deadItemsTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = deadItemsTemplate.pdf; path = Images/deadItemsTemplate.pdf; sourceTree = ""; }; + 834A42C4287B01B600EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = Audio/Chain/AudioChunk.h; sourceTree = SOURCE_ROOT; }; 834B05E82859C006000B7DC0 /* TotalTimeTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TotalTimeTransformer.h; path = Transformers/TotalTimeTransformer.h; sourceTree = ""; }; 834B05E92859C006000B7DC0 /* TotalTimeTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TotalTimeTransformer.m; path = Transformers/TotalTimeTransformer.m; sourceTree = ""; }; 8355D6B4180612F300D05687 /* NSData+MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+MD5.h"; sourceTree = ""; }; @@ -1227,6 +1228,7 @@ 177EC0110B8BC2CF0000BC8C /* Utils */ = { isa = PBXGroup; children = ( + 834A42C4287B01B600EB9D9B /* AudioChunk.h */, 8384912518080F2D00E7332D /* Logging.h */, 07E18DF10D62B38400BB0E11 /* NSArray+ShuffleUtils.h */, 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */, diff --git a/Plugins/APL/APL.xcodeproj/project.pbxproj b/Plugins/APL/APL.xcodeproj/project.pbxproj index 0d18a4c92..4cbe91672 100644 --- a/Plugins/APL/APL.xcodeproj/project.pbxproj +++ b/Plugins/APL/APL.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 32DBCF630370AF2F00C91783 /* APL_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APL_Prefix.pch; sourceTree = ""; }; + 834A42AF287AF34300EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747FE32862E8B60021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 838491281808135500E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -74,6 +75,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42AF287AF34300EB9D9B /* AudioChunk.h */, 838491281808135500E7332D /* Logging.h */, 8E8D423C0CBB0FF600135C1B /* Plugin.h */, 8E8D42350CBB0F9800135C1B /* APLDecoder.h */, diff --git a/Plugins/APL/APLDecoder.m b/Plugins/APL/APLDecoder.m index 9fc7fd36d..da93d0f19 100644 --- a/Plugins/APL/APLDecoder.m +++ b/Plugins/APL/APLDecoder.m @@ -108,18 +108,24 @@ return framePosition; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { - if(framePosition + frames > trackEnd) - frames = (UInt32)(trackEnd - framePosition); +- (AudioChunk *)readAudio { + int maxFrames = INT_MAX; - if(!frames) { + if(framePosition + maxFrames > trackEnd) + maxFrames = (int)(trackEnd - framePosition); + + if(!maxFrames) { DLog(@"APL readAudio Returning 0"); - return 0; + return nil; } - int n = [decoder readAudio:buf frames:frames]; - framePosition += n; - return n; + AudioChunk *chunk = [decoder readAudio]; + if(chunk.frameCount > maxFrames) { + [chunk setFrameCount:maxFrames]; + } + + framePosition += chunk.frameCount; + return chunk; } - (BOOL)isSilence { diff --git a/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj b/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj index 427939dd4..cacfb9829 100644 --- a/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj +++ b/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ /* Begin PBXFileReference section */ 833A8999286FF2FD0022E036 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 834A42AE287AF27A00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747C6D2862DDDB0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83D3C5F3201C674D005564CB /* AdPlug.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AdPlug.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 83D3C5F6201C674D005564CB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -123,6 +124,7 @@ 83D3C5F5201C674D005564CB /* AdPlug */ = { isa = PBXGroup; children = ( + 834A42AE287AF27A00EB9D9B /* AudioChunk.h */, 83D3C667201C7020005564CB /* adplug.db */, 83D3C657201C6E24005564CB /* AdPlugContainer.h */, 83D3C654201C6E24005564CB /* AdPlugContainer.mm */, diff --git a/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm b/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm index 6e57a2263..6e4d0033f 100644 --- a/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm +++ b/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm @@ -103,7 +103,14 @@ static CAdPlugDatabase *g_database = NULL; return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + int frames = 1024; + int16_t buffer[1024 * 2]; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + void *buf = (void *)buffer; + int total = 0; bool dont_loop = !IsRepeatOneSet(); if(dont_loop && current_pos + frames > length) @@ -128,7 +135,9 @@ static CAdPlugDatabase *g_database = NULL; total += samples_now; } - return total; + [chunk assignSamples:buffer frameCount:total]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/ArchiveSource/ArchiveSource.xcodeproj/project.pbxproj b/Plugins/ArchiveSource/ArchiveSource.xcodeproj/project.pbxproj index 66890f936..3fb853ae2 100644 --- a/Plugins/ArchiveSource/ArchiveSource.xcodeproj/project.pbxproj +++ b/Plugins/ArchiveSource/ArchiveSource.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ /* Begin PBXFileReference section */ 8307D31A286070EA000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../../Utils/SandboxBroker.h; sourceTree = ""; }; + 834A42B0287AF4BF00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8359009717FEF6490060F3ED /* ArchiveSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchiveSource.h; sourceTree = ""; }; 8359009817FEF6490060F3ED /* ArchiveSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArchiveSource.m; sourceTree = ""; }; 8359009A17FEFDA80060F3ED /* ArchiveContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchiveContainer.h; sourceTree = ""; }; @@ -105,6 +106,7 @@ 8359FF2017FEF35C0060F3ED /* ArchiveSource */ = { isa = PBXGroup; children = ( + 834A42B0287AF4BF00EB9D9B /* AudioChunk.h */, 8307D31A286070EA000FF8EB /* SandboxBroker.h */, 8384913518081BA000E7332D /* Logging.h */, 835900A017FF079C0060F3ED /* Plugin.h */, diff --git a/Plugins/CoreAudio/CoreAudio.xcodeproj/project.pbxproj b/Plugins/CoreAudio/CoreAudio.xcodeproj/project.pbxproj index 5ac7741a0..08b340b05 100644 --- a/Plugins/CoreAudio/CoreAudio.xcodeproj/project.pbxproj +++ b/Plugins/CoreAudio/CoreAudio.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 17C93EAB0B8FF3CE008627D6 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; 17C93EB20B8FF3E1008627D6 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; 32DBCF630370AF2F00C91783 /* CoreAudio_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreAudio_Prefix.pch; sourceTree = ""; }; + 834A42B1287AF4D900EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747C5E2862DD880021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83849129180813E800E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* CoreAudio.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreAudio.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -77,6 +78,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42B1287AF4D900EB9D9B /* AudioChunk.h */, 83849129180813E800E7332D /* Logging.h */, 177FCFCA0B90C9A10011C3B5 /* Plugin.h */, 17C93E720B8FF192008627D6 /* CoreAudioDecoder.h */, diff --git a/Plugins/CoreAudio/CoreAudioDecoder.m b/Plugins/CoreAudio/CoreAudioDecoder.m index 854115ab2..e343427fa 100644 --- a/Plugins/CoreAudio/CoreAudioDecoder.m +++ b/Plugins/CoreAudio/CoreAudioDecoder.m @@ -306,25 +306,33 @@ static SInt64 getSizeProc(void *clientData) { return YES; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { OSStatus err; AudioBufferList bufferList; UInt32 frameCount; + int frames = 1024; + size_t bytesPerFrame = channels * (bitsPerSample / 8); + uint8_t buffer[frames * bytesPerFrame]; + // Set up the AudioBufferList bufferList.mNumberBuffers = 1; bufferList.mBuffers[0].mNumberChannels = channels; - bufferList.mBuffers[0].mData = buf; + bufferList.mBuffers[0].mData = buffer; bufferList.mBuffers[0].mDataByteSize = frames * channels * (bitsPerSample / 8); // Read a chunk of PCM input (converted from whatever format) frameCount = frames; err = ExtAudioFileRead(_in, &frameCount, &bufferList); if(err != noErr) { - return 0; + return nil; } - return frameCount; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:frameCount]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj b/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj index c6da499f9..502a71937 100644 --- a/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj +++ b/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 17DA346D0CC04FCD0003F6B2 /* CueSheetMetadataReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CueSheetMetadataReader.m; sourceTree = ""; }; 32DBCF630370AF2F00C91783 /* CueSheet_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CueSheet_Prefix.pch; sourceTree = ""; }; 833F68371CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42B2287AF59900EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 835C888E22CC1883001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 83747C592862DD660021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8384912A180814D900E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; @@ -89,6 +90,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42B2287AF59900EB9D9B /* AudioChunk.h */, 839DA7D3274A2FD4001B18E5 /* NSDictionary+Merge.h */, 839DA7D0274A2EA9001B18E5 /* AudioMetadataReader.h */, 8384912A180814D900E7332D /* Logging.h */, diff --git a/Plugins/CueSheet/CueSheetDecoder.m b/Plugins/CueSheet/CueSheetDecoder.m index 8d3f8e6e4..c32fdba41 100644 --- a/Plugins/CueSheet/CueSheetDecoder.m +++ b/Plugins/CueSheet/CueSheetDecoder.m @@ -309,25 +309,32 @@ static void *kCueSheetDecoderContext = &kCueSheetDecoderContext; return framePosition - trackStart; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { if(!seekedToStart) { [self seek:0]; } + int frames = INT_MAX; + if(!noFragment && framePosition + frames > trackEnd) { frames = (UInt32)(trackEnd - framePosition); } if(!frames) { DLog(@"Returning 0"); - return 0; + return nil; } - int n = [decoder readAudio:buf frames:frames]; + AudioChunk *chunk = [decoder readAudio]; - framePosition += n; + size_t n = chunk.frameCount; + if(n > frames) { + [chunk setFrameCount:frames]; + } - return n; + framePosition += chunk.frameCount; + + return chunk; } - (BOOL)isSilence { diff --git a/Plugins/FFMPEG/FFMPEG.xcodeproj/project.pbxproj b/Plugins/FFMPEG/FFMPEG.xcodeproj/project.pbxproj index 512b32c73..c560f028c 100644 --- a/Plugins/FFMPEG/FFMPEG.xcodeproj/project.pbxproj +++ b/Plugins/FFMPEG/FFMPEG.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ 089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 834A42B3287AF65000EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8352D48E1CDDB023009D16AA /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 8352D4901CDDB02A009D16AA /* VideoDecodeAcceleration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoDecodeAcceleration.framework; path = System/Library/Frameworks/VideoDecodeAcceleration.framework; sourceTree = SDKROOT; }; 8352D4921CDDB034009D16AA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; @@ -145,6 +146,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42B3287AF65000EB9D9B /* AudioChunk.h */, 8356BD1A27B3D06F0074E50C /* HTTPSource.h */, 8356BCEA27B37DA40074E50C /* TagLibID3v2Reader.h */, 8356BCE827B37C6F0074E50C /* NSDictionary+Merge.h */, diff --git a/Plugins/FFMPEG/FFMPEGDecoder.h b/Plugins/FFMPEG/FFMPEGDecoder.h index cd546d50e..2d62c0e7e 100644 --- a/Plugins/FFMPEG/FFMPEGDecoder.h +++ b/Plugins/FFMPEG/FFMPEGDecoder.h @@ -45,8 +45,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence); BOOL metadataUpdated; - int prebufferedAudio; - uint8_t *prebufferedAudioData; + AudioChunk *prebufferedChunk; BOOL rawDSD; BOOL rawDSDReverseBits; diff --git a/Plugins/FFMPEG/FFMPEGDecoder.m b/Plugins/FFMPEG/FFMPEGDecoder.m index 463e1ba1e..20557dd58 100644 --- a/Plugins/FFMPEG/FFMPEGDecoder.m +++ b/Plugins/FFMPEG/FFMPEGDecoder.m @@ -471,13 +471,10 @@ static uint8_t reverse_bits[0x100]; metadataUpdated = NO; [self updateMetadata]; - prebufferedAudio = 0; - prebufferedAudioData = NULL; + prebufferedChunk = nil; if(attachedPicIndex >= 0) { - int frameSize = rawDSD ? channels : channels * (bitsPerSample / 8); - prebufferedAudioData = malloc(1024 * frameSize); - [self readAudio:prebufferedAudioData frames:1024]; + prebufferedChunk = [self readAudio]; } return YES; @@ -681,30 +678,31 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va } } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { if(!seekedToStart) { [self seek:0]; } + if(prebufferedChunk) { + // A bit of ignored read-ahead to support embedded artwork + size_t framesReadNow = prebufferedChunk.frameCount; + framesRead -= framesReadNow; + AudioChunk *chunk = prebufferedChunk; + prebufferedChunk = nil; + return chunk; + } + + if(totalFrames && framesRead >= totalFrames) + return nil; + + int frames = 1024; + int frameSize = rawDSD ? channels : channels * (bitsPerSample / 8); int bytesToRead = frames * frameSize; int bytesRead = 0; - if(prebufferedAudio) { - // A bit of ignored read-ahead to support embedded artwork - int bytesBuffered = prebufferedAudio * frameSize; - int bytesToCopy = (bytesBuffered > bytesToRead) ? bytesToRead : bytesBuffered; - memcpy(buf, prebufferedAudioData, bytesToCopy); - memmove(prebufferedAudioData, prebufferedAudioData + bytesToCopy, bytesBuffered - bytesToCopy); - prebufferedAudio -= bytesToCopy / frameSize; - bytesRead = bytesToCopy; - - int framesReadNow = bytesRead / frameSize; - framesRead -= framesReadNow; - } - - if(totalFrames && framesRead >= totalFrames) - return 0; + uint8_t buffer[bytesToRead]; + void *buf = (void *)buffer; int dataSize = 0; @@ -909,7 +907,11 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va framesRead += framesReadNow; - return framesReadNow; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:framesReadNow]; + + return chunk; } - (long)seek:(long)frame { @@ -918,7 +920,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va seekedToStart = YES; - prebufferedAudio = 0; + prebufferedChunk = nil; if(frame >= totalFrames) { framesRead = totalFrames; diff --git a/Plugins/FileSource/FileSource.xcodeproj/project.pbxproj b/Plugins/FileSource/FileSource.xcodeproj/project.pbxproj index 669bcbadc..2ccd0a398 100644 --- a/Plugins/FileSource/FileSource.xcodeproj/project.pbxproj +++ b/Plugins/FileSource/FileSource.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 32DBCF630370AF2F00C91783 /* FileSource_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileSource_Prefix.pch; sourceTree = ""; }; 8307D31B2860722C000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../Utils/SandboxBroker.h; sourceTree = ""; }; 8335FF6817FF765A002D8DD2 /* File_Extractor.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = File_Extractor.xcodeproj; path = ../../Frameworks/File_Extractor/File_Extractor.xcodeproj; sourceTree = ""; }; + 834A42AD287AF25600EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747C4F2862DD2F0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* FileSource.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FileSource.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -91,6 +92,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42AD287AF25600EB9D9B /* AudioChunk.h */, 8307D31B2860722C000FF8EB /* SandboxBroker.h */, 17ADB4080B979A8A00257CA2 /* Plugin.h */, 17ADB4180B979AEB00257CA2 /* FileSource.h */, diff --git a/Plugins/Flac/Flac.xcodeproj/project.pbxproj b/Plugins/Flac/Flac.xcodeproj/project.pbxproj index 8781fe57d..a7265f2d1 100644 --- a/Plugins/Flac/Flac.xcodeproj/project.pbxproj +++ b/Plugins/Flac/Flac.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 32DBCF630370AF2F00C91783 /* Flac_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Flac_Prefix.pch; sourceTree = ""; }; 8301C145287805F500651A6E /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../Utils/NSDictionary+Merge.h"; sourceTree = ""; }; 8301C146287805F500651A6E /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Merge.m"; path = "../../Utils/NSDictionary+Merge.m"; sourceTree = ""; }; + 834A42B4287AF7AA00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8356BD1927B3CCBB0074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = ""; }; 836EF0D927BB970B00BF35B2 /* libFLAC.8.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libFLAC.8.dylib; path = ../../ThirdParty/flac/lib/libFLAC.8.dylib; sourceTree = ""; }; 83747C4A2862DCF40021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; @@ -92,6 +93,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42B4287AF7AA00EB9D9B /* AudioChunk.h */, 8301C145287805F500651A6E /* NSDictionary+Merge.h */, 8301C146287805F500651A6E /* NSDictionary+Merge.m */, 83AA660A27B7DAE40098D4B8 /* cuesheet.m */, diff --git a/Plugins/Flac/FlacDecoder.m b/Plugins/Flac/FlacDecoder.m index 876682d9e..f594cec6d 100644 --- a/Plugins/Flac/FlacDecoder.m +++ b/Plugins/Flac/FlacDecoder.m @@ -361,39 +361,23 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS return YES; } -- (int)readAudio:(void *)buffer frames:(UInt32)frames { - int framesRead = 0; - while(framesRead < frames) { - if(blockBufferFrames == 0) { - if(framesRead) { - break; - } +- (AudioChunk *)readAudio { + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = nil; - if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) { - break; - } + if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) { + return nil; + } - if(!FLAC__stream_decoder_process_single(decoder)) { - break; - } - } + if(!FLAC__stream_decoder_process_single(decoder)) { + return nil; + } - int bytesPerFrame = ((bitsPerSample + 7) / 8) * channels; + if(blockBufferFrames > 0) { + chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:blockBuffer frameCount:blockBufferFrames]; - int framesToRead = blockBufferFrames; - if(blockBufferFrames > frames) { - framesToRead = frames; - } - - memcpy(((uint8_t *)buffer) + (framesRead * bytesPerFrame), (uint8_t *)blockBuffer, framesToRead * bytesPerFrame); - - frames -= framesToRead; - framesRead += framesToRead; - blockBufferFrames -= framesToRead; - - if(blockBufferFrames > 0) { - memmove((uint8_t *)blockBuffer, ((uint8_t *)blockBuffer) + (framesToRead * bytesPerFrame), blockBufferFrames * bytesPerFrame); - } + blockBufferFrames = 0; } if(![source seekable]) { @@ -429,7 +413,7 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS } } - return framesRead; + return chunk; } - (void)close { diff --git a/Plugins/GME/GME.xcodeproj/project.pbxproj b/Plugins/GME/GME.xcodeproj/project.pbxproj index 010a16d66..4aa981e84 100644 --- a/Plugins/GME/GME.xcodeproj/project.pbxproj +++ b/Plugins/GME/GME.xcodeproj/project.pbxproj @@ -63,6 +63,7 @@ 8319C74E237629D300BFFAE0 /* GamePropertiesReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GamePropertiesReader.h; sourceTree = ""; }; 8319C74F237629D400BFFAE0 /* GamePropertiesReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GamePropertiesReader.m; sourceTree = ""; }; 833F68351CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42B5287AF8FE00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 835C888F22CC1883001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 83747C452862DCD90021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8384912E1808175400E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; @@ -119,6 +120,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42B5287AF8FE00EB9D9B /* AudioChunk.h */, 17C8F33B0CBED3BE008D969D /* GameContainer.h */, 17C8F33C0CBED3BE008D969D /* GameContainer.m */, 17C8F33D0CBED3BE008D969D /* GameDecoder.h */, diff --git a/Plugins/GME/GameDecoder.m b/Plugins/GME/GameDecoder.m index cec7ae0fa..528669e23 100644 --- a/Plugins/GME/GameDecoder.m +++ b/Plugins/GME/GameDecoder.m @@ -174,11 +174,18 @@ gme_err_t readCallback(void *data, void *out, int count) { return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + int frames = 1024; + int16_t buffer[frames * 2]; + void *buf = (void *)buffer; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + int numSamples = frames * 2; // channels = 2 if(gme_track_ended(emu)) { - return 0; + return nil; } if(IsRepeatOneSet()) @@ -190,7 +197,11 @@ gme_err_t readCallback(void *data, void *out, int count) { // Some formats support length, but we'll add that in the future. //(From gme.txt) If track length, then use it. If loop length, play for intro + loop * 2. Otherwise, default to 2.5 minutes - return frames; // GME will always generate samples. There's no real EOS. + // GME will always generate samples. There's no real EOS. + + [chunk assignSamples:buffer frameCount:numSamples]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj b/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj index 73695ae71..93628d75a 100644 --- a/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj +++ b/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 17ADB60C0B97A74800257CA2 /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HTTPSource.h; sourceTree = ""; }; 17ADB6340B97A8B400257CA2 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = SOURCE_ROOT; }; 32DBCF630370AF2F00C91783 /* HTTPSource_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPSource_Prefix.pch; sourceTree = ""; }; + 834A42B9287AFAB500EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8356BD1727B3B7340074E50C /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; 83747C362862DC0D0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8384912F1808180000E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; @@ -87,6 +88,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42B9287AFAB500EB9D9B /* AudioChunk.h */, 8384912F1808180000E7332D /* Logging.h */, 17ADB6340B97A8B400257CA2 /* Plugin.h */, 17ADB60C0B97A74800257CA2 /* HTTPSource.h */, diff --git a/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj b/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj index 95ea4807c..90c114974 100644 --- a/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj +++ b/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj @@ -190,6 +190,7 @@ 8343790C17F96E2600584396 /* HighlyQuixotic.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyQuixotic.xcodeproj; path = ../../Frameworks/HighlyQuixotic/HighlyQuixotic.xcodeproj; sourceTree = ""; }; 8343796317F97BDB00584396 /* HighlyAdvanced.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyAdvanced.xcodeproj; path = ../../Frameworks/HighlyAdvanced/HighlyAdvanced.xcodeproj; sourceTree = ""; }; 834379A717F9818400584396 /* HCDecoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HCDecoder.mm; sourceTree = ""; }; + 834A42B6287AF99600EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8360EEE417F92AC8005208A4 /* HighlyComplete.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HighlyComplete.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 8360EEE717F92AC8005208A4 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 8360EEEA17F92AC8005208A4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -311,6 +312,7 @@ 8360EEED17F92AC8005208A4 /* HighlyComplete */ = { isa = PBXGroup; children = ( + 834A42B6287AF99600EB9D9B /* AudioChunk.h */, 83AA660827B7CCB00098D4B8 /* Logging.h */, 83FAF8A318ADD27F00057CAF /* PlaylistController.h */, 8324C584181513A10046F78F /* circular_buffer.h */, diff --git a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm index 432a219a2..1bcaafe87 100644 --- a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm +++ b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm @@ -72,7 +72,7 @@ - (psf_file_container *)init { if((self = [super init])) { lock = [[NSLock alloc] init]; - list = [[NSMutableDictionary alloc] initWithCapacity:0]; + list = [[NSMutableDictionary alloc] init]; } return self; } @@ -1302,7 +1302,7 @@ static int usf_info(void *context, const char *name, const char *value) { return frames; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { if(!emulatorCore) { if(![self initializeDecoder]) return 0; @@ -1314,6 +1314,10 @@ static int usf_info(void *context, const char *name, const char *value) { usfRemoveSilence = NO; } + int frames = 1024; + int16_t buffer[frames * 2]; + void *buf = (void *)buffer; + unsigned long written = silence_test_buffer.data_available() / 2; if(written > frames) written = frames; @@ -1342,7 +1346,11 @@ static int usf_info(void *context, const char *name, const char *value) { framesRead += written; - return (int)written; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:written]; + + return chunk; } - (void)closeDecoder { diff --git a/Plugins/Hively/Hively.xcodeproj/project.pbxproj b/Plugins/Hively/Hively.xcodeproj/project.pbxproj index b779471a6..0e4551046 100644 --- a/Plugins/Hively/Hively.xcodeproj/project.pbxproj +++ b/Plugins/Hively/Hively.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ /* Begin PBXFileReference section */ 831C7F6918ADD73F00CE4A69 /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = ""; }; 833F68471CDBCABF00AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42B8287AFA3600EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 836FB52D1820538700B3AD2D /* Hively.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Hively.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 836FB5301820538700B3AD2D /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 836FB5331820538700B3AD2D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -122,6 +123,7 @@ 836FB5361820538700B3AD2D /* Hively */ = { isa = PBXGroup; children = ( + 834A42B8287AFA3600EB9D9B /* AudioChunk.h */, 831C7F6918ADD73F00CE4A69 /* PlaylistController.h */, 836FB5A31820557E00B3AD2D /* Plugin.h */, 836FB59A1820556F00B3AD2D /* HVLDecoder.h */, diff --git a/Plugins/Hively/Hively/HVLDecoder.m b/Plugins/Hively/Hively/HVLDecoder.m index d6747800b..b56c4ad98 100644 --- a/Plugins/Hively/Hively/HVLDecoder.m +++ b/Plugins/Hively/Hively/HVLDecoder.m @@ -107,7 +107,11 @@ static void oneTimeInit(void) { return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + int frames = 1024; + float buffer[frames * 2]; + void *buf = (void *)buffer; + BOOL repeatone = IsRepeatOneSet(); if(!repeatone && framesRead >= totalFrames) @@ -157,7 +161,11 @@ static void oneTimeInit(void) { framesRead += total; - return total; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:total]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/M3u/M3u.xcodeproj/project.pbxproj b/Plugins/M3u/M3u.xcodeproj/project.pbxproj index f7b79b86e..00b256b23 100644 --- a/Plugins/M3u/M3u.xcodeproj/project.pbxproj +++ b/Plugins/M3u/M3u.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 32DBCF630370AF2F00C91783 /* M3u_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = M3u_Prefix.pch; sourceTree = ""; }; 833F68391CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42BA287AFAEF00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 835C889122CC1885001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 83747C2C2862DBBE0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83849130180818B100E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; @@ -75,6 +76,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42BA287AFAEF00EB9D9B /* AudioChunk.h */, 83849130180818B100E7332D /* Logging.h */, 8E8D401B0CBAFEF200135C1B /* Plugin.h */, 8E8D40270CBAFF4300135C1B /* M3uContainer.h */, diff --git a/Plugins/MAD/MAD.xcodeproj/project.pbxproj b/Plugins/MAD/MAD.xcodeproj/project.pbxproj index b1fc88e11..38917b0ad 100644 --- a/Plugins/MAD/MAD.xcodeproj/project.pbxproj +++ b/Plugins/MAD/MAD.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 834A42BB287AFB0700EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8372C92327C785BD00E250C9 /* MAD.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MAD.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 8372C93327C7861300E250C9 /* MADDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MADDecoder.h; sourceTree = ""; }; 8372C93427C7861300E250C9 /* MADDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MADDecoder.m; sourceTree = ""; }; @@ -48,6 +49,7 @@ children = ( 83747C262862DB9F0021245F /* Xcode-config */, 83F97B6628600F9300A70B97 /* ThirdParty */, + 834A42BB287AFB0700EB9D9B /* AudioChunk.h */, 8372C93A27C786DD00E250C9 /* HTTPSource.h */, 8372C93927C7866B00E250C9 /* Logging.h */, 8372C93827C7865A00E250C9 /* Plugin.h */, diff --git a/Plugins/MAD/MADDecoder.m b/Plugins/MAD/MADDecoder.m index 52b8cc680..2136f14ae 100644 --- a/Plugins/MAD/MADDecoder.m +++ b/Plugins/MAD/MADDecoder.m @@ -651,7 +651,7 @@ return 1; } -- (BOOL)syncFormat:(BOOL)updateNow { +- (BOOL)syncFormat { float _sampleRate = _frame.header.samplerate; int _channels = MAD_NCHANNELS(&_frame.header); int _layer = 3; @@ -674,7 +674,7 @@ _channels != channels || _layer != layer); - if(changed && updateNow) { + if(changed) { sampleRate = _sampleRate; channels = _channels; layer = _layer; @@ -686,29 +686,24 @@ return changed; } -- (int)readAudio:(void *)buffer frames:(UInt32)frames { +- (AudioChunk *)readAudio { int framesRead = 0; if(!_firstFrame) - [self syncFormat:YES]; + [self syncFormat]; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = nil; for(;;) { - long framesRemaining = frames - framesRead; - long framesToCopy = (_outputFrames > framesRemaining ? framesRemaining : _outputFrames); + long framesToCopy = _outputFrames; if(framesToCopy) { - memcpy(buffer + (framesRead * channels * sizeof(float)), _outputBuffer, framesToCopy * channels * sizeof(float)); - framesRead += framesToCopy; - - if(framesToCopy != _outputFrames) { - memmove(_outputBuffer, _outputBuffer + (framesToCopy * channels), (_outputFrames - framesToCopy) * channels * sizeof(float)); - } - - _outputFrames -= framesToCopy; - } - - if(framesRead == frames) + chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:_outputBuffer frameCount:framesToCopy]; + _outputFrames = 0; break; + } int r = [self decodeMPEGFrame]; // DLog(@"Decoding frame: %i", r); @@ -720,18 +715,13 @@ [self writeOutput]; // DLog(@"Wrote output"); - if([self syncFormat:NO]) { - if(framesRead) - break; - else - [self syncFormat:YES]; - } + [self syncFormat]; } [self updateMetadata]; // DLog(@"Read: %i/%i", bytesRead, size); - return framesRead; + return chunk; } - (void)close { diff --git a/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj b/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj index 66fe9f117..1fd5879e0 100644 --- a/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj +++ b/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj @@ -99,6 +99,7 @@ 831E2A9427B4B2FA006F1C86 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = ""; }; 831E2A9527B4B2FA006F1C86 /* json-builder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "json-builder.h"; sourceTree = ""; }; 833F68431CDBCABE00AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42BC287AFC7F00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 834BE9191DE407CB00A07DCD /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = ""; }; 834BE91A1DE407CB00A07DCD /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; 8356BCC427B352620074E50C /* BMPlayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BMPlayer.cpp; sourceTree = ""; }; @@ -306,6 +307,7 @@ 83B06690180D5668008E3612 /* MIDI */ = { isa = PBXGroup; children = ( + 834A42BC287AFC7F00EB9D9B /* AudioChunk.h */, 8307D31E28607377000FF8EB /* SandboxBroker.h */, 831E2A9127B4B2FA006F1C86 /* json */, 831E2A7D27B4B2B2006F1C86 /* BASS */, diff --git a/Plugins/MIDI/MIDI/MIDIDecoder.mm b/Plugins/MIDI/MIDI/MIDIDecoder.mm index 1da27f543..2e7b01a60 100644 --- a/Plugins/MIDI/MIDI/MIDIDecoder.mm +++ b/Plugins/MIDI/MIDI/MIDIDecoder.mm @@ -276,14 +276,14 @@ static OSType getOSType(const char *in_) { return YES; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { BOOL repeatone = IsRepeatOneSet(); long localFramesLength = framesLength; long localTotalFrames = totalFrames; if(!player) { if(![self initDecoder]) - return -1; + return nil; } player->setLoopMode((repeatone || isLooped) ? (MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force) : 0); @@ -302,7 +302,10 @@ static OSType getOSType(const char *in_) { soundFontsAssigned = YES; } - UInt32 frames_done = player->Play((float *)buf, frames); + int frames = 1024; + float buffer[frames * 2]; + + UInt32 frames_done = player->Play(buffer, frames); if(!frames_done) return 0; @@ -315,7 +318,7 @@ static OSType getOSType(const char *in_) { long fadeEnd = (framesRead + frames > localTotalFrames) ? localTotalFrames : (framesRead + frames); long fadePos; - float *buff = (float *)buf; + float *buff = buffer; float fadeScale = (float)(framesFade - (fadeStart - localFramesLength)) / framesFade; float fadeStep = 1.0 / (float)framesFade; @@ -337,13 +340,17 @@ static OSType getOSType(const char *in_) { } framesRead += frames; - return frames; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:frames]; + + return chunk; } - (long)seek:(long)frame { if(!player) { - float temp[2]; - if([self readAudio:temp frames:1] < 1) + if(![self readAudio]) return -1; } diff --git a/Plugins/Musepack/Musepack.xcodeproj/project.pbxproj b/Plugins/Musepack/Musepack.xcodeproj/project.pbxproj index a04724bbe..bb54d933a 100644 --- a/Plugins/Musepack/Musepack.xcodeproj/project.pbxproj +++ b/Plugins/Musepack/Musepack.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 1703330A0B8FB64500327265 /* MusepackDecoder.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MusepackDecoder.m; sourceTree = ""; }; 17F562570C3BD97B0019975C /* MPCDec.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MPCDec.xcodeproj; path = ../../Frameworks/MPCDec/MPCDec.xcodeproj; sourceTree = SOURCE_ROOT; }; 32DBCF630370AF2F00C91783 /* Musepack_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Musepack_Prefix.pch; sourceTree = ""; }; + 834A42BD287AFD0D00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747C1D2862DB560021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 838491311808190400E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* Musepack.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Musepack.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -105,6 +106,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42BD287AFD0D00EB9D9B /* AudioChunk.h */, 838491311808190400E7332D /* Logging.h */, 8E2B8B4A0B9B48D000F2D9E8 /* Plugin.h */, 170333090B8FB64500327265 /* MusepackDecoder.h */, diff --git a/Plugins/Musepack/MusepackDecoder.m b/Plugins/Musepack/MusepackDecoder.m index 263c3abdf..8cdf86fda 100644 --- a/Plugins/Musepack/MusepackDecoder.m +++ b/Plugins/Musepack/MusepackDecoder.m @@ -109,11 +109,15 @@ mpc_bool_t CanSeekProc(mpc_reader *p_reader) { return YES; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH]; + int frames = 1024; + float buffer[frames * 2]; + void *buf = (void *)buffer; + int framesRead = 0; - int bytesPerFrame = sizeof(float) * 2; // bitsPerSample == 16, channels == 2 + int bytesPerFrame = sizeof(float) * 2; // bitsPerSample == 32, channels == 2 while(framesRead < frames) { // Fill from buffer, going by bufferFrames // if still needs more, decode and repeat @@ -150,7 +154,11 @@ mpc_bool_t CanSeekProc(mpc_reader *p_reader) { } } - return framesRead; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:framesRead]; + + return chunk; } - (void)close { diff --git a/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj b/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj index 3ba706b64..993436f50 100644 --- a/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj +++ b/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ /* Begin PBXFileReference section */ 833A899B286FF3150022E036 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 834A42BE287AFDC300EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747C182862DB2F0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83E5EFA31FFEF78100659F0F /* OpenMPT.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenMPT.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 83E5EFA61FFEF78100659F0F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -124,6 +125,7 @@ 83E5FE6A1FFF003900659F0F /* Classes */ = { isa = PBXGroup; children = ( + 834A42BE287AFDC300EB9D9B /* AudioChunk.h */, 83E5FE6B1FFF004D00659F0F /* Logging.h */, 83E5FE761FFF076F00659F0F /* PlaylistController.h */, 83E5FE6C1FFF006400659F0F /* Plugin.h */, diff --git a/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm b/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm index db410f2b5..ca2226cda 100644 --- a/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm +++ b/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm @@ -112,9 +112,13 @@ static void g_push_archive_extensions(std::vector &list) { return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { mod->set_repeat_count(IsRepeatOneSet() ? -1 : 0); + int frames = 1024; + float buffer[frames * 2]; + void *buf = (void *)buffer; + int total = 0; while(total < frames) { int framesToRender = 1024; @@ -131,7 +135,11 @@ static void g_push_archive_extensions(std::vector &list) { break; } - return total; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:total]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/Opus/Opus/OpusDecoder.m b/Plugins/Opus/Opus/OpusDecoder.m index d625f9524..6c92cbaa3 100644 --- a/Plugins/Opus/Opus/OpusDecoder.m +++ b/Plugins/Opus/Opus/OpusDecoder.m @@ -222,7 +222,7 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va } } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { int numread; int total = 0; @@ -236,7 +236,10 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va [self updateMetadata]; } + int frames = 1024; int size = frames * channels; + float buffer[size]; + void *buf = (void *)buffer; do { float *out = ((float *)buf) + total; @@ -265,7 +268,11 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va [self updateIcyMetadata]; - return total / channels; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:total / channels]; + + return chunk; } - (void)close { diff --git a/Plugins/Opus/OpusPlugin.xcodeproj/project.pbxproj b/Plugins/Opus/OpusPlugin.xcodeproj/project.pbxproj index 40e6acad8..bbaf6262e 100644 --- a/Plugins/Opus/OpusPlugin.xcodeproj/project.pbxproj +++ b/Plugins/Opus/OpusPlugin.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 83186314285CEC91001422CC /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../../Utils/NSDictionary+Merge.h"; sourceTree = ""; }; 83186315285CEC91001422CC /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Merge.m"; path = "../../../Utils/NSDictionary+Merge.m"; sourceTree = ""; }; 833F68411CDBCABC00AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42BF287AFE2600EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8356BD1B27B469B80074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../../HTTPSource/HTTPSource.h; sourceTree = ""; }; 836EF0CE27BB952F00BF35B2 /* libopusfile.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libopusfile.0.dylib; path = ../../ThirdParty/opusfile/lib/libopusfile.0.dylib; sourceTree = ""; }; 83747C0E2862DAC70021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; @@ -114,6 +115,7 @@ 8375B04517FFEA400092A79F /* Opus */ = { isa = PBXGroup; children = ( + 834A42BF287AFE2600EB9D9B /* AudioChunk.h */, 83186314285CEC91001422CC /* NSDictionary+Merge.h */, 83186315285CEC91001422CC /* NSDictionary+Merge.m */, 8356BD1B27B469B80074E50C /* HTTPSource.h */, diff --git a/Plugins/Pls/Pls.xcodeproj/project.pbxproj b/Plugins/Pls/Pls.xcodeproj/project.pbxproj index 371a919ba..d2a06dea0 100644 --- a/Plugins/Pls/Pls.xcodeproj/project.pbxproj +++ b/Plugins/Pls/Pls.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 32DBCF630370AF2F00C91783 /* Pls_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pls_Prefix.pch; sourceTree = ""; }; 833F68381CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 834A42C0287AFEB100EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 835C889422CC1887001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 83747C092862DAA90021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 838491321808193F00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; @@ -75,6 +76,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42C0287AFEB100EB9D9B /* AudioChunk.h */, 838491321808193F00E7332D /* Logging.h */, 8E8D41A50CBB0CBE00135C1B /* Plugin.h */, 8E8D419F0CBB0CA700135C1B /* PlsContainer.h */, diff --git a/Plugins/Shorten/Shorten.xcodeproj/project.pbxproj b/Plugins/Shorten/Shorten.xcodeproj/project.pbxproj index 4050798ab..6bd680791 100644 --- a/Plugins/Shorten/Shorten.xcodeproj/project.pbxproj +++ b/Plugins/Shorten/Shorten.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 177FCFAC0B90C96B0011C3B5 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = SOURCE_ROOT; }; 17F563DD0C3BDBF10019975C /* Shorten.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Shorten.xcodeproj; path = ../../Frameworks/Shorten/Shorten.xcodeproj; sourceTree = SOURCE_ROOT; }; 32DBCF630370AF2F00C91783 /* Shorten_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shorten_Prefix.pch; sourceTree = ""; }; + 834A42A9287AEF1300EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747C042862DA780021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* Shorten.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Shorten.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -104,6 +105,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42A9287AEF1300EB9D9B /* AudioChunk.h */, 177FCFAC0B90C96B0011C3B5 /* Plugin.h */, 1745C42B0B90C1DC00A6768C /* ShortenDecoder.h */, 1745C42C0B90C1DC00A6768C /* ShortenDecoder.mm */, diff --git a/Plugins/Shorten/ShortenDecoder.mm b/Plugins/Shorten/ShortenDecoder.mm index 222cc3ee6..f1fa809c8 100644 --- a/Plugins/Shorten/ShortenDecoder.mm +++ b/Plugins/Shorten/ShortenDecoder.mm @@ -41,16 +41,25 @@ return YES; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + long frames = 1024; long bytesPerFrame = channels * (bitsPerSample / 8); long amountRead; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + + uint8_t buffer[bytesPerFrame * 1024]; + void *buf = (void *)buffer; + // For some reason a busy loop is causing pops when output is set to 48000. Probably CPU starvation, since the SHN decoder seems to use a multithreaded nonblocking approach. do { amountRead = decoder->read(buf, frames * bytesPerFrame); } while(amountRead == -1); - return (int)(amountRead / bytesPerFrame); + [chunk assignSamples:buf frameCount:amountRead / bytesPerFrame]; + + return chunk; } - (long)seek:(long)sample { diff --git a/Plugins/SilenceDecoder/SilenceDecoder.xcodeproj/project.pbxproj b/Plugins/SilenceDecoder/SilenceDecoder.xcodeproj/project.pbxproj index c68a1b3a9..d48a77452 100644 --- a/Plugins/SilenceDecoder/SilenceDecoder.xcodeproj/project.pbxproj +++ b/Plugins/SilenceDecoder/SilenceDecoder.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 834A42C1287AFED700EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747BFA2862D95C0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83F9D7E71A884B44007ABEC2 /* SilenceDecoder.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SilenceDecoder.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 83F9D7EB1A884B44007ABEC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -64,6 +65,7 @@ 83F9D7E91A884B44007ABEC2 /* SilenceDecoder */ = { isa = PBXGroup; children = ( + 834A42C1287AFED700EB9D9B /* AudioChunk.h */, 83F9D8091A884CB5007ABEC2 /* Logging.h */, 83F9D8081A884C93007ABEC2 /* Plugin.h */, 83F9D8041A884C23007ABEC2 /* PlaylistController.h */, diff --git a/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m b/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m index b049dc5cd..a7a1b4e17 100644 --- a/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m +++ b/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m @@ -50,7 +50,11 @@ enum { channels = 2 }; return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + int frames = 1024; + float buffer[frames * channels]; + void *buf = (void *)buffer; + int total = frames; if(!IsRepeatOneSet()) { @@ -62,7 +66,11 @@ enum { channels = 2 }; memset(buf, 0, sizeof(float) * total * channels); - return total; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:total]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/TagLib/TagLib.xcodeproj/project.pbxproj b/Plugins/TagLib/TagLib.xcodeproj/project.pbxproj index e173e3b13..7f142aac0 100644 --- a/Plugins/TagLib/TagLib.xcodeproj/project.pbxproj +++ b/Plugins/TagLib/TagLib.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 17F563B40C3BDBB30019975C /* TagLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17F563A60C3BDB8F0019975C /* TagLib.framework */; }; 17F563B60C3BDBB50019975C /* TagLib.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17F563A60C3BDB8F0019975C /* TagLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8307D31D286072BF000FF8EB /* SandboxBroker.h in Headers */ = {isa = PBXBuildFile; fileRef = 8307D31C286072BF000FF8EB /* SandboxBroker.h */; }; + 834A42C3287AFF5E00EB9D9B /* AudioChunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 834A42C2287AFF5E00EB9D9B /* AudioChunk.h */; }; 8356BCE527B377C20074E50C /* TagLibID3v2Reader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8356BCE327B377C20074E50C /* TagLibID3v2Reader.h */; }; 8356BCE627B377C20074E50C /* TagLibID3v2Reader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8356BCE427B377C20074E50C /* TagLibID3v2Reader.mm */; }; 8384913A18081FFC00E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384913918081FFC00E7332D /* Logging.h */; }; @@ -60,6 +61,7 @@ 17F563A00C3BDB8F0019975C /* TagLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TagLib.xcodeproj; path = ../../Frameworks/TagLib/TagLib.xcodeproj; sourceTree = SOURCE_ROOT; }; 32DBCF630370AF2F00C91783 /* TagLib_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagLib_Prefix.pch; sourceTree = ""; }; 8307D31C286072BF000FF8EB /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../Utils/SandboxBroker.h; sourceTree = ""; }; + 834A42C2287AFF5E00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8356BCE327B377C20074E50C /* TagLibID3v2Reader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TagLibID3v2Reader.h; sourceTree = ""; }; 8356BCE427B377C20074E50C /* TagLibID3v2Reader.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TagLibID3v2Reader.mm; sourceTree = ""; }; 83747BF52862D9470021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; @@ -115,6 +117,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42C2287AFF5E00EB9D9B /* AudioChunk.h */, 8307D31C286072BF000FF8EB /* SandboxBroker.h */, 8384913918081FFC00E7332D /* Logging.h */, 07CACE890ED1AD1000C0F1E8 /* TagLibMetadataWriter.h */, @@ -188,6 +191,7 @@ buildActionMask = 2147483647; files = ( 8384913A18081FFC00E7332D /* Logging.h in Headers */, + 834A42C3287AFF5E00EB9D9B /* AudioChunk.h in Headers */, 8307D31D286072BF000FF8EB /* SandboxBroker.h in Headers */, 8356BCE527B377C20074E50C /* TagLibID3v2Reader.h in Headers */, ); diff --git a/Plugins/Vorbis/VorbisDecoder.m b/Plugins/Vorbis/VorbisDecoder.m index 410ed5641..a89b0e770 100644 --- a/Plugins/Vorbis/VorbisDecoder.m +++ b/Plugins/Vorbis/VorbisDecoder.m @@ -200,9 +200,10 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va } } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { int numread; int total = 0; + int frames = 1024; if(currentSection != lastSection) { vorbis_info *vi; @@ -218,6 +219,12 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va [self updateMetadata]; } + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + + float buffer[frames * channels]; + void *buf = (void *)buffer; + do { lastSection = currentSection; float **pcm; @@ -247,7 +254,9 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va [self updateIcyMetadata]; - return total; + [chunk assignSamples:buffer frameCount:total]; + + return chunk; } - (void)close { diff --git a/Plugins/Vorbis/VorbisPlugin.xcodeproj/project.pbxproj b/Plugins/Vorbis/VorbisPlugin.xcodeproj/project.pbxproj index a55517f99..68ac88223 100644 --- a/Plugins/Vorbis/VorbisPlugin.xcodeproj/project.pbxproj +++ b/Plugins/Vorbis/VorbisPlugin.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 8301C14A287810F300651A6E /* libFLAC.8.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libFLAC.8.dylib; path = ../../ThirdParty/flac/lib/libFLAC.8.dylib; sourceTree = ""; }; 83186311285CEBD2001422CC /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../Utils/NSDictionary+Merge.h"; sourceTree = ""; }; 83186312285CEBD2001422CC /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Merge.m"; path = "../../Utils/NSDictionary+Merge.m"; sourceTree = ""; }; + 834A42AB287AF0B000EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 8356BD1C27B46A2D0074E50C /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = ""; }; 836EF0D427BB969D00BF35B2 /* libvorbisfile.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libvorbisfile.3.dylib; path = ../../ThirdParty/vorbis/lib/libvorbisfile.3.dylib; sourceTree = ""; }; 836EF0DE27BB987000BF35B2 /* libvorbis.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libvorbis.0.dylib; path = ../../ThirdParty/vorbis/lib/libvorbis.0.dylib; sourceTree = ""; }; @@ -92,6 +93,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42AB287AF0B000EB9D9B /* AudioChunk.h */, 83186311285CEBD2001422CC /* NSDictionary+Merge.h */, 83186312285CEBD2001422CC /* NSDictionary+Merge.m */, 8356BD1C27B46A2D0074E50C /* HTTPSource.h */, diff --git a/Plugins/WavPack/WavPack.xcodeproj/project.pbxproj b/Plugins/WavPack/WavPack.xcodeproj/project.pbxproj index 81002ed8b..16a29f5dd 100644 --- a/Plugins/WavPack/WavPack.xcodeproj/project.pbxproj +++ b/Plugins/WavPack/WavPack.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 177FCF940B90C9450011C3B5 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = SOURCE_ROOT; }; 17F562C20C3BDA5A0019975C /* WavPack.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = WavPack.xcodeproj; path = ../../Frameworks/WavPack/WavPack.xcodeproj; sourceTree = SOURCE_ROOT; }; 32DBCF630370AF2F00C91783 /* WavPack_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WavPack_Prefix.pch; sourceTree = ""; }; + 834A42AA287AEFC300EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 83747BE62862D8D60021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83849133180819EB00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* WavPack.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WavPack.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -105,6 +106,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42AA287AEFC300EB9D9B /* AudioChunk.h */, 83849133180819EB00E7332D /* Logging.h */, 177FCF940B90C9450011C3B5 /* Plugin.h */, 1745C4D50B90C42500A6768C /* WavPackDecoder.h */, diff --git a/Plugins/WavPack/WavPackDecoder.m b/Plugins/WavPack/WavPackDecoder.m index 8b6b8e2e1..99d41b5c1 100644 --- a/Plugins/WavPack/WavPackDecoder.m +++ b/Plugins/WavPack/WavPackDecoder.m @@ -196,7 +196,12 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) { return n; } */ -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + int32_t frames = 1024; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + uint32_t sample; int32_t audioSample; uint32_t samplesRead; @@ -204,6 +209,10 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) { int16_t *alias16; int32_t *alias32; + const size_t bufferSize = frames * [chunk format].mBytesPerFrame; + uint8_t buffer[bufferSize]; + void *buf = (void *)buffer; + size_t newSize = frames * sizeof(int32_t) * channels; if(!inputBuffer || newSize > inputBufferSize) { inputBuffer = realloc(inputBuffer, inputBufferSize = newSize); @@ -248,7 +257,9 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) { ALog(@"Unsupported sample size: %d", bitsPerSample); } - return samplesRead; + [chunk assignSamples:buffer frameCount:samplesRead]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/libvgmPlayer/libvgmDecoder.mm b/Plugins/libvgmPlayer/libvgmDecoder.mm index 0c88639c4..61c45267b 100644 --- a/Plugins/libvgmPlayer/libvgmDecoder.mm +++ b/Plugins/libvgmPlayer/libvgmDecoder.mm @@ -208,9 +208,18 @@ const int masterVol = 0x10000; // Fixed point 16.16 return @{}; } -- (int)readAudio:(void*)buf frames:(UInt32)frames { +- (AudioChunk*)readAudio { if([self trackEnded]) - return 0; + return nil; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk* chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + + int frames = 1024; + const size_t bytesPerFrame = [chunk format].mBytesPerFrame; + uint8_t buffer[frames * bytesPerFrame]; + + void* buf = (void*)buffer; BOOL repeatOne = IsRepeatOneSet(); uint32_t maxLoops = repeatOne ? 0 : (uint32_t)loopCount; @@ -238,7 +247,9 @@ const int masterVol = 0x10000; // Fixed point 16.16 framesDone += framesToDo; } - return framesDone; + [chunk assignSamples:buffer frameCount:framesDone]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj b/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj index 7bde5bb11..71abb71c4 100644 --- a/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj +++ b/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ 83489C602782F39D00BDCEA2 /* libvgm-player.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libvgm-player.a"; path = "../../ThirdParty/libvgm/lib/libvgm-player.a"; sourceTree = ""; }; 83489C652782F74800BDCEA2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 83489C672782F74E00BDCEA2 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; + 834A42AC287AF18E00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 835C888F22CC1883001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 83747C312862DBE80021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8384912E1808175400E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; @@ -102,6 +103,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 834A42AC287AF18E00EB9D9B /* AudioChunk.h */, 17C8F33B0CBED3BE008D969D /* libvgmContainer.h */, 17C8F33C0CBED3BE008D969D /* libvgmContainer.mm */, 17C8F33D0CBED3BE008D969D /* libvgmDecoder.h */, diff --git a/Plugins/sidplay/SidDecoder.mm b/Plugins/sidplay/SidDecoder.mm index 7c18ca2d8..3ef8a6668 100644 --- a/Plugins/sidplay/SidDecoder.mm +++ b/Plugins/sidplay/SidDecoder.mm @@ -62,7 +62,7 @@ static const char *extListStr[] = { ".str", NULL }; - (sid_file_container *)init { if((self = [super init])) { lock = [[NSLock alloc] init]; - list = [[NSMutableDictionary alloc] initWithCapacity:0]; + list = [[NSMutableDictionary alloc] init]; } return self; } @@ -275,59 +275,54 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { int total = 0; - int16_t *sampleBuffer = (int16_t *)buf; - while(total < frames) { - int framesToRender = 1024; - if(framesToRender > frames) - framesToRender = frames; - int rendered = engine->play(sampleBuffer + total * n_channels, framesToRender * n_channels) / n_channels; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; - if(rendered <= 0) - break; + int16_t buffer[1024 * n_channels]; - if(n_channels == 2) { - for(int i = 0, j = rendered * 2; i < j; i += 2) { - int16_t *sample = sampleBuffer + total * 2 + i; - int mid = (int)(sample[0] + sample[1]) / 2; - int side = (int)(sample[0] - sample[1]) / 4; - sample[0] = mid + side; - sample[1] = mid - side; - } + int framesToRender = 1024; + int rendered = engine->play(buffer, framesToRender * n_channels) / n_channels; + + if(rendered <= 0) + return nil; + + if(n_channels == 2) { + for(int i = 0, j = rendered * 2; i < j; i += 2) { + int16_t *sample = buffer + total * 2 + i; + int mid = (int)(sample[0] + sample[1]) / 2; + int side = (int)(sample[0] - sample[1]) / 4; + sample[0] = mid + side; + sample[1] = mid - side; } - - renderedTotal += rendered; - - if(!IsRepeatOneSet() && renderedTotal >= length) { - int16_t *sampleBuf = (int16_t *)buf + total * n_channels; - long fadeEnd = fadeRemain - rendered; - if(fadeEnd < 0) - fadeEnd = 0; - float fadePosf = (float)fadeRemain / (float)fadeTotal; - const float fadeStep = 1.0f / (float)fadeTotal; - for(long fadePos = fadeRemain; fadePos > fadeEnd; --fadePos, fadePosf -= fadeStep) { - long offset = (fadeRemain - fadePos) * n_channels; - float sampleLeft = sampleBuf[offset + 0]; - sampleLeft *= fadePosf; - sampleBuf[offset + 0] = (int16_t)sampleLeft; - if(n_channels == 2) { - float sampleRight = sampleBuf[offset + 1]; - sampleRight *= fadePosf; - sampleBuf[offset + 1] = (int16_t)sampleRight; - } - } - rendered = (int)(fadeRemain - fadeEnd); - fadeRemain = fadeEnd; - } - - total += rendered; - - if(rendered < framesToRender) - break; } - return total; + if(!IsRepeatOneSet() && renderedTotal >= length) { + int16_t *sampleBuf = buffer; + long fadeEnd = fadeRemain - rendered; + if(fadeEnd < 0) + fadeEnd = 0; + float fadePosf = (float)fadeRemain / (float)fadeTotal; + const float fadeStep = 1.0f / (float)fadeTotal; + for(long fadePos = fadeRemain; fadePos > fadeEnd; --fadePos, fadePosf -= fadeStep) { + long offset = (fadeRemain - fadePos) * n_channels; + float sampleLeft = sampleBuf[offset + 0]; + sampleLeft *= fadePosf; + sampleBuf[offset + 0] = (int16_t)sampleLeft; + if(n_channels == 2) { + float sampleRight = sampleBuf[offset + 1]; + sampleRight *= fadePosf; + sampleBuf[offset + 1] = (int16_t)sampleRight; + } + } + rendered = (int)(fadeRemain - fadeEnd); + fadeRemain = fadeEnd; + } + + [chunk assignSamples:buffer frameCount:rendered]; + + return chunk; } - (long)seek:(long)frame { diff --git a/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj b/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj index c7274937a..f9bda9b1b 100644 --- a/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj +++ b/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 8314D80D1A35658C00EEE8E6 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../../Utils/Logging.h; sourceTree = ""; }; 8314D80E1A3565AC00EEE8E6 /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = ""; }; 833A8996286FF2E30022E036 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 834A42A6287AEAAB00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 836F5BEA1A357915002730CC /* roms.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = roms.cpp; sourceTree = SOURCE_ROOT; }; 836F5BEB1A357915002730CC /* roms.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = roms.hpp; sourceTree = SOURCE_ROOT; }; 83747BFF2862DA420021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; @@ -92,6 +93,7 @@ 8314D6331A354DFE00EEE8E6 /* sidplay */ = { isa = PBXGroup; children = ( + 834A42A6287AEAAB00EB9D9B /* AudioChunk.h */, 836F5BEA1A357915002730CC /* roms.cpp */, 836F5BEB1A357915002730CC /* roms.hpp */, 8314D80E1A3565AC00EEE8E6 /* PlaylistController.h */, diff --git a/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj index 483427a91..51c581829 100644 --- a/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj +++ b/Plugins/vgmstream/vgmstream.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 833F68491CDBCAC000AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; 8340888B1F6F604A00DCD404 /* VGMMetadataReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VGMMetadataReader.m; sourceTree = ""; }; 8340888D1F6F604B00DCD404 /* VGMMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VGMMetadataReader.h; sourceTree = ""; }; + 834A42A8287AEDFB00EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../../Audio/Chain/AudioChunk.h; sourceTree = ""; }; 835D241E235AB318009A1251 /* VGMPropertiesReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VGMPropertiesReader.m; sourceTree = ""; }; 835D241F235AB319009A1251 /* VGMPropertiesReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VGMPropertiesReader.h; sourceTree = ""; }; 836F6B1018BDB80D0095E648 /* vgmstream.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = vgmstream.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -141,6 +142,7 @@ 836F705A18BDC40E0095E648 /* VGMDecoder.h */, 836F705B18BDC40E0095E648 /* VGMDecoder.m */, 83AA5D2F1F6E301B0020821C /* Logging.h */, + 834A42A8287AEDFB00EB9D9B /* AudioChunk.h */, 836F706018BDC84D0095E648 /* Plugin.h */, 836F6B1A18BDB80D0095E648 /* Supporting Files */, ); diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index 5f49855c4..39355d33e 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -311,10 +311,17 @@ static NSString *get_description_tag(const char *description, const char *tag, c return @{}; } -- (int)readAudio:(void *)buf frames:(UInt32)frames { +- (AudioChunk *)readAudio { + UInt32 frames = 1024; UInt32 framesMax = frames; UInt32 framesDone = 0; + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + + int16_t buffer[1024 * channels]; + void *buf = (void *)buffer; + if(canPlayForever) { BOOL repeatone = IsRepeatOneSet(); @@ -354,7 +361,9 @@ static NSString *get_description_tag(const char *description, const char *tag, c frames -= frames_to_do; } - return framesDone; + [chunk assignSamples:buffer frameCount:framesDone]; + + return chunk; } - (long)seek:(long)frame {